diff --git a/apache-rat-core/src/it/java/org/apache/rat/ReportTest.java b/apache-rat-core/src/it/java/org/apache/rat/ReportTest.java index b695134a6..10f457b9d 100644 --- a/apache-rat-core/src/it/java/org/apache/rat/ReportTest.java +++ b/apache-rat-core/src/it/java/org/apache/rat/ReportTest.java @@ -80,15 +80,27 @@ * associated with the exception. * */ -public class ReportTest { +class ReportTest { + /** + * Converts an argument lists to an argument array. + * @param argsList the list to convert. + * @return the array of arguments. + */ private String[] asArgs(final List argsList) { return argsList.toArray(new String[0]); } + /** + * Runs the commands specified by the `commandLine.txt` file in the `resources/ReportTest/*` directories + * and validates the results using the {@code verify.groovy} file in the test directory. + * @param testName the name of the test based on the directory the test was found in. + * @param commandLineDoc the document that is the command line. + * @throws Exception on execution error. + */ @ParameterizedTest(name = "{index} {0}") - @MethodSource("args") - public void integrationTest(String testName, Document commandLineDoc) throws Exception { + @MethodSource("integrationTestData") + void integrationTest(String testName, Document commandLineDoc) throws Exception { DefaultLog.getInstance().log(Log.Level.INFO, "Running test for " + testName); File baseDir = new File(commandLineDoc.getName().getName()).getParentFile(); @@ -119,9 +131,11 @@ public void integrationTest(String testName, Document commandLineDoc) throws Exc File expectedMsg = new File(baseDir, "expected-message.txt"); if (expectedMsg.exists()) { - String msg = IOUtils.readLines(new FileReader(expectedMsg)).get(0).trim(); - assertThrows(RatDocumentAnalysisException.class, () -> Report.main(asArgs(argsList)), - msg); + try (FileReader fr = new FileReader(expectedMsg)) { + String msg = IOUtils.readLines(fr).get(0).trim(); + assertThrows(RatDocumentAnalysisException.class, () -> Report.main(asArgs(argsList)), + msg); + } } else { Report.main(asArgs(argsList)); } @@ -142,15 +156,21 @@ public void integrationTest(String testName, Document commandLineDoc) throws Exc try { Object value = shell.run(groovyScript, new String[]{outputFile.getAbsolutePath(), logFile.getAbsolutePath()}); if (value != null) { - fail(String.format("%s", value)); + fail(testName + ": " + value); } } catch (AssertionError e) { - throw new AssertionError(String.format("%s: %s", testName, e.getMessage()), e); + throw new AssertionError(testName + ": " + e.getMessage(), e); } } } - static Stream args() throws RatException { + /** + * Reads each directory under the ReportTest directory in the test resources and creates a test from it. + * The {@code commandLine.txt} file is parsed to create the command line to execute the tests. + * @return a stream of arguments for each test case. + * @throws RatException on parsing error. + */ + static Stream integrationTestData() throws RatException { List results = new ArrayList<>(); URL url = ReportTest.class.getResource("/ReportTest"); @@ -170,11 +190,11 @@ static Stream args() throws RatException { DirectoryWalker walker = new DirectoryWalker(document); RatReport report = new RatReport() { @Override - public void report(Document document) { - if (!document.isIgnored()) { - String[] tokens = DocumentName.FSInfo.getDefault().tokenize(document.getName().localized()); - results.add(Arguments.of(tokens[1], document)); - } + public void report(Document document) { + if (!document.isIgnored()) { + String[] tokens = DocumentName.FSInfo.getDefault().tokenize(document.getName().localized()); + results.add(Arguments.of(tokens[1], document)); + } } }; walker.run(report); @@ -185,25 +205,27 @@ public void report(Document document) { * Log that captures output for later review. */ public static class FileLog implements Log { - + /** + * The output from the log. + */ private final PrintStream logFile; /** - * The level at which we will write messages + * The level at which we will write messages. */ private Level level; + /** + * Constructor to write at level {@code INFO}. + * @param logFile the file to write to. + * @throws IOException on error. + */ FileLog(File logFile) throws IOException { this.logFile = new PrintStream(logFile); level = Level.INFO; } - /** - * Sets the level.Log messages below the specified level will - * not be written to the log. - * - * @param level the level to use when writing messages. - */ + @Override public void setLevel(final Level level) { this.level = level; } @@ -220,6 +242,9 @@ public void log(Level level, String msg) { } } + /** + * Closes the log file. + */ public void close() { logFile.close(); } diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_406/commandLine.txt b/apache-rat-core/src/it/resources/ReportTest/RAT_406/commandLine.txt index 0d6433f57..cec3b5e30 100644 --- a/apache-rat-core/src/it/resources/ReportTest/RAT_406/commandLine.txt +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_406/commandLine.txt @@ -1,2 +1,3 @@ --licenses-denied DOJO +-- 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 a17077e8c..2434dbefa 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 @@ -104,6 +104,10 @@ public enum Processing { */ private final String description; + /** + * Constructor. + * @param description the description for this processing strategy + */ Processing(final String description) { this.description = description; } @@ -139,7 +143,7 @@ public String desc() { /** * The IODescriptor that provides the output stream to write the report to. */ - private IODescriptor out; + private IODescriptor outputDescriptor; /** * The IODescriptor that provides the stylesheet to style the XML output. @@ -205,6 +209,10 @@ public ReportConfiguration() { reportables = new ArrayList<>(); } + /** + * A serializer/deserializer for a ReportConfiguration. + * @return the serializer/deserializer for a ReportConfiguration. + */ public SerDes serDes() { return new SerDes(); } @@ -227,14 +235,21 @@ public void reportExclusions(final Appendable appendable) { * File within the file must be in linux format with a * {@code "/"} file separator. * @param file the file to process. + * @throws ConfigurationException if the file is {@code null}. */ public void addSource(final File file) { notNull(file, "File may not be null."); sources.add(file); } - private void notNull(final Object o, final String msg) { - if (o == null) { + /** + * Throws ConfigurationException if the object is {@code null}. + * @param object the object to test. + * @param msg the message to create the exception with. + * @throws ConfigurationException if the object is {@code null}. + */ + private void notNull(final Object object, final String msg) { + if (object == null) { throw new ConfigurationException(msg); } } @@ -242,6 +257,7 @@ private void notNull(final Object o, final String msg) { /** * Adds a Reportable as a source of files to scan. * @param reportable the reportable to process. + * @throws ConfigurationException if the reportable is {@code null}. */ public void addSource(final Reportable reportable) { notNull(reportable, "Reportable may not be null."); @@ -257,8 +273,8 @@ public boolean hasSource() { } /** - * Gets a builder initialized with any files specified as sources. - * @return a configured builder. + * Gets a ReportListWalker.Builder initialized with any files specified as sources. + * @return a configured ReportListWalker.Builder. */ public ReportableListWalker.Builder getSources() { DocumentName name = DocumentName.builder(new File(".")).build(); @@ -527,7 +543,7 @@ public void setStyleSheet(final IODescriptor styleSheet) { */ public void setFrom(final Defaults defaults) { licenseSetFactory.add(defaults.getLicenseSetFactory()); - if (getStyleSheet() == null) { + if (getStyleSheetDescriptor() == null) { setStyleSheet(StyleSheets.PLAIN.getStyleSheet()); } defaults.getStandardExclusion().forEach(this::addExcludedCollection); @@ -571,22 +587,22 @@ public void setStyleSheet(final URL styleSheet) { * times to provide the stream. Suppliers should prepare streams that are * 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 + * @param outputDescriptor the OutputStream supplier that provides the output stream to write. * the report to. A {@code null} value will use {@code System.out}. * @see CloseShieldOutputStream */ - public void setOut(final IODescriptor out) { - this.out = out; + public void setOutput(final IODescriptor outputDescriptor) { + this.outputDescriptor = outputDescriptor; } /** * Sets the OutputStream supplier to use the specified file. The file may be * opened and closed several times. File is deleted first and then may be * repeatedly opened in append mode. - * @see #setOut(IODescriptor) + * @see #setOutput(IODescriptor) * @param file The file to create the supplier with. */ - public void setOut(final File file) { + public void setOutput(final File file) { Objects.requireNonNull(file, "output file should not be null"); if (file.exists()) { try { @@ -600,7 +616,7 @@ public void setOut(final File file) { if (!parent.mkdirs() && !parent.isDirectory()) { DefaultLog.getInstance().warn("Unable to create directory: " + file.getParentFile()); } - setOut(IODescriptor.output(file)); + setOutput(IODescriptor.output(file)); } /** @@ -618,7 +634,7 @@ public IOSupplier getOutput() { * @return the IODescriptor of the output stream to write the report to. */ public IODescriptor getOutputDescriptor() { - return out == null ? SYSTEM_OUT : out; + return outputDescriptor == null ? SYSTEM_OUT : outputDescriptor; } /** @@ -982,7 +998,7 @@ public void serialize(final Appendable appendable) throws IOException { .attribute("archiveProcessing", getArchiveProcessing().name()) .attribute("standardProcessing", getStandardProcessing().name()) .attribute("stylesheet", styleSheet.name()) - .attribute("output", out.name()); + .attribute("output", outputDescriptor.name()); if (StringUtils.isNotEmpty(copyrightMessage)) { writer.startElement("copyrightMessage").content(copyrightMessage).closeElement(); } @@ -1015,6 +1031,13 @@ public void serialize(final Appendable appendable) throws IOException { } } + /** + * Reads an input stream as an XML document and parses the report configuration from that. + * Note: The reportable objects (Files) in a deserialized ReportConfigurations are not executable. + * @param inputStreamSupplier The XML document written by {@link #serialize(Appendable)} + * @param workingDirectory the directory to resolve short XSLT and output names from. + * @throws IOException on parse error. + */ public void deserialize(final IOSupplier inputStreamSupplier, final DocumentName workingDirectory) throws IOException { org.w3c.dom.Document document; try (InputStream stream = inputStreamSupplier.get()) { @@ -1036,14 +1059,14 @@ public void deserialize(final IOSupplier inputStreamSupplier, final standardProcessing = Processing.valueOf(attributes.get("standardProcessing")); String styleName = attributes.get("stylesheet"); if (styleName != null) { - styleSheet = StyleSheets.getStyleSheet(styleName); + styleSheet = StyleSheets.getStyleSheet(styleName, workingDirectory); } String outputName = attributes.get("output"); if (outputName != null) { if (outputName.equals(ReportConfiguration.SYSTEM_OUT.name())) { - out = ReportConfiguration.SYSTEM_OUT; + outputDescriptor = ReportConfiguration.SYSTEM_OUT; } else { - out = IODescriptor.output(outputName, workingDirectory); + outputDescriptor = IODescriptor.output(outputName, workingDirectory); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/commandline/Arg.java b/apache-rat-core/src/main/java/org/apache/rat/commandline/Arg.java index d1378f119..96ffa1070 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/commandline/Arg.java +++ b/apache-rat-core/src/main/java/org/apache/rat/commandline/Arg.java @@ -165,7 +165,6 @@ public enum Arg { .build()), (context, selected) -> context.getConfiguration().addApprovedLicenseIds(context.getParsedOptionValue(selected)) - ), /** @@ -515,14 +514,14 @@ public enum Arg { if ("x".equals(key)) { // display deprecated message. context.hasOption("x"); - context.getConfiguration().setStyleSheet(StyleSheets.getStyleSheet("xml")); + context.getConfiguration().setStyleSheet(StyleSheets.getStyleSheet("xml", context.getWorkingDirectory())); } else { List style = context.getOptionValues(selected); if (style.size() != 1) { DefaultLog.getInstance().error("Please specify a single stylesheet"); throw new ConfigurationException("Please specify a single stylesheet"); } - context.getConfiguration().setStyleSheet(StyleSheets.getStyleSheet(style.get(0))); + context.getConfiguration().setStyleSheet(StyleSheets.getStyleSheet(style.get(0), context.getWorkingDirectory())); } }), @@ -597,7 +596,7 @@ public enum Arg { .build()), (context, selected) -> { DocumentName documentName = context.getParsedOptionValue(selected, () -> { - context.getConfiguration().setOut(ReportConfiguration.SYSTEM_OUT); + context.getConfiguration().setOutput(ReportConfiguration.SYSTEM_OUT); return null; }); if (documentName != null) { @@ -606,7 +605,7 @@ public enum Arg { if (!parent.mkdirs() && !parent.isDirectory()) { DefaultLog.getInstance().error("Could not create report parent directory " + documentName); } - context.getConfiguration().setOut(document); + context.getConfiguration().setOutput(document); } }), diff --git a/apache-rat-core/src/main/java/org/apache/rat/commandline/Converters.java b/apache-rat-core/src/main/java/org/apache/rat/commandline/Converters.java index becbbcfcf..0fd435a7b 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/commandline/Converters.java +++ b/apache-rat-core/src/main/java/org/apache/rat/commandline/Converters.java @@ -41,12 +41,12 @@ private Converters() { } /** - * Creates a File with fully qualified name. + * Creates a file with fully qualified name. */ public static final FileConverter FILE_CONVERTER = new FileConverter(); /** - * Converts the Converter pattern into a Converter, count pair. + * Converts the converter pattern into a pair of Converter and count. */ public static final Converter, ConfigurationException> COUNTER_CONVERTER = arg -> { String[] parts = arg.split(":"); @@ -98,7 +98,7 @@ public void setWorkingDirectory(final DocumentName workingDirectory) { * Applies the conversion function to the specified file name. * @param fileName the file name to create a file from. * @return the DocumentName - * @throws NullPointerException if {@code fileName} is null. + * @throws NullPointerException if given {@code fileName} is null. */ public DocumentName apply(final String fileName) throws NullPointerException { DocumentName.FSInfo fsInfo = workingDirectory.fsInfo(); @@ -117,7 +117,7 @@ public DocumentName apply(final String fileName) throws NullPointerException { } else { builder.setBaseName(workingDirectory); } - return builder.setName(normalizedFileName).build(); + return builder.setName(normalizedFileName).build(); } } } 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 ea0c11133..dc716a8e2 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 @@ -21,12 +21,11 @@ import java.io.InputStream; import java.net.URL; import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Objects; import org.apache.rat.ConfigurationException; import org.apache.rat.ReportConfiguration; +import org.apache.rat.document.DocumentName; import static java.lang.String.format; @@ -49,8 +48,11 @@ public enum StyleSheets { /** * The pretty-printed XML style sheet. */ - XML("xml", "Produces output in pretty-printed XML."); - + XML("xml", "Produces output in pretty-printed XML."), + /** + * Official HTML5 stylesheet. + */ + XHTML5("xhtml5", "Produces a HTML5 report."); /** * The name of the style sheet. Must map to bundled resource XSLT file */ @@ -73,6 +75,7 @@ public enum StyleSheets { /** * Gets the IODescriptor for a style sheet. * @return an IODescriptor for the sheet. + * @throws NullPointerException if the name can not be resolved. */ public ReportConfiguration.IODescriptor getStyleSheet() { URL url = StyleSheets.class.getClassLoader().getResource(format("org/apache/rat/%s.xsl", name)); @@ -83,18 +86,20 @@ public ReportConfiguration.IODescriptor getStyleSheet() { /** * Gets the IODescriptor for a style sheet. * @param name the short name for or the path to a style sheet. + * @param workingDirectory the working directory to resolve the name against. * @return the IODescriptor for the style sheet. + * @throws ConfigurationException if the style sheet can not be found. */ - public static ReportConfiguration.IODescriptor getStyleSheet(final String name) { + public static ReportConfiguration.IODescriptor getStyleSheet(final String name, final DocumentName workingDirectory) { URL url = StyleSheets.class.getClassLoader().getResource(format("org/apache/rat/%s.xsl", name)); if (url != null) { return new ReportConfiguration.IODescriptor<>(name, url::openStream); } - Path p = Paths.get(name); - if (p.toFile().exists()) { - return new ReportConfiguration.IODescriptor<>(name, () -> Files.newInputStream(p)); + DocumentName xslt = workingDirectory.resolve(name); + if (xslt.asFile().exists()) { + return new ReportConfiguration.IODescriptor<>(xslt.toString(), () -> Files.newInputStream(xslt.asFile().toPath())); } - throw new ConfigurationException(format("Stylesheet file '%s' not found", name)); + throw new ConfigurationException(format("Stylesheet file '%s' not found: %s", name, xslt.getName())); } /** 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 d57e21181..d5610ec9f 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 @@ -66,7 +66,7 @@ public class ExclusionProcessor { private final Set excludedCollections; /** The last generated PathMatcher */ private DocumentNameMatcher lastMatcher; - /** The base dir for the last PathMatcher */ + /** The base document name for the last PathMatcher */ private DocumentName lastMatcherBaseDir; /** @@ -86,7 +86,8 @@ public SerDes serDes() { return new SerDes(); } - /* the following set of methods are here for testing purposes */ + // START OF TESTING PURPOSES methods + // visible for testing Set getExcludedPatterns() { return new HashSet<>(excludedPatterns); } @@ -122,6 +123,7 @@ DocumentNameMatcher getLastMatcher() { DocumentName getLastMatcherBaseDir() { return lastMatcherBaseDir; } + // END OF TESTING PURPOSES methods /** * Reset the {@link #lastMatcher} and {@link #lastMatcherBaseDir} to start again. @@ -132,15 +134,15 @@ private void resetLastMatcher() { } /** - * Add the iterable of strings to the collection of file/directory patters to ignore. + * Add the iterable of strings to the collection of file/directory patterns 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(); + DefaultLog.getInstance().debug(format("Including patterns: %s", String.join(", ", patterns))); + patterns.forEach(includedPatterns::add); + resetLastMatcher(); } return this; } @@ -193,9 +195,9 @@ public ExclusionProcessor addIncludedCollection(final StandardCollection collect */ public ExclusionProcessor addExcludedPatterns(final Iterable patterns) { if (patterns != null) { - DefaultLog.getInstance().debug(format("Excluding patterns: %s", String.join(", ", patterns))); - patterns.forEach(excludedPatterns::add); - resetLastMatcher(); + DefaultLog.getInstance().debug(format("Excluding patterns: %s", String.join(", ", patterns))); + patterns.forEach(excludedPatterns::add); + resetLastMatcher(); } return this; } diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryDocument.java b/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryDocument.java deleted file mode 100644 index dabc848bc..000000000 --- a/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryDocument.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 * - * * - * http://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.document; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.Collections; -import java.util.SortedSet; - -import org.apache.rat.api.Document; - -/** - * A Document that wraps an Archive entry. - */ -public class ArchiveEntryDocument extends Document { - - /** The contents of the entry */ - private final byte[] contents; - - /** - * Creates an Archive entry. - * @param entryName the name of this entry from outside the archive. - * @param contents the contents of the entry. - * @param nameMatcher the name matcher to filter contents with. - */ - public ArchiveEntryDocument(final ArchiveEntryName entryName, final byte[] contents, final DocumentNameMatcher nameMatcher) { - super(entryName, nameMatcher); - this.contents = contents; - } - - @Override - public InputStream inputStream() { - return new ByteArrayInputStream(contents); - } - - @Override - public boolean isDirectory() { - return false; - } - - @Override - public SortedSet listChildren() { - return Collections.emptySortedSet(); - } -} diff --git a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/FileUtils.java b/apache-rat-core/src/main/java/org/apache/rat/utils/FileUtils.java similarity index 72% rename from apache-rat-core/src/test/java/org/apache/rat/testhelpers/FileUtils.java rename to apache-rat-core/src/main/java/org/apache/rat/utils/FileUtils.java index 5681e7972..08c7c8947 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/FileUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/utils/FileUtils.java @@ -16,41 +16,46 @@ * specific language governing permissions and limitations * * under the License. * */ -package org.apache.rat.testhelpers; +package org.apache.rat.utils; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; +import java.nio.file.Files; import java.util.Arrays; import java.util.Collections; -import static org.assertj.core.api.Fail.fail; - -public class FileUtils { +/** + * A set of utilities to help process files. + */ +public final class FileUtils { + private FileUtils() { + // do not instantiate + } /** * Creates a directory if it does not exist. * @param dir the directory to make. */ - public static void mkDir(File dir) { + public static void mkDir(final File dir) { boolean ignored = dir.mkdirs(); } /** - * Deletes a file if it exists. + * Deletes a file if it exists (ignoring all IO-related exceptions). * @param file the file to delete. */ - public static void delete(File file) { + public static void delete(final File file) { if (file.exists()) { - if (file.isDirectory()) { - try { + try { + if (file.isDirectory()) { org.apache.commons.io.FileUtils.deleteDirectory(file); - } catch (IOException ignore) { - // + } else { + Files.delete(file.toPath()); } - } else { - boolean ignored = file.delete(); + } catch (IOException ignore) { + // ignore } } } @@ -62,15 +67,16 @@ public static void delete(File file) { * @param lines the lines to write into the file. * @return the new File. */ - static public File writeFile(File dir, final String name, final Iterable lines) { + public static File writeFile(final File dir, final String name, final Iterable lines) { if (dir == null) { - fail("base directory not specified"); + throw new IllegalArgumentException("base directory not specified"); } + mkDir(dir); File file = new File(dir, name); try (PrintWriter writer = new PrintWriter(new FileWriter(file))) { lines.forEach(writer::println); } catch (IOException e) { - fail(e.getMessage()); + throw new RuntimeException(e.getMessage(), e); } return file; } @@ -82,7 +88,7 @@ static public File writeFile(File dir, final String name, final Iterable * @param lines the lines to write into the file. * @return the new File. */ - static public File writeFile(File dir, final String name, final String... lines) { + public static File writeFile(final File dir, final String name, final String... lines) { return writeFile(dir, name, Arrays.asList(lines)); } @@ -92,7 +98,7 @@ static public File writeFile(File dir, final String name, final String... lines) * @param name the name of the file. * @return the new file. */ - public static File writeFile(File dir, String name) { + public static File writeFile(final File dir, final String name) { return writeFile(dir, name, Collections.singletonList(name)); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/walker/ArchiveWalker.java b/apache-rat-core/src/main/java/org/apache/rat/walker/ArchiveWalker.java index a50aa5ef8..f6dffb6bb 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/walker/ArchiveWalker.java +++ b/apache-rat-core/src/main/java/org/apache/rat/walker/ArchiveWalker.java @@ -20,12 +20,15 @@ package org.apache.rat.walker; import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.SortedSet; import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveException; @@ -34,9 +37,9 @@ import org.apache.commons.io.IOUtils; import org.apache.rat.api.Document; import org.apache.rat.api.RatException; -import org.apache.rat.document.ArchiveEntryDocument; import org.apache.rat.document.ArchiveEntryName; import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.report.RatReport; import org.apache.rat.utils.DefaultLog; @@ -56,7 +59,7 @@ public ArchiveWalker(final Document document) { } /** - * Run a report over all files and directories in this GZIPWalker, + * Run a report over all files and directories in the archive * ignoring any files/directories set to be ignored. * * @param report the defined RatReport to run on this GZIP walker. @@ -71,11 +74,12 @@ public void run(final RatReport report) throws RatException { /** * Creates an input stream from the directory being walked. * @return A buffered input stream reading the archive data. - * @throws IOException on error + * @throws IOException on error. */ private InputStream createInputStream() throws IOException { return new BufferedInputStream(getDocument().inputStream()); } + /** * Retrieves the documents from the archive. * @return A collection of documents that pass the file filter. @@ -87,13 +91,29 @@ public Collection getDocuments() throws RatException { ArchiveEntry entry; while ((entry = input.getNextEntry()) != null) { if (!entry.isDirectory() && input.canReadEntryData(entry)) { - DocumentName innerName = DocumentName.builder().setName(entry.getName()) + final DocumentName innerName = DocumentName.builder().setName(entry.getName()) .setBaseName(".").build(); - if (this.getDocument().getNameMatcher().matches(innerName)) { + final DocumentNameMatcher documentNameMatcher = getDocument().getNameMatcher(); + if (documentNameMatcher.matches(innerName)) { + ArchiveEntryName entryName = new ArchiveEntryName(getDocument().getName(), entry.getName()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); IOUtils.copy(input, baos); - ArchiveEntryName entryName = new ArchiveEntryName(getDocument().getName(), entry.getName()); - result.add(new ArchiveEntryDocument(entryName, baos.toByteArray(), getDocument().getNameMatcher())); + result.add(new Document(entryName, documentNameMatcher) { + @Override + public InputStream inputStream() { + return new ByteArrayInputStream(baos.toByteArray()); + } + + @Override + public boolean isDirectory() { + return false; + } + + @Override + public SortedSet listChildren() { + return Collections.emptySortedSet(); + } + }); } } } diff --git a/apache-rat-core/src/main/resources/org/apache/rat/xhtml5.xsl b/apache-rat-core/src/main/resources/org/apache/rat/xhtml5.xsl new file mode 100644 index 000000000..120cbcb39 --- /dev/null +++ b/apache-rat-core/src/main/resources/org/apache/rat/xhtml5.xsl @@ -0,0 +1,354 @@ + + + + + + + + + ❗ + 🗜 + 🔠 + 🚫 + ℹ + ✅ + ❓ + 📂 + + + + + + + + + + + + + + + +

RAT Report

+ + + + + + + + + + + + +

Details

+ +

+ Documents with unapproved licenses will start with a + The first character on the next line identifies the document type. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Symbols used in this RAT report +
SymbolType
Archive file
Binary file
Ignored file
Notice file
Standard file
Unknown file
Directory
+ + + + + + + + + +
+ Resources discovered in this RAT report +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ + + + +
+ ID: + + UUID + + + + Family: + + Unknown + + + +
+
+
+
+ + +

Summary

+ +
+

Generated at by + +

+ + + + + + + + + + + + + + + +
+ Table 1: A summary of statistics from this RAT report. +
Name:Count:Description:
+ + + + + Unknown + + +
+ +

License Statistics

+
+

Categories

+
+ + + + + + + + + + + + + +
+ Table 2: License categories found in this RAT report. +
Name:Count:
+ + + + + Unknown + + +
+
+ +

Licenses

+
+ + + + + + + + + + + + + +
+ Table 3: Licenses found in this RAT report. +
Name:Count:
+ + + + + Unknown + + +
+
+
+ +

Document types

+
+ + + + + + + + + + + + + +
+ Table 4: Document types found in this RAT report. +
Name:Count:
+
+
+
+ + +

Files with unapproved licenses

+ +
    + +
  • +
    +
+
+ + +

Archives

+
    + +
  • +
    +
+
+ + + + + + + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+ + +
+
diff --git a/apache-rat-core/src/test/java/org/apache/rat/OptionCollectionParserTest.java b/apache-rat-core/src/test/java/org/apache/rat/OptionCollectionParserTest.java index 761230f33..f59a82365 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/OptionCollectionParserTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/OptionCollectionParserTest.java @@ -36,6 +36,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +/** + * Test for option collection parsers. + */ class OptionCollectionParserTest { @TempDir(cleanup = CleanupMode.NEVER) @@ -78,7 +81,7 @@ void printHelpExceptionTest() throws ParseException { Options options = new Options(); ReportConfiguration cfg = new ReportConfiguration(); ArgumentContext ctxt = new ArgumentContext(testPath.toFile(), cfg, options, new String[0]); - cfg.setOut(new ReportConfiguration.IODescriptor("Bad Supplier", () -> { throw new IOException("Bad Supplier");})); + cfg.setOutput(new ReportConfiguration.IODescriptor("Bad Supplier", () -> { throw new IOException("Bad Supplier");})); assertThatThrownBy(() -> underTest.printHelp(ctxt)) .isInstanceOf(RatException.class) .hasMessageContaining("Unable to print help: Bad Supplier"); diff --git a/apache-rat-core/src/test/java/org/apache/rat/OptionCollectionTest.java b/apache-rat-core/src/test/java/org/apache/rat/OptionCollectionTest.java index ccc7e3bb8..b0489f04b 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/OptionCollectionTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/OptionCollectionTest.java @@ -42,6 +42,7 @@ import org.apache.rat.testhelpers.TestingLog; import org.apache.rat.utils.CasedString; import org.apache.rat.utils.DefaultLog; +import org.apache.rat.utils.FileUtils; import org.apache.rat.utils.Log; import org.apache.rat.walker.ArchiveWalker; import org.apache.rat.walker.DirectoryWalker; @@ -106,13 +107,22 @@ default String formatMsg(String msg) { return String.format("%s: %s", this, msg); } + /** + * Get the name of the test. + * By default, this method returns {@code toString()}. + * @return the name of the test. + */ + default String name() { + return toString(); + } + /** * Creates a named OptionTest. * @param name the name of the test. * @param test the test to execute. * @return a named option test. */ - static OptionTest namedTest(String name, OptionTest test) { + static OptionTest namedTest(String providerName, String name, OptionTest test) { return new OptionTest() { @Override public void exec() { @@ -120,6 +130,10 @@ public void exec() { } @Override public String toString() { + return String.join(":", providerName, name); + } + @Override + public String name() { return name; } }; @@ -145,7 +159,7 @@ public static Path getTestPath() { /** * Process methods in a test provider. * Tests are detected by looking for the {@link TestFunction} annotation. - * @param testProvider the test provider + * @param testProvider the test provider. * @return a map of named tests to a named OptionTest. */ public static Map processTestFunctionAnnotations(Object testProvider) { @@ -162,7 +176,7 @@ public static Map processTestFunctionAnnotations(Object test name = name.substring(testLength); } name = new CasedString(CasedString.StringCase.CAMEL, name).toCase(CasedString.StringCase.KEBAB).toLowerCase(Locale.ROOT); - result.put(name, OptionTest.namedTest(name, () -> { + result.put(name, OptionTest.namedTest(clazz.getName(), name, () -> { try { method.invoke(testProvider); } catch (IllegalAccessException | InvocationTargetException e) { @@ -179,6 +193,7 @@ public static Map processTestFunctionAnnotations(Object test public void testDeprecatedUseLogged() throws IOException { TestingLog log = new TestingLog(); try { + FileUtils.mkDir(testPath.resolve("target").toFile()); DefaultLog.setInstance(log); String[] args = {"--dir", "target", "-a"}; ReportConfiguration config = OptionCollection.parseCommands(testPath.toFile(), args, o -> fail("Help printed"), true); @@ -186,8 +201,8 @@ public void testDeprecatedUseLogged() throws IOException { } finally { DefaultLog.setInstance(null); } - log.assertContainsExactly(1, "WARN: Option [-d, --dir] used. Deprecated for removal since 0.17: Use the standard '--'"); - log.assertContainsExactly(1, "WARN: Option [-a] used. Deprecated for removal since 0.17: Use --edit-license"); + assertThat(log.getCaptured()).containsOnlyOnce("WARN: Option [-d, --dir] used. Deprecated for removal since 0.17: Use the standard '--'") + .containsOnlyOnce("WARN: Option [-a] used. Deprecated for removal since 0.17: Use --edit-license"); } @Test @@ -203,7 +218,7 @@ public void testDirOptionCapturesDirectoryToScan() throws IOException { DefaultLog.setInstance(null); } assertThat(config).isNotNull(); - log.assertContainsExactly(1,"WARN: Option [-d, --dir] used. Deprecated for removal since 0.17: Use the standard '--'"); + assertThat(log.getCaptured()).containsOnlyOnce("WARN: Option [-d, --dir] used. Deprecated for removal since 0.17: Use the standard '--'"); } @Test @@ -260,11 +275,11 @@ void getReportable() throws IOException { /** * A parameterized test for the options. - * @param name The name of the test. + * @param name the name of the test. * @param test the option test to execute. */ @ParameterizedTest( name = "{index} {0}") - @ArgumentsSource(CliOptionsProvider.class) + @ArgumentsSource(ArgOptionsProvider.class) public void testOptionsUpdateConfig(String name, OptionTest test) { DefaultLog.getInstance().log(Log.Level.INFO, "Running test for: " + name); test.test(); @@ -273,9 +288,9 @@ public void testOptionsUpdateConfig(String name, OptionTest test) { /** * A class to provide the Options and tests to the testOptionsUpdateConfig. */ - static class CliOptionsProvider extends AbstractConfigurationOptionsProvider implements ArgumentsProvider { + static class ArgOptionsProvider extends AbstractConfigurationOptionsProvider implements ArgumentsProvider { - /** A flag to determine if help was called */ + /** A flag to determine if help was called. */ final AtomicBoolean helpCalled = new AtomicBoolean(false); /** @@ -294,9 +309,9 @@ public void helpTest() { /** * Constructor. Sets the baseDir and loads the testMap. */ - public CliOptionsProvider() { - super(Collections.emptyList(), testPath.toFile()); - addTest(OptionCollectionTest.OptionTest.namedTest("help", this::helpTest)); + public ArgOptionsProvider() { + super("ArgsOptionsProvider", Collections.emptyList(), testPath.toFile()); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "help", this::helpTest)); } /** 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 index f523f55e3..57b0321a9 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/OutputTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/OutputTest.java @@ -30,8 +30,8 @@ import org.apache.rat.license.LicenseSetFactory; import org.apache.rat.report.claim.ClaimStatistic; import org.apache.rat.report.claim.ClaimStatisticTest; +import org.apache.rat.utils.FileUtils; 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; @@ -163,7 +163,7 @@ void configurationReadingTest() throws IOException { underTest.setArchiveProcessing(ReportConfiguration.Processing.NOTIFICATION); underTest.setStandardProcessing(ReportConfiguration.Processing.ABSENCE); underTest.setStyleSheet(StyleSheets.MISSING_HEADERS.getStyleSheet()); - underTest.setOut(new File("/some/file/somewhere")); + underTest.setOutput(new File("/some/file/somewhere")); underTest.setCopyrightMessage("the copyright message"); underTest.addSource(new File("/my/file")); underTest.addSource(new ReportConfigurationTest.TestingReportable()); @@ -211,7 +211,7 @@ private ReportConfiguration initializeConfiguration() throws URISyntaxException void listLicensesReportTest() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); ReportConfiguration configuration = initializeConfiguration(); - configuration.setOut(new ReportConfiguration.IODescriptor<>("listLicensesReportTest", () -> out)); + configuration.setOutput(new ReportConfiguration.IODescriptor<>("listLicensesReportTest", () -> out)); configuration.setStyleSheet(StyleSheets.UNAPPROVED_LICENSES.getStyleSheet()); Reporter.Output output = Reporter.Output.builder() .statistic(new ClaimStatistic()) 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 098669e82..c0ce6c4a1 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 @@ -43,6 +43,7 @@ import java.util.List; import java.util.SortedSet; import java.util.function.Function; +import java.util.stream.Collectors; import org.apache.commons.io.filefilter.DirectoryFileFilter; import org.apache.commons.io.output.CloseShieldOutputStream; @@ -254,8 +255,8 @@ void testAddAndRemoveApproveLicenseIds() { /** * Sets up underTest to have a set of licenses named after - * cartoon cats - * all in the license family 'catz' + * cartoon cats + * all in the license family 'catz'. */ private void addCatz() { underTest.addLicense(new TestingLicense("catz", "Garfield")); @@ -269,8 +270,8 @@ private void addCatz() { /** * Sets up underTest to have a set of licenses named after - * cartoon catscartoon dogs - * all in the license family 'dogz' + * cartoon dogs + * all in the license family 'dogz'. */ private void addDogz() { underTest.addLicense(new TestingLicense("dogz", "Odie")); @@ -472,7 +473,7 @@ void outputTest() throws IOException { assertThat(underTest.getWriter()).isNotNull(); ByteArrayOutputStream stream = new ByteArrayOutputStream(); - underTest.setOut(new ReportConfiguration.IODescriptor<>("outputTest", () -> stream)); + underTest.setOutput(new ReportConfiguration.IODescriptor<>("outputTest", () -> stream)); assertThat(underTest.getOutput().get()).isEqualTo(stream); PrintWriter writer = underTest.getWriter().get(); assertThat(writer).isNotNull(); @@ -560,7 +561,7 @@ void testValidate() { void testSetOut() throws IOException { ReportConfiguration config = new ReportConfiguration(); try (OutputStreamInterceptor osi = new OutputStreamInterceptor()) { - config.setOut(new ReportConfiguration.IODescriptor<>("testSetOut",() -> osi)); + config.setOutput(new ReportConfiguration.IODescriptor<>("testSetOut", () -> osi)); assertThat(osi.closeCount).isEqualTo(0); try (OutputStream os = config.getOutput().get()) { assertThat(os).isNotNull(); @@ -591,8 +592,11 @@ void logFamilyCollisionTest() { log.clear(); underTest.logFamilyCollisions(l); underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name2")); - assertThat(log.getCaptured().contains("CAT")).as("'CAT' not found").isTrue(); - assertThat(log.getCaptured().contains(l.name())).as("logging not set to "+l).isTrue(); + if (DefaultLog.getInstance().isEnabled(l)) { + assertThat(log.getCaptured()).contains("CAT").contains(l.name()); + } else { + assertThat(log.getCaptured()).doesNotContain("CAT").doesNotContain(l.name()); + } } } @@ -711,19 +715,23 @@ public Appendable append(char c) throws IOException { * Validates that the configuration contains the default approved licenses. * @param config the configuration to test. */ - public static void validateDefaultApprovedLicenses(ReportConfiguration config) { - validateDefaultApprovedLicenses(config, 0); - } - + public static void validateDefaultApprovedLicenses(ReportConfiguration config, String... additionalIds) { + validateLicenses(config, Arrays.asList(additionalIds), LicenseFilter.APPROVED, XMLConfigurationReaderTest.APPROVED_LICENSES); + } + /** - * Validates that the configuration contains the default approved licenses. + * Validates that the configuration contains all the default licenses along with any additional licenses. * @param config the configuration to test. + * @param additionalLicenses Additional license ids that are expected. */ - public static void validateDefaultApprovedLicenses(ReportConfiguration config, int additionalIdCount) { - assertThat(config.getLicenseCategories(LicenseFilter.APPROVED)).hasSize(XMLConfigurationReaderTest.APPROVED_IDS.length + additionalIdCount); - for (String s : XMLConfigurationReaderTest.APPROVED_IDS) { - assertThat(config.getLicenseCategories(LicenseFilter.APPROVED)).contains(ILicenseFamily.makeCategory(s)); - } + public static void validateDefaultLicenses(ReportConfiguration config, String...additionalLicenses) { + validateLicenses(config, Arrays.asList(additionalLicenses), LicenseFilter.ALL, XMLConfigurationReaderTest.EXPECTED_LICENSES); + } + + private static void validateLicenses(ReportConfiguration config, List additionalIds, LicenseFilter filter, String[] approvedIds) { + List expected = new ArrayList<>(Arrays.asList(approvedIds)); + expected.addAll(additionalIds); + assertThat(config.getLicenses(filter).stream().map(ILicense::getId).collect(Collectors.toSet())).containsExactlyInAnyOrderElementsOf(expected); } /** @@ -731,27 +739,22 @@ public static void validateDefaultApprovedLicenses(ReportConfiguration config, i * @param config the configuration to test. */ public static void validateDefaultLicenseFamilies(ReportConfiguration config, String...additionalIds) { - assertThat(config.getLicenseFamilies(LicenseFilter.ALL)).hasSize(XMLConfigurationReaderTest.EXPECTED_IDS.length + additionalIds.length); - List expected = new ArrayList<>(); - expected.addAll(Arrays.asList(XMLConfigurationReaderTest.EXPECTED_IDS)); - expected.addAll(Arrays.asList(additionalIds)); - for (ILicenseFamily family : config.getLicenseFamilies(LicenseFilter.ALL)) { - assertThat(expected).contains(family.getFamilyCategory().trim()); - } + validateLicenseFamilies(config, Arrays.asList(additionalIds), LicenseFilter.ALL, XMLConfigurationReaderTest.EXPECTED_IDS); } /** - * Validates that the configuration contains the default licenses. + * Validates that the configuration contains the default license families. * @param config the configuration to test. */ - public static void validateDefaultLicenses(ReportConfiguration config, String...additionalLicenses) { - assertThat(config.getLicenses(LicenseFilter.ALL)).hasSize(XMLConfigurationReaderTest.EXPECTED_LICENSES.length + additionalLicenses.length); - List expected = new ArrayList<>(); - expected.addAll(Arrays.asList(XMLConfigurationReaderTest.EXPECTED_LICENSES)); - expected.addAll(Arrays.asList(additionalLicenses)); - for (ILicense license : config.getLicenses(LicenseFilter.ALL)) { - assertThat(expected).contains(license.getId()); + static void validateDefaultApprovedLicenseFamilies(ReportConfiguration config, String...additionalIds) { + validateLicenseFamilies(config, Arrays.asList(additionalIds), LicenseFilter.APPROVED, XMLConfigurationReaderTest.APPROVED_IDS); } + + private static void validateLicenseFamilies(ReportConfiguration config, List additionalIds, LicenseFilter filter, String[] approvedIds) { + List expected = new ArrayList<>(Arrays.asList(approvedIds)); + expected.addAll(additionalIds); + assertThat(config.getLicenseFamilies(filter).stream().map(lf -> lf.getFamilyCategory().trim()) + .collect(Collectors.toSet())).containsExactlyInAnyOrderElementsOf(expected); } /** @@ -767,6 +770,7 @@ public static void validateDefault(ReportConfiguration config) { validateDefaultApprovedLicenses(config); validateDefaultLicenseFamilies(config); validateDefaultLicenses(config); + validateDefaultApprovedLicenses(config); } public static void assertSame(ReportConfiguration actual, ReportConfiguration expected) { @@ -796,7 +800,7 @@ void serDesTest() throws IOException { underTest.setArchiveProcessing(ReportConfiguration.Processing.NOTIFICATION); underTest.setStandardProcessing(ReportConfiguration.Processing.ABSENCE); underTest.setStyleSheet(StyleSheets.MISSING_HEADERS.getStyleSheet()); - underTest.setOut(new File("/some/file/somewhere")); + underTest.setOutput(new File("/some/file/somewhere")); underTest.setCopyrightMessage("the copyright message"); underTest.addSource(new File("/my/file")); underTest.addSource(new TestingReportable()); @@ -837,7 +841,7 @@ static class OutputStreamInterceptor extends OutputStream { public void write(int arg0) { throw new UnsupportedOperationException(); } - + @Override public void close() { ++closeCount; 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 56ad9ba7e..fb3ef9e65 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 @@ -20,7 +20,6 @@ import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; @@ -54,7 +53,7 @@ import org.apache.rat.test.AbstractOptionsProvider; import org.apache.rat.test.utils.OptionFormatter; import org.apache.rat.test.utils.Resources; -import org.apache.rat.testhelpers.FileUtils; +import org.apache.rat.utils.FileUtils; import org.apache.rat.testhelpers.TestingLog; import org.apache.rat.testhelpers.TextUtils; import org.apache.rat.testhelpers.XmlUtils; @@ -81,7 +80,7 @@ class ReporterOptionsProvider extends AbstractOptionsProvider implements Argumen final AtomicBoolean helpCalled = new AtomicBoolean(false); public ReporterOptionsProvider() { - super(ReporterOptionsTest.testPath.toFile()); + super("ReporterOptionsProvider", ReporterOptionsTest.testPath.toFile()); processTestFunctionAnnotations(); testMap.put("addLicense", this::addLicenseTest); testMap.remove("add-license"); @@ -115,20 +114,30 @@ protected final ReportConfiguration generateConfig(List> return config; } + /** + * Creates the option/.rat directory + * @param option the name for the sourceDirectory. + */ private File configureRatDir(Option option) { configureSourceDir(option); - File result = new File(sourceDir, ".rat"); - FileUtils.mkDir(result); - return result; + File ratDir = new File(sourceDir, ".rat"); + FileUtils.mkDir(ratDir); + return ratDir; } + /** + * Creates the srcDir. + * @param option the name for the srcDir. + */ private void configureSourceDir(Option option) { sourceDir = new File(baseDir, OptionFormatter.getName(option)); FileUtils.mkDir(sourceDir); } + /** + * Verify that without args the report is ok. + */ private void validateNoArgSetup() throws IOException, RatException { - // verify that without args the report is ok. TestingLog log = new TestingLog(); DefaultLog.setInstance(log); try { @@ -229,8 +238,7 @@ protected void licensesDeniedTest() { @OptionCollectionTest.TestFunction protected void licensesDeniedFileTest() { Option option = Arg.LICENSES_DENIED_FILE.find("licenses-denied-file"); - File ratDir = configureRatDir(option); - File outputFile = FileUtils.writeFile(ratDir, "licensesDenied.txt", Collections.singletonList("ILLUMOS")); + File outputFile = FileUtils.writeFile(configureRatDir(option), "licensesDenied.txt", Collections.singletonList("ILLUMOS")); execLicensesDeniedTest(option, new String[]{outputFile.getAbsolutePath()}); } @@ -241,7 +249,6 @@ private void noDefaultsTest(final Option option) { "*/\n\n", "class Test {}\n")); validateNoArgSetup(); - ReportConfiguration config = generateConfig(ImmutablePair.of(option, null)); Reporter reporter = new Reporter(config); assertThatThrownBy(reporter::execute) @@ -309,8 +316,13 @@ protected void counterMinTest() { }); } - // exclude tests - private void execExcludeTest(final Option option, final String[] args, final boolean addIgnored) { + /** + * Runs the exclude tests. + * @param option the exclude option to run. + * @param args the arguments for the command line. + * @param includesRatDir @{code true} if the .rat directory was created. + */ + private void execExcludeTest(final Option option, final String[] args, final boolean includesRatDir) { String[] notExcluded = {"notbaz", "well._afile"}; String[] excluded = {"some.foo", "B.bar", "justbaz"}; @@ -326,20 +338,19 @@ private void execExcludeTest(final Option option, final String[] args, final boo Reporter reporter = new Reporter(config); 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); + assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(includesRatDir ? 1 : 0); // filter out source config = generateConfig(ImmutablePair.of(option, args)); reporter = new Reporter(config); output = reporter.execute(); assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2); - assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(addIgnored ? 4 : 3); + assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(includesRatDir ? 4 : 3); }); } private void excludeFileTest(final Option option) { - File ratDir = configureRatDir(option); - File outputFile = FileUtils.writeFile(ratDir, "exclude.txt", Arrays.asList(EXCLUDE_ARGS)); + File outputFile = FileUtils.writeFile(configureRatDir(option), "exclude.txt", Arrays.asList(EXCLUDE_ARGS)); execExcludeTest(option, new String[]{outputFile.getAbsolutePath()}, true); } @@ -479,8 +490,13 @@ protected void inputExcludeParsedScmTest() { }); } - // include tests - private void execIncludeTest(final Option option, final String[] args, boolean addIgnored) { + /** + * Runs the include tests. + * @param option the include option to run. + * @param args the arguments for the command line. + * @param includesRatDir @{code true} if the .rat directory was created. + */ + private void execIncludeTest(final Option option, final String[] args, final boolean includesRatDir) { Option excludeOption = Arg.EXCLUDE.option(); String[] notExcluded = {"B.bar", "justbaz", "notbaz"}; String[] excluded = {"some.foo"}; @@ -496,15 +512,15 @@ private void execIncludeTest(final Option option, final String[] args, boolean a Reporter reporter = new Reporter(config); 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); + assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(includesRatDir ? 1 : 0); - // verify exclude removes most files. + // verify exclude removes most files config = generateConfig(ImmutablePair.of(excludeOption, EXCLUDE_ARGS)); reporter = new Reporter(config); 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(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(addIgnored ? 4 : 3); + assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(includesRatDir ? 4 : 3); // verify include put them back config = generateConfig(ImmutablePair.of(option, args), ImmutablePair.of(excludeOption, EXCLUDE_ARGS)); @@ -512,13 +528,12 @@ private void execIncludeTest(final Option option, final String[] args, boolean a 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(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(addIgnored ? 2 : 1); + assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(includesRatDir ? 2 : 1 ); }); } private void includeFileTest(final Option option) { - File ratDir = configureRatDir(option); - File outputFile = FileUtils.writeFile(ratDir, "include.txt", Arrays.asList(INCLUDE_ARGS)); + File outputFile = FileUtils.writeFile(configureRatDir(option), "include.txt", Arrays.asList(INCLUDE_ARGS)); execIncludeTest(option, new String[]{outputFile.getAbsolutePath()}, true); } @@ -759,8 +774,7 @@ protected void execLicensesApprovedTest(final Option option, String[] args) { @OptionCollectionTest.TestFunction protected void licensesApprovedFileTest() { Option option = Arg.LICENSES_APPROVED_FILE.find("licenses-approved-file"); - File ratDir = configureRatDir(option); - File outputFile = FileUtils.writeFile(ratDir, "licensesApproved.txt", Collections.singletonList("GPL1")); + File outputFile = FileUtils.writeFile(configureRatDir(option), "licensesApproved.txt", Collections.singletonList("GPL1")); execLicensesApprovedTest(option, new String[]{outputFile.getAbsolutePath()}); } @@ -816,8 +830,8 @@ private void outTest(final Option option) { assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isZero(); output.format(config); String actualText = TextUtils.readFile(outFile); - TextUtils.assertContainsExactly(1, "Apache License 2.0: 1 ", actualText); - TextUtils.assertContainsExactly(1, "STANDARD: 1 ", actualText); + assertThat(actualText).containsOnlyOnce("Apache License 2.0: 1 ") + .containsOnlyOnce("STANDARD: 1 "); }); } @@ -837,7 +851,7 @@ private void styleSheetTest(final Option option) { try (PrintStream out = new PrintStream(baos)) { System.setOut(out); configureSourceDir(option); - // create a dummy stylesheet so that we have a local file for users of the testing jar. + // create a dummy stylesheet so that we have a local file for users of the testing jar File file = writeFile("stylesheet", """ @@ -858,18 +872,21 @@ private void styleSheetTest(final Option option) { String actualText = baos.toString(StandardCharsets.UTF_8); switch (sheet) { case MISSING_HEADERS: - TextUtils.assertContainsExactly(1, "Files with missing headers:" + System.lineSeparator() + - " /stylesheet", actualText); + assertThat(actualText).containsOnlyOnce("Files with missing headers:" + System.lineSeparator() + + " /stylesheet"); break; case PLAIN: - TextUtils.assertContainsExactly(1, "Unknown license: 1 ", actualText); - TextUtils.assertContainsExactly(1, "?????: 1 ", actualText); + assertThat(actualText).containsOnlyOnce("Unknown license: 1 "); + assertThat(actualText).containsOnlyOnce("?????: 1 "); break; case XML: - TextUtils.assertContainsExactly(1, "", actualText); + assertThat(actualText).containsOnlyOnce(""); break; case UNAPPROVED_LICENSES: - TextUtils.assertContainsExactly(1, "Files with unapproved licenses:" + System.lineSeparator() + " /stylesheet", actualText); + assertThat(actualText).containsOnlyOnce("Files with unapproved licenses:" + System.lineSeparator() + " /stylesheet"); + break; + case XHTML5: + assertThat(actualText).containsPattern("Approved\\s+\\d+\\s+A count of approved licenses."); break; default: fail("No test for stylesheet " + sheet); @@ -886,7 +903,7 @@ private void styleSheetTest(final Option option) { assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1); output.format(config); String actualText = baos.toString(StandardCharsets.UTF_8); - TextUtils.assertContainsExactly(1, "Hello world", actualText); + assertThat(actualText).containsOnlyOnce("Hello world"); } catch (IOException | RatException e) { fail(e.getMessage(), e); } finally { @@ -928,9 +945,10 @@ protected void xmlTest() { assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1); output.format(config); String actualText = baos.toString(StandardCharsets.UTF_8); - TextUtils.assertContainsExactly(1, "", actualText); + assertThat(actualText) + .containsOnlyOnce(""); - try (InputStream expected = StyleSheets.getStyleSheet("xml").ioSupplier().get(); + try (InputStream expected = StyleSheets.getStyleSheet("xml", null).ioSupplier().get(); InputStream actual = config.getStyleSheet().get()) { assertThat(IOUtils.contentEquals(expected, actual)).as("'xml' does not match").isTrue(); } @@ -954,12 +972,12 @@ protected void logLevelTest() { ReportConfiguration config = generateConfig(); Reporter reporter = new Reporter(config); reporter.execute(); - TextUtils.assertNotContains("DEBUG", baos.toString(StandardCharsets.UTF_8)); + assertThat(baos.toString(StandardCharsets.UTF_8)).doesNotContain("DEBUG"); config = generateConfig(ImmutablePair.of(option, new String[]{"debug"})); reporter = new Reporter(config); reporter.execute(); - TextUtils.assertContains("DEBUG", baos.toString(StandardCharsets.UTF_8)); + assertThat(baos.toString(StandardCharsets.UTF_8)).contains("DEBUG"); } catch (IOException | RatException e) { fail(e.getMessage(), e); } finally { @@ -974,16 +992,12 @@ private void listLicenses(final Option option) { assertDoesNotThrow(() -> { configureSourceDir(option); - File outFile = new File(sourceDir, "out.xml"); - FileUtils.delete(outFile); - ImmutablePair outputFile = ImmutablePair.of(Arg.OUTPUT_FILE.option(), new String[]{outFile.getAbsolutePath()}); - ImmutablePair stylesheet = ImmutablePair.of(Arg.OUTPUT_STYLE.option(), new String[]{StyleSheets.XML.arg()}); for (LicenseSetFactory.LicenseFilter filter : LicenseSetFactory.LicenseFilter.values()) { args[0] = filter.name(); - ReportConfiguration config = generateConfig(outputFile, stylesheet, ImmutablePair.of(option, args)); + ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); Reporter reporter = new Reporter(config); - reporter.execute().format(config); - Document document = XmlUtils.toDom(new FileInputStream(outFile)); + Reporter.Output output = reporter.execute(); + Document document = output.getDocument(); switch (filter) { case ALL: XmlUtils.assertIsPresent(filter.name(), document, xPath, "/rat-report/rat-config/licenses/license[@id='AL2.0']"); @@ -1020,16 +1034,12 @@ private void listFamilies(final Option option) { assertDoesNotThrow(() -> { configureSourceDir(option); - File outFile = new File(sourceDir, "out.xml"); - FileUtils.delete(outFile); - ImmutablePair outputFile = ImmutablePair.of(Arg.OUTPUT_FILE.option(), new String[]{outFile.getAbsolutePath()}); - ImmutablePair stylesheet = ImmutablePair.of(Arg.OUTPUT_STYLE.option(), new String[]{StyleSheets.XML.arg()}); for (LicenseSetFactory.LicenseFilter filter : LicenseSetFactory.LicenseFilter.values()) { args[0] = filter.name(); - ReportConfiguration config = generateConfig(outputFile, stylesheet, ImmutablePair.of(option, args)); + ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); Reporter reporter = new Reporter(config); - reporter.execute().format(config); - Document document = XmlUtils.toDom(Files.newInputStream(outFile.toPath())); + Reporter.Output output = reporter.execute(); + Document document = output.getDocument(); switch (filter) { case ALL: XmlUtils.assertIsPresent(filter.name(), document, xPath, "/rat-report/rat-config/families/family[@id='AL']"); @@ -1083,7 +1093,7 @@ private void archiveTest(final Option option) { Reporter reporter = new Reporter(config); reporter.execute().format(config); - Document document = XmlUtils.toDom(Files.newInputStream(outFile.toPath())); + Document document = reporter.execute().getDocument(); XmlUtils.assertIsPresent(proc.name(), document, xPath, "/rat-report/resource[@name='/dummy.jar']"); switch (proc) { case ABSENCE: @@ -1131,9 +1141,9 @@ private void standardTest(final Option option) { args[0] = proc.name(); ReportConfiguration config = generateConfig(outputFile, stylesheet, ImmutablePair.of(option, args)); Reporter reporter = new Reporter(config); - reporter.execute().format(config); + Reporter.Output output = reporter.execute(); - Document document = XmlUtils.toDom(Files.newInputStream(outFile.toPath())); + Document document = output.getDocument(); XmlUtils.assertIsPresent(proc.name(), document, xPath, testDoc); XmlUtils.assertIsPresent(proc.name(), document, xPath, missingDoc); @@ -1184,7 +1194,7 @@ private void editCopyrightTest(final Option option, final Option extraOption) { reporter.execute(); String actualText = TextUtils.readFile(javaFile); - TextUtils.assertNotContains(myCopyright, actualText); + assertThat(actualText).doesNotContain(myCopyright); Pair arg2 = ImmutablePair.of(Arg.EDIT_ADD.find("edit-license"), null); config = extraArg != null ? generateConfig(arg1, arg2, extraArg) : generateConfig(arg1, arg2); @@ -1193,13 +1203,13 @@ private void editCopyrightTest(final Option option, final Option extraOption) { actualText = TextUtils.readFile(javaFile); if (forced) { - TextUtils.assertContains(myCopyright, actualText); + assertThat(actualText).contains(myCopyright); assertThat(newJavaFile).doesNotExist(); } else if (dryRun) { - TextUtils.assertNotContains(myCopyright, actualText); + assertThat(actualText).doesNotContain(myCopyright); assertThat(newJavaFile).doesNotExist(); } else { - TextUtils.assertNotContains(myCopyright, actualText); + assertThat(actualText).doesNotContain(myCopyright); assertThat(newJavaFile).exists(); } }); @@ -1294,10 +1304,8 @@ protected void helpLicensesTest() { System.setOut(origin); } - assertThat(actualText).isNotNull(); - TextUtils.assertContains("====== Licenses ======", actualText); - TextUtils.assertContains("====== Defined Matchers ======", actualText); - TextUtils.assertContains("====== Defined Families ======", actualText); + assertThat(actualText).isNotNull() + .contains("====== Licenses ======", "====== Defined Matchers ======", "====== Defined Families ======"); } @OptionCollectionTest.TestFunction diff --git a/apache-rat-core/src/test/java/org/apache/rat/ReporterOptionsTest.java b/apache-rat-core/src/test/java/org/apache/rat/ReporterOptionsTest.java index d98a46468..775fdaf3a 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/ReporterOptionsTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/ReporterOptionsTest.java @@ -21,13 +21,14 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; +import java.util.Map; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.apache.rat.api.RatException; import org.apache.rat.report.claim.ClaimStatistic; import org.apache.rat.test.AbstractConfigurationOptionsProvider; -import org.apache.rat.testhelpers.FileUtils; +import org.apache.rat.utils.FileUtils; import org.apache.rat.testhelpers.XmlUtils; import org.apache.rat.utils.DefaultLog; import org.apache.rat.utils.Log; @@ -59,7 +60,7 @@ void setup() { /** * A parameterized test for the options. - * @param name The name of the test. + * @param name the name of the test. */ @ParameterizedTest( name = "{index} {0}") @ArgumentsSource(ReporterOptionsProvider.class) @@ -83,7 +84,7 @@ void testRat362() { XPath xpath = XPathFactory.newInstance().newXPath(); XmlUtils.assertIsPresent(output.getDocument(), xpath, "/rat-report/resource[@name='/foo.md']"); XmlUtils.assertAttributes(output.getDocument(), xpath, "/rat-report/resource[@name='/foo.md']", - XmlUtils.mapOf("type", "IGNORED")); + Map.of("type", "IGNORED")); assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(0); assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(2); } catch (IOException | RatException | XPathExpressionException e) { diff --git a/apache-rat-core/src/test/java/org/apache/rat/ReporterTest.java b/apache-rat-core/src/test/java/org/apache/rat/ReporterTest.java index 4dc54ac7b..f7b76b4da 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/ReporterTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/ReporterTest.java @@ -19,6 +19,7 @@ package org.apache.rat; 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 java.io.ByteArrayOutputStream; @@ -39,6 +40,7 @@ import java.util.Optional; import java.util.TreeMap; import java.util.UUID; +import java.util.stream.Stream; import java.util.regex.Pattern; import javax.xml.XMLConstants; import javax.xml.transform.Source; @@ -66,6 +68,9 @@ import org.apache.rat.testhelpers.BaseOption; import org.apache.rat.testhelpers.BaseOptionCollection; import org.apache.rat.testhelpers.XmlUtils; +import org.apache.rat.testhelpers.data.ReportTestDataProvider; +import org.apache.rat.testhelpers.data.TestData; +import org.apache.rat.testhelpers.data.ValidatorData; import org.apache.rat.utils.StandardXmlFactory; import org.apache.rat.walker.DirectoryWalker; import org.junit.jupiter.api.AfterAll; @@ -73,6 +78,9 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; @@ -82,8 +90,7 @@ */ public class ReporterTest { /** - * temporary file. Not using tempDir because it does not - * always work. + * Temporary file. Not using tempDir because it does not always work properly. */ private static Path tempPath; @@ -271,7 +278,7 @@ void testXMLOutput() throws Exception { "type", "STANDARD")); File output = testPath.resolve(".rat/testXMLOutput").toFile(); - output.getParentFile().mkdirs(); + org.apache.rat.utils.FileUtils.mkDir(output.getParentFile()); ArgumentContext ctxt = collectionParser.parseCommands(testPath.toFile(), new String[]{"--output-style", "xml", "--output-file", output.getPath(), basedir}); new Reporter(ctxt.getConfiguration()).execute().format(ctxt.getConfiguration()); @@ -367,8 +374,8 @@ void testXMLOutput() throws Exception { * * @param doc the document to check * @param xpath the XPath instance to use. - * @param resource the xpath statement to locate the node. - * @param licenseInfo the license info for the node. (can be null) + * @param resource the XPath statement to locate the node. + * @param licenseInfo the license info for the node (can be {@code null}). * @param type the type of resource located. * @throws Exception on XPath error. */ @@ -503,7 +510,7 @@ void plainReportTest() throws Exception { "Generated at: "; ByteArrayOutputStream out = new ByteArrayOutputStream(); ReportConfiguration configuration = initializeConfiguration(); - configuration.setOut(new ReportConfiguration.IODescriptor<>("plainReportTest", () -> out)); + configuration.setOutput(new ReportConfiguration.IODescriptor<>("plainReportTest", () -> out)); new Reporter(configuration).execute().format(configuration); String document = out.toString(); @@ -519,7 +526,7 @@ void plainReportTest() throws Exception { void unapprovedLicensesReportTest() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); ReportConfiguration configuration = initializeConfiguration(); - configuration.setOut(new ReportConfiguration.IODescriptor<>("unapprovedLicensesReportTest", () -> out)); + configuration.setOutput(new ReportConfiguration.IODescriptor<>("unapprovedLicensesReportTest", () -> out)); configuration.setStyleSheet(this.getClass().getResource("/org/apache/rat/unapproved-licenses.xsl")); new Reporter(configuration).execute().format(configuration); @@ -546,16 +553,47 @@ void counterMaxTest() throws Exception { .isTrue(); } + static Stream getTestData() { + BaseOptionCollection.Builder builder = BaseOptionCollection.builder() + .unsupported(Arg.OUTPUT_FILE); + return new ReportTestDataProvider().getOptionTests(builder.build()).stream().map(testData -> + Arguments.of(testData.getTestName(), testData)); + } + + @ParameterizedTest( name = "{index} {0}") + @MethodSource("getTestData") + void testReportData(String name, TestData test) throws Exception { + Path invokePath = testPath.resolve(test.getTestName()); + org.apache.rat.utils.FileUtils.mkDir(invokePath.toFile()); + + test.setupFiles(invokePath); + ArgumentContext ctxt = collectionParser.parseCommands(invokePath.toFile(), + test.getCommandLine(invokePath.toString())); + if (test.expectingException()) { + assertThatThrownBy(() -> new Reporter(ctxt.getConfiguration()).execute()).as("Expected throws from " + name) + .hasMessageContaining(test.getExpectedException().getMessage()); + ValidatorData data = new ValidatorData(Reporter.Output.builder().configuration(ctxt.getConfiguration()).build(), + invokePath.toString()); + test.getValidator().accept(data); + } else { + Reporter.Output output = ctxt.getConfiguration() != null ? new Reporter(ctxt.getConfiguration()).execute() : + Reporter.Output.builder().build(); + ValidatorData data = new ValidatorData(output, invokePath.toString()); + data.getOutput().format(data.getConfiguration()); + test.getValidator().accept(data); + } + } + private record LicenseInfo(String id, String family, boolean approval, boolean hasNotes) { - LicenseInfo(String id, boolean approval, boolean hasNotes) { - this(id, id, approval, hasNotes); - } + LicenseInfo(String id, boolean approval, boolean hasNotes) { + this(id, id, approval, hasNotes); + } - private LicenseInfo(String id, String family, boolean approval, boolean hasNotes) { - this.id = id; - this.family = ILicenseFamily.makeCategory(family); - this.approval = approval; - this.hasNotes = hasNotes; - } + private LicenseInfo(String id, String family, boolean approval, boolean hasNotes) { + this.id = id; + this.family = ILicenseFamily.makeCategory(family); + this.approval = approval; + this.hasNotes = hasNotes; } + } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/analysis/AnalyserFactoryTest.java b/apache-rat-core/src/test/java/org/apache/rat/analysis/AnalyserFactoryTest.java index 22a4945f3..f4ef0792c 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/analysis/AnalyserFactoryTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/analysis/AnalyserFactoryTest.java @@ -41,7 +41,6 @@ import org.apache.rat.test.utils.Resources; import org.apache.rat.testhelpers.TestingDocument; import org.apache.rat.testhelpers.TestingDocumentAnalyser; -import org.apache.rat.testhelpers.TextUtils; import org.assertj.core.util.Files; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -49,12 +48,24 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +/** + * A collection of tests for the AnalyserFactory. + */ public class AnalyserFactoryTest { + /** + * The document name for the base directory. + */ private final DocumentName basedir; + /** + * The analyzer created by the factory. + */ private DocumentAnalyser analyser; + /** + * Constructor. + */ AnalyserFactoryTest() { basedir = DocumentName.builder(new File(Files.currentFolder(), Resources.SRC_TEST_RESOURCES)).build(); } @@ -185,9 +196,7 @@ public void RAT147_unix_Test() throws Exception { Resources.getResourceFile("/jira/RAT147/unix-newlines.txt.bin"), DocumentNameMatcher.MATCHES_ALL); analyser.analyse(document); String result = buildReport(document); - TextUtils.assertPatternInTarget( - " StyleSheets.getStyleSheet("does-not-exist", documentName) + ); + assertThat(exception.getMessage()).isEqualTo("Stylesheet file 'does-not-exist' not found: null"); + } + +} \ No newline at end of file diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/results/ClaimValidatorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/results/ClaimValidatorTest.java index 1418941f8..c8e344921 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/results/ClaimValidatorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/results/ClaimValidatorTest.java @@ -34,6 +34,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +/** + * Tests for the Claim Validator. + */ class ClaimValidatorTest { @Test @@ -125,16 +128,17 @@ void logIssuesTest() { statistic.incCounter(counter, expected); validator.logIssues(statistic); assertThat(log.getCaptured()).isNotEmpty(); - required.entrySet().stream().filter(e -> e.getKey() != counter) - .map(Map.Entry::getValue).forEach(log::assertContains); + List expectedEntries = required.entrySet().stream().filter(e -> e.getKey() != counter) + .map(Map.Entry::getValue).toList(); + assertThat(log.getCaptured()).contains(expectedEntries); if (required.entrySet().contains(counter)) { - log.assertNotContains(required.get(counter)); + assertThat(log.getCaptured()).doesNotContain(required.get(counter)); } statistic.incCounter(counter, 1); validator.logIssues(statistic); String expectedStr = format("ERROR: Unexpected count for %s, limit is [%s,5]. Count: 6", counter, counter.getDefaultMinValue()); - log.assertContains(expectedStr); + assertThat(log.getCaptured()).contains(expectedStr); log.clear(); statistic.incCounter(counter, -1 - expected); } diff --git a/apache-rat-core/src/test/java/org/apache/rat/configuration/XMLConfigurationReaderTest.java b/apache-rat-core/src/test/java/org/apache/rat/configuration/XMLConfigurationReaderTest.java index f0779b31f..827cc41ca 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/configuration/XMLConfigurationReaderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/configuration/XMLConfigurationReaderTest.java @@ -41,17 +41,36 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +/** + * Tests and constants for XML reader tests. + */ public class XMLConfigurationReaderTest { + /** + * The expected IDs for the default configuration. + */ public static final String[] EXPECTED_IDS = {"AL", "BSD-3", "CDDL1", "GPL", "MIT", "OASIS", "W3C", "W3CD"}; + /** + * The approved IDs for the default configuration. + */ public static final String[] APPROVED_IDS = {"AL", "BSD-3", "CDDL1", "MIT", "OASIS", "W3C", "W3CD"}; + /** + * The expected licenses for the default configuration. + */ public static final String[] EXPECTED_LICENSES = {"AL1.0", "AL1.1", "AL2.0", "BSD-3", "DOJO", "TMF", "CDDL1", "ILLUMOS", "GPL1", "GPL2", "GPL3", "MIT", "OASIS", "W3C", "W3CD"}; + /** + * The approved licenses for the default configuration. + */ + public static final String[] APPROVED_LICENSES = { "AL1.0", "AL1.1", "AL2.0", "BSD-3", "DOJO", "TMF", "CDDL1", "ILLUMOS", + "MIT", "OASIS", "W3C", "W3CD" }; + + @Test void approvedLicenseIdTest() throws URISyntaxException { XMLConfigurationReader reader = new XMLConfigurationReader(); @@ -59,15 +78,15 @@ void approvedLicenseIdTest() throws URISyntaxException { assertThat(url).isNotNull(); reader.read(url.toURI()); - Collection readCategories = reader.approvedLicenseId(); - assertThat(readCategories.toArray(new String[readCategories.size()])) - .containsExactly(APPROVED_IDS); + Collection actual = reader.approvedLicenseId(); + assertThat(actual).containsExactlyInAnyOrder(APPROVED_IDS); } @Test void LicensesTest() throws URISyntaxException { XMLConfigurationReader reader = new XMLConfigurationReader(); URL url = XMLConfigurationReaderTest.class.getResource("/org/apache/rat/default.xml"); + assertThat(url).isNotNull(); reader.read(url.toURI()); assertThat(reader.readLicenses().stream().map(IHeaderMatcher::getId).toArray(String[]::new)) .containsExactly(EXPECTED_LICENSES); @@ -77,12 +96,19 @@ void LicensesTest() throws URISyntaxException { void LicenseFamiliesTest() throws URISyntaxException { XMLConfigurationReader reader = new XMLConfigurationReader(); URL url = XMLConfigurationReaderTest.class.getResource("/org/apache/rat/default.xml"); + assertThat(url).isNotNull(); reader.read(url.toURI()); - assertThat(reader.readFamilies().stream().map(x -> x.getFamilyCategory().trim()).toArray(String[]::new)) - .containsExactly(EXPECTED_IDS); + Collection actual = reader.readFamilies().stream().map(lf -> lf.getFamilyCategory().trim()) + .toList(); + assertThat(actual).containsExactlyInAnyOrder(EXPECTED_IDS); } + /** + * Checks if a matcher built from the class name is an instance of the provided class. + * @param name the matcher name from the tracker. + * @param clazz the expected class type. + */ private void checkMatcher(String name, Class clazz) { AbstractBuilder builder = MatcherBuilderTracker.getMatcherBuilder(name); assertThat(builder).isNotNull(); @@ -93,7 +119,9 @@ private void checkMatcher(String name, Class clazz) { @Test void checkSystemMatcherTest() throws URISyntaxException { XMLConfigurationReader reader = new XMLConfigurationReader(); - URI uri = XMLConfigurationReaderTest.class.getResource("/org/apache/rat/default.xml").toURI(); + URL url = XMLConfigurationReaderTest.class.getResource("/org/apache/rat/default.xml"); + assertThat(url).isNotNull(); + URI uri = url.toURI(); assertThat(uri).isNotNull(); reader.read(uri); reader.readMatcherBuilders(); @@ -110,7 +138,9 @@ void checkSystemMatcherTest() throws URISyntaxException { @Test void descriptionTest() throws SecurityException, URISyntaxException { XMLConfigurationReader reader = new XMLConfigurationReader(); - URI uri = XMLConfigurationReaderTest.class.getResource("/org/apache/rat/default.xml").toURI(); + URL url = XMLConfigurationReaderTest.class.getResource("/org/apache/rat/default.xml"); + assertThat(url).isNotNull(); + URI uri = url.toURI(); assertThat(uri).isNotNull(); reader.read(uri); reader.readMatcherBuilders(); @@ -136,6 +166,7 @@ void descriptionTest() throws SecurityException, URISyntaxException { @Test void checkWithXXETest() throws SecurityException { + // as DOCTYPE is configured to be disallowed, we expect an error here final String contents = """ argTypes = OptionCollection.getArgumentTypes().keySet(); + Set argTypes = Arrays.stream(OptionCollection.ArgumentType.values()) + .map(OptionCollection.ArgumentType::getDisplayName) + .collect(Collectors.toSet()); StringWriter out = new StringWriter(); new Help(out).printUsage(opts); String result = out.toString(); @@ -63,7 +70,9 @@ public void verifyArgumentsListed() { for (Option option : opts.getOptions()) { if (option.getArgName() != null) { assertTrue(argTypes.contains(option.getArgName()), () -> format("Argument '%s' is missing from list", option.getArgName())); - TextUtils.assertPatternInTarget(format("^<%s>", option.getArgName()), result); + Pattern pattern = Pattern.compile(format("^<%s>", option.getArgName()), Pattern.MULTILINE); // NOSONAR + assertThat(result).as(format("argument name for option `%s`.", option.getKey())) + .containsPattern(pattern); } } assertThat(result).doesNotContain(".."); diff --git a/apache-rat-core/src/test/java/org/apache/rat/report/xml/writer/impl/base/XmlWriterTest.java b/apache-rat-core/src/test/java/org/apache/rat/report/xml/writer/XmlWriterTest.java similarity index 98% rename from apache-rat-core/src/test/java/org/apache/rat/report/xml/writer/impl/base/XmlWriterTest.java rename to apache-rat-core/src/test/java/org/apache/rat/report/xml/writer/XmlWriterTest.java index 287db7677..9bc47a890 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/report/xml/writer/impl/base/XmlWriterTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/report/xml/writer/XmlWriterTest.java @@ -16,11 +16,9 @@ * specific language governing permissions and limitations * * under the License. * */ -package org.apache.rat.report.xml.writer.impl.base; +package org.apache.rat.report.xml.writer; + -import org.apache.rat.report.xml.writer.InvalidXmlException; -import org.apache.rat.report.xml.writer.OperationNotAllowedException; -import org.apache.rat.report.xml.writer.XmlWriter; import org.apache.rat.testhelpers.XmlUtils; import org.junit.jupiter.api.Test; import org.w3c.dom.Document; diff --git a/apache-rat-core/src/test/java/org/apache/rat/test/AbstractConfigurationOptionsProvider.java b/apache-rat-core/src/test/java/org/apache/rat/test/AbstractConfigurationOptionsProvider.java index 84e30dc59..d79354062 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/test/AbstractConfigurationOptionsProvider.java +++ b/apache-rat-core/src/test/java/org/apache/rat/test/AbstractConfigurationOptionsProvider.java @@ -19,6 +19,7 @@ package org.apache.rat.test; import java.io.FileWriter; +import java.nio.charset.StandardCharsets; import java.nio.file.FileSystems; import java.nio.file.Path; import org.apache.commons.cli.Option; @@ -41,7 +42,6 @@ import org.apache.rat.report.claim.ClaimStatistic; import org.apache.rat.report.xml.writer.XmlWriter; import org.apache.rat.test.utils.Resources; -import org.apache.rat.testhelpers.TextUtils; import org.apache.rat.utils.DefaultLog; import org.apache.rat.utils.Log.Level; @@ -80,7 +80,7 @@ public abstract class AbstractConfigurationOptionsProvider extends AbstractOptio */ public static void preserveData(File baseDir, String targetDir) { final Path recordPath = FileSystems.getDefault().getPath("target", targetDir); - org.apache.rat.testhelpers.FileUtils.mkDir(recordPath.toFile()); + org.apache.rat.utils.FileUtils.mkDir(recordPath.toFile()); try { FileUtils.copyDirectory(baseDir, recordPath.toFile()); } catch (IOException e) { @@ -103,57 +103,63 @@ public static File setup(final File baseDir) { return baseDir; } - protected AbstractConfigurationOptionsProvider(final Collection unsupportedArgs, final File baseDir) { - super(setup(baseDir)); - addTest(OptionCollectionTest.OptionTest.namedTest("addLicense", this::addLicenseTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("config", this::configTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("configuration-no-defaults", this::configurationNoDefaultsTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("copyright", this::copyrightTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("counter-min", this::counterMinTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("counter-max", this::counterMaxTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("dir", () -> DefaultLog.getInstance().info("--dir has no valid test"))); - addTest(OptionCollectionTest.OptionTest.namedTest("dry-run", this::dryRunTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("edit-copyright", this::editCopyrightTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("edit-license", this::editLicenseTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("edit-overwrite", this::editOverwriteTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("exclude", this::excludeTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("exclude-file", this::excludeFileTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("force", this::forceTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("help-licenses", this::helpLicenses)); - addTest(OptionCollectionTest.OptionTest.namedTest("include", this::includeTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("includes-file", this::includesFileTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("input-exclude", this::inputExcludeTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("input-exclude-file", this::inputExcludeFileTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("input-exclude-parsed-scm", this::inputExcludeParsedScmTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("input-exclude-std", this::inputExcludeStdTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("input-exclude-size", this::inputExcludeSizeTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("input-include", this::inputIncludeTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("input-include-file", this::inputIncludeFileTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("input-include-std", this::inputIncludeStdTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("input-source", this::inputSourceTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("license-families-approved", this::licenseFamiliesApprovedTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("license-families-approved-file", this::licenseFamiliesApprovedFileTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("license-families-denied", this::licenseFamiliesDeniedTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("license-families-denied-file", this::licenseFamiliesDeniedFileTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("licenses", this::licensesTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("licenses-approved", this::licensesApprovedTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("licenses-approved-file", this::licensesApprovedFileTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("licenses-denied", this::licensesDeniedTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("licenses-denied-file", this::licensesDeniedFileTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("list-families", this::listFamiliesTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("list-licenses", this::listLicensesTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("log-level", this::logLevelTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("no-default-licenses", this::noDefaultsTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("out", this::outTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("output-archive", this::outputArchiveTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("output-families", this::outputFamiliesTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("output-file", this::outputFileTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("output-licenses", this::outputLicensesTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("output-standard", this::outputStandardTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("output-style", this::outputStyleTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("scan-hidden-directories", this::scanHiddenDirectoriesTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("stylesheet", this::styleSheetTest)); - addTest(OptionCollectionTest.OptionTest.namedTest("xml", this::xmlTest)); + /** + * Construct the tests. + * @param providerName the common name of the provider under test. + * @param unsupportedArgs the list of unsupported arguments. + * @param baseDir the base directory for the tests. Tests and test data will be copied to directories under this directory. + */ + protected AbstractConfigurationOptionsProvider(final String providerName, final Collection unsupportedArgs, final File baseDir) { + super(providerName, setup(baseDir)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "addLicense", this::addLicenseTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "config", this::configTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "configuration-no-defaults", this::configurationNoDefaultsTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "copyright", this::copyrightTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "counter-min", this::counterMinTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "counter-max", this::counterMaxTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "dir", () -> DefaultLog.getInstance().info("--dir has no valid test"))); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "dry-run", this::dryRunTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "edit-copyright", this::editCopyrightTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "edit-license", this::editLicenseTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "edit-overwrite", this::editOverwriteTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "exclude", this::excludeTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "exclude-file", this::excludeFileTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "force", this::forceTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "help-licenses", this::helpLicenses)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "include", this::includeTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "includes-file", this::includesFileTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "input-exclude", this::inputExcludeTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "input-exclude-file", this::inputExcludeFileTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "input-exclude-parsed-scm", this::inputExcludeParsedScmTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "input-exclude-std", this::inputExcludeStdTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "input-exclude-size", this::inputExcludeSizeTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "input-include", this::inputIncludeTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "input-include-file", this::inputIncludeFileTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "input-include-std", this::inputIncludeStdTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "input-source", this::inputSourceTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "license-families-approved", this::licenseFamiliesApprovedTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "license-families-approved-file", this::licenseFamiliesApprovedFileTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "license-families-denied", this::licenseFamiliesDeniedTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "license-families-denied-file", this::licenseFamiliesDeniedFileTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "licenses", this::licensesTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "licenses-approved", this::licensesApprovedTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "licenses-approved-file", this::licensesApprovedFileTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "licenses-denied", this::licensesDeniedTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "licenses-denied-file", this::licensesDeniedFileTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "list-families", this::listFamiliesTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "list-licenses", this::listLicensesTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "log-level", this::logLevelTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "no-default-licenses", this::noDefaultsTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "out", this::outTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "output-archive", this::outputArchiveTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "output-families", this::outputFamiliesTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "output-file", this::outputFileTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "output-licenses", this::outputLicensesTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "output-standard", this::outputStandardTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "output-style", this::outputStyleTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "scan-hidden-directories", this::scanHiddenDirectoriesTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "stylesheet", this::styleSheetTest)); + addTest(OptionCollectionTest.OptionTest.namedTest(providerName, "xml", this::xmlTest)); super.validate(unsupportedArgs); } @@ -232,10 +238,10 @@ protected void inputExcludeParsedScmTest() { writeFile(".gitignore", Arrays.asList(lines)); File dir = new File(baseDir, "red"); - org.apache.rat.testhelpers.FileUtils.mkDir(dir); + org.apache.rat.utils.FileUtils.mkDir(dir); dir = new File(baseDir, "blue"); dir = new File(dir, "fish"); - org.apache.rat.testhelpers.FileUtils.mkDir(dir); + org.apache.rat.utils.FileUtils.mkDir(dir); assertDoesNotThrow(() -> { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); @@ -381,9 +387,7 @@ protected void helpLicenses() { System.setOut(origin); } String txt = output.toString(); - TextUtils.assertContains("====== Licenses ======", txt); - TextUtils.assertContains("====== Defined Matchers ======", txt); - TextUtils.assertContains("====== Defined Families ======", txt); + assertThat(txt).contains("====== Licenses ======", "====== Defined Matchers ======", "====== Defined Families ======"); } protected void licensesApprovedFileTest() { @@ -514,7 +518,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + 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, @@ -800,6 +804,7 @@ protected void outputStandardTest() { private void styleSheetTest(final Option option) { // copy the dummy stylesheet so that we have a local file for users of the testing jar. File file = new File(baseDir, "stylesheet-" + option.getLongOpt()); + DocumentName xsltFile = DocumentName.builder(file).build(); try ( InputStream in = ReporterTest.class.getResourceAsStream("MatcherContainerResource.txt"); OutputStream out = Files.newOutputStream(file.toPath())) { @@ -815,12 +820,18 @@ private void styleSheetTest(final Option option) { // run the test String[] args = {null}; assertDoesNotThrow(() -> { - for (String sheet : new String[]{"plain-rat", "missing-headers", "unapproved-licenses", file.getAbsolutePath()}) { + for (String sheet : new String[]{"plain-rat", "missing-headers", "unapproved-licenses", xsltFile.getName()}) { args[0] = sheet; ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); - try (InputStream expected = StyleSheets.getStyleSheet(sheet).ioSupplier().get(); + try (InputStream expected = StyleSheets.getStyleSheet(sheet, xsltFile.getBaseDocumentName()).ioSupplier().get(); InputStream actual = config.getStyleSheet().get()) { - assertThat(IOUtils.contentEquals(expected, actual)).as(() -> String.format("'%s' does not match", sheet)).isTrue(); + String expectedStr = IOUtils.toString(expected, StandardCharsets.UTF_8); + String actualStr = IOUtils.toString(actual, StandardCharsets.UTF_8); + assertThat(actualStr).as( + () -> String.format("'%s' is not correct: %s != %s", + config.getStyleSheetDescriptor().name(), + actualStr, expectedStr)) + .isEqualTo(expectedStr); } } }); @@ -845,7 +856,7 @@ protected void scanHiddenDirectoriesTest() { protected void xmlTest() { assertDoesNotThrow(() -> { ReportConfiguration config = generateConfig(ImmutablePair.of(Arg.OUTPUT_STYLE.find("xml"), null)); - try (InputStream expected = StyleSheets.getStyleSheet("xml").ioSupplier().get(); + try (InputStream expected = StyleSheets.getStyleSheet("xml", null).ioSupplier().get(); InputStream actual = config.getStyleSheet().get()) { assertThat(IOUtils.contentEquals(expected, actual)).as("'xml' does not match").isTrue(); } diff --git a/apache-rat-core/src/test/java/org/apache/rat/test/AbstractOptionsProvider.java b/apache-rat-core/src/test/java/org/apache/rat/test/AbstractOptionsProvider.java index f4a188099..fb6649f49 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/test/AbstractOptionsProvider.java +++ b/apache-rat-core/src/test/java/org/apache/rat/test/AbstractOptionsProvider.java @@ -42,28 +42,33 @@ import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.support.ParameterDeclarations; import static org.assertj.core.api.Fail.fail; /** * A list of methods that an OptionsProvider in a test case must support. * Use of this interface ensures consistent testing across the UIs. Each method - * tests an Option from OptionCollection that must be implemented in the UI. + * tests an option from OptionCollection that must be implemented in the UI. * Each method in this interface tests an Option in {@link org.apache.rat.OptionCollection}. */ public abstract class AbstractOptionsProvider implements ArgumentsProvider { /** - * A map of test Options to tests. + * A map of test options to tests. */ protected final Map testMap = new TreeMap<>(); - /** The list of exclude args */ + /** The list of exclude args. */ protected static final String[] EXCLUDE_ARGS = {"*.foo", "%regex[[A-Z]\\.bar]", "justbaz"}; - /** the list of include args */ + /** The list of include args. */ protected static final String[] INCLUDE_ARGS = {"B.bar", "justbaz"}; /** * The directory to place test data in. */ protected final File baseDir; + /** + * The name of the provider of the options. + */ + protected final String providerName; /** * Copy the runtime data to the "target" directory. @@ -72,7 +77,7 @@ public abstract class AbstractOptionsProvider implements ArgumentsProvider { */ public static void preserveData(File baseDir, String targetDir) { final Path recordPath = FileSystems.getDefault().getPath("target", targetDir); - recordPath.toFile().mkdirs(); + org.apache.rat.utils.FileUtils.mkDir(recordPath.toFile()); try { FileUtils.copyDirectory(baseDir, recordPath.toFile()); } catch (IOException e) { @@ -85,7 +90,7 @@ protected void processTestFunctionAnnotations() { } protected void addTest(OptionCollectionTest.OptionTest test) { - testMap.put(test.toString(), test); + testMap.put(test.name(), test); } /** @@ -96,12 +101,17 @@ protected DocumentName baseName() { return DocumentName.builder(baseDir).build(); } - protected AbstractOptionsProvider(final File baseDir) { + protected AbstractOptionsProvider(final String providerName, final File baseDir) { + this.providerName = providerName; this.baseDir = baseDir; } - protected void validate(final Collection unsupportedArgs) { + private void removeUnsupportedArgs(final Collection unsupportedArgs) { unsupportedArgs.forEach(testMap::remove); + } + + protected void validate(final Collection unsupportedArgs) { + removeUnsupportedArgs(unsupportedArgs); verifyAllMethodsDefinedAndNeeded(unsupportedArgs); } @@ -131,7 +141,7 @@ private void verifyAllMethodsDefinedAndNeeded(final Collection unsupport if (!argNames.isEmpty()) { fail("Extra methods defined: " + String.join(", ", argNames)); } - unsupportedArgs.forEach(testMap::remove); + removeUnsupportedArgs(unsupportedArgs); } @SafeVarargs @@ -170,7 +180,7 @@ public static String[] extractArgs(List> args) { } protected File writeFile(final String name, final Iterable lines) { - return org.apache.rat.testhelpers.FileUtils.writeFile(baseDir, name, lines); + return org.apache.rat.utils.FileUtils.writeFile(baseDir, name, lines); } final protected DocumentName mkDocName(final String name) { @@ -194,7 +204,7 @@ final protected String dump(final Option option, final String fname, final Docum } @Override - public Stream provideArguments(final ExtensionContext context) { + public Stream provideArguments(final ParameterDeclarations parameters, final ExtensionContext context) { List lst = new ArrayList<>(); List missingTests = new ArrayList<>(); diff --git a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/BaseOption.java b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/BaseOption.java index a37f4a74a..83418def7 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/BaseOption.java +++ b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/BaseOption.java @@ -25,27 +25,40 @@ import java.util.function.Function; +/** + * An implementation of UIOption to use in general (non-UI limited or adjusted) testing. + */ public final class BaseOption extends UIOption { - BaseOption(BaseOptionBuilder builder) { + private BaseOption(BaseOptionBuilder builder) { super(builder); } - public UIOption.Builder builder() { + /** + * Creates a builder for the BaseOption. + * @return the BaseOptionBuilder. + */ + public BaseOptionBuilder builder() { return new BaseOptionBuilder(); } + @Override protected String cleanupName(Option option) { return ArgumentTracker.extractKey(option); } + @Override public String getExample() { return ""; } + @Override public String getText() { return ""; } + /** + * The BaseOptionBuilder implementation. + */ public static class BaseOptionBuilder extends UIOption.Builder { @Override diff --git a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/BaseOptionCollection.java b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/BaseOptionCollection.java index 5e6793d4c..6e62fa12f 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/BaseOptionCollection.java +++ b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/BaseOptionCollection.java @@ -20,14 +20,50 @@ import org.apache.rat.ui.UIOptionCollection; +/** + * A UIOptionCollection for testing purposes. The contained UIOptions are not UI limited or adjusted. + */ public final class BaseOptionCollection extends UIOptionCollection { + /** + * Constructs a BaseOptionCollection builder. + * @return the BaseOptionCollection.Builder. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Constructs a default BaseOptionCollection. + */ public BaseOptionCollection() { super(new Builder()); } + /** + * Constructs a BaseOptionCollection from the provided builder. + * @param builder the builder for this collection. + */ + public BaseOptionCollection(Builder builder) { + super(builder); + } + + /** + * The BaseOptionCollection Builder implementation. + */ public static final class Builder extends UIOptionCollection.Builder { - public Builder() { + /** + * Constructor. + */ + Builder() { super(BaseOption.BaseOptionBuilder::new); } + + /** + * Builds a BaserOptionCollection. + * @return a new BaseOptionCollection implementation. + */ + public BaseOptionCollection build() { + return new BaseOptionCollection(this); + } } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingDocument.java b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingDocument.java index 1bd66377b..fae6a7d74 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingDocument.java +++ b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingDocument.java @@ -31,58 +31,112 @@ import org.apache.rat.document.DocumentName; import org.apache.rat.document.FSInfoTest; +/** + * A Document for testing. The document is guaranteed to have a name and may have content (specified in the constructor). + */ public class TestingDocument extends Document { private final Reader reader; private final IOSupplier input; + /** + * Constructs a TestingDocument with the name {@code "name"} and no content. + */ public TestingDocument() { this("name"); } + /** + * Constructs a TestingDocument with the specified {@code "name"}, + * no content and will not have an associated document name matcher. + * @param name the name of the document. + */ public TestingDocument(String name) { this(name, null); } + /** + * Constructs a TestingDocument with the specified DocumentName, + * no content and the {@link DocumentNameMatcher#MATCHES_ALL} + * name matcher associated with it. + * @param documentName the document name. + */ public TestingDocument(DocumentName documentName) { super(documentName, DocumentNameMatcher.MATCHES_ALL); this.reader = null; this.input = null; } + /** + * Constructs a TestingDocument with the specified {@code "name"}, + * no content and the specified DocumentNameMatcher + * associated with it. + * @param name the document name. + * @param matcher the associated document name matcher. + */ public TestingDocument(String name, DocumentNameMatcher matcher) { super(DocumentName.builder().setName(name).setBaseName("").build(), matcher); this.reader = null; this.input = null; } + /** + * Constructs a TestingDocument with the name {@code "name"} and the content provided by the reader. + * @param reader the reader that provides content for the document. + * @param name the name of the document. + */ public TestingDocument(Reader reader, String name) { super(DocumentName.builder().setName(name).setBaseName("").build(), DocumentNameMatcher.MATCHES_ALL); this.reader = reader; this.input = null; } - public TestingDocument(IOSupplier inputStream, String name) { + /** + * Constructs a TestingDocument with the name {@code "name"} and the content provided by the input stream. + * @param inputSupplier the input supplier that provides content for the document as an input stream. + * @param name the name of the document. + */ + public TestingDocument(IOSupplier inputSupplier, String name) { super(DocumentName.builder(FSInfoTest.UNIX).setName(name).setBaseName("").build(), DocumentNameMatcher.MATCHES_ALL); - this.input = inputStream; + this.input = inputSupplier; this.reader = null; } + /** + * Gets the reader for the document content. + * @return the reader for the contents. + * @throws IOException on IO error when reading from input stream. + * @throws NullPointerException if neither the reader nor the input stream were provided. + */ @Override public Reader reader() throws IOException { return reader == null ? new InputStreamReader(input.get()) : reader; } + /** + * Returns {@code false} as a document is no directory. + * @return always returns {@code false}. + */ @Override public boolean isDirectory() { return false; } + /** + * A document does not have any children. + * @return always returns an empty set. + */ @Override public SortedSet listChildren() { return Collections.emptySortedSet(); } + /** + * Returns the input stream if it was provided in the constructor. + * @return the input stream if it was provided in the constructor. + * @throws IOException if the input stream can not be retrieved. + * @throws UnsupportedOperationException if the input stream was not provided. + */ @Override public InputStream inputStream() throws IOException { if (input != null) { diff --git a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingDocumentAnalyser.java b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingDocumentAnalyser.java index a4daaba08..cecf250fd 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingDocumentAnalyser.java +++ b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingDocumentAnalyser.java @@ -24,8 +24,14 @@ import org.apache.rat.api.Document; import org.apache.rat.document.DocumentAnalyser; +/** + * A document analyzer to be used in test where an actual analysis is not desired. + */ public class TestingDocumentAnalyser implements DocumentAnalyser { + /** + * A list of document that this analyser "analysed". + */ public final List matches = new ArrayList<>(); @Override diff --git a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingLicense.java b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingLicense.java index efc651be0..57b28499c 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingLicense.java +++ b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingLicense.java @@ -37,7 +37,7 @@ public class TestingLicense implements ILicense { /** * Creates a testing license with the specified id and a default TestingMatcher - * @param id The ID to use. + * @param id the id to use. * @see TestingMatcher */ public TestingLicense(String id) { @@ -46,8 +46,8 @@ public TestingLicense(String id) { /** * Creates a testing license with the specified id and a default TestingMatcher - * @param family the Family id - * @param id The ID to use. + * @param family the Family id. + * @param id the id to use. * @see TestingMatcher */ public TestingLicense(String family, String id) { @@ -55,8 +55,8 @@ public TestingLicense(String family, String id) { } /** - * Creates a testing license wit the specified id and matcher. - * @param id the ID to use + * Creates a testing license with the specified id and matcher. + * @param id the id to use. * @param matcher the matcher to execute. */ public TestingLicense(String family, String id, IHeaderMatcher matcher) { @@ -66,7 +66,7 @@ public TestingLicense(String family, String id, IHeaderMatcher matcher) { /** * Creates a testing license with the specified matcher and family. - * @param id the license id + * @param id the license id to use. * @param matcher the matcher to use. * @param family the family for this license. */ @@ -79,7 +79,7 @@ public TestingLicense(String id, IHeaderMatcher matcher, ILicenseFamily family) } /** - * Gets the family from the license + * Gets the family from the license. * @return the license family. */ public ILicenseFamily getFamily() { @@ -87,7 +87,7 @@ public ILicenseFamily getFamily() { } /** - * Gets the matcher from the license + * Gets the matcher from the license. * @return the matcher. */ @Override diff --git a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingLog.java b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingLog.java index 171cacacd..012b1a063 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingLog.java +++ b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingLog.java @@ -24,11 +24,13 @@ * Log that captures output for later review. */ public class TestingLog implements Log { - + /** The captured logging. */ private StringBuilder captured = new StringBuilder(); + /** The log level to capture. */ + private Log.Level level = Log.Level.INFO; /** - * Clears the captured buffer + * Clears the captured buffer. */ public void clear() { captured = new StringBuilder(); @@ -36,66 +38,30 @@ public void clear() { /** * Gets the captured log entries. - * @return the log entries + * @return the log entries. */ public String getCaptured() { return captured.toString(); } - /** - * Asserts the text was found in the given log entry. - * @param expected the text to find. - */ - public void assertContains(String expected) { - TextUtils.assertContains(expected, captured.toString()); - } - - /** - * Asserts the text was found exactly n times in the log. - * @param times the number of times to find the expected text. - * @param expected the expected test. - */ - public void assertContainsExactly(int times, String expected) { - TextUtils.assertContainsExactly(times, expected, getCaptured()); - } - - /** - * Asserts that the text is not found in the log. - * @param notExpected the text that should not be in the log. - */ - public void assertNotContains(String notExpected) { - TextUtils.assertNotContains(notExpected, captured.toString()); - } - - - /** - * Asserts that a regular expression is found in the log. - * @param pattern the regular expression to search for. - */ - public void assertContainsPattern(String pattern) { - TextUtils.assertPatternInTarget(pattern, captured.toString()); - } - - /** - * Asserts that a regular expression is not found in the log. - * @param pattern the regular expression that should not be in the log. - */ - public void assertNotContainsPattern(String pattern) { - TextUtils.assertPatternNotInTarget(pattern, captured.toString()); + @Override + public Level getLevel() { + return level; } @Override - public Level getLevel() { - return Level.DEBUG; + public void setLevel(Level level) { + this.level = level; } @Override public void log(Level level, String msg) { - captured.append(String.format("%s: %s%n", level, msg)); + if (isEnabled(level)) + captured.append(String.format("%s: %s%n", level, msg)); } /** - * Returns true if the log is empty. + * Determines if the log is empty. * @return {@code true} if the log is empty. */ public boolean isEmpty() { diff --git a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingMatcher.java b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingMatcher.java index 6aba39889..d290e3362 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingMatcher.java +++ b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TestingMatcher.java @@ -27,7 +27,7 @@ import org.apache.rat.config.parameters.ConfigComponent; /** - * A Matcher for testing. + * A matcher for testing. */ @ConfigComponent(type = ComponentType.MATCHER, name = "TestingMatcher", desc = "Matcher used in testing") public class TestingMatcher extends AbstractHeaderMatcher { @@ -35,7 +35,7 @@ public class TestingMatcher extends AbstractHeaderMatcher { private final Queue results; /** - * Constructs a matcher with an ID of "dfltMtch" that does not match anything. + * Constructs a matcher with an id of {@code "dfltMtch"} that does not match anything. */ public TestingMatcher() { this("dfltMtch", false); @@ -51,7 +51,7 @@ public TestingMatcher(boolean result) { /** * Constructs a matcher with the specified id and matching result. - * @param id the ID for this matcher + * @param id the id for this matcher. * @param result if {@code true} will match everything, otherwise it matches nothing. */ public TestingMatcher(String id, boolean result) { @@ -59,8 +59,8 @@ public TestingMatcher(String id, boolean result) { } /** - * Constructs a matcher with the specified ID that returns the matching values in order. - * Will throw NPE if more {@code matches()} are called than there are results. + * Constructs a matcher with the specified id that returns the matching values in order. + * Will throw NullPointerException if more {@code matches()} are called than there are results. * @param id the id of the matcher. * @param results the result for each call to match. */ diff --git a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TextUtils.java b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TextUtils.java index e90a30b9c..bf2d6fba4 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TextUtils.java +++ b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/TextUtils.java @@ -32,15 +32,17 @@ * Utilities to assert text appears or does not appear in text. */ public class TextUtils { - /** An empty list of strings */ + /** An empty list of strings. */ public static final String[] EMPTY = {}; /** - * Asserts a regular expression pattern is in a string. + * Asserts a regular expression pattern is in a given string. * * @param pattern the pattern to match. * @param target the string to match. + * @deprecated use assertThat(target).containsPattern(pattern) */ + @Deprecated public static void assertPatternInTarget(String pattern, String target) { assertThat(isMatching(pattern, target)).as(() -> format("Target does not match string: %s%n%s", pattern, target)) .isTrue(); @@ -51,7 +53,9 @@ public static void assertPatternInTarget(String pattern, String target) { * * @param pattern the pattern to match. * @param target the string to match. + * @deprecated use assertThat(target).doesNotContainPattern(pattern) */ + @Deprecated public static void assertPatternNotInTarget(String pattern, String target) { assertThat(isMatching(pattern, target)).as(() -> format("Target matches the pattern: %s%n%s", pattern, target)) .isFalse(); @@ -62,49 +66,14 @@ public static void assertPatternNotInTarget(String pattern, String target) { * * @param pattern the pattern to match. * @param target the string to match. - * @return {@code true} if a regular expression pattern is in a string + * @return {@code true} if a regular expression pattern is in a string. + * @deprecated use assertThat(target).matches(pattern) */ + @Deprecated public static boolean isMatching(final String pattern, final String target) { return Pattern.compile(pattern, Pattern.MULTILINE).matcher(target).find(); } - /** - * Asserts that a string is contained within another string. - * @param find The string to find. - * @param target The string to search. - */ - public static void assertContains(final String find, final String target) { - assertThat(target.contains(find)).as(() -> format("Target does not contain the text: %s%n%s", find, target)) - .isTrue(); - } - - /** - * Asserts that a string is contained exactly a specified number of times within another string. - * @param times The number of times to find the string in the target. - * @param find The string to find. - * @param target The string to search. - */ - public static void assertContainsExactly(int times, String find, String target) { - String t = target; - for (int i = 0; i < times; i++) { - assertThat(t.contains(find)).as(() -> format("Target does not contain %s copies of %s%n%s", times, find, target)) - .isTrue(); - t = t.substring(t.indexOf(find) + find.length()); - } - assertThat(t.contains(find)).as(() -> format("Target contains more than %s copies of %s%n%s", times, find, target)) - .isFalse(); - } - - /** - * Asserts that a string is not contained within another string. - * @param find The string to find. - * @param target The string to search. - */ - public static void assertNotContains(final String find, final String target) { - assertThat(target.contains(find)).as(() -> format("Target contains the text: %s%n%s", find , target)) - .isFalse(); - } - /** * Read given file as UTF-8. * @param f File to read from. diff --git a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/XmlUtils.java b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/XmlUtils.java index 7f53c9a61..4493e702c 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/XmlUtils.java +++ b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/XmlUtils.java @@ -34,6 +34,7 @@ import java.util.List; import java.util.Map; +import javax.xml.namespace.QName; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.OutputKeys; @@ -44,11 +45,13 @@ import javax.xml.transform.stream.StreamResult; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import org.apache.rat.report.xml.writer.XmlWriter; import org.apache.rat.utils.DefaultLog; import org.apache.rat.utils.StandardXmlFactory; +import org.opentest4j.AssertionFailedError; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -57,6 +60,9 @@ import org.xml.sax.SAXException; import org.xml.sax.XMLReader; +/** + * Utilities to help test XML documents. + */ public final class XmlUtils { /** * Private constructor, to prevent accidental instantiation. @@ -65,6 +71,12 @@ private XmlUtils() { // Does nothing } + /** + * Construct a safe XML reader. + * @return an XML reader. + * @throws SAXException on SAX exception. + * @throws ParserConfigurationException on parser configuration exception. + */ public static XMLReader newXMLReader() throws SAXException, ParserConfigurationException { final SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setValidating(false); @@ -72,14 +84,29 @@ public static XMLReader newXMLReader() throws SAXException, ParserConfigurationE return spf.newSAXParser().getXMLReader(); } + /** + * Determines whether the document string is well-formed. + * @param string the document string to check. + * @return {@code true} if the document is well-formed, {@code false} otherwise. + */ public static boolean isWellFormedXml(final String string) { return isWellFormedXml(new InputSource(new StringReader(string))); } + /** + * Determines whether the document in the input stream is well-formed. + * @param in the input stream containing the document. + * @return {@code true} if the document is well-formed, {@code false} otherwise. + */ public static boolean isWellFormedXml(final InputStream in) { return isWellFormedXml(new InputSource(in)); } + /** + * Determines whether the document in the input source is well-formed. + * @param isource the input source containing the document. + * @return {@code true} if the document is well-formed, {@code false} otherwise. + */ public static boolean isWellFormedXml(final InputSource isource) { try { newXMLReader().parse(isource); @@ -92,15 +119,39 @@ public static boolean isWellFormedXml(final InputSource isource) { } } + /** + * Gets a Nodelist from an XPath string. + * @param source the context for the XPath statement to be evaluated in. See {@link XPathExpression#evaluate(Object, QName)}. + * @param xPath the XPath object to compile the statement with. + * @param xpath the XPath statement to compile. + * @return the NodeList of nodes that matches the XPath. + * @throws XPathExpressionException on error. + */ public static NodeList getNodeList(Object source, XPath xPath, String xpath) throws XPathExpressionException { return (NodeList) xPath.compile(xpath).evaluate(source, XPathConstants.NODESET); } + /** + * Determines whether an XPath identified a node in the source. + * @param source the context for the XPath statement to be evaluated in. See {@link XPathExpression#evaluate(Object, QName)}. + * @param xPath the XPath object to compile the statement with. + * @param xpath the XPath statement to compile. + * @return {@code true} if the document contains the node identified by the XPath statement, {@code false} otherwise. + * @throws XPathExpressionException on error. + */ public static boolean isPresent(Object source, XPath xPath, String xpath) throws XPathExpressionException { Object node = xPath.compile(xpath).evaluate(source, XPathConstants.NODE); return node != null; } + /** + * Gets a List of Nodes from an XPath string. + * @param source the context for the XPath statement to be evaluated in. See {@link XPathExpression#evaluate(Object, QName)}. + * @param xPath the XPath object to compile the statement with. + * @param xpath the XPath statement to compile. + * @return the list of nodes that match the XPath. + * @throws XPathExpressionException on error. + */ public static List getNodes(Object source, XPath xPath, String xpath) throws XPathExpressionException { NodeList nodeList = (NodeList) xPath.compile(xpath).evaluate(source, XPathConstants.NODESET); List result = new ArrayList<>(); @@ -110,12 +161,26 @@ public static List getNodes(Object source, XPath xPath, String xpath) thro return result; } + /** + * Gets a node identified by an XPath. + * @param source the context for the XPath statement to be evaluated in. See {@link XPathExpression#evaluate(Object, QName)}. + * @param xPath the XPath object to compile the statement with. + * @param xpath the XPath statement to compile. + * @return the identified Node. + * @throws XPathExpressionException on error. + * @throws AssertionFailedError if more than one node is found. + */ public static Node getNode(Object source, XPath xPath, String xpath) throws XPathExpressionException { NodeList nodeList = getNodeList(source, xPath, xpath); - assertEquals(1, nodeList.getLength(), "Could not find exactly one" + xpath); + assertEquals(1, nodeList.getLength(), "Could not find exactly one " + xpath); return nodeList.item(0); } + /** + * Prints the specified NodeList as a string representation of its contents. + * @param nodeList the Nodelist to print. + * @return the string that contains the textual representation of the NodeList nodes. + */ public static String printNodeList(NodeList nodeList) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < nodeList.getLength(); i++) { @@ -134,7 +199,7 @@ public static String printNodeList(NodeList nodeList) { /** * Reads an input stream into a document. * @param inputStream the input stream to read. - * @return the Document + * @return the Document. * @throws SAXException on sax Error * @throws IOException on IO Error */ @@ -143,6 +208,13 @@ public static Document toDom(final InputStream inputStream) return StandardXmlFactory.documentBuilder().parse(inputStream); } + /** + * Writes a boolean attribute to an XML writer. + * @param writer the writer to write to. + * @param name the name of the attribute. + * @param booleanValue the boolean value. + * @throws IOException on write error. + */ public static void writeAttribute(final XmlWriter writer, final String name, final boolean booleanValue) throws IOException { final String value = Boolean.toString(booleanValue); @@ -150,10 +222,10 @@ public static void writeAttribute(final XmlWriter writer, final String name, fin } /** - * Print the properties and XML document to the output stream - * + * Print the XML document to the output stream. + * * @param out the OutputStream to print the document to. - * @param document The XML DOM document to print + * @param document The XML DOM document to print. */ public static void printDocument(OutputStream out, Document document) { TransformerFactory tf = TransformerFactory.newInstance(); @@ -173,6 +245,15 @@ public static void printDocument(OutputStream out, Document document) { } } + /** + * Get an attribute from an XPath statement + * @param source the context for the XPath statement to be evaluated in. See {@link XPathExpression#evaluate(Object, QName)}. + * @param xPath the XPath object to compile the statement with. + * @param xpath the XPath statement to compile. + * @param attribute attribute to retrieve from the node specified by the XPath statement. + * @return the string value of the attribute. + * @throws XPathExpressionException on error + */ public static String getAttribute(Object source, XPath xPath, String xpath, String attribute) throws XPathExpressionException { Node node = XmlUtils.getNode(source, xPath, xpath); NamedNodeMap attr = node.getAttributes(); @@ -189,10 +270,14 @@ public static Map mapOf(String... parts) { return map; } - public static void assertAttributes(Object source, XPath xPath, String xpath, String... mapValues) throws XPathExpressionException { - assertAttributes(source, xPath, xpath, mapOf(mapValues)); - } - + /** + * Assert that attributes are set on a node. + * @param source the context for the XPath statement to be evaluated in. See {@link XPathExpression#evaluate(Object, QName)}. + * @param xPath the XPath object to compile the statement with. + * @param xpath the XPath statement to compile. + * @param attributes a map of attribute names to values. + * @throws XPathExpressionException on error. + */ public static void assertAttributes(Object source, XPath xPath, String xpath, Map attributes) throws XPathExpressionException { Node node = XmlUtils.getNode(source, xPath, xpath); NamedNodeMap attr = node.getAttributes(); @@ -203,18 +288,44 @@ public static void assertAttributes(Object source, XPath xPath, String xpath, Ma } } + /** + * Assert that an XPath is present in the document. + * @param source the context for the XPath statement to be evaluated in. See {@link XPathExpression#evaluate(Object, QName)}. + * @param xPath the XPath object to compile the statement with. + * @param xpath the XPath statement to compile. + */ public static void assertIsPresent(Object source, XPath xPath, String xpath) throws XPathExpressionException { assertThat(isPresent(source, xPath, xpath)).as("Presence of " + xpath).isTrue(); } + /** + * Assert that an XPath is not present in the document. + * @param source the context for the XPath statement to be evaluated in. See {@link XPathExpression#evaluate(Object, QName)}. + * @param xPath the XPath object to compile the statement with. + * @param xpath the XPath statement to compile. + */ public static void assertIsNotPresent(Object source, XPath xPath, String xpath) throws XPathExpressionException { assertThat(isPresent(source, xPath, xpath)).as("Non-presence of " + xpath).isFalse(); } + /** + * Assert that a named XPath is present in the document. + * @param identifier the name of the object. + * @param source the context for the XPath statement to be evaluated in. See {@link XPathExpression#evaluate(Object, QName)}. + * @param xPath The XPath object to compile the statement with. + * @param xpath the XPath statement to compile. + */ public static void assertIsPresent(String identifier, Object source, XPath xPath, String xpath) throws XPathExpressionException { assertThat(isPresent(source, xPath, xpath)).as(identifier + ": Presence of " + xpath).isTrue(); } + /** + * Assert that a named XPath is not present in the document. + * @param identifier the name of the object. + * @param source the context for the XPath statement to be evaluated in. See {@link XPathExpression#evaluate(Object, QName)}. + * @param xPath The XPath object to compile the statement with. + * @param xpath the XPath statement to compile. + */ public static void assertIsNotPresent(String identifier, Object source, XPath xPath, String xpath) throws XPathExpressionException { assertThat(isPresent(source, xPath, xpath)).as(identifier + ": Non-presence of " + xpath).isFalse(); } diff --git a/apache-rat-core/src/test/java/org/apache/rat/testhelpers/data/AbstractTestDataProvider.java b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/data/AbstractTestDataProvider.java new file mode 100644 index 000000000..6906a0002 --- /dev/null +++ b/apache-rat-core/src/test/java/org/apache/rat/testhelpers/data/AbstractTestDataProvider.java @@ -0,0 +1,363 @@ +/* + * 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 * + * * + * http://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.testhelpers.data; + +import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.stream.Stream; +import org.apache.commons.cli.Option; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.rat.commandline.Arg; +import org.apache.rat.ui.UIOptionCollection; +import org.apache.rat.ui.ArgumentTracker; +import org.apache.rat.utils.DefaultLog; + +/** + * Generates a list of TestData to test an implementation. + * The tests work by creating a Path Consumer to construct a directory under the test base directory and creating files and/or + * directories within that directory. A test validator is created to validate the expected results of the operation and a {@link TestData} + * object is created for each test. + *
+ * Each {@code TestData} represents a single test of a command line option or set of options. + *
+ * Use of this class ensures consistent testing across all available UIs. + */ +public abstract class AbstractTestDataProvider { + /** The list of exclude arguments. */ + static final String[] EXCLUDE_ARGS = {"*.foo", "%regex[[A-Z]\\.bar]", "justbaz"}; + /** The list of include arguments. */ + static final String[] INCLUDE_ARGS = {"B.bar", "justbaz"}; + // Sonar suggests List.of(), but we need an Immutable list. + public static final ImmutableList> NO_OPTIONS = ImmutableList.of(ImmutablePair.nullPair()); // NOSONAR + + /** + * Generates a map of TestData indexed by the testName. + * @param optionCollection the collection of options for the UI under test. + * @return the map of testName to Test Data. + */ + public final Map getOptionTestMap(final UIOptionCollection optionCollection) { + Map map = new TreeMap<>(); + for (TestData test : getOptionTests(optionCollection)) { + map.put(test.getTestName(), test); + } + return map; + } + + /** + * Generates a list of test data for Option testing. + * This is different from UI testing as this is to test + * that the command line is properly parsed into a configuration. + * @param optionCollection the collection of options for the UI under test. + * @return a set of TestData for the tests. + */ + public final Set getOptionTests(final UIOptionCollection optionCollection) { + // the optionCollection establishes any changes to the Arg values. + List