From 64db2181bf295ff3659ee1e7f00a9b4b55c3fd2f Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Mon, 13 Jan 2025 22:46:12 +0000 Subject: [PATCH 001/123] added working directory --- .../resources/ReportTest/RAT_14/verify.groovy | 2 +- .../java/org/apache/rat/OptionCollection.java | 34 +- .../src/main/java/org/apache/rat/Report.java | 4 +- .../rat/commandline/ArgumentContext.java | 28 +- .../config/exclusion/ExclusionProcessor.java | 4 +- .../config/exclusion/plexus/MatchPattern.java | 10 +- .../exclusion/plexus/MatchPatterns.java | 40 +- .../rat/document/DocumentNameMatcher.java | 390 ++++++++++++++++-- .../org/apache/rat/OptionCollectionTest.java | 45 +- .../java/org/apache/rat/ReporterTest.java | 17 +- .../org/apache/rat/commandline/ArgTests.java | 2 +- .../rat/document/DocumentNameMatcherTest.java | 94 +++++ .../rat/test/AbstractOptionsProvider.java | 311 ++++++++------ .../org/apache/rat/test/utils/Resources.java | 20 +- .../org/apache/rat/testhelpers/XmlUtils.java | 24 +- .../org/apache/rat/mp/AbstractRatMojo.java | 36 +- .../org/apache/rat/mp/OptionMojoTest.java | 94 ++--- .../apache/rat/anttasks/ReportOptionTest.java | 34 +- .../org/apache/rat/tools/Documentation.java | 3 +- 19 files changed, 852 insertions(+), 340 deletions(-) create mode 100644 apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_14/verify.groovy b/apache-rat-core/src/it/resources/ReportTest/RAT_14/verify.groovy index 431b0b046..226394df0 100644 --- a/apache-rat-core/src/it/resources/ReportTest/RAT_14/verify.groovy +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_14/verify.groovy @@ -64,7 +64,7 @@ myArgs[1] = "UNAPPROVED:-1" myArgs[2] = "--" myArgs[3] = src.getAbsolutePath() -ReportConfiguration configuration = OptionCollection.parseCommands(myArgs, { opts -> }) +ReportConfiguration configuration = OptionCollection.parseCommands(src, myArgs, { opts -> }) assertNotNull(configuration) configuration.validate(DefaultLog.getInstance().&error) Reporter reporter = new Reporter(configuration) diff --git a/apache-rat-core/src/main/java/org/apache/rat/OptionCollection.java b/apache-rat-core/src/main/java/org/apache/rat/OptionCollection.java index dca321c9c..7dc33fd88 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/OptionCollection.java +++ b/apache-rat-core/src/main/java/org/apache/rat/OptionCollection.java @@ -132,25 +132,28 @@ private static String asString(final Object[] args) { /** * Parses the standard options to create a ReportConfiguration. * + * @param workingDirectory The directory to resolve relative file names against. * @param args the arguments to parse * @param helpCmd the help command to run when necessary. * @return a ReportConfiguration or null if Help was printed. * @throws IOException on error. */ - public static ReportConfiguration parseCommands(final String[] args, final Consumer helpCmd) throws IOException { - return parseCommands(args, helpCmd, false); + public static ReportConfiguration parseCommands(final File workingDirectory, final String[] args, final Consumer helpCmd) throws IOException { + return parseCommands(workingDirectory, args, helpCmd, false); } /** * Parses the standard options to create a ReportConfiguration. * + * @param workingDirectory The directory to resolve relative file names against. * @param args the arguments to parse * @param helpCmd the help command to run when necessary. * @param noArgs If true then the commands do not need extra arguments * @return a ReportConfiguration or {@code null} if Help was printed. * @throws IOException on error. */ - public static ReportConfiguration parseCommands(final String[] args, final Consumer helpCmd, final boolean noArgs) throws IOException { + public static ReportConfiguration parseCommands(final File workingDirectory, final String[] args, + final Consumer helpCmd, final boolean noArgs) throws IOException { Options opts = buildOptions(); CommandLine commandLine; try { @@ -166,27 +169,23 @@ public static ReportConfiguration parseCommands(final String[] args, final Consu Arg.processLogLevel(commandLine); + ArgumentContext argumentContext = new ArgumentContext(workingDirectory, commandLine); if (commandLine.hasOption(HELP)) { helpCmd.accept(opts); return null; } if (commandLine.hasOption(HELP_LICENSES)) { - new Licenses(createConfiguration(commandLine), new PrintWriter(System.out)).printHelp(); - return null; - } - - if (commandLine.hasOption(HELP_LICENSES)) { - new Licenses(createConfiguration(commandLine), new PrintWriter(System.out)).printHelp(); + new Licenses(createConfiguration(argumentContext), new PrintWriter(System.out)).printHelp(); return null; } if (commandLine.hasOption(Arg.HELP_LICENSES.option())) { - new Licenses(createConfiguration(commandLine), new PrintWriter(System.out)).printHelp(); + new Licenses(createConfiguration(argumentContext), new PrintWriter(System.out)).printHelp(); return null; } - ReportConfiguration configuration = createConfiguration(commandLine); + ReportConfiguration configuration = createConfiguration(argumentContext); if (!noArgs && !configuration.hasSource()) { String msg = "No directories or files specified for scanning. Did you forget to close a multi-argument option?"; DefaultLog.getInstance().error(msg); @@ -201,14 +200,15 @@ public static ReportConfiguration parseCommands(final String[] args, final Consu * Create the report configuration. * Note: this method is package private for testing. * You probably want one of the {@code ParseCommands} methods. - * @param commandLine the parsed command line. + * @param argumentContext The context to execute in. * @return a ReportConfiguration - * @see #parseCommands(String[], Consumer) - * @see #parseCommands(String[], Consumer, boolean) + * @see #parseCommands(File, String[], Consumer) + * @see #parseCommands(File, String[], Consumer, boolean) */ - static ReportConfiguration createConfiguration(final CommandLine commandLine) { - final ReportConfiguration configuration = new ReportConfiguration(); - new ArgumentContext(configuration, commandLine).processArgs(); + static ReportConfiguration createConfiguration(final ArgumentContext argumentContext) { + argumentContext.processArgs(); + final ReportConfiguration configuration = argumentContext.getConfiguration(); + final CommandLine commandLine = argumentContext.getCommandLine(); if (Arg.DIR.isSelected()) { try { configuration.addSource(getReportable(commandLine.getParsedOptionValue(Arg.DIR.getSelected()), configuration)); diff --git a/apache-rat-core/src/main/java/org/apache/rat/Report.java b/apache-rat-core/src/main/java/org/apache/rat/Report.java index 6a7847e5b..ff4103c4c 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/Report.java +++ b/apache-rat-core/src/main/java/org/apache/rat/Report.java @@ -18,6 +18,8 @@ */ package org.apache.rat; +import java.io.File; + import org.apache.commons.cli.Options; import org.apache.rat.document.RatDocumentAnalysisException; import org.apache.rat.help.Help; @@ -39,7 +41,7 @@ public final class Report { */ public static void main(final String[] args) throws Exception { DefaultLog.getInstance().info(new VersionInfo().toString()); - ReportConfiguration configuration = OptionCollection.parseCommands(args, Report::printUsage); + ReportConfiguration configuration = OptionCollection.parseCommands(new File("."), args, Report::printUsage); if (configuration != null) { configuration.validate(DefaultLog.getInstance()::error); Reporter reporter = new Reporter(configuration); diff --git a/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java b/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java index 31abfd073..b69c5b7f8 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java +++ b/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java @@ -18,10 +18,13 @@ */ package org.apache.rat.commandline; +import java.io.File; + import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Option; import org.apache.commons.cli.ParseException; import org.apache.rat.ReportConfiguration; +import org.apache.rat.document.DocumentName; import org.apache.rat.utils.DefaultLog; import static java.lang.String.format; @@ -35,17 +38,30 @@ public class ArgumentContext { private final ReportConfiguration configuration; /** The command line that is building the configuration */ private final CommandLine commandLine; + /** The directory from which relative file names will be resolved */ + private final DocumentName workingDirectory; /** - * Constructor. + * Creates a context with the specified configuration. + * @param workingDirectory the directory from which relative file names will be resolved. * @param configuration The configuration that is being built. * @param commandLine The command line that is building the configuration. */ - public ArgumentContext(final ReportConfiguration configuration, final CommandLine commandLine) { + public ArgumentContext(final File workingDirectory, final ReportConfiguration configuration, final CommandLine commandLine) { + this.workingDirectory = DocumentName.builder(workingDirectory).build(); this.commandLine = commandLine; this.configuration = configuration; } + /** + * Creates a context with an empty configuration. + * @param workingDirectory The directory from which to resolve relative file names. + * @param commandLine The command line. + */ + public ArgumentContext(final File workingDirectory, final CommandLine commandLine) { + this(workingDirectory, new ReportConfiguration(), commandLine); + } + /** * Process the arguments specified in this context. */ @@ -69,6 +85,14 @@ public CommandLine getCommandLine() { return commandLine; } + /** + * Gets the directory name from which relative file names will be resolved. + * @return The directory name from which releative file names will be resolved. + */ + public DocumentName getWorkingDirectory() { + return workingDirectory; + } + /** * Logs a ParseException as a warning. * @param exception the parse exception to log 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 e21432e03..c1de611ff 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 @@ -255,10 +255,10 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { .addTo(new ArrayList<>()); if (!incl.isEmpty()) { - inclMatchers.add(new DocumentNameMatcher("included patterns", MatchPatterns.from(incl), basedir)); + inclMatchers.add(new DocumentNameMatcher("included patterns", MatchPatterns.from(basedir.getDirectorySeparator(), incl), basedir)); } if (!excl.isEmpty()) { - exclMatchers.add(new DocumentNameMatcher("excluded patterns", MatchPatterns.from(excl), basedir)); + exclMatchers.add(new DocumentNameMatcher("excluded patterns", MatchPatterns.from(basedir.getDirectorySeparator(), excl), basedir)); } if (!includedPaths.isEmpty()) { diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java index c43836ecd..b606136af 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java @@ -19,6 +19,7 @@ import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.StringTokenizer; @@ -49,7 +50,7 @@ public final class MatchPattern { private final char[][] tokenizedChar; - private MatchPattern(final String source, final String separator) { + public MatchPattern(final String source, final String separator) { regexPattern = SelectorUtils.isRegexPrefixedPattern(source) ? source.substring( SelectorUtils.REGEX_HANDLER_PREFIX.length(), @@ -83,7 +84,7 @@ boolean matchPath(final String str, final char[][] strDirs, final boolean isCase } else { result = SelectorUtils.matchAntPathPattern(getTokenizedPathChars(), strDirs, isCaseSensitive); } - if (result && DefaultLog.getInstance().isEnabled(Log.Level.DEBUG)) { + if (DefaultLog.getInstance().isEnabled(Log.Level.DEBUG)) { DefaultLog.getInstance().debug(format("%s match %s -> %s", this, str, result)); } return result; @@ -116,7 +117,7 @@ public boolean startsWith(final String string) { @Override public String toString() { - return source; + return Arrays.asList(tokenized).toString(); } public String source() { @@ -141,7 +142,4 @@ static char[][] tokenizePathToCharArray(final String path, final String separato return tokenizedNameChar; } - public static MatchPattern fromString(final String source) { - return new MatchPattern(source, File.separator); - } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java index 454ba304e..9a6d443e4 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java @@ -22,8 +22,9 @@ import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import java.util.function.Predicate; +import java.util.stream.Collectors; @SuppressWarnings({"checkstyle:RegexpSingleLine", "checkstyle:JavadocVariable"}) /** @@ -41,15 +42,15 @@ private MatchPatterns(final MatchPattern[] patterns) { @Override public String toString() { - return source(); + return Arrays.stream(patterns).map(MatchPattern::toString).collect(Collectors.toList()).toString(); } public String source() { - List sources = new ArrayList<>(); - for (MatchPattern pattern : patterns) { - sources.add(pattern.source()); - } - return "[" + String.join(", ", sources) + "]"; + return Arrays.stream(patterns).map(MatchPattern::source).collect(Collectors.toList()).toString(); + } + + public Iterable patterns() { + return Arrays.asList(patterns); } /** @@ -83,36 +84,23 @@ public boolean matches(final String name, final char[][] tokenizedNameChar, fina return false; } - public Predicate asPredicate(final boolean isCaseSensitive) { - return name -> matches(name, isCaseSensitive); - } - - public boolean matchesPatternStart(final String name, final boolean isCaseSensitive) { - for (MatchPattern includesPattern : patterns) { - if (includesPattern.matchPatternStart(name, isCaseSensitive)) { - return true; - } - } - return false; - } - - public static MatchPatterns from(final String... sources) { + public static MatchPatterns from(final String separator, final String... sources) { final int length = sources.length; MatchPattern[] result = new MatchPattern[length]; for (int i = 0; i < length; i++) { - result[i] = MatchPattern.fromString(sources[i]); + result[i] = new MatchPattern(sources[i], separator); } return new MatchPatterns(result); } - public static MatchPatterns from(final Iterable strings) { - return new MatchPatterns(getMatchPatterns(strings)); + public static MatchPatterns from(final String separator, final Iterable strings) { + return new MatchPatterns(getMatchPatterns(separator, strings)); } - private static MatchPattern[] getMatchPatterns(final Iterable items) { + private static MatchPattern[] getMatchPatterns(final String separator, final Iterable items) { List result = new ArrayList<>(); for (String string : items) { - result.add(MatchPattern.fromString(string)); + result.add(new MatchPattern(string, separator)); } return result.toArray(new MatchPattern[0]); } diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 30bbbbede..0e66b19f7 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -23,9 +23,14 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Optional; +import java.util.Set; import java.util.function.Predicate; +import org.apache.rat.ConfigurationException; import org.apache.rat.config.exclusion.plexus.MatchPattern; import org.apache.rat.config.exclusion.plexus.MatchPatterns; @@ -40,6 +45,8 @@ public final class DocumentNameMatcher { private final Predicate predicate; /** The name of this matcher. */ private final String name; + /** {@code true} this this matcher is a collection of matchers */ + private final boolean isCollection; /** * A matcher that matches all documents. @@ -59,6 +66,7 @@ public final class DocumentNameMatcher { public DocumentNameMatcher(final String name, final Predicate predicate) { this.name = name; this.predicate = predicate; + this.isCollection = predicate instanceof CollectionPredicateImpl; } /** @@ -77,9 +85,22 @@ public DocumentNameMatcher(final String name, final DocumentNameMatcher delegate * @param basedir the base directory for the scanning. */ public DocumentNameMatcher(final String name, final MatchPatterns patterns, final DocumentName basedir) { - this(name, (Predicate) documentName -> patterns.matches(documentName.getName(), - MatchPattern.tokenizePathToString(documentName.getName(), basedir.getDirectorySeparator()), - basedir.isCaseSensitive())); + this(name, new MatchPatternsPredicate(basedir, patterns)); + } + + /** + * Tokenizes name for faster Matcher processing. + * @param name the name to tokenize + * @param dirSeparator the directory separator + * @return the tokenized name. + */ + private static char[][] tokenize(final String name, final String dirSeparator) { + String[] tokenizedName = MatchPattern.tokenizePathToString(name, dirSeparator); + char[][] tokenizedNameChar = new char[tokenizedName.length][]; + for (int i = 0; i < tokenizedName.length; i++) { + tokenizedNameChar[i] = tokenizedName[i].toCharArray(); + } + return tokenizedNameChar; } /** @@ -88,7 +109,20 @@ public DocumentNameMatcher(final String name, final MatchPatterns patterns, fina * @param matchers fully specified matchers. */ public DocumentNameMatcher(final String name, final MatchPatterns matchers) { - this(name, (Predicate) documentName -> matchers.matches(documentName.getName(), documentName.isCaseSensitive())); + this(name, new CollectionPredicate() { + @Override + public Iterable getMatchers() { + final List result = new ArrayList<>(); + matchers.patterns().forEach(p -> result.add(new DocumentNameMatcher(p.source(), + (Predicate) x -> MatchPatterns.from("/", p.source()).matches(x.getName(), x.isCaseSensitive())))); + return result; + } + + @Override + public boolean test(final DocumentName documentName) { + return matchers.matches(documentName.getName(), documentName.isCaseSensitive()); + } + }); } /** @@ -97,7 +131,7 @@ public DocumentNameMatcher(final String name, final MatchPatterns matchers) { * @param fileFilter the file filter to execute. */ public DocumentNameMatcher(final String name, final FileFilter fileFilter) { - this(name, (Predicate) documentName -> fileFilter.accept(new File(documentName.getName()))); + this(name, new FileFilterPredicate(fileFilter)); } /** @@ -108,11 +142,39 @@ public DocumentNameMatcher(final FileFilter fileFilter) { this(fileFilter.toString(), fileFilter); } + public boolean isCollection() { + return isCollection; + } + + /** + * Returns the predicate that this DocumentNameMatcher is using. + * @return The predicate that this DocumentNameMatcher is using. + */ + public Predicate getPredicate() { + return predicate; + } + @Override public String toString() { return name; } + /** + * Decomposes the matcher execution against the candidate. + * @param candidate the candiate to check. + * @return a list of {@link DecomposeData} for each evaluation in the matcher. + */ + public List decompose(final DocumentName candidate) { + final List result = new ArrayList<>(); + decompose(0, this, candidate, result); + return result; + } + + private void decompose(final int level, final DocumentNameMatcher matcher, final DocumentName candidate, final List result) { + final Predicate pred = matcher.getPredicate(); + result.add(new DecomposeData(level, matcher, candidate, pred.test(candidate))); + } + /** * Performs the match against the DocumentName. * @param documentName the document name to check. @@ -135,8 +197,7 @@ public static DocumentNameMatcher not(final DocumentNameMatcher nameMatcher) { return MATCHES_ALL; } - return new DocumentNameMatcher(format("not(%s)", nameMatcher), - (Predicate) documentName -> !nameMatcher.matches(documentName)); + return new DocumentNameMatcher(format("not(%s)", nameMatcher), new NotPredicate(nameMatcher)); } /** @@ -150,30 +211,43 @@ private static String join(final Collection matchers) { return String.join(", ", children); } + private static Optional standardCollectionCheck(final Collection matchers, + final DocumentNameMatcher override) { + if (matchers.isEmpty()) { + throw new ConfigurationException("Empty matcher collection"); + } + if (matchers.size() == 1) { + return Optional.of(matchers.iterator().next()); + } + if (matchers.contains(override)) { + return Optional.of(override); + } + return Optional.empty(); + } + /** * Performs a logical {@code OR} across the collection of matchers. * @param matchers the matchers to check. * @return a matcher that returns {@code true} if any of the enclosed matchers returns {@code true}. */ public static DocumentNameMatcher or(final Collection matchers) { - if (matchers.isEmpty()) { - return MATCHES_NONE; - } - if (matchers.size() == 1) { - return matchers.iterator().next(); - } - if (matchers.contains(MATCHES_ALL)) { - return MATCHES_ALL; + Optional opt = standardCollectionCheck(matchers, MATCHES_ALL); + if (opt.isPresent()) { + return opt.get(); } - return new DocumentNameMatcher(format("or(%s)", join(matchers)), (Predicate) documentName -> { - for (DocumentNameMatcher matcher : matchers) { - if (matcher.matches(documentName)) { - return true; - } - } - return false; - }); + // preserve order + Set workingSet = new LinkedHashSet<>(); + for (DocumentNameMatcher matcher : matchers) { + // check for nested or + if (matcher.predicate instanceof Or) { + ((Or) matcher.predicate).getMatchers().forEach(workingSet::add); + } else { + workingSet.add(matcher); + } + } + return standardCollectionCheck(matchers, MATCHES_ALL) + .orElseGet(() -> new DocumentNameMatcher(format("or(%s)", join(workingSet)), new Or(workingSet))); } /** @@ -191,24 +265,45 @@ public static DocumentNameMatcher or(final DocumentNameMatcher... matchers) { * @return a matcher that returns {@code true} if all the enclosed matchers return {@code true}. */ public static DocumentNameMatcher and(final Collection matchers) { - if (matchers.isEmpty()) { - return MATCHES_NONE; - } - if (matchers.size() == 1) { - return matchers.iterator().next(); + Optional opt = standardCollectionCheck(matchers, MATCHES_NONE); + if (opt.isPresent()) { + return opt.get(); } - if (matchers.contains(MATCHES_NONE)) { - return MATCHES_NONE; + + // preserve order + Set workingSet = new LinkedHashSet<>(); + for (DocumentNameMatcher matcher : matchers) { + // check for nexted And + if (matcher.predicate instanceof And) { + ((And) matcher.predicate).getMatchers().forEach(workingSet::add); + } else { + workingSet.add(matcher); + } } + opt = standardCollectionCheck(matchers, MATCHES_NONE); + return opt.orElseGet(() -> new DocumentNameMatcher(format("and(%s)", join(workingSet)), new And(workingSet))); + } - return new DocumentNameMatcher(format("and(%s)", join(matchers)), (Predicate) documentName -> { - for (DocumentNameMatcher matcher : matchers) { - if (!matcher.matches(documentName)) { - return false; - } + /** + * A particular matcher that will not match any excluded unless they are listed in the includes. + * @param includes the DocumentNameMatcher to match the includes. + * @param excludes the DocumentNameMatcher to match the excludes. + * @return a DocumentNameMatcher with the specified logic. + */ + public static DocumentNameMatcher matcherSet(final DocumentNameMatcher includes, + final DocumentNameMatcher excludes) { + if (excludes == MATCHES_NONE) { + return MATCHES_ALL; + } else { + if (includes == MATCHES_NONE) { + return not(excludes); } - return true; - }); + } + if (includes == MATCHES_ALL) { + return MATCHES_ALL; + } + List workingSet = Arrays.asList(includes, excludes); + return new DocumentNameMatcher(format("matcherSet(%s)", join(workingSet)), new MatcherPredicate(workingSet)); } /** @@ -219,4 +314,225 @@ public static DocumentNameMatcher and(final Collection matc public static DocumentNameMatcher and(final DocumentNameMatcher... matchers) { return and(Arrays.asList(matchers)); } + + + + /** + * A DocumentName predicate that uses MatchPatterns. + */ + public static final class MatchPatternsPredicate implements Predicate { + /** The base diirectory for the pattern matches */ + private final DocumentName basedir; + /** The patter matchers */ + private final MatchPatterns patterns; + + private MatchPatternsPredicate(final DocumentName basedir, final MatchPatterns patterns) { + this.basedir = basedir; + this.patterns = patterns; + } + + @Override + public boolean test(final DocumentName documentName) { + return patterns.matches(documentName.getName(), + tokenize(documentName.getName(), basedir.getDirectorySeparator()), + basedir.isCaseSensitive()); + } + + @Override + public String toString() { + return patterns.toString(); + } + } + + /** + * A DocumentName predicate reverses another DocumentNameMatcher + */ + public static final class NotPredicate implements Predicate { + /** The document name matcher to reverse */ + private final DocumentNameMatcher nameMatcher; + + private NotPredicate(final DocumentNameMatcher nameMatcher) { + this.nameMatcher = nameMatcher; + } + + @Override + public boolean test(final DocumentName documentName) { + return !nameMatcher.matches(documentName); + } + + @Override + public String toString() { + return nameMatcher.predicate.toString(); + } + } + + /** + * A DocumentName predicate that uses FileFilter. + */ + public static final class FileFilterPredicate implements Predicate { + /** The file filter */ + private final FileFilter fileFilter; + + private FileFilterPredicate(final FileFilter fileFilter) { + this.fileFilter = fileFilter; + } + + @Override + public boolean test(final DocumentName documentName) { + return fileFilter.accept(new File(documentName.getName())); + } + + @Override + public String toString() { + return fileFilter.toString(); + } + } + + interface CollectionPredicate extends Predicate { + Iterable getMatchers(); + } + /** + * A marker interface to indicate this predicate contains a collection of matchers. + */ + abstract static class CollectionPredicateImpl implements CollectionPredicate { + /** The collection for matchers that make up this predicate */ + private final Iterable matchers; + + /** + * Constructs a collecton predicate from the collection of matchers + * @param matchers the colleciton of matchers to use. + */ + protected CollectionPredicateImpl(final Iterable matchers) { + this.matchers = matchers; + } + + /** + * Gets the internal matchers. + * @return an iterable over the internal matchers. + */ + public Iterable getMatchers() { + return matchers; + } + + public String toString() { + StringBuilder builder = new StringBuilder(this.getClass().getName()).append(": ").append(System.lineSeparator()); + for (DocumentNameMatcher matcher : matchers) { + builder.append(matcher.predicate.toString()).append(System.lineSeparator()); + } + return builder.toString(); + } + } + + /** + * An implementation of "and" logic across a collection of DocumentNameMatchers. + */ + // package private for testing access + static class And extends CollectionPredicateImpl { + And(final Iterable matchers) { + super(matchers); + } + + @Override + public boolean test(final DocumentName documentName) { + for (DocumentNameMatcher matcher : getMatchers()) { + if (!matcher.matches(documentName)) { + return false; + } + } + return true; + } + } + + /** + * An implementation of "or" logic across a collection of DocumentNameMatchers. + */ + // package private for testing access + static class Or extends CollectionPredicateImpl { + Or(final Iterable matchers) { + super(matchers); + } + + @Override + public boolean test(final DocumentName documentName) { + for (DocumentNameMatcher matcher : getMatchers()) { + if (matcher.matches(documentName)) { + return true; + } + } + return false; + } + } + + /** + * An implementation of "or" logic across a collection of DocumentNameMatchers. + */ + // package private for testing access + static class MatcherPredicate extends CollectionPredicateImpl { + MatcherPredicate(final Iterable matchers) { + super(matchers); + } + + @Override + public boolean test(final DocumentName documentName) { + Iterator iter = getMatchers().iterator(); + // included + if (iter.next().matches(documentName)) { + return true; + } + // excluded + if (iter.next().matches(documentName)) { + return false; + } + return true; + } + } + + /** + * Data from a {@link DocumentNameMatcher#decompose(DocumentName)} call. + */ + public static final class DecomposeData { + /** the level this data was generated at */ + private final int level; + /** The name of the DocumentNameMatcher that created this result */ + private final DocumentNameMatcher matcher; + /** The result of the check. */ + private final boolean result; + /** The candidate */ + private final DocumentName candidate; + + private DecomposeData(final int level, final DocumentNameMatcher matcher, final DocumentName candidate, final boolean result) { + this.level = level; + this.matcher = matcher; + this.result = result; + this.candidate = candidate; + } + + @Override + public String toString() { + final String fill = createFill(level); + return format("%s%s: >>%s<< %s%n%s", + fill, matcher.toString(), result, + level == 0 ? candidate.getName() : "", + matcher.predicate instanceof CollectionPredicate ? + decompose(level + 1, (CollectionPredicate) matcher.predicate, candidate) : + String.format("%s%s >>%s<<", createFill(level + 1), matcher.predicate.toString(), matcher.predicate.test(candidate))); + } + + private String createFill(final int level) { + final char[] chars = new char[level * 2]; + Arrays.fill(chars, ' '); + return new String(chars); + } + + private String decompose(final int level, final CollectionPredicate predicate, final DocumentName candidate) { + List result = new ArrayList<>(); + + for (DocumentNameMatcher nameMatcher : predicate.getMatchers()) { + nameMatcher.decompose(level, nameMatcher, candidate, result); + } + StringBuilder sb = new StringBuilder(); + result.forEach(x -> sb.append(x).append(System.lineSeparator())); + return sb.toString(); + } + } } 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 ab1ce763a..e761afe32 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 @@ -18,21 +18,25 @@ */ package org.apache.rat; +import java.nio.file.Path; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.Option; import org.apache.commons.cli.ParseException; import org.apache.commons.lang3.tuple.Pair; +import org.apache.rat.commandline.ArgumentContext; import org.apache.rat.license.LicenseSetFactory; import org.apache.rat.report.IReportable; import org.apache.rat.test.AbstractOptionsProvider; import org.apache.rat.testhelpers.TestingLog; import org.apache.rat.utils.DefaultLog; import org.apache.rat.utils.Log; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.api.condition.OS; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; @@ -55,6 +59,14 @@ public class OptionCollectionTest { + @TempDir + static Path testPath; + + @AfterAll + static void preserveData() { + AbstractOptionsProvider.preserveData(testPath.toFile(), "optionTest"); + } + /** * The base directory for the test. * We do not use TempFile because we want the evidence of the run @@ -103,7 +115,7 @@ public void testDeprecatedUseLogged() throws IOException { try { DefaultLog.setInstance(log); String[] args = {"--dir", "target", "-a"}; - ReportConfiguration config = OptionCollection.parseCommands(args, o -> fail("Help printed"), true); + ReportConfiguration config = OptionCollection.parseCommands(testPath.toFile(), args, o -> fail("Help printed"), true); assertThat(config).isNotNull(); } finally { DefaultLog.setInstance(null); @@ -119,7 +131,7 @@ public void testDirOptionCapturesDirectoryToScan() throws IOException { try { DefaultLog.setInstance(log); String[] args = {"--dir", baseDir.getAbsolutePath()}; - config = OptionCollection.parseCommands(args, (o) -> { + config = OptionCollection.parseCommands(testPath.toFile(), args, (o) -> { }, true); } finally { DefaultLog.setInstance(null); @@ -131,7 +143,7 @@ public void testDirOptionCapturesDirectoryToScan() throws IOException { @Test public void testShortenedOptions() throws IOException { String[] args = {"--output-lic", "ALL"}; - ReportConfiguration config = OptionCollection.parseCommands(args, (o) -> { + ReportConfiguration config = OptionCollection.parseCommands(testPath.toFile(), args, (o) -> { }, true); assertThat(config).isNotNull(); assertThat(config.listLicenses()).isEqualTo(LicenseSetFactory.LicenseFilter.ALL); @@ -141,7 +153,8 @@ public void testShortenedOptions() throws IOException { public void testDefaultConfiguration() throws ParseException { String[] empty = {}; CommandLine cl = new DefaultParser().parse(OptionCollection.buildOptions(), empty); - ReportConfiguration config = OptionCollection.createConfiguration(cl); + ArgumentContext context = new ArgumentContext(new File("."), cl); + ReportConfiguration config = OptionCollection.createConfiguration(context); ReportConfigurationTest.validateDefault(config); } @@ -149,7 +162,7 @@ public void testDefaultConfiguration() throws ParseException { @ValueSource(strings = { ".", "./", "target", "./target" }) public void getReportableTest(String fName) throws IOException { File expected = new File(fName); - ReportConfiguration config = OptionCollection.parseCommands(new String[]{fName}, o -> fail("Help called"), false); + ReportConfiguration config = OptionCollection.parseCommands(testPath.toFile(), new String[]{fName}, o -> fail("Help called"), false); IReportable reportable = OptionCollection.getReportable(expected, config); assertNotNull(reportable, () -> format("'%s' returned null", fName)); assertThat(reportable.getName().getName()).isEqualTo(expected.getAbsolutePath()); @@ -160,8 +173,8 @@ public void getReportableTest(String fName) throws IOException { * @param name The name of the test. * @param test the option test to execute. */ - @ParameterizedTest - @ArgumentsSource(OptionsProvider.class) + @ParameterizedTest( name = "{index} {0}") + @ArgumentsSource(CliOptionsProvider.class) public void testOptionsUpdateConfig(String name, OptionTest test) { DefaultLog.getInstance().log(Log.Level.INFO, "Running test for: " + name); test.test(); @@ -170,7 +183,7 @@ public void testOptionsUpdateConfig(String name, OptionTest test) { /** * A class to provide the Options and tests to the testOptionsUpdateConfig. */ - static class OptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { + static class CliOptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { /** A flag to determine if help was called */ final AtomicBoolean helpCalled = new AtomicBoolean(false); @@ -179,9 +192,9 @@ static class OptionsProvider extends AbstractOptionsProvider implements Argument public void helpTest() { String[] args = {longOpt(OptionCollection.HELP)}; try { - ReportConfiguration config = OptionCollection.parseCommands(args, o -> helpCalled.set(true), true); - assertNull(config, "Should not have config"); - assertTrue(helpCalled.get(), "Help was not called"); + ReportConfiguration config = OptionCollection.parseCommands(testPath.toFile(), args, o -> helpCalled.set(true), true); + assertThat(config).as("Should not have config").isNull(); + assertThat(helpCalled.get()).as("Help was not called").isTrue(); } catch (IOException e) { fail(e.getMessage()); } @@ -190,8 +203,8 @@ public void helpTest() { /** * Constructor. Sets the baseDir and loads the testMap. */ - public OptionsProvider() { - super(Collections.emptyList()); + public CliOptionsProvider() { + super(Collections.emptyList(), testPath.toFile()); } /** @@ -201,7 +214,7 @@ public OptionsProvider() { * @return A ReportConfiguration * @throws IOException on critical error. */ - protected ReportConfiguration generateConfig(Pair... args) throws IOException { + protected final ReportConfiguration generateConfig(List> args) throws IOException { helpCalled.set(false); List sArgs = new ArrayList<>(); for (Pair pair : args) { @@ -213,8 +226,8 @@ protected ReportConfiguration generateConfig(Pair... args) thr } } } - ReportConfiguration config = OptionCollection.parseCommands(sArgs.toArray(new String[0]), o -> helpCalled.set(true), true); - assertFalse(helpCalled.get(), "Help was called"); + ReportConfiguration config = OptionCollection.parseCommands(testPath.toFile(), sArgs.toArray(new String[0]), o -> helpCalled.set(true), true); + assertThat(helpCalled.get()).as("Help was called").isFalse(); return config; } } 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 725174420..5e64a6b62 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 @@ -52,6 +52,7 @@ import org.apache.commons.io.FileUtils; import org.apache.rat.api.Document.Type; import org.apache.rat.api.RatException; +import org.apache.rat.commandline.ArgumentContext; import org.apache.rat.commandline.StyleSheets; import org.apache.rat.document.FileDocument; import org.apache.rat.document.DocumentName; @@ -84,7 +85,8 @@ public void testExecute() throws RatException, ParseException { File output = new File(tempDirectory, "testExecute"); CommandLine cl = new DefaultParser().parse(OptionCollection.buildOptions(), new String[]{"--output-style", "xml", "--output-file", output.getPath(), basedir}); - ReportConfiguration config = OptionCollection.createConfiguration(cl); + ArgumentContext ctxt = new ArgumentContext(new File("."), cl); + ReportConfiguration config = OptionCollection.createConfiguration(ctxt); ClaimStatistic statistic = new Reporter(config).execute(); assertThat(statistic.getCounter(Type.ARCHIVE)).isEqualTo(1); @@ -137,7 +139,9 @@ public void testExecute() throws RatException, ParseException { public void testOutputOption() throws Exception { File output = new File(tempDirectory, "test"); CommandLine commandLine = new DefaultParser().parse(OptionCollection.buildOptions(), new String[]{"-o", output.getCanonicalPath(), basedir}); - ReportConfiguration config = OptionCollection.createConfiguration(commandLine); + ArgumentContext ctxt = new ArgumentContext(new File("."), commandLine); + + ReportConfiguration config = OptionCollection.createConfiguration(ctxt); new Reporter(config).output(); assertThat(output.exists()).isTrue(); String content = FileUtils.readFileToString(output, StandardCharsets.UTF_8); @@ -154,7 +158,9 @@ public void testDefaultOutput() throws Exception { try (PrintStream out = new PrintStream(output)) { System.setOut(out); CommandLine commandLine = new DefaultParser().parse(OptionCollection.buildOptions(), new String[]{basedir}); - ReportConfiguration config = OptionCollection.createConfiguration(commandLine); + ArgumentContext ctxt = new ArgumentContext(new File("."), commandLine); + + ReportConfiguration config = OptionCollection.createConfiguration(ctxt); new Reporter(config).output(); } finally { System.setOut(origin); @@ -204,9 +210,10 @@ public void testXMLOutput() throws Exception { "type", "STANDARD")); File output = new File(tempDirectory, "testXMLOutput"); - CommandLine commandLine = new DefaultParser().parse(OptionCollection.buildOptions(), new String[]{"--output-style", "xml", "--output-file", output.getPath(), basedir}); - ReportConfiguration config = OptionCollection.createConfiguration(commandLine); + ArgumentContext ctxt = new ArgumentContext(new File("."), commandLine); + + ReportConfiguration config = OptionCollection.createConfiguration(ctxt); new Reporter(config).output(); assertThat(output).exists(); diff --git a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java index 88079ec68..fc4c980f9 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java +++ b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java @@ -56,7 +56,7 @@ public void setOut(File file) { CommandLine commandLine = createCommandLine(new String[] {"--output-file", name}); OutputFileConfig configuration = new OutputFileConfig(); - ArgumentContext ctxt = new ArgumentContext(configuration, commandLine); + ArgumentContext ctxt = new ArgumentContext(new File("."), configuration, commandLine); Arg.processArgs(ctxt); assertEquals(expected.getAbsolutePath(), configuration.actual.getAbsolutePath()); } diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java new file mode 100644 index 000000000..7526ca05d --- /dev/null +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java @@ -0,0 +1,94 @@ +/* + * 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.util.function.Predicate; +import org.apache.commons.io.filefilter.NameFileFilter; +import org.apache.rat.config.exclusion.plexus.MatchPatterns; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.apache.rat.document.DocumentNameMatcher.MATCHES_ALL; +import static org.apache.rat.document.DocumentNameMatcher.MATCHES_NONE; + +public class DocumentNameMatcherTest { + + private final static DocumentNameMatcher TRUE = new DocumentNameMatcher("T", (Predicate)name -> true); + private final static DocumentNameMatcher FALSE = new DocumentNameMatcher("F", (Predicate)name -> false); + private final static DocumentNameMatcher SOME = new DocumentNameMatcher("X", (Predicate)name -> false); + private final static DocumentName testName = DocumentName.builder().setName("testName").setBaseName("/").build(); + + public static String processDecompose(DocumentNameMatcher matcher, DocumentName candidate) { + StringBuilder sb = new StringBuilder(); + matcher.decompose(candidate).forEach(s -> sb.append(s).append("\n")); + return sb.toString(); + } + + @Test + public void orTest() { + assertThat(DocumentNameMatcher.or(TRUE, FALSE).matches(testName)).as("T,F").isTrue(); + assertThat(DocumentNameMatcher.or(FALSE, TRUE).matches(testName)).as("F,T").isTrue(); + assertThat(DocumentNameMatcher.or(TRUE, TRUE).matches(testName)).as("T,T").isTrue(); + assertThat(DocumentNameMatcher.or(FALSE, FALSE).matches(testName)).as("F,F").isFalse(); + } + + @Test + public void andTest() { + assertThat(DocumentNameMatcher.and(TRUE, FALSE).matches(testName)).as("T,F").isFalse(); + assertThat(DocumentNameMatcher.and(FALSE, TRUE).matches(testName)).as("F,T").isFalse(); + assertThat(DocumentNameMatcher.and(TRUE, TRUE).matches(testName)).as("T,T").isTrue(); + assertThat(DocumentNameMatcher.and(FALSE, FALSE).matches(testName)).as("F,F").isFalse(); + } + + @Test + public void matcherSetTest() { + assertThat(DocumentNameMatcher.matcherSet(TRUE, FALSE).matches(testName)).as("T,F").isTrue(); + assertThat(DocumentNameMatcher.matcherSet(FALSE, TRUE).matches(testName)).as("F,T").isFalse(); + assertThat(DocumentNameMatcher.matcherSet(TRUE, TRUE).matches(testName)).as("T,T").isTrue(); + assertThat(DocumentNameMatcher.matcherSet(FALSE, FALSE).matches(testName)).as("F,F").isTrue(); + + assertThat(DocumentNameMatcher.matcherSet(MATCHES_ALL, MATCHES_ALL)).as("All,All").isEqualTo(MATCHES_ALL); + assertThat(DocumentNameMatcher.matcherSet(MATCHES_ALL, MATCHES_NONE)).as("All,None").isEqualTo(MATCHES_ALL); + assertThat(DocumentNameMatcher.matcherSet(MATCHES_ALL, SOME)).as("All,X").isEqualTo(MATCHES_ALL); + + assertThat(DocumentNameMatcher.matcherSet(MATCHES_NONE, MATCHES_ALL)).as("None,All").isEqualTo(MATCHES_NONE); + assertThat(DocumentNameMatcher.matcherSet(MATCHES_NONE, MATCHES_NONE)).as("None,None").isEqualTo(MATCHES_ALL); + assertThat(DocumentNameMatcher.matcherSet(MATCHES_NONE, SOME).toString()).as("None,X").isEqualTo("not(X)"); + + assertThat(DocumentNameMatcher.matcherSet(SOME, MATCHES_ALL).toString()).as("X,All").isEqualTo("matcherSet(X, TRUE)"); + assertThat(DocumentNameMatcher.matcherSet(SOME, MATCHES_NONE)).as("X,None").isEqualTo(MATCHES_ALL); + assertThat(DocumentNameMatcher.matcherSet(SOME, SOME).toString()).as("X,X").isEqualTo("matcherSet(X, X)"); + } + + @Test + void testDecompose() { + DocumentNameMatcher matcher1 = new DocumentNameMatcher("FileFilterTest", new NameFileFilter("File.name")); + String result = processDecompose(matcher1, testName); + assertThat(result).contains("FileFilterTest: >>false<<").contains(" NameFileFilter(File.name)"); + + DocumentNameMatcher matcher2 = new DocumentNameMatcher("MatchPatternsTest", MatchPatterns.from("/", "**/test1*", "**/*Name")); + result = processDecompose(matcher2, testName); + assertThat(result).contains("MatchPatternsTest: >>true<<").contains(" **/test1*: >>false<<").contains(" **/*Name: >>true<<"); + + DocumentNameMatcher matcher3 = DocumentNameMatcher.matcherSet(matcher1, matcher2); + result = processDecompose(matcher3, testName); + assertThat(result).contains("MatchPatternsTest: >>true<<").contains(" **/test1*: >>false<<").contains(" **/*Name: >>true<<"); + + } +} 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 baf44eada..863f32bd0 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 @@ -18,7 +18,10 @@ */ package org.apache.rat.test; +import java.nio.file.FileSystems; +import java.nio.file.Path; import org.apache.commons.cli.Option; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; @@ -30,14 +33,15 @@ import org.apache.rat.config.exclusion.StandardCollection; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcherTest; import org.apache.rat.license.ILicense; import org.apache.rat.license.ILicenseFamily; import org.apache.rat.license.LicenseSetFactory; import org.apache.rat.report.claim.ClaimStatistic; +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; -import org.apache.rat.utils.ExtendedIterator; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.provider.Arguments; @@ -61,14 +65,11 @@ import java.util.SortedSet; import java.util.TreeMap; import java.util.stream.Stream; +import org.junit.jupiter.params.provider.ArgumentsProvider; import static org.apache.rat.commandline.Arg.HELP_LICENSES; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; +import static org.assertj.core.api.Fail.fail; /** * A list of methods that an OptionsProvider in a test case must support. @@ -76,26 +77,60 @@ * 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 { - /** A map of test Options to tests */ +public abstract class AbstractOptionsProvider implements ArgumentsProvider { + /** + * A map of test Options to tests + */ protected final Map testMap = new TreeMap<>(); - - protected static final String[] EXCLUDE_ARGS = { "*.foo", "%regex[[A-Z]\\.bar]", "justbaz"}; - protected static final String[] INCLUDE_ARGS = { "B.bar", "justbaz" }; + /** The list of exclude args */ + protected static final String[] EXCLUDE_ARGS = {"*.foo", "%regex[[A-Z]\\.bar]", "justbaz"}; + /** the list of include args */ + protected static final String[] INCLUDE_ARGS = {"B.bar", "justbaz"}; /** * The directory to place test data in. - * We do not use temp file here as we want the evidence to survive failure. */ - protected final File baseDir; + protected File baseDir; + + /** + * Copy the runtime data to the "target" directory. + * @param baseDir the base directory to copy to. + * @param targetDir the directory relative to the base directory to copy to. + */ + public static void preserveData(File baseDir, String targetDir) { + final Path recordPath = FileSystems.getDefault().getPath("target", targetDir); + recordPath.toFile().mkdirs(); + try { + FileUtils.copyDirectory(baseDir, recordPath.toFile()); + } catch (IOException e) { + System.err.format("Unable to copy data from %s to %s%n", baseDir, recordPath); + } + } + /** + * Gets the document name based on the baseDir. + * @return The document name based on the baseDir. + */ protected DocumentName baseName() { return DocumentName.builder(baseDir).build(); } - protected AbstractOptionsProvider(Collection unsupportedArgs) { - baseDir = new File("target/optionTools"); - baseDir.mkdirs(); + /** + * Copies the test data to the specified directory. + * @param baseDir the directory to copy the /src/test/resources to. + * @return the {@code baseDir} argument. + */ + public static File setup(File baseDir) { + try { + final File sourceDir = Resources.getResourceDirectory("OptionTools"); + FileUtils.copyDirectory(sourceDir, new File(baseDir,"/src/test/resources/OptionTools")); + } catch (IOException e) { + DefaultLog.getInstance().error("Can not copy 'OptionTools' to " + baseDir, e); + } + return baseDir; + } + protected AbstractOptionsProvider(Collection unsupportedArgs, File baseDir) { + this.baseDir = setup(baseDir); testMap.put("addLicense", this::addLicenseTest); testMap.put("config", this::configTest); testMap.put("configuration-no-defaults", this::configurationNoDefaultsTest); @@ -179,21 +214,28 @@ private void verifyAllMethodsDefinedAndNeeded(Collection unsupportedArgs unsupportedArgs.forEach(testMap::remove); } + @SafeVarargs + protected final ReportConfiguration generateConfig(Pair... args) throws IOException { + List> options = Arrays.asList(args); + return generateConfig(options); + } + /** * Create the report configuration from the argument pairs. * There must be at least one arg. It may be `ImmutablePair.nullPair()`. + * * @param args Pairs comprising the argument option and the values for the option. * @return The generated ReportConfiguration. * @throws IOException on error. */ - protected abstract ReportConfiguration generateConfig(Pair... args) throws IOException; + protected abstract ReportConfiguration generateConfig(List> args) throws IOException; protected File writeFile(String name, Iterable lines) { File file = new File(baseDir, name); try (PrintWriter writer = new PrintWriter(new FileWriter(file))) { lines.forEach(writer::println); } catch (IOException e) { - fail(e.getMessage(), e); + fail(e.getMessage()); } return file; } @@ -205,18 +247,30 @@ protected DocumentName mkDocName(String name) { /* tests to be implemented */ protected abstract void helpTest(); + /** Displayd the option and value under test */ + private String displayArgAndName(Option option, String fname) { + return String.format("%s %s", option.getLongOpt(), fname); + } + + private String dump(Option option, String fname, DocumentNameMatcher matcher, DocumentName name) { + return String.format("Argument and Name: %s%nMatcher decomposition:%n%s", displayArgAndName(option, fname), + DocumentNameMatcherTest.processDecompose(matcher, name)); + } + // exclude tests private void execExcludeTest(Option option, String[] args) { - String[] notExcluded = { "notbaz", "well._afile" }; - String[] excluded = { "some.foo", "B.bar", "justbaz"}; + String[] notExcluded = {"notbaz", "well._afile"}; + String[] excluded = {"some.foo", "B.bar", "justbaz"}; try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : notExcluded) { - assertTrue(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); } for (String fname : excluded) { - assertFalse(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); } } catch (IOException e) { fail(e.getMessage()); @@ -225,7 +279,7 @@ private void execExcludeTest(Option option, String[] args) { private void excludeFileTest(Option option) { File outputFile = writeFile("exclude.txt", Arrays.asList(EXCLUDE_ARGS)); - execExcludeTest(option, new String[] {outputFile.getPath()}); + execExcludeTest(option, new String[]{outputFile.getAbsolutePath()}); } protected void excludeFileTest() { @@ -246,17 +300,19 @@ protected void inputExcludeTest() { protected void inputExcludeStdTest() { Option option = Arg.EXCLUDE_STD.find("input-exclude-std"); - String[] args = { StandardCollection.MISC.name() }; - String[] excluded = { "afile~", ".#afile", "%afile%", "._afile" }; - String[] notExcluded = { "afile~more", "what.#afile", "%afile%withMore", "well._afile" }; + String[] args = {StandardCollection.MISC.name()}; + String[] excluded = {"afile~", ".#afile", "%afile%", "._afile"}; + String[] notExcluded = {"afile~more", "what.#afile", "%afile%withMore", "well._afile"}; try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { - assertFalse(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); } for (String fname : notExcluded) { - assertTrue(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -265,7 +321,7 @@ protected void inputExcludeStdTest() { protected void inputExcludeParsedScmTest() { Option option = Arg.EXCLUDE_PARSE_SCM.find("input-exclude-parsed-scm"); - String[] args = { "GIT" }; + String[] args = {"GIT"}; String[] lines = { "# somethings", "!thingone", "thing*", System.lineSeparator(), @@ -273,22 +329,28 @@ protected void inputExcludeParsedScmTest() { "**/fish", "*_fish", "# some colorful directories", "red/", "blue/*/"}; - String[] notExcluded = { "thingone", "dir/fish_two"}; - String[] excluded = { "thingtwo", "dir/fish", "red/fish", "blue/fish" }; + + String[] notExcluded = {"thingone", "dir/fish_two", "some/thingone", "blue/fish/dory" }; + String[] excluded = {"thingtwo", "some/things", "dir/fish", "red/fish", "blue/fish", "some/fish", "another/red_fish"}; writeFile(".gitignore", Arrays.asList(lines)); + File dir = new File(baseDir, "red"); + dir.mkdirs(); + dir = new File(baseDir, "blue"); + dir = new File(dir, "fish"); + dir.mkdirs(); + - List expected = ExtendedIterator.create(Arrays.asList("thing*", "**/fish", "*_fish", "red/**", "blue/*/**").iterator()) - .map(s -> new File(baseDir, s).getPath()).addTo(new ArrayList<>()); - expected.add(0, "!" + new File(baseDir, "thingone").getPath()); try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { - assertFalse(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isFalse(); } for (String fname : notExcluded) { - assertTrue(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -297,22 +359,24 @@ protected void inputExcludeParsedScmTest() { private void inputExcludeSizeTest() { Option option = Arg.EXCLUDE_SIZE.option(); - String[] args = { "5" }; - writeFile("Hi.txt", Arrays.asList("Hi")); - writeFile("Hello.txt", Arrays.asList("Hello")); - writeFile("HelloWorld.txt", Arrays.asList("HelloWorld")); + String[] args = {"5"}; + writeFile("Hi.txt", Collections.singletonList("Hi")); + writeFile("Hello.txt", Collections.singletonList("Hello")); + writeFile("HelloWorld.txt", Collections.singletonList("HelloWorld")); - String[] notExcluded = { "Hello.txt", "HelloWorld.txt"}; - String[] excluded = { "Hi.txt" }; + String[] notExcluded = {"Hello.txt", "HelloWorld.txt"}; + String[] excluded = {"Hi.txt"}; try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { - assertFalse(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); } for (String fname : notExcluded) { - assertTrue(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -329,10 +393,12 @@ private void execIncludeTest(Option option, String[] args) { ImmutablePair.of(excludeOption, EXCLUDE_ARGS)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { - assertFalse(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); } for (String fname : notExcluded) { - assertTrue(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -341,7 +407,7 @@ private void execIncludeTest(Option option, String[] args) { private void includeFileTest(Option option) { File outputFile = writeFile("include.txt", Arrays.asList(INCLUDE_ARGS)); - execIncludeTest(option, new String[] {outputFile.getPath()}); + execIncludeTest(option, new String[]{outputFile.getAbsolutePath()}); } protected void inputIncludeFileTest() { @@ -362,19 +428,21 @@ protected void inputIncludeTest() { protected void inputIncludeStdTest() { ImmutablePair excludes = ImmutablePair.of(Arg.EXCLUDE.find("input-exclude"), - new String[] { "*~more", "*~" }); + new String[]{"*~more", "*~"}); Option option = Arg.INCLUDE_STD.find("input-include-std"); - String[] args = { StandardCollection.MISC.name() }; - String[] excluded = { "afile~more" }; - String[] notExcluded = { "afile~", ".#afile", "%afile%", "._afile", "what.#afile", "%afile%withMore", "well._afile" }; + String[] args = {StandardCollection.MISC.name()}; + String[] excluded = {"afile~more"}; + String[] notExcluded = {"afile~", ".#afile", "%afile%", "._afile", "what.#afile", "%afile%withMore", "well._afile"}; try { ReportConfiguration config = generateConfig(excludes, ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { - assertFalse(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); } for (String fname : notExcluded) { - assertTrue(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -385,7 +453,7 @@ protected void inputSourceTest() { Option option = Arg.SOURCE.find("input-source"); try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, new String[]{baseDir.getAbsolutePath()})); - assertTrue(config.hasSource()); + assertThat(config.hasSource()).isTrue(); } catch (IOException e) { fail(e.getMessage()); } @@ -393,7 +461,7 @@ protected void inputSourceTest() { // LICENSE tests protected void execLicensesApprovedTest(Option option, String[] args) { - Pair arg1 = ImmutablePair.of(option, args); + Pair arg1 = ImmutablePair.of(option, args); try { ReportConfiguration config = generateConfig(arg1); SortedSet result = config.getLicenseIds(LicenseSetFactory.LicenseFilter.APPROVED); @@ -402,13 +470,13 @@ protected void execLicensesApprovedTest(Option option, String[] args) { fail(e.getMessage()); } - Pair arg2 = ImmutablePair.of( + Pair arg2 = ImmutablePair.of( Arg.CONFIGURATION_NO_DEFAULTS.find("configuration-no-defaults"), null ); try { - ReportConfiguration config = generateConfig(arg1, arg2 ); + ReportConfiguration config = generateConfig(arg1, arg2); SortedSet result = config.getLicenseIds(LicenseSetFactory.LicenseFilter.APPROVED); assertThat(result).containsExactly("one", "two"); } catch (IOException e) { @@ -419,7 +487,7 @@ protected void execLicensesApprovedTest(Option option, String[] args) { protected void helpLicenses() { ByteArrayOutputStream output = new ByteArrayOutputStream(); PrintStream origin = System.out; - try (PrintStream out = new PrintStream(output)){ + try (PrintStream out = new PrintStream(output)) { System.setOut(out); generateConfig(ImmutablePair.of(HELP_LICENSES.option(), null)); } catch (IOException e) { @@ -436,12 +504,12 @@ protected void helpLicenses() { protected void licensesApprovedFileTest() { File outputFile = writeFile("licensesApproved.txt", Arrays.asList("one", "two")); execLicensesApprovedTest(Arg.LICENSES_APPROVED_FILE.find("licenses-approved-file"), - new String[] { outputFile.getPath()}); + new String[]{outputFile.getAbsolutePath()}); } protected void licensesApprovedTest() { execLicensesApprovedTest(Arg.LICENSES_APPROVED.find("licenses-approved"), - new String[] { "one", "two"}); + new String[]{"one", "two"}); } private void execLicensesDeniedTest(Option option, String[] args) { @@ -456,12 +524,13 @@ private void execLicensesDeniedTest(Option option, String[] args) { } protected void licensesDeniedTest() { - execLicensesDeniedTest(Arg.LICENSES_DENIED.find("licenses-denied"), new String[] {"ILLUMOS"}); + execLicensesDeniedTest(Arg.LICENSES_DENIED.find("licenses-denied"), new String[]{"ILLUMOS"}); } protected void licensesDeniedFileTest() { File outputFile = writeFile("licensesDenied.txt", Collections.singletonList("ILLUMOS")); - execLicensesDeniedTest(Arg.LICENSES_DENIED_FILE.find("licenses-denied-file"), new String[] {outputFile.getPath()}); + execLicensesDeniedTest(Arg.LICENSES_DENIED_FILE.find("licenses-denied-file"), + new String[]{outputFile.getAbsolutePath()}); } private void execLicenseFamiliesApprovedTest(Option option, String[] args) { @@ -488,12 +557,12 @@ private void execLicenseFamiliesApprovedTest(Option option, String[] args) { protected void licenseFamiliesApprovedFileTest() { File outputFile = writeFile("familiesApproved.txt", Collections.singletonList("catz")); execLicenseFamiliesApprovedTest(Arg.FAMILIES_APPROVED_FILE.find("license-families-approved-file"), - new String[] { outputFile.getPath() }); + new String[]{outputFile.getAbsolutePath()}); } protected void licenseFamiliesApprovedTest() { execLicenseFamiliesApprovedTest(Arg.FAMILIES_APPROVED.find("license-families-approved"), - new String[] {"catz"}); + new String[]{"catz"}); } private void execLicenseFamiliesDeniedTest(Option option, String[] args) { @@ -508,15 +577,15 @@ private void execLicenseFamiliesDeniedTest(Option option, String[] args) { } } - protected void licenseFamiliesDeniedFileTest() { + protected void licenseFamiliesDeniedFileTest() { File outputFile = writeFile("familiesDenied.txt", Collections.singletonList("GPL")); execLicenseFamiliesDeniedTest(Arg.FAMILIES_DENIED_FILE.find("license-families-denied-file"), - new String[] { outputFile.getPath() }); + new String[]{outputFile.getAbsolutePath()}); } protected void licenseFamiliesDeniedTest() { execLicenseFamiliesDeniedTest(Arg.FAMILIES_DENIED.find("license-families-denied"), - new String[] { "GPL" }); + new String[]{"GPL"}); } protected void counterMaxTest() { @@ -525,17 +594,17 @@ protected void counterMaxTest() { try { ReportConfiguration config = generateConfig(ImmutablePair.nullPair()); - assertEquals(0, config.getClaimValidator().getMax(ClaimStatistic.Counter.UNAPPROVED)); + assertThat(config.getClaimValidator().getMax(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(0); args[0] = "Unapproved:-1"; args[1] = "ignored:1"; config = generateConfig(ImmutablePair.of(option, args)); - assertEquals(Integer.MAX_VALUE, config.getClaimValidator().getMax(ClaimStatistic.Counter.UNAPPROVED)); - assertEquals(1, config.getClaimValidator().getMax(ClaimStatistic.Counter.IGNORED)); + assertThat(config.getClaimValidator().getMax(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(Integer.MAX_VALUE); + assertThat(config.getClaimValidator().getMax(ClaimStatistic.Counter.IGNORED)).isEqualTo(1); args[1] = "unapproved:5"; args[0] = "ignored:0"; config = generateConfig(ImmutablePair.of(option, args)); - assertEquals(5, config.getClaimValidator().getMax(ClaimStatistic.Counter.UNAPPROVED)); - assertEquals(0, config.getClaimValidator().getMax(ClaimStatistic.Counter.IGNORED)); + assertThat(config.getClaimValidator().getMax(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(5); + assertThat(config.getClaimValidator().getMax(ClaimStatistic.Counter.IGNORED)).isEqualTo(0); } catch (IOException e) { fail(e.getMessage()); } @@ -547,17 +616,17 @@ protected void counterMinTest() { try { ReportConfiguration config = generateConfig(ImmutablePair.nullPair()); - assertEquals(0, config.getClaimValidator().getMin(ClaimStatistic.Counter.UNAPPROVED)); + assertThat(config.getClaimValidator().getMin(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(0); args[0] = "Unapproved:1"; args[1] = "ignored:1"; config = generateConfig(ImmutablePair.of(option, args)); - assertEquals(1, config.getClaimValidator().getMin(ClaimStatistic.Counter.UNAPPROVED)); - assertEquals(1, config.getClaimValidator().getMin(ClaimStatistic.Counter.IGNORED)); + assertThat(config.getClaimValidator().getMin(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1); + assertThat(config.getClaimValidator().getMin(ClaimStatistic.Counter.IGNORED)).isEqualTo(1); args[1] = "unapproved:5"; args[0] = "ignored:0"; config = generateConfig(ImmutablePair.of(option, args)); - assertEquals(5, config.getClaimValidator().getMin(ClaimStatistic.Counter.UNAPPROVED)); - assertEquals(0, config.getClaimValidator().getMin(ClaimStatistic.Counter.IGNORED)); + assertThat(config.getClaimValidator().getMin(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(5); + assertThat(config.getClaimValidator().getMin(ClaimStatistic.Counter.IGNORED)).isEqualTo(0); } catch (IOException e) { fail(e.getMessage()); } @@ -569,17 +638,17 @@ private void configTest(Option option) { try { ReportConfiguration config = generateConfig(arg1); SortedSet set = config.getLicenses(LicenseSetFactory.LicenseFilter.ALL); - assertTrue(set.size() > 2); - assertTrue(LicenseSetFactory.search("ONE", "ONE", set).isPresent()); - assertTrue(LicenseSetFactory.search("TWO", "TWO", set).isPresent()); + assertThat(set).hasSizeGreaterThan(2); + assertThat(LicenseSetFactory.search("ONE", "ONE", set)).isPresent(); + assertThat(LicenseSetFactory.search("TWO", "TWO", set)).isPresent(); Pair arg2 = ImmutablePair.of(Arg.CONFIGURATION_NO_DEFAULTS.find("configuration-no-defaults"), null); config = generateConfig(arg1, arg2); set = config.getLicenses(LicenseSetFactory.LicenseFilter.ALL); - assertEquals(2, set.size()); - assertTrue(LicenseSetFactory.search("ONE", "ONE", set).isPresent()); - assertTrue(LicenseSetFactory.search("TWO", "TWO", set).isPresent()); + assertThat(set).hasSize(2); + assertThat(LicenseSetFactory.search("ONE", "ONE", set)).isPresent(); + assertThat(LicenseSetFactory.search("TWO", "TWO", set)).isPresent(); } catch (IOException e) { fail(e.getMessage()); } @@ -596,9 +665,9 @@ protected void configTest() { private void noDefaultsTest(Option arg) { try { ReportConfiguration config = generateConfig(ImmutablePair.of(arg, null)); - assertTrue(config.getLicenses(LicenseSetFactory.LicenseFilter.ALL).isEmpty()); + assertThat(config.getLicenses(LicenseSetFactory.LicenseFilter.ALL)).isEmpty(); config = generateConfig(ImmutablePair.nullPair()); - assertFalse(config.getLicenses(LicenseSetFactory.LicenseFilter.ALL).isEmpty()); + assertThat(config.getLicenses(LicenseSetFactory.LicenseFilter.ALL)).isNotEmpty(); } catch (IOException e) { fail(e.getMessage()); } @@ -615,9 +684,9 @@ protected void configurationNoDefaultsTest() { protected void dryRunTest() { try { ReportConfiguration config = generateConfig(ImmutablePair.of(Arg.DRY_RUN.find("dry-run"), null)); - assertTrue(config.isDryRun()); + assertThat(config.isDryRun()).isTrue(); config = generateConfig(ImmutablePair.nullPair()); - assertFalse(config.isDryRun()); + assertThat(config.isDryRun()).isFalse(); } catch (IOException e) { fail(e.getMessage()); } @@ -627,10 +696,10 @@ private void editCopyrightTest(Option option) { try { Pair arg1 = ImmutablePair.of(option, new String[]{"MyCopyright"}); ReportConfiguration config = generateConfig(arg1); - assertNull(config.getCopyrightMessage(), "Copyright without --edit-license should not work"); + assertThat(config.getCopyrightMessage()).as("Copyright without --edit-license should not work").isNull(); Pair arg2 = ImmutablePair.of(Arg.EDIT_ADD.find("edit-license"), null); config = generateConfig(arg1, arg2); - assertEquals("MyCopyright", config.getCopyrightMessage()); + assertThat(config.getCopyrightMessage()).isEqualTo("MyCopyright"); } catch (IOException e) { fail(e.getMessage()); } @@ -647,9 +716,9 @@ protected void editCopyrightTest() { private void editLicenseTest(Option option) { try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, null)); - assertTrue(config.isAddingLicenses()); + assertThat(config.isAddingLicenses()).isTrue(); config = generateConfig(ImmutablePair.nullPair()); - assertFalse(config.isAddingLicenses()); + assertThat(config.isAddingLicenses()).isFalse(); } catch (IOException e) { fail(e.getMessage()); } @@ -658,6 +727,7 @@ private void editLicenseTest(Option option) { protected void addLicenseTest() { editLicenseTest(Arg.EDIT_ADD.find("addLicense")); } + protected void editLicensesTest() { editLicenseTest(Arg.EDIT_ADD.find("edit-license")); } @@ -666,11 +736,11 @@ private void overwriteTest(Option option) { Pair arg1 = ImmutablePair.of(option, null); try { ReportConfiguration config = generateConfig(arg1); - assertFalse(config.isAddingLicensesForced()); + assertThat(config.isAddingLicensesForced()).isFalse(); Pair arg2 = ImmutablePair.of(Arg.EDIT_ADD.find("edit-license"), null); config = generateConfig(arg1, arg2); - assertTrue(config.isAddingLicensesForced()); + assertThat(config.isAddingLicensesForced()).isTrue(); } catch (IOException e) { fail(e.getMessage()); } @@ -693,7 +763,7 @@ protected void logLevelTest() { try { args[0] = level.name(); generateConfig(ImmutablePair.of(option, args)); - assertEquals(level, DefaultLog.getInstance().getLevel()); + assertThat(DefaultLog.getInstance().getLevel()).isEqualTo(level); } catch (IOException e) { fail(e.getMessage()); } @@ -709,7 +779,7 @@ private void archiveTest(Option option) { for (ReportConfiguration.Processing proc : ReportConfiguration.Processing.values()) { args[0] = proc.name(); ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); - assertEquals(proc, config.getArchiveProcessing()); + assertThat(config.getArchiveProcessing()).isEqualTo(proc); } } catch (IOException e) { fail(e.getMessage()); @@ -726,7 +796,7 @@ private void listFamilies(Option option) { try { args[0] = filter.name(); ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); - assertEquals(filter, config.listFamilies()); + assertThat(config.listFamilies()).isEqualTo(filter); } catch (IOException e) { fail(e.getMessage()); } @@ -752,7 +822,7 @@ private void outTest(Option option) { throw new RuntimeException(e); } try (BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(outFile.toPath())))) { - assertEquals("Hello world", reader.readLine()); + assertThat(reader.readLine()).isEqualTo("Hello world"); } catch (IOException e) { throw new RuntimeException(e); } @@ -775,7 +845,7 @@ private void listLicenses(Option option) { try { args[0] = filter.name(); ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); - assertEquals(filter, config.listLicenses()); + assertThat(config.listLicenses()).isEqualTo(filter); } catch (IOException e) { fail(e.getMessage()); } @@ -791,12 +861,12 @@ protected void outputLicensesTest() { } private void standardTest(Option option) { - String[] args = { null}; + String[] args = {null}; try { for (ReportConfiguration.Processing proc : ReportConfiguration.Processing.values()) { args[0] = proc.name(); ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); - assertEquals(proc, config.getStandardProcessing()); + assertThat(config.getStandardProcessing()).isEqualTo(proc); } } catch (IOException e) { fail(e.getMessage()); @@ -815,7 +885,7 @@ private void styleSheetTest(Option option) { OutputStream out = Files.newOutputStream(file.toPath())) { IOUtils.copy(in, out); } catch (IOException e) { - fail("Could not copy MatcherContainerResource.txt: "+e.getMessage()); + fail("Could not copy MatcherContainerResource.txt: " + e.getMessage()); } // run the test String[] args = {null}; @@ -825,11 +895,11 @@ private void styleSheetTest(Option option) { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); try (InputStream expected = StyleSheets.getStyleSheet(sheet).get(); InputStream actual = config.getStyleSheet().get()) { - assertTrue(IOUtils.contentEquals(expected, actual), () -> String.format("'%s' does not match", sheet)); + assertThat(IOUtils.contentEquals(expected, actual)).as(() -> String.format("'%s' does not match", sheet)).isTrue(); } } } catch (IOException e) { - fail(e.getMessage(), e); + fail(e.getMessage()); } } @@ -845,7 +915,7 @@ protected void scanHiddenDirectoriesTest() { try { ReportConfiguration config = generateConfig(ImmutablePair.of(Arg.INCLUDE_STD.find("scan-hidden-directories"), null)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); - assertTrue(excluder.matches(mkDocName(".file")), ".file"); + assertThat(excluder.matches(mkDocName(".file"))).as(".file").isTrue(); } catch (IOException e) { fail(e.getMessage()); } @@ -856,28 +926,29 @@ protected void xmlTest() { ReportConfiguration config = generateConfig(ImmutablePair.of(Arg.OUTPUT_STYLE.find("xml"), null)); try (InputStream expected = StyleSheets.getStyleSheet("xml").get(); InputStream actual = config.getStyleSheet().get()) { - assertTrue(IOUtils.contentEquals(expected, actual), "'xml' does not match"); + assertThat(IOUtils.contentEquals(expected, actual)).as("'xml' does not match").isTrue(); } } catch (IOException e) { fail(e.getMessage()); } } - final public Stream provideArguments(ExtensionContext context) { - List lst = new ArrayList<>(); - List missingTests = new ArrayList<>(); + @Override + final public Stream provideArguments(ExtensionContext context) { + List lst = new ArrayList<>(); + List missingTests = new ArrayList<>(); - for (String key : OptionsList.getKeys()) { - OptionCollectionTest.OptionTest test = testMap.get(key); - if (test == null) { - missingTests.add(key); - } else { - lst.add(Arguments.of(key, test)); - } - } - if (!missingTests.isEmpty()) { - System.out.println("The following tests are excluded: '" + String.join( "', '", missingTests ) + "'"); - } - return lst.stream(); + for (String key : OptionsList.getKeys()) { + OptionCollectionTest.OptionTest test = testMap.get(key); + if (test == null) { + missingTests.add(key); + } else { + lst.add(Arguments.of(key, test)); } + } + if (!missingTests.isEmpty()) { + System.out.println("The following tests are excluded: '" + String.join("', '", missingTests) + "'"); + } + return lst.stream(); + } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/test/utils/Resources.java b/apache-rat-core/src/test/java/org/apache/rat/test/utils/Resources.java index fda2b5897..67a96afd9 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/test/utils/Resources.java +++ b/apache-rat-core/src/test/java/org/apache/rat/test/utils/Resources.java @@ -50,7 +50,22 @@ private Resources() { * Locates a test resource file in the class path. */ public static File getResourceFile(String pResource) throws IOException { - return getResourceFromBase(TEST_RESOURCE_BASE_PATH, pResource); + File f = getResourceFromBase(TEST_RESOURCE_BASE_PATH, pResource); + if (!f.isFile()) { + throw new FileNotFoundException("Unable to locate resource file: " + pResource); + } + return f; + } + + /** + * Locates a test resource directory in the class path. + */ + public static File getResourceDirectory(String pResource) throws IOException { + File f = getResourceFromBase(TEST_RESOURCE_BASE_PATH, pResource); + if (!f.isDirectory()) { + throw new FileNotFoundException("Unable to locate resource file: " + pResource); + } + return f; } @@ -71,9 +86,6 @@ public static File getExampleResource(String pResource) { */ private static File getResourceFromBase(File baseDir, String pResource) throws IOException { File f = new File(baseDir, pResource); - if (!f.isFile()) { - throw new FileNotFoundException("Unable to locate resource file: " + pResource); - } return f.getCanonicalFile(); } 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 67a9c0c70..69b2b00b0 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 @@ -30,6 +30,7 @@ import java.lang.reflect.UndeclaredThrowableException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -98,7 +99,8 @@ public static NodeList getNodeList(Object source, XPath xPath, String xpath) thr } public static boolean isPresent(Object source, XPath xPath, String xpath) throws XPathExpressionException { - return !xPath.compile(xpath).evaluate(source).equals("null"); + Object node = xPath.compile(xpath).evaluate(source, XPathConstants.NODE); + return node != null; } public static List getNodes(Object source, XPath xPath, String xpath) throws XPathExpressionException { @@ -177,6 +179,18 @@ public static String getAttribute(Object source, XPath xPath, String xpath, Stri return node.getNodeValue(); } + public static Map mapOf(String... parts) { + Map map = new HashMap<>(); + for (int i=0; i attributes) throws XPathExpressionException { Node node = XmlUtils.getNode(source, xPath, xpath); NamedNodeMap attr = node.getAttributes(); @@ -186,4 +200,12 @@ public static void assertAttributes(Object source, XPath xPath, String xpath, Ma assertThat(node.getNodeValue()).as(() -> entry.getKey() + " on " + xpath).isEqualTo(entry.getValue()); } } + + public static void assertIsPresent(Object source, XPath xPath, String xpath) throws XPathExpressionException { + assertThat(isPresent(source, xPath, xpath)).as("Presence of "+xpath).isTrue(); + } + + public static void assertIsNotPresent(Object source, XPath xPath, String xpath) throws XPathExpressionException { + assertThat(isPresent(source, xPath, xpath)).as("Non-presence of "+xpath).isFalse(); + } } diff --git a/apache-rat-plugin/src/main/java/org/apache/rat/mp/AbstractRatMojo.java b/apache-rat-plugin/src/main/java/org/apache/rat/mp/AbstractRatMojo.java index 2603c50ae..1f69e3c12 100644 --- a/apache-rat-plugin/src/main/java/org/apache/rat/mp/AbstractRatMojo.java +++ b/apache-rat-plugin/src/main/java/org/apache/rat/mp/AbstractRatMojo.java @@ -78,7 +78,7 @@ public abstract class AbstractRatMojo extends BaseRatMojo { * Specifies the licenses to accept. By default, these are added to the default * licenses, unless you set <addDefaultLicenseMatchers> to false. Arguments should be * file name of <Configs> file structure. - * @deprecated Use specific configuration under <configuration>. + * @deprecated Use <config>. * @since 0.8 */ @Parameter @@ -87,7 +87,7 @@ public abstract class AbstractRatMojo extends BaseRatMojo { /** * Specifies the additional licenses file. - * @deprecated Use specific configuration under <configuration>. + * @deprecated Use <config>. */ @Parameter @Deprecated @@ -105,21 +105,21 @@ public void setAddDefaultLicenses(final boolean addDefaultLicenses) { /** * Whether to add the default list of license matchers. - * @deprecated By default, license matchers are added. Use <configurationNoDefaults> to remove them. + * @deprecated Use <config>. */ @Deprecated @Parameter(property = "rat.addDefaultLicenseMatchers") private boolean addDefaultLicenseMatchers; /** The list of approved licenses - * @deprecated Use specific configuration under <configuration>. + * @deprecated Use <config>. */ @Deprecated @Parameter(required = false) private String[] approvedLicenses; /** The file of approved licenses - * @deprecated Use specific configuration under <configuration>. + * @deprecated Use <config>. */ @Deprecated @Parameter(property = "rat.approvedFile") @@ -176,8 +176,9 @@ public void setAddDefaultLicenses(final boolean addDefaultLicenses) { *
  • configuration files for IDEA, see * useIdeaDefaultExcludes
  • * - * @deprecated use <inputExcludeStd><exclude>STANDARD_PATTERNS</exclude> - * <exclude>STANDARD_SCM</exclude></inputExcludeStd> + * @deprecated When set to true specifies that the STANDARD_PATTERNS are excluded, as are + * the STANDARD_SCMS patterns. Use the various InputExclude and InputInclude elements to + * explicitly specify what to include or exclude. */ @Parameter(property = "rat.useDefaultExcludes", defaultValue = "true") @Deprecated @@ -255,6 +256,10 @@ public void setAddDefaultLicenses(final boolean addDefaultLicenses) { @Parameter(defaultValue = "${project}", required = true, readonly = true) protected MavenProject project; + protected AbstractRatMojo() { + DefaultLog.setInstance(makeLog()); + } + /** * @return the Maven project. */ @@ -349,10 +354,9 @@ protected void removeKey(final Arg arg) { private org.apache.rat.utils.Log makeLog() { return new org.apache.rat.utils.Log() { - private final org.apache.maven.plugin.logging.Log log = getLog(); - @Override public Level getLevel() { + final org.apache.maven.plugin.logging.Log log = getLog(); if (log.isDebugEnabled()) { return Level.DEBUG; } @@ -370,6 +374,7 @@ public Level getLevel() { @Override public void log(final Level level, final String message, final Throwable throwable) { + final org.apache.maven.plugin.logging.Log log = getLog(); switch (level) { case DEBUG: if (throwable != null) { @@ -406,6 +411,7 @@ public void log(final Level level, final String message, final Throwable throwab @Override public void log(final Level level, final String msg) { + final org.apache.maven.plugin.logging.Log log = getLog(); switch (level) { case DEBUG: log.debug(msg); @@ -459,10 +465,9 @@ private void setIncludeExclude() { } protected ReportConfiguration getConfiguration() throws MojoExecutionException { + Log log = DefaultLog.getInstance(); if (reportConfiguration == null) { - DefaultLog.setInstance(makeLog()); try { - Log log = DefaultLog.getInstance(); if (super.getLog().isDebugEnabled()) { log.debug("Start BaseRatMojo Configuration options"); for (Map.Entry> entry : args.entrySet()) { @@ -476,7 +481,8 @@ protected ReportConfiguration getConfiguration() throws MojoExecutionException { setIncludeExclude(); - ReportConfiguration config = OptionCollection.parseCommands(args().toArray(new String[0]), + getLog().warn("Basedir is : " + basedir); + ReportConfiguration config = OptionCollection.parseCommands(basedir, args().toArray(new String[0]), o -> getLog().warn("Help option not supported"), true); reportDeprecatedProcessing(); @@ -498,7 +504,7 @@ protected ReportConfiguration getConfiguration() throws MojoExecutionException { } } if (families != null || getDeprecatedConfigs().findAny().isPresent()) { - if (super.getLog().isDebugEnabled()) { + if (log.isEnabled(Log.Level.DEBUG)) { log.debug(format("%s license families loaded from pom", families.length)); } Consumer logger = super.getLog().isDebugEnabled() ? l -> log.debug(format("Family: %s", l)) @@ -519,10 +525,10 @@ protected ReportConfiguration getConfiguration() throws MojoExecutionException { } if (licenses != null) { - if (super.getLog().isDebugEnabled()) { + if (log.isEnabled(Log.Level.DEBUG)) { log.debug(format("%s licenses loaded from pom", licenses.length)); } - Consumer logger = super.getLog().isDebugEnabled() ? l -> log.debug(format("License: %s", l)) + Consumer logger = log.isEnabled(Log.Level.DEBUG) ? l -> log.debug(format("License: %s", l)) : l -> { }; Consumer addApproved = (approvedLicenses == null || approvedLicenses.length == 0) diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java index 07c461dae..67b71126d 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java @@ -30,8 +30,10 @@ import org.apache.rat.ReportConfiguration; import org.apache.rat.plugin.BaseRatMojo; import org.codehaus.plexus.component.configurator.ComponentConfigurationException; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; @@ -41,7 +43,6 @@ import java.io.IOException; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystems; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -51,30 +52,40 @@ public class OptionMojoTest { - static final Path testPath = FileSystems.getDefault().getPath("target", "optionTest"); + + @TempDir + static Path testPath; + static String POM_FMT; @BeforeAll public static void makeDirs() throws IOException { - testPath.toFile().mkdirs(); POM_FMT = IOUtils.resourceToString("/optionTest/pom.tpl", StandardCharsets.UTF_8); } + @AfterAll + static void preserveData() { + AbstractOptionsProvider.preserveData(testPath.toFile(), "optionTest"); + } + @ParameterizedTest - @ArgumentsSource(OptionsProvider.class) - public void testOptionsUpdateConfig(String name, OptionCollectionTest.OptionTest test) { + @ArgumentsSource(MojoOptionsProvider.class) + void testOptionsUpdateConfig(String name, OptionCollectionTest.OptionTest test) { test.test(); } - public static class OptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { + static class MojoOptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { private RatCheckMojo mojo = null; - public OptionsProvider() { - super(BaseRatMojo.unsupportedArgs()); + + public MojoOptionsProvider() { + super(BaseRatMojo.unsupportedArgs(), testPath.toFile()); } - private RatCheckMojo generateMojo(Pair... args) throws IOException { - MavenOption keyOption = new MavenOption(args[0].getKey() == null ? Option.builder().longOpt("no-option").build() : args[0].getKey()); + private RatCheckMojo generateMojo(List> args) throws IOException { + MavenOption keyOption = new MavenOption(args.get(0).getKey() == null ? + Option.builder().longOpt("no-option").build() : + args.get(0).getKey()); List mavenOptions = new ArrayList<>(); for (Pair pair : args) { if (pair.getKey() != null) { @@ -84,7 +95,6 @@ private RatCheckMojo generateMojo(Pair... args) throws IOExcept mavenOptions.add(new MavenOption(pair.getKey()).xmlNode(value)); } } else { - MavenOption mavenOption = new MavenOption(pair.getKey()); mavenOptions.add(new MavenOption(pair.getKey()).xmlNode("true")); } } @@ -111,9 +121,10 @@ private RatCheckMojo generateMojo(Pair... args) throws IOExcept } @Override - protected ReportConfiguration generateConfig(Pair... args) throws IOException { + protected final ReportConfiguration generateConfig(List> args) throws IOException { try { this.mojo = generateMojo(args); + AbstractOptionsProvider.setup(this.mojo.getProject().getBasedir()); return mojo.getConfiguration(); } catch (MojoExecutionException e) { throw new IOException(e.getMessage(), e); @@ -124,65 +135,6 @@ protected ReportConfiguration generateConfig(Pair... args) thr protected void helpTest() { fail("Should not call help"); } - -/* - private void execExcludeTest(Option option, String[] args) { - - try { - ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); - File workingDir = mojo.getProject().getBasedir(); - for (String fn : new String[] {"some.foo", "B.bar", "justbaz", "notbaz"}) { - try (FileOutputStream fos = new FileOutputStream(new File(workingDir, fn))) { - fos.write("Hello world".getBytes()); - } - } - - assertThat(ds.getExcludedList()).contains("some.foo"); - assertThat(ds.getExcludedList()).contains("B.bar"); - assertThat(ds.getExcludedList()).contains("justbaz"); - assertThat(ds.getIncludedList()).contains("notbaz"); - } catch (IOException | MojoExecutionException e) { - fail(e.getMessage(), e); - } - } - - @Override - protected void excludeTest() { - String[] args = { "*.foo", "*.bar", "justbaz"}; - execExcludeTest(Arg.EXCLUDE.find("exclude"), args); - } - - @Override - protected void inputExcludeTest() { - String[] args = { "*.foo", "*.bar", "justbaz"}; - execExcludeTest(Arg.EXCLUDE.find("input-exclude"), args); - } - - private void excludeFileTest(Option option) { - File outputFile = new File(baseDir, "exclude.txt"); - try (FileWriter fw = new FileWriter(outputFile)) { - fw.write("*.foo"); - fw.write(System.lineSeparator()); - fw.write("*.bar"); - fw.write(System.lineSeparator()); - fw.write("justbaz"); - fw.write(System.lineSeparator()); - } catch (IOException e) { - throw new RuntimeException(e); - } - execExcludeTest(option, new String[] {outputFile.getPath()}); - } - - protected void excludeFileTest() { - excludeFileTest(Arg.EXCLUDE_FILE.find("exclude-file")); - } - - - protected void inputExcludeFileTest() { - excludeFileTest(Arg.EXCLUDE_FILE.find("input-exclude-file")); - } - - */ } public abstract static class SimpleMojoTestcase extends BetterAbstractMojoTestCase { diff --git a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java index 6b2432c0b..db7440a90 100644 --- a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java +++ b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java @@ -16,6 +16,8 @@ */ package org.apache.rat.anttasks; +import java.nio.file.Path; +import java.util.List; import org.apache.commons.cli.Option; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; @@ -25,7 +27,8 @@ import org.apache.rat.testhelpers.TestingLog; import org.apache.rat.utils.DefaultLog; import org.apache.rat.utils.Log; -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; @@ -43,17 +46,18 @@ * Tests to ensure the option setting works correctly. */ public class ReportOptionTest { - // devhint: we do want to keep data in case of test failures, thus do not use TempDir here - static final File baseDir = new File("target/optionTest"); + @TempDir + static Path testPath; + static ReportConfiguration reportConfiguration; - @BeforeAll - public static void makeDirs() { - baseDir.mkdirs(); + @AfterAll + static void preserveData() { + AbstractOptionsProvider.preserveData(testPath.toFile(), "optionTest"); } @ParameterizedTest - @ArgumentsSource(OptionsProvider.class) + @ArgumentsSource(AntOptionsProvider.class) public void testOptionsUpdateConfig(String name, OptionCollectionTest.OptionTest test) { test.test(); } @@ -68,16 +72,16 @@ public void execute() { } } - static class OptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { + final static class AntOptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { final AtomicBoolean helpCalled = new AtomicBoolean(false); - public OptionsProvider() { - super(BaseAntTask.unsupportedArgs()); + public AntOptionsProvider() { + super(BaseAntTask.unsupportedArgs(), testPath.toFile()); } - protected ReportConfiguration generateConfig(Pair... args) { - BuildTask task = args[0].getKey() == null ? new BuildTask() : new BuildTask(args[0].getKey()); + protected final ReportConfiguration generateConfig(List> args) { + BuildTask task = args.get(0).getKey() == null ? new BuildTask() : new BuildTask(args.get(0).getKey()); task.setUp(args); task.buildRule.executeTarget(task.name); return reportConfiguration; @@ -94,6 +98,8 @@ public void helpLicenses() { Log oldLog = DefaultLog.setInstance(testLog); try { ReportConfiguration config = generateConfig(ImmutablePair.of(HELP_LICENSES.option(), null)); + } catch (IOException e) { + throw new RuntimeException(e); } finally { DefaultLog.setInstance(oldLog); } @@ -118,10 +124,10 @@ private class BuildTask extends AbstractRatAntTaskTest { antFile = new File(baseDir, name + ".xml"); } - public void setUp(Pair... args) { + public final void setUp(List> args) { StringBuilder childElements = new StringBuilder(); StringBuilder attributes = new StringBuilder(); - if (args[0].getKey() != null) { + if (args.get(0).getKey() != null) { for (Pair pair : args) { AntOption argOption = new AntOption(pair.getKey()); diff --git a/apache-rat-tools/src/main/java/org/apache/rat/tools/Documentation.java b/apache-rat-tools/src/main/java/org/apache/rat/tools/Documentation.java index a96fe9ae2..0ebfc3d81 100644 --- a/apache-rat-tools/src/main/java/org/apache/rat/tools/Documentation.java +++ b/apache-rat-tools/src/main/java/org/apache/rat/tools/Documentation.java @@ -18,6 +18,7 @@ */ package org.apache.rat.tools; +import java.io.File; import java.io.IOException; import java.io.Writer; @@ -45,7 +46,7 @@ private Documentation() { * @throws IOException on error */ public static void main(final String[] args) throws IOException { - ReportConfiguration config = OptionCollection.parseCommands(args, Documentation::printUsage, true); + ReportConfiguration config = OptionCollection.parseCommands(new File("."), args, Documentation::printUsage, true); if (config != null) { try (Writer writer = config.getWriter().get()) { new Licenses(config, writer).output(); From 4a68b3cfbbd775ee64ada21a140d4480e261d0ed Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Mon, 13 Jan 2025 23:04:41 +0000 Subject: [PATCH 002/123] updated merge issues --- .../rat/test/AbstractOptionsProvider.java | 20 +++++++++---------- .../java/org/apache/rat/anttasks/Report.java | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) 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 863f32bd0..d508e39f8 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 @@ -266,11 +266,11 @@ private void execExcludeTest(Option option, String[] args) { DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : notExcluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isTrue(); } for (String fname : excluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isFalse(); } } catch (IOException e) { fail(e.getMessage()); @@ -308,11 +308,11 @@ protected void inputExcludeStdTest() { DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isFalse(); } for (String fname : notExcluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -372,11 +372,11 @@ private void inputExcludeSizeTest() { DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isFalse(); } for (String fname : notExcluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -394,11 +394,11 @@ private void execIncludeTest(Option option, String[] args) { DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isFalse(); } for (String fname : notExcluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -438,11 +438,11 @@ protected void inputIncludeStdTest() { DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isFalse(); } for (String fname : notExcluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); diff --git a/apache-rat-tasks/src/main/java/org/apache/rat/anttasks/Report.java b/apache-rat-tasks/src/main/java/org/apache/rat/anttasks/Report.java index 493b032cd..156d7779a 100644 --- a/apache-rat-tasks/src/main/java/org/apache/rat/anttasks/Report.java +++ b/apache-rat-tasks/src/main/java/org/apache/rat/anttasks/Report.java @@ -352,7 +352,7 @@ public ReportConfiguration getConfiguration() { boolean helpLicenses = !getValues(Arg.HELP_LICENSES).isEmpty(); removeKey(Arg.HELP_LICENSES); - final ReportConfiguration configuration = OptionCollection.parseCommands(args().toArray(new String[0]), + final ReportConfiguration configuration = OptionCollection.parseCommands(new File("."), args().toArray(new String[0]), o -> DefaultLog.getInstance().warn("Help option not supported"), true); if (getValues(Arg.OUTPUT_FILE).isEmpty()) { From 9939413c68f9adaf6aaa1504cf465c5aaf9a0c90 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 14 Dec 2024 08:40:52 +0000 Subject: [PATCH 003/123] initial design comments --- .../config/exclusion/fileProcessors/GitFileProcessor.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessor.java index 8cf2d0960..37af81b61 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessor.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessor.java @@ -29,6 +29,11 @@ * @see .gitignore documentation */ public class GitFileProcessor extends DescendingFileProcessor { + // create a list of levels that a list of processors at that level. + // will return a custom matcher that from an overridden FileProcessor.customDocumentNameMatchers method + // build LevelMatcher as a system that returns Include, Exclude or no status for each check. + // put the level matcher in an array with other level matchers at the specific level below the root + // When searching start at the lowest level and work up the tree. /** * Constructs a file processor that processes a .gitignore file and ignores any lines starting with "#". From 8d5d83b99933150a65610e6845d51a9cb3279622 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 21 Dec 2024 08:55:25 +0000 Subject: [PATCH 004/123] fixes for tests --- .../config/exclusion/ExclusionProcessor.java | 208 ++++++++------- .../rat/config/exclusion/ExclusionUtils.java | 7 +- .../rat/config/exclusion/FileProcessor.java | 115 --------- .../rat/config/exclusion/MatcherSet.java | 244 ++++++++++++++++++ .../config/exclusion/StandardCollection.java | 32 +-- ...rocessor.java => BazaarIgnoreBuilder.java} | 5 +- ...leProcessor.java => CVSIgnoreBuilder.java} | 17 +- .../DescendingFileProcessor.java | 121 --------- .../fileProcessors/GitFileProcessor.java | 75 ------ .../fileProcessors/GitIgnoreBuilder.java | 180 +++++++++++++ ...oreProcessor.java => HgIgnoreBuilder.java} | 10 +- .../rat/document/DocumentNameMatcher.java | 102 +++++--- .../main/java/org/apache/rat/help/Help.java | 2 +- .../development/write_file_processor.md | 2 +- .../apache/rat/ReportConfigurationTest.java | 3 +- .../config/exclusion/FileProcessorTest.java | 2 +- .../exclusion/StandardCollectionTest.java | 2 +- ...st.java => AbstractIgnoreBuilderTest.java} | 2 +- .../BazaarIgnoreBuilderTest.java | 59 +++++ ...sorTest.java => CVSIgnoreBuilderTest.java} | 23 +- .../DescendingFileProcessorTest.java | 70 ----- .../fileProcessors/GitFileProcessorTest.java | 118 --------- .../fileProcessors/GitIgnoreBuilderTest.java | 147 +++++++++++ .../fileProcessors/HgIgnoreBuilderTest.java | 82 ++++++ .../fileProcessors/HgIgnoreProcessorTest.java | 66 ----- 25 files changed, 964 insertions(+), 730 deletions(-) delete mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/FileProcessor.java create mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java rename apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/{BazaarIgnoreProcessor.java => BazaarIgnoreBuilder.java} (90%) rename apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/{CVSFileProcessor.java => CVSIgnoreBuilder.java} (78%) delete mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/DescendingFileProcessor.java delete mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessor.java create mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java rename apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/{HgIgnoreProcessor.java => HgIgnoreBuilder.java} (90%) rename apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/{AbstractIgnoreProcessorTest.java => AbstractIgnoreBuilderTest.java} (97%) create mode 100644 apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java rename apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/{CVSFileProcessorTest.java => CVSIgnoreBuilderTest.java} (60%) delete mode 100644 apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/DescendingFileProcessorTest.java delete mode 100644 apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessorTest.java create mode 100644 apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java create mode 100644 apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java delete mode 100644 apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreProcessorTest.java 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 e21432e03..02f529f65 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 @@ -25,13 +25,16 @@ import java.util.Set; import java.util.TreeSet; -import org.apache.rat.config.exclusion.plexus.MatchPatterns; +import java.util.function.Predicate; +import javax.print.Doc; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.utils.DefaultLog; import org.apache.rat.utils.ExtendedIterator; import static java.lang.String.format; +import static org.apache.rat.document.DocumentNameMatcher.MATCHES_ALL; +import static org.apache.rat.document.DocumentNameMatcher.MATCHES_NONE; /** * Processes the include and exclude patterns and applies the result against a base directory @@ -85,10 +88,8 @@ private void resetLastMatcher() { * @return this */ public ExclusionProcessor addIncludedPatterns(final Iterable patterns) { - List lst = new ArrayList<>(); - patterns.forEach(lst::add); - DefaultLog.getInstance().info(format("Including patterns: %s", String.join(", ", lst))); - includedPatterns.addAll(lst); + DefaultLog.getInstance().info(format("Including patterns: %s", String.join(", ", patterns))); + patterns.forEach(includedPatterns::add); resetLastMatcher(); return this; } @@ -140,10 +141,8 @@ public ExclusionProcessor addIncludedCollection(final StandardCollection collect * @return this */ public ExclusionProcessor addExcludedPatterns(final Iterable patterns) { - List lst = new ArrayList<>(); - patterns.forEach(lst::add); - DefaultLog.getInstance().info(format("Excluding patterns: %s", String.join(", ", lst))); - excludedPatterns.addAll(lst); + DefaultLog.getInstance().info(format("Excluding patterns: %s", String.join(", ", patterns))); + patterns.forEach(excludedPatterns::add); resetLastMatcher(); return this; } @@ -175,22 +174,6 @@ public ExclusionProcessor addExcludedCollection(final StandardCollection collect return this; } - /** - * Adds to lists of qualified file patterns. Non-matching patterns start with a {@code !}. - * @param matching the list to put matching file patterns into. - * @param notMatching the list to put non-matching files patterns into. - * @param patterns the patterns to match. - */ - private void segregateList(final Set matching, final Set notMatching, - final Iterable patterns) { - if (patterns.iterator().hasNext()) { - ExtendedIterator.create(patterns.iterator()).filter(ExclusionUtils.MATCH_FILTER).forEachRemaining(matching::add); - ExtendedIterator.create(patterns.iterator()).filter(ExclusionUtils.NOT_MATCH_FILTER) - .map(s -> s.substring(1)) - .forEachRemaining(notMatching::add); - } - } - /** * Creates a Document name matcher that will return {@code false} on any * document that is excluded. @@ -204,84 +187,133 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { if (lastMatcher == null || !basedir.equals(lastMatcherBaseDir)) { lastMatcherBaseDir = basedir; - final Set incl = new TreeSet<>(); - final Set excl = new TreeSet<>(); - final List inclMatchers = new ArrayList<>(); - // add the file processors - for (StandardCollection sc : fileProcessors) { - ExtendedIterator iter = sc.fileProcessor(); - if (iter.hasNext()) { - iter.forEachRemaining(fp -> { - segregateList(excl, incl, fp.apply(basedir)); - fp.customDocumentNameMatchers().forEach(inclMatchers::add); - }); - } else { - DefaultLog.getInstance().info(String.format("%s does not have a fileProcessor.", sc)); - } + final List fileProcessors = extractFileProcessors(basedir, new ArrayList<>()); + + DocumentName.Builder nameBuilder = DocumentName.builder().setBaseName(basedir); + MatcherSet.Builder fromCommandLine = new MatcherSet.Builder() + .addExcluded(nameBuilder.setName("excludedPatterns").build(), excludedPatterns) + .addIncluded(nameBuilder.setName("includedPatterns").build(), includedPatterns); + extractCollectionPatterns(nameBuilder, fromCommandLine); + extractCollectionMatchers(fromCommandLine); + extractPaths(fromCommandLine); + + fileProcessors.add(fromCommandLine.build(basedir)); + + lastMatcher = createMatcher(fileProcessors); + } + return lastMatcher; + } + + private List extractFileProcessors(final DocumentName basedir, final List fileProcessorList) { + for (StandardCollection sc : fileProcessors) { + ExtendedIterator iter = sc.fileProcessorBuilder().map(builder -> builder.build(basedir)); + if (iter.hasNext()) { + iter.forEachRemaining(fileProcessorList::add); + } else { + DefaultLog.getInstance().debug(String.format("%s does not have a fileProcessor.", sc)); } + } + return fileProcessorList; + } - // add the standard patterns - segregateList(incl, excl, new FileProcessor(includedPatterns).apply(basedir)); - segregateList(excl, incl, new FileProcessor(excludedPatterns).apply(basedir)); - - // add the collection patterns - for (StandardCollection sc : includedCollections) { - Set patterns = sc.patterns(); - if (patterns.isEmpty()) { - DefaultLog.getInstance().info(String.format("%s does not have a defined collection for inclusion.", sc)); - } else { - segregateList(incl, excl, new FileProcessor(sc.patterns()).apply(basedir)); - } + private void extractPatterns(final DocumentName commandLine, final MatcherSet.Builder fromCommandLine) { + fromCommandLine + .addExcluded(commandLine, excludedPatterns) + .addIncluded(commandLine, includedPatterns); + } + + private void extractCollectionPatterns(final DocumentName.Builder nameBuilder, final MatcherSet.Builder fileProcessorBuilder) { + // add the collection patterns + final Set incl = new TreeSet<>(); + final Set excl = new TreeSet<>(); + for (StandardCollection sc : includedCollections) { + Set patterns = sc.patterns(); + if (patterns.isEmpty()) { + DefaultLog.getInstance().debug(String.format("%s does not have a defined collection for inclusion.", sc)); + } else { + MatcherSet.Builder.segregateList(incl, excl, sc.patterns()); } - for (StandardCollection sc : excludedCollections) { - Set patterns = sc.patterns(); - if (patterns.isEmpty()) { - DefaultLog.getInstance().info(String.format("%s does not have a defined collection for exclusion.", sc)); - } else { - segregateList(excl, incl, new FileProcessor(sc.patterns()).apply(basedir)); - } + } + for (StandardCollection sc : excludedCollections) { + Set patterns = sc.patterns(); + if (patterns.isEmpty()) { + DefaultLog.getInstance().info(String.format("%s does not have a defined collection for exclusion.", sc)); + } else { + MatcherSet.Builder.segregateList(excl, incl, sc.patterns()); } + } + nameBuilder.setName("collections"); + fileProcessorBuilder + .addExcluded(nameBuilder.setName("excludedCollections").build(), excl) + .addIncluded(nameBuilder.setName("includedCollections").build(), incl); + + } + + private void extractCollectionMatchers(final MatcherSet.Builder fromCommandLine) { + // add the matchers + ExtendedIterator.create(includedCollections.iterator()) + .map(StandardCollection::staticDocumentNameMatcher) + .filter(Objects::nonNull) + .forEachRemaining(fromCommandLine::addIncluded); - // add the matchers - ExtendedIterator.create(includedCollections.iterator()) - .map(StandardCollection::staticDocumentNameMatcher) - .filter(Objects::nonNull) - .forEachRemaining(inclMatchers::add); + ExtendedIterator.create(excludedCollections.iterator()) + .map(StandardCollection::staticDocumentNameMatcher) + .filter(Objects::nonNull) + .forEachRemaining(fromCommandLine::addExcluded); - List exclMatchers = ExtendedIterator.create(excludedCollections.iterator()) - .map(StandardCollection::staticDocumentNameMatcher) - .filter(Objects::nonNull) - .addTo(new ArrayList<>()); + } - if (!incl.isEmpty()) { - inclMatchers.add(new DocumentNameMatcher("included patterns", MatchPatterns.from(incl), basedir)); + private void extractPaths(final MatcherSet.Builder fromCommandLine) { + if (!includedPaths.isEmpty()) { + for (DocumentNameMatcher matcher : includedPaths) { + DefaultLog.getInstance().info(format("Including path matcher %s", matcher)); + fromCommandLine.addIncluded(matcher); } - if (!excl.isEmpty()) { - exclMatchers.add(new DocumentNameMatcher("excluded patterns", MatchPatterns.from(excl), basedir)); + } + if (!excludedPaths.isEmpty()) { + for (DocumentNameMatcher matcher : excludedPaths) { + DefaultLog.getInstance().info(format("Excluding path matcher %s", matcher)); + fromCommandLine.addExcluded(matcher); } + } - if (!includedPaths.isEmpty()) { - for (DocumentNameMatcher matcher : includedPaths) { - DefaultLog.getInstance().info(format("Including path matcher %s", matcher)); - inclMatchers.add(matcher); - } + } + + private DocumentNameMatcher createMatcher(List fileProcessors) { + + List includedList = new ArrayList<>(); + List excludedList = new ArrayList<>(); + + for (MatcherSet processor : fileProcessors) { + if (processor.includes().isPresent()) { + includedList.add(processor.includes().get()); } - if (!excludedPaths.isEmpty()) { - for (DocumentNameMatcher matcher : excludedPaths) { - DefaultLog.getInstance().info(format("Excluding path matcher %s", matcher)); - exclMatchers.add(matcher); - } + if (processor.excludes().isPresent()) { + excludedList.add(processor.excludes().get()); } + } - lastMatcher = DocumentNameMatcher.MATCHES_ALL; - if (!exclMatchers.isEmpty()) { - lastMatcher = DocumentNameMatcher.not(DocumentNameMatcher.or(exclMatchers)); - if (!inclMatchers.isEmpty()) { - lastMatcher = DocumentNameMatcher.or(DocumentNameMatcher.or(inclMatchers), lastMatcher); - } + final DocumentNameMatcher included = includedList.isEmpty() ? MATCHES_NONE : DocumentNameMatcher.or(includedList); + final DocumentNameMatcher excluded = excludedList.isEmpty() ? MATCHES_NONE : DocumentNameMatcher.or(excludedList); + + if (excluded == MATCHES_NONE) { + return (included == MATCHES_NONE) ? MATCHES_ALL : included; + } else { + if (included == MATCHES_NONE) { + return DocumentNameMatcher.not(excluded); } + Predicate pred = documentName -> { + if (included.matches(documentName)) { + return true; + } + if (excluded.matches(documentName)) { + return false; + } + return true; + }; + final String name = format("or(%s, not(%s)", included, excluded); + return new DocumentNameMatcher(name, pred); } - return lastMatcher; } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java index 339ce0978..90a8f1a1d 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java @@ -48,11 +48,14 @@ public final class ExclusionUtils { /** The list of comment prefixes that are used to filter comment lines. */ public static final List COMMENT_PREFIXES = Arrays.asList("#", "##", "//", "/**", "/*"); + /** Prefix used to negate the given pattern. */ + public static final String NEGATION_PREFIX = "!"; + /** A predicate that filters out lines that do NOT start with "!" */ - public static final Predicate NOT_MATCH_FILTER = s -> s.startsWith("!"); + public static final Predicate NOT_MATCH_FILTER = s -> s.startsWith(NEGATION_PREFIX); /** A predicate that filters out lines that start with "!" */ - public static final Predicate MATCH_FILTER = s -> !s.startsWith("!"); + public static final Predicate MATCH_FILTER = NOT_MATCH_FILTER.negate(); private ExclusionUtils() { // do not instantiate diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/FileProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/FileProcessor.java deleted file mode 100644 index 9d7886596..000000000 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/FileProcessor.java +++ /dev/null @@ -1,115 +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.config.exclusion; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Function; -import java.util.stream.Collectors; - -import org.apache.rat.config.exclusion.plexus.MatchPattern; -import org.apache.rat.config.exclusion.plexus.SelectorUtils; -import org.apache.rat.document.DocumentName; -import org.apache.rat.document.DocumentNameMatcher; - -/** - * The file processor reads the file specified in the DocumentName. - * It must return a list of fully qualified strings for the {@link MatchPattern} to process. - * It may return either Ant or Regex style strings, or a mixture of both. - * See {@link SelectorUtils} for a description of the formats. - * It may also generate custom DocumentNameMatchers which are added to the customMatchers instance variable. - */ -public class FileProcessor implements Function> { - /** A String format pattern to print a regex string */ - public static final String REGEX_FMT = "%%regex[%s]"; - /** An empty file processor returning no entries.*/ - public static final FileProcessor EMPTY = new FileProcessor(); - /** Prefix used to negate the given pattern. */ - public static final String NEGATION_PREFIX = "!"; - /** The list of patterns that will be converted into DocumentNameMatchers */ - private final List patterns = new ArrayList<>(); - /** The collection of custom DocumentNameMatchers generated by this processor */ - protected final List customMatchers = new ArrayList<>(); - - /** - * Protected constructor. - */ - protected FileProcessor() { - } - - /** - * Create a file processor out of a list of file patterns. - * @param patterns the patterns to simulate the file from. - */ - public FileProcessor(final Iterable patterns) { - patterns.forEach(this.patterns::add); - } - - @Override - public Iterable apply(final DocumentName documentName) { - return patterns.stream().map(entry -> localizePattern(documentName, entry)).collect(Collectors.toList()); - } - - /** - * If this FileProcessor builds custom matchers to handles special cases this method returns them - * to the processing stream. - * @return A collection of DocumentNameMatchers. Default returns an empty list. - */ - public final Iterable customDocumentNameMatchers() { - return customMatchers; - } - - /** - * Allows modification of the file entry to match the {@link MatchPattern} format. - * Default implementation returns the @{code entry} argument. - * @param documentName the name of the document that the file was read from. - * @param entry the entry from that document. - * @return the modified string or null to skip the string. - */ - protected String modifyEntry(final DocumentName documentName, final String entry) { - return entry; - } - - /** - * Modifies the {@link MatchPattern} formatted {@code pattern} argument by expanding the pattern and - * by adjusting the pattern to include the basename from the {@code documentName} argument. - * @param documentName the name of the file being read. - * @param pattern the pattern to format. - * @return the completely formatted pattern - */ - protected final String localizePattern(final DocumentName documentName, final String pattern) { - boolean prefix = pattern.startsWith(NEGATION_PREFIX); - String workingPattern = prefix ? pattern.substring(1) : pattern; - String normalizedPattern = SelectorUtils.extractPattern(workingPattern, documentName.getDirectorySeparator()); - StringBuilder sb = new StringBuilder(); - if (SelectorUtils.isRegexPrefixedPattern(workingPattern)) { - sb.append(prefix ? NEGATION_PREFIX : "") - .append(SelectorUtils.REGEX_HANDLER_PREFIX) - .append("\\Q").append(documentName.getBaseName()) - .append(documentName.getDirectorySeparator()) - .append("\\E").append(normalizedPattern) - .append(SelectorUtils.PATTERN_HANDLER_SUFFIX); - return sb.toString(); - } else { - sb.append(documentName.getBaseName()) - .append(documentName.getDirectorySeparator()).append(normalizedPattern); - return (prefix ? NEGATION_PREFIX : "") + DocumentName.builder(documentName).setName(sb.toString()).build().getName(); - } - } -} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java new file mode 100644 index 000000000..c13b1cee9 --- /dev/null +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -0,0 +1,244 @@ +/* + * 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.config.exclusion; + +import java.io.File; +import java.io.FileFilter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import java.util.Set; +import java.util.function.Predicate; +import org.apache.commons.io.filefilter.DirectoryFileFilter; +import org.apache.commons.io.filefilter.NameFileFilter; +import org.apache.commons.lang3.StringUtils; +import org.apache.rat.config.exclusion.plexus.MatchPattern; +import org.apache.rat.config.exclusion.plexus.MatchPatterns; +import org.apache.rat.config.exclusion.plexus.SelectorUtils; +import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; +import org.apache.rat.utils.ExtendedIterator; + +/** + * The file processor reads the file specified in the DocumentName. + * It must return a list of fully qualified strings for the {@link MatchPattern} to process. + * It may return either Ant or Regex style strings, or a mixture of both. + * See {@link SelectorUtils} for a description of the formats. + * It may also generate custom DocumentNameMatchers which are added to the customMatchers instance variable. + */ +public interface MatcherSet { + Optional includes(); + Optional excludes(); + + /** + * A MatcherSet that assumes the files contain the already formatted strings and just need to be + * localized for the fileName. + */ + class Builder { + + /** A String format pattern to print a regex string */ + public static final String REGEX_FMT = "%%regex[%s]"; + + /** + * Modifies the {@link MatchPattern} formatted {@code pattern} argument by expanding the pattern and + * by adjusting the pattern to include the basename from the {@code documentName} argument. + * @param documentName the name of the file being read. + * @param pattern the pattern to format. + * @return the completely formatted pattern + */ + public static String localizePattern(final DocumentName documentName, final String pattern) { + boolean prefix = pattern.startsWith(ExclusionUtils.NEGATION_PREFIX); + String workingPattern = prefix ? pattern.substring(1) : pattern; + String normalizedPattern = SelectorUtils.extractPattern(workingPattern, documentName.getDirectorySeparator()); + StringBuilder sb = new StringBuilder(); + if (SelectorUtils.isRegexPrefixedPattern(workingPattern)) { + sb.append(prefix ? ExclusionUtils.NEGATION_PREFIX : "") + .append(SelectorUtils.REGEX_HANDLER_PREFIX) + .append("\\Q").append(documentName.getBaseName()) + .append(documentName.getDirectorySeparator()) + .append("\\E").append(normalizedPattern) + .append(SelectorUtils.PATTERN_HANDLER_SUFFIX); + return sb.toString(); + } else { + sb.append(documentName.getBaseName()) + .append(documentName.getDirectorySeparator()).append(normalizedPattern); + return (prefix ? ExclusionUtils.NEGATION_PREFIX : "") + DocumentName.builder(documentName).setName(sb.toString()).build().getName(); + } + } + + /** + * Adds to lists of qualified file patterns. Non-matching patterns start with a {@code !}. + * @param matching the list to put matching file patterns into. + * @param notMatching the list to put non-matching files patterns into. + * @param patterns the patterns to match. + */ + public static void segregateList(final Set matching, final Set notMatching, + final Iterable patterns) { + patterns.forEach(s -> { + if (ExclusionUtils.MATCH_FILTER.test(s)) { + matching.add(s); + } else { + notMatching.add(s.substring(1)); + } + }); + } + + /** The name of the file being processed */ + protected final String fileName; + + /** The predicate that will return {@code false} for any comment line in the file. */ + protected final Predicate commentFilter; + + protected DocumentNameMatcher included; + + protected DocumentNameMatcher excluded; + + Builder() { + fileName = StringUtils.EMPTY; + commentFilter = StringUtils::isNotBlank; + } + + /** + * Constructor. + * @param fileName The name of the file to process. + * @param commentPrefix the comment prefix + */ + protected Builder(final String fileName, final String commentPrefix) { + this(fileName, commentPrefix == null ? null : Collections.singletonList(commentPrefix)); + } + + /** + * Constructor. + * @param fileName name of the file to process + * @param commentPrefixes a collection of comment prefixes. + */ + protected Builder(final String fileName, final Iterable commentPrefixes) { + super(); + this.fileName = fileName; + // null prefixes = check prefix may not be blank. + this.commentFilter = commentPrefixes == null ? StringUtils::isNotBlank : ExclusionUtils.commentFilter(commentPrefixes); + } + + /** + * Allows modification of the file entry to match the {@link MatchPattern} format. + * Default implementation returns the @{code entry} argument. + * @param documentName the name of the document that the file was read from. + * @param entry the entry from that document. + * @return the modified string or null to skip the string. + */ + protected String modifyEntry(final DocumentName documentName, final String entry) { + return entry; + } + + public Builder addIncluded(DocumentName fromDocument, Set names) { + if (!names.isEmpty()) { + addIncluded(new DocumentNameMatcher(fromDocument.localized("/"), MatchPatterns.from(names), fromDocument.getBaseDocumentName())); + } + return this; + } + + public Builder addExcluded(DocumentName fromDocument, Set names) { + if (!names.isEmpty()) { + addExcluded(new DocumentNameMatcher(fromDocument.localized("/"), MatchPatterns.from(names), fromDocument.getBaseDocumentName())); + } + return this; + } + + public Builder addIncluded(DocumentNameMatcher matcher) { + this.included = this.included == null ? matcher : DocumentNameMatcher.or(this.included, matcher); + return this; + } + + public Builder addExcluded(DocumentNameMatcher matcher) { + this.excluded = this.excluded == null ? matcher : DocumentNameMatcher.or(this.excluded, matcher); + return this; + } + + /** + * Process by reading the file setting the {@link #included} and {@link #excluded} DocumentMatchers. + * @param documentName the file to read. + */ + protected void process(final DocumentName documentName) { + Set included = new HashSet<>(); + Set excluded = new HashSet<>(); + List iterable = new ArrayList<>(); + ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) + .map(entry -> modifyEntry(documentName, entry)) + .filter(Objects::nonNull) + .map(entry -> localizePattern(documentName, entry)) + .forEachRemaining(iterable::add); + segregateList(included, excluded, iterable); + addExcluded(documentName, excluded); + addIncluded(documentName, included); + } + + /** + * Create a list of files by applying the filter to the specified directory. + * @param dir the directory. + * @param filter the filter. + * @return an array of files. May be empty but will not be null. + */ + protected File[] listFiles(final File dir, final FileFilter filter) { + File[] result = dir.listFiles(filter); + return result == null ? new File[0] : result; + } + + /** + * Process the directory tree looking for files that match the filter. Call {@link #process} on any matching file. + * @param directory The name of the directory to process. + * @param fileFilter the filter to detect processable files with. + */ + protected void checkDirectory(final DocumentName directory, final FileFilter fileFilter) { + File dirFile = new File(directory.getName()); + for (File f : listFiles(dirFile, fileFilter)) { + process(DocumentName.builder(f).setBaseName(directory.getBaseName()).build()); + } + for (File dir : listFiles(dirFile, DirectoryFileFilter.DIRECTORY)) { + checkDirectory(DocumentName.builder(dir).build(), fileFilter); + } + } + + public MatcherSet build(final DocumentName dir) { + checkDirectory(dir, new NameFileFilter(fileName)); + + MatcherSet result = new MatcherSet() { + final DocumentNameMatcher myIncluded = included; + final DocumentNameMatcher myExcluded = excluded; + + @Override + public Optional includes() { + return Optional.ofNullable(myIncluded); + } + + @Override + public Optional excludes() { + return Optional.ofNullable(myExcluded); + } + }; + included = null; + excluded = null; + return result; + } + + } +} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java index 1bd805f41..9d6874c40 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java @@ -28,10 +28,10 @@ import java.util.Set; import java.util.function.Predicate; -import org.apache.rat.config.exclusion.fileProcessors.BazaarIgnoreProcessor; -import org.apache.rat.config.exclusion.fileProcessors.CVSFileProcessor; -import org.apache.rat.config.exclusion.fileProcessors.GitFileProcessor; -import org.apache.rat.config.exclusion.fileProcessors.HgIgnoreProcessor; +import org.apache.rat.config.exclusion.fileProcessors.BazaarIgnoreBuilder; +import org.apache.rat.config.exclusion.fileProcessors.CVSIgnoreBuilder; +import org.apache.rat.config.exclusion.fileProcessors.GitIgnoreBuilder; +import org.apache.rat.config.exclusion.fileProcessors.HgIgnoreBuilder; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.utils.ExtendedIterator; @@ -55,7 +55,7 @@ public enum StandardCollection { * The files and directories created by a Bazaar source code control based tool. */ BAZAAR("The files and directories created by a Bazaar source code control based tool.", - Arrays.asList("**/.bzr/**", "**/.bzrignore"), null, new BazaarIgnoreProcessor()), + Arrays.asList("**/.bzr/**", "**/.bzrignore"), null, new BazaarIgnoreBuilder()), /** * The files and directories created by a Bitkeeper source code control based tool. */ @@ -74,7 +74,7 @@ public enum StandardCollection { "**/*.orig", "**/*.rej", "**/.del-*", "**/*.a", "**/*.old", "**/*.o", "**/*.obj", "**/*.so", "**/*.exe", "**/*.Z", "**/*.elc", "**/*.ln", "**/core"), - null, new CVSFileProcessor()), + null, new CVSIgnoreBuilder()), /** * The files and directories created by a DARCS source code control based tool. */ @@ -93,7 +93,7 @@ null, new CVSFileProcessor()), GIT("The files and directories created by GIT source code control to support GIT, also processes files listed in '.gitignore'.", Arrays.asList("**/.git/**", "**/.gitignore"), null, - new GitFileProcessor() + new GitIgnoreBuilder() ), /** * The hidden directories. Directories with names that start with '.' @@ -142,7 +142,7 @@ null, new CVSFileProcessor()), * The files and directories created by a Mercurial source code control based tool. */ MERCURIAL("The files and directories created by a Mercurial source code control based tool.", - Arrays.asList("**/.hg/**", "**/.hgignore"), null, new HgIgnoreProcessor()), + Arrays.asList("**/.hg/**", "**/.hgignore"), null, new HgIgnoreBuilder()), /** * The set of miscellaneous files generally left by editors and the like. */ @@ -199,17 +199,17 @@ null, new CVSFileProcessor()), private final Collection patterns; /** A document name matcher supplier to create a document name matcher. May be null */ private final DocumentNameMatcher staticDocumentNameMatcher; - /** The FileProcessor to process the exclude file associated with this exclusion. May be null. */ - private final FileProcessor fileProcessor; + /** The MatcherSet to process the exclude file associated with this exclusion. May be null. */ + private final MatcherSet.Builder fileProcessorBuilder; /** The description of this collection */ private final String desc; StandardCollection(final String desc, final Collection patterns, final DocumentNameMatcher documentNameMatcher, - final FileProcessor fileProcessor) { + final MatcherSet.Builder fileProcessorBuilder) { this.desc = desc; this.patterns = patterns == null ? Collections.emptyList() : new HashSet<>(patterns); this.staticDocumentNameMatcher = documentNameMatcher; - this.fileProcessor = fileProcessor; + this.fileProcessorBuilder = fileProcessorBuilder; } /** @@ -263,11 +263,11 @@ public Set patterns() { * * @return the fileProcessor if it exists, {@code null} otherwise. */ - public ExtendedIterator fileProcessor() { - List lst = new ArrayList<>(); + public ExtendedIterator fileProcessorBuilder() { + List lst = new ArrayList<>(); for (StandardCollection sc : getCollections()) { - if (sc.fileProcessor != null) { - lst.add(sc.fileProcessor); + if (sc.fileProcessorBuilder != null) { + lst.add(sc.fileProcessorBuilder); } } return ExtendedIterator.create(lst.iterator()); diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java similarity index 90% rename from apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreProcessor.java rename to apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java index 65217c37f..315ec99dc 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreProcessor.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java @@ -18,6 +18,7 @@ */ package org.apache.rat.config.exclusion.fileProcessors; +import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; import static java.lang.String.format; @@ -25,11 +26,11 @@ /** * A processor for {@code .bzrignore} files. */ -public final class BazaarIgnoreProcessor extends DescendingFileProcessor { +public final class BazaarIgnoreBuilder extends MatcherSet.Builder { /** * Constructor. */ - public BazaarIgnoreProcessor() { + public BazaarIgnoreBuilder() { super(".bzrignore", "#"); } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSFileProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java similarity index 78% rename from apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSFileProcessor.java rename to apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java index a1f6582c2..cd308e923 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSFileProcessor.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java @@ -19,39 +19,40 @@ package org.apache.rat.config.exclusion.fileProcessors; import java.io.File; -import java.util.ArrayList; +import java.util.HashSet; import java.util.Iterator; -import java.util.List; +import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.apache.rat.config.exclusion.ExclusionUtils; +import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; /** * A file processor for the {@code .csvignore} file. */ -public class CVSFileProcessor extends DescendingFileProcessor { +public class CVSIgnoreBuilder extends MatcherSet.Builder { /** * The constructor. */ - public CVSFileProcessor() { + public CVSIgnoreBuilder() { super(".cvsignore", (String) null); } @Override - protected List process(final DocumentName documentName) { + protected void process(final DocumentName documentName) { final File dir = new File(documentName.getName()); - List result = new ArrayList<>(); + Set result = new HashSet<>(); Iterator iter = ExclusionUtils.asIterator(dir, StringUtils::isNotBlank); while (iter.hasNext()) { String line = iter.next(); String[] parts = line.split("\\s+"); for (String part : parts) { if (!part.isEmpty()) { - result.add(this.localizePattern(documentName, part)); + result.add(localizePattern(documentName, part)); } } } - return result; + addIncluded(documentName.getBaseDocumentName(), result); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/DescendingFileProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/DescendingFileProcessor.java deleted file mode 100644 index 438f00752..000000000 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/DescendingFileProcessor.java +++ /dev/null @@ -1,121 +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.config.exclusion.fileProcessors; - -import java.io.File; -import java.io.FileFilter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.function.Predicate; - -import org.apache.commons.io.filefilter.DirectoryFileFilter; -import org.apache.commons.io.filefilter.NameFileFilter; -import org.apache.commons.lang3.StringUtils; -import org.apache.rat.config.exclusion.ExclusionUtils; -import org.apache.rat.config.exclusion.FileProcessor; -import org.apache.rat.document.DocumentName; - -/** - * A FileProcessor that assumes the files contain the already formatted strings and just need to be - * localized for the fileName. - */ -public class DescendingFileProcessor extends FileProcessor { - /** The name of the file being processed */ - private final String fileName; - /** The predicate that will return {@code false} for any comment line in the file. */ - protected final Predicate commentFilter; - - /** - * Constructor. - * @param fileName The name of the file to process. - * @param commentPrefix the comment prefix - */ - public DescendingFileProcessor(final String fileName, final String commentPrefix) { - this(fileName, commentPrefix == null ? null : Collections.singletonList(commentPrefix)); - } - - /** - * Constructor. - * @param fileName name of the file to process - * @param commentPrefixes a collection of comment prefixes. - */ - public DescendingFileProcessor(final String fileName, final Iterable commentPrefixes) { - super(); - this.fileName = fileName; - // null prefixes = check prefix may not be blank. - this.commentFilter = commentPrefixes == null ? StringUtils::isNotBlank : ExclusionUtils.commentFilter(commentPrefixes); - } - - /** - * Process by reading the file and return a list of properly formatted patterns. - * The default implementation does the following: - *
      - *
    • reads lines from the file specified by documentName
    • - *
    • modifies those entries by calling {@link FileProcessor#modifyEntry(DocumentName, String)}
    • - *
    • further modifies the entry by calling {@link FileProcessor#localizePattern(DocumentName, String)}
    • - *
    • retrieving the name from the resulting DocumentName
    • - *
    - * @param documentName the file to read. - * @return the list of properly formatted patterns - */ - protected List process(final DocumentName documentName) { - return ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) - .map(entry -> this.modifyEntry(documentName, entry)) - .filter(Objects::nonNull) - .map(entry -> this.localizePattern(documentName, entry)) - .addTo(new ArrayList<>()); - } - - /** - * Create a list of files by applying the filter to the specified directory. - * @param dir the directory. - * @param filter the filter. - * @return an array of files. May be empty but will not be null. - */ - private File[] listFiles(final File dir, final FileFilter filter) { - File[] result = dir.listFiles(filter); - return result == null ? new File[0] : result; - } - - /** - * Process the directory tree looking for files that match the filter. Process any matching file and return - * a list of fully qualified patterns. - * @param directory The name of the directory to process. - * @param fileFilter the filter to detect processable files with. - * @return the list of fully qualified file patterns. - */ - protected List checkDirectory(final DocumentName directory, final FileFilter fileFilter) { - List fileNames = new ArrayList<>(); - File dirFile = new File(directory.getName()); - for (File f : listFiles(dirFile, fileFilter)) { - fileNames.addAll(process(DocumentName.builder(f).setBaseName(directory.getBaseName()).build())); - } - for (File dir : listFiles(dirFile, DirectoryFileFilter.DIRECTORY)) { - fileNames.addAll(checkDirectory(DocumentName.builder(dir).build(), fileFilter)); - } - return fileNames; - } - - @Override - public List apply(final DocumentName dir) { - return checkDirectory(dir, new NameFileFilter(fileName)); - } -} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessor.java deleted file mode 100644 index 37af81b61..000000000 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessor.java +++ /dev/null @@ -1,75 +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.config.exclusion.fileProcessors; - -import java.io.File; - -import org.apache.rat.config.exclusion.plexus.MatchPatterns; -import org.apache.rat.document.DocumentName; -import org.apache.rat.document.DocumentNameMatcher; - -/** - * Processes the .gitignore file. - * @see .gitignore documentation - */ -public class GitFileProcessor extends DescendingFileProcessor { - // create a list of levels that a list of processors at that level. - // will return a custom matcher that from an overridden FileProcessor.customDocumentNameMatchers method - // build LevelMatcher as a system that returns Include, Exclude or no status for each check. - // put the level matcher in an array with other level matchers at the specific level below the root - // When searching start at the lowest level and work up the tree. - - /** - * Constructs a file processor that processes a .gitignore file and ignores any lines starting with "#". - */ - public GitFileProcessor() { - super(".gitignore", "#"); - } - - @Override - public String modifyEntry(final DocumentName documentName, final String entry) { - // An optional prefix "!" which negates the pattern; - boolean prefix = entry.startsWith("!"); - String pattern = prefix || entry.startsWith("\\#") || entry.startsWith("\\!") ? entry.substring(1) : entry; - - // If there is a separator at the beginning or middle (or both) of the pattern, then - // the pattern is relative to the directory level of the particular .gitignore file itself. - // Otherwise, the pattern may also match at any level below the .gitignore level. - int slashPos = pattern.indexOf("/"); - // no slash or at end already - if (slashPos == -1 || slashPos == pattern.length() - 1) { - pattern = "**/" + pattern; - } - if (slashPos == 0) { - pattern = pattern.substring(1); - } - // If there is a separator at the end of the pattern then the pattern will only match directories, - // otherwise the pattern can match both files and directories. - if (pattern.endsWith("/")) { - pattern = pattern.substring(0, pattern.length() - 1); - String name = prefix ? "!" + pattern : pattern; - DocumentName matcherPattern = DocumentName.builder(documentName).setName(name.replace("/", documentName.getDirectorySeparator())) - .build(); - customMatchers.add(DocumentNameMatcher.and(new DocumentNameMatcher("isDirectory", File::isDirectory), - new DocumentNameMatcher(name, MatchPatterns.from(matcherPattern.localized("/"))))); - return null; - } - return prefix ? "!" + pattern : pattern; - } -} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java new file mode 100644 index 000000000..319f2a137 --- /dev/null +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java @@ -0,0 +1,180 @@ +/* + * 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.config.exclusion.fileProcessors; + +import java.io.File; + +import java.io.FileFilter; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.function.Consumer; +import org.apache.commons.io.filefilter.DirectoryFileFilter; +import org.apache.rat.config.exclusion.ExclusionUtils; +import org.apache.rat.config.exclusion.MatcherSet; +import org.apache.rat.config.exclusion.plexus.MatchPatterns; +import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; + +import static org.apache.rat.config.exclusion.ExclusionUtils.NEGATION_PREFIX; + +/** + * Processes the .gitignore file. + * @see .gitignore documentation + */ +public class GitIgnoreBuilder extends MatcherSet.Builder { + // create a list of levels that a list of processors at that level. + // will return a custom matcher that from an overridden MatcherSet.customDocumentNameMatchers method + // build LevelMatcher as a system that returns Include, Exclude or no status for each check. + // put the level matcher in an array with other level matchers at the specific level below the root + // When searching start at the lowest level and work up the tree. + + private static final String IGNORE_FILE = ".gitignore"; + private static final String COMMENT_PREFIX = "#"; + private static final String ESCAPED_COMMENT = "\\#"; + private static final String ESCAPED_NEGATION = "\\!"; + private static final String SLASH = "/"; + + private SortedMap levelBuilders = new TreeMap<>(); + + + /** + * Constructs a file processor that processes a .gitignore file and ignores any lines starting with "#". + */ + public GitIgnoreBuilder() { + super(IGNORE_FILE, COMMENT_PREFIX); + } + + /** + * Process the directory tree looking for files that match the filter. Process any matching file and return + * a list of fully qualified patterns. + * @param directory The name of the directory to process. + * @param fileFilter the filter to detect processable files with. + * @return the list of fully qualified file patterns. + */ + protected void checkDirectory(final DocumentName directory, final FileFilter fileFilter) { + checkDirectory(0, directory, fileFilter); + List keys = new ArrayList<>(levelBuilders.keySet()); + keys.sort( (a, b) -> -1 * a.compareTo(b)); + for (int level : keys) { + LevelBuilder levelBuilder = levelBuilders.get(level); + MatcherSet fileProcessor = levelBuilder.build(directory); + fileProcessor.excludes().ifPresent(this::addExcluded); + fileProcessor.includes().ifPresent(this::addIncluded); + } + } + + private void checkDirectory(final int level, final DocumentName directory, final FileFilter fileFilter) { + File dirFile = new File(directory.getName()); + for (File f : listFiles(dirFile, fileFilter)) { + LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(level, LevelBuilder::new); + DocumentName dirBasedName = DocumentName.builder(f).setBaseName(directory.getBaseName()).build(); + levelBuilder.process(dirBasedName, DocumentName.builder(f).setBaseName(directory.getName()).build()); + } + for (File dir : listFiles(dirFile, DirectoryFileFilter.DIRECTORY)) { + checkDirectory(level + 1, DocumentName.builder(dir).setBaseName(directory.getBaseName()).build(), fileFilter); + } + } + /** + * package private for testing. + * @return the included DocumentNameMatcher. + */ + DocumentNameMatcher getIncluded() { + return included; + } + + /** + * package private for testing. + * @return the excluded DocumentNameMatcher. + */ + DocumentNameMatcher getExcluded() { + return excluded; + } + + @Override + public String modifyEntry(final DocumentName documentName, final String entry) { + return modifyEntry(documentName, entry, this::addIncluded, this::addExcluded); + } + + private static String modifyEntry(final DocumentName documentName, final String entry, Consumer include, + Consumer exclude) { + // An optional prefix "!" which negates the pattern; + boolean prefix = entry.startsWith(NEGATION_PREFIX); + String pattern = prefix || entry.startsWith(ESCAPED_COMMENT) || entry.startsWith(ESCAPED_NEGATION) ? + entry.substring(1) : entry; + + // If there is a separator at the beginning or middle (or both) of the pattern, then + // the pattern is relative to the directory level of the particular .gitignore file itself. + // Otherwise, the pattern may also match at any level below the .gitignore level. + int slashPos = pattern.indexOf(SLASH); + // no slash or at end already + if (slashPos == -1 || slashPos == pattern.length() - 1) { + pattern = "**/" + pattern; + } + if (slashPos == 0) { + pattern = pattern.substring(1); + } + // If there is a separator at the end of the pattern then the pattern will only match directories, + // otherwise the pattern can match both files and directories. + if (pattern.endsWith(SLASH)) { + pattern = pattern.substring(0, pattern.length() - 1); + String name = prefix ? NEGATION_PREFIX + pattern : pattern; + DocumentName matcherPattern = DocumentName.builder(documentName).setName(name.replace(SLASH, documentName.getDirectorySeparator())) + .build(); + DocumentNameMatcher matcher = DocumentNameMatcher.and(new DocumentNameMatcher("isDirectory", File::isDirectory), + new DocumentNameMatcher(name, MatchPatterns.from(matcherPattern.localized(SLASH)))); + if (prefix) { + exclude.accept(matcher); + } else { + include.accept(matcher); + } + return null; + } + return prefix ? NEGATION_PREFIX + pattern : pattern; + } + + private class LevelBuilder extends MatcherSet.Builder { + LevelBuilder(int level) { + super(IGNORE_FILE+"-"+level, COMMENT_PREFIX); + } + + public String modifyEntry(final DocumentName documentName, final String entry) { + return GitIgnoreBuilder.modifyEntry(documentName, entry, this::addIncluded, this::addExcluded); + } + + public void process(DocumentName directory, DocumentName documentName) { + Set included = new HashSet<>(); + Set excluded = new HashSet<>(); + List iterable = new ArrayList<>(); + ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) + .map(entry -> modifyEntry(documentName, entry)) + .filter(Objects::nonNull) + .map(entry -> localizePattern(documentName, entry)) + .forEachRemaining(iterable::add); + segregateList(included, excluded, iterable); + addExcluded(directory, excluded); + addIncluded(directory, included); + + } + } +} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java similarity index 90% rename from apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreProcessor.java rename to apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java index d88e60c50..036333ea6 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreProcessor.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java @@ -18,11 +18,11 @@ */ package org.apache.rat.config.exclusion.fileProcessors; -import java.util.List; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; import static java.lang.String.format; @@ -30,7 +30,7 @@ /** * A processor for the {@code .hgignore} files. */ -public final class HgIgnoreProcessor extends DescendingFileProcessor { +public final class HgIgnoreBuilder extends MatcherSet.Builder { /** * The state enumeration for the processor. When processing the file the processor changes * syntax state depending on the input. @@ -50,15 +50,15 @@ enum Syntax { /** * Constructs the .hgignore processor. */ - public HgIgnoreProcessor() { + public HgIgnoreBuilder() { super(".hgignore", "#"); state = Syntax.REGEXP; } @Override - protected List process(final DocumentName baseName) { + protected void process(final DocumentName baseName) { state = Syntax.REGEXP; - return super.process(baseName); + super.process(baseName); } @Override diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 30bbbbede..043f3b0df 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -23,9 +23,13 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Optional; +import java.util.Set; import java.util.function.Predicate; +import org.apache.rat.ConfigurationException; import org.apache.rat.config.exclusion.plexus.MatchPattern; import org.apache.rat.config.exclusion.plexus.MatchPatterns; @@ -41,6 +45,8 @@ public final class DocumentNameMatcher { /** The name of this matcher. */ private final String name; + private final boolean isCollection; + /** * A matcher that matches all documents. */ @@ -59,6 +65,7 @@ public final class DocumentNameMatcher { public DocumentNameMatcher(final String name, final Predicate predicate) { this.name = name; this.predicate = predicate; + this.isCollection = predicate instanceof MatcherPredicate; } /** @@ -108,6 +115,10 @@ public DocumentNameMatcher(final FileFilter fileFilter) { this(fileFilter.toString(), fileFilter); } + public boolean isCollection() { + return isCollection; + } + @Override public String toString() { return name; @@ -150,30 +161,41 @@ private static String join(final Collection matchers) { return String.join(", ", children); } + private static Optional standardCollectionCheck(Collection matchers, DocumentNameMatcher override) { + if (matchers.isEmpty()) { + throw new ConfigurationException("Empty matcher collection"); + } + if (matchers.size() == 1) { + return Optional.of(matchers.iterator().next()); + } + if (matchers.contains(override)) { + return Optional.of(override); + } + return Optional.empty(); + } + /** * Performs a logical {@code OR} across the collection of matchers. * @param matchers the matchers to check. * @return a matcher that returns {@code true} if any of the enclosed matchers returns {@code true}. */ public static DocumentNameMatcher or(final Collection matchers) { - if (matchers.isEmpty()) { - return MATCHES_NONE; - } - if (matchers.size() == 1) { - return matchers.iterator().next(); - } - if (matchers.contains(MATCHES_ALL)) { - return MATCHES_ALL; + Optional opt = standardCollectionCheck(matchers, MATCHES_ALL); + if (opt.isPresent()) { + return opt.get(); } - return new DocumentNameMatcher(format("or(%s)", join(matchers)), (Predicate) documentName -> { - for (DocumentNameMatcher matcher : matchers) { - if (matcher.matches(documentName)) { - return true; - } - } - return false; - }); + Set myList = new HashSet<>(); + for (DocumentNameMatcher matcher : matchers) { + if (matcher.predicate instanceof MatcherPredicate && ((MatcherPredicate)matcher.predicate).matchValue) { + // nested "or" + ((MatcherPredicate)matcher.predicate).matchers.forEach(myList::add); + } else { + myList.add(matcher); + } + } + opt = standardCollectionCheck(matchers, MATCHES_ALL); + return opt.orElseGet(() -> new DocumentNameMatcher(format("or(%s)", join(myList)), new MatcherPredicate(true, myList))); } /** @@ -191,24 +213,22 @@ public static DocumentNameMatcher or(final DocumentNameMatcher... matchers) { * @return a matcher that returns {@code true} if all the enclosed matchers return {@code true}. */ public static DocumentNameMatcher and(final Collection matchers) { - if (matchers.isEmpty()) { - return MATCHES_NONE; - } - if (matchers.size() == 1) { - return matchers.iterator().next(); - } - if (matchers.contains(MATCHES_NONE)) { - return MATCHES_NONE; + Optional opt = standardCollectionCheck(matchers, MATCHES_NONE); + if (opt.isPresent()) { + return opt.get(); } - return new DocumentNameMatcher(format("and(%s)", join(matchers)), (Predicate) documentName -> { - for (DocumentNameMatcher matcher : matchers) { - if (!matcher.matches(documentName)) { - return false; - } + Set myList = new HashSet<>(); + for (DocumentNameMatcher matcher : matchers) { + if (matcher.predicate instanceof MatcherPredicate && !((MatcherPredicate)matcher.predicate).matchValue) { + // nested "and" + ((MatcherPredicate)matcher.predicate).matchers.forEach(myList::add); + } else { + myList.add(matcher); } - return true; - }); + } + opt = standardCollectionCheck(matchers, MATCHES_NONE); + return opt.orElseGet(() -> new DocumentNameMatcher(format("and(%s)", join(myList)), new MatcherPredicate(false, myList))); } /** @@ -219,4 +239,24 @@ public static DocumentNameMatcher and(final Collection matc public static DocumentNameMatcher and(final DocumentNameMatcher... matchers) { return and(Arrays.asList(matchers)); } + + private static class MatcherPredicate implements Predicate { + final Iterable matchers; + final boolean matchValue; + + MatcherPredicate(boolean matchValue, Iterable matchers) { + this.matchers = matchers; + this.matchValue = matchValue; + } + + @Override + public boolean test(DocumentName documentName) { + for (DocumentNameMatcher matcher : matchers) { + if (matcher.matches(documentName)) { + return true; + } + } + return !matchValue; + } + } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/help/Help.java b/apache-rat-core/src/main/java/org/apache/rat/help/Help.java index 06202375e..8623c175d 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/help/Help.java +++ b/apache-rat-core/src/main/java/org/apache/rat/help/Help.java @@ -85,7 +85,7 @@ public void printUsage(final Options opts) { helpFormatter.printWrapped(writer, helpFormatter.getWidth(), helpFormatter.getLeftPadding() + HELP_PADDING + HELP_PADDING, argumentPadding + "Provides a path matcher: " + sc.hasStaticDocumentNameMatcher()); helpFormatter.printWrapped(writer, helpFormatter.getWidth(), helpFormatter.getLeftPadding() + HELP_PADDING + HELP_PADDING, - argumentPadding + "Provides a file processor: " + sc.fileProcessor().hasNext()); + argumentPadding + "Provides a file processor: " + sc.fileProcessorBuilder().hasNext()); } writer.println("\nA path matcher will match specific information about the file."); writer.println("\nA file processor will process the associated \"ignore\" file for include and exclude directives"); diff --git a/apache-rat-core/src/site/markdown/development/write_file_processor.md b/apache-rat-core/src/site/markdown/development/write_file_processor.md index 77d843b70..11fb3e620 100644 --- a/apache-rat-core/src/site/markdown/development/write_file_processor.md +++ b/apache-rat-core/src/site/markdown/development/write_file_processor.md @@ -22,7 +22,7 @@ > * Rat [Exclude Expressions](../exclusion_expression.html): The expressions that are used to match file names -A FileProcessor is a module that locates files with a specific name in the directory tree and reads from them file patterns that are translated into Rat exclude expressions. These files are normally found in the file directory tree and their restrictions normally only applies to files at the same directory level as the processed file or below. This type of file is implemented by the `org.apache.rat.config.exclusion.fileProcessors.DescendingFileProcessor`. +A FileProcessor is a module that locates files with a specific name in the directory tree and reads from them file patterns that are translated into Rat exclude expressions. These files are normally found in the file directory tree and their restrictions normally only applies to files at the same directory level as the processed file or below. This type of file is implemented by the `org.apache.rat.config.exclusion.MatcherSet.Builder`. The `DescendingFileProcessor` takes a file name and one or more comment prefixes as in the constructor. The file name is normally a file that is generally hidden on Linux systems like ".gitignore" or ".hgignore". The `DescendingFileProcessor` will scan the directories looking for files with the specified name. If one is found it is passed to the `process(DocumentName)` method which reads the document and returns a list of exclude expressions. 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 327aa9051..11a8ce013 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 @@ -89,8 +89,9 @@ public void cleanup() { @Test public void testAddIncludedFilter() { + DocumentName dirName = DocumentName.builder(tempDir).build(); underTest.addExcludedFilter(DirectoryFileFilter.INSTANCE); - DocumentNameMatcher exlcuder = underTest.getDocumentExcluder(DocumentName.builder(new File(File.separator)).build()); + DocumentNameMatcher exlcuder = underTest.getDocumentExcluder(dirName); assertEquals("not(DirectoryFileFilter)", exlcuder.toString()); assertFalse(exlcuder.matches(DocumentName.builder(tempDir).build())); File f = new File(tempDir, "foo.txt"); diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java index 0519cee82..629873401 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java @@ -35,7 +35,7 @@ public class FileProcessorTest { @ParameterizedTest(name="{index} {1}") @MethodSource("localizePatternData") void localizePatternTest(DocumentName baseName, String pattern, String expectedStr) { - assertThat(FileProcessor.EMPTY.localizePattern(baseName, pattern)).isEqualTo(expectedStr); + assertThat(MatcherSet.Builder.localizePattern(baseName, pattern)).isEqualTo(expectedStr); } public static Stream localizePatternData() { diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/StandardCollectionTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/StandardCollectionTest.java index 5a9186f83..9f62c6fc3 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/StandardCollectionTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/StandardCollectionTest.java @@ -36,7 +36,7 @@ public class StandardCollectionTest { @ParameterizedTest @MethodSource("collectionData") public void testState(StandardCollection scm, boolean hasFileProcessor, boolean hasPathMatchSupplier, boolean hasPatterns) { - assertEquals(hasFileProcessor, scm.fileProcessor().hasNext(), () -> scm.name() + " FileProcessor state wrong."); + assertEquals(hasFileProcessor, scm.fileProcessorBuilder().hasNext(), () -> scm.name() + " MatcherSet state wrong."); assertEquals(hasPathMatchSupplier, scm.hasStaticDocumentNameMatcher(), () -> scm.name() + " PathMatcherSupplier state wrong."); assertEquals(hasPatterns, !scm.patterns().isEmpty(), () -> scm.name() + " patterns state wrong."); } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java similarity index 97% rename from apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreProcessorTest.java rename to apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java index 741a1ab44..9a9e3898c 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java @@ -30,7 +30,7 @@ import java.io.IOException; import java.io.PrintWriter; -public class AbstractIgnoreProcessorTest { +public class AbstractIgnoreBuilderTest { @TempDir protected File baseDir; diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java new file mode 100644 index 000000000..f2a860161 --- /dev/null +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java @@ -0,0 +1,59 @@ +/* + * 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.config.exclusion.fileProcessors; + +import java.util.ArrayList; +import org.apache.rat.config.exclusion.MatcherSet; +import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; +import org.apache.rat.utils.ExtendedIterator; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class BazaarIgnoreBuilderTest extends AbstractIgnoreBuilderTest { + + @Test + public void processExampleFileTest() throws IOException { + String[] lines = { + "# a comment", "*.elc", "*.pyc", "*~", System.lineSeparator(), + "# switch to regexp syntax.", "RE:^\\.pc" }; + + List expected = Arrays.asList("test.elc", "test.pyc", "test.thing~", ".pc"); + + writeFile(".bzrignore", Arrays.asList(lines)); + + BazaarIgnoreBuilder processor = new BazaarIgnoreBuilder(); + MatcherSet matcherSet = processor.build(baseName); + assertThat(matcherSet.includes()).isPresent(); + assertThat(matcherSet.excludes()).isNotPresent(); + DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + for (String name : expected) { + DocumentName docName = baseName.resolve(name); + assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); + } + } + +} diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSFileProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java similarity index 60% rename from apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSFileProcessorTest.java rename to apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java index 57d0d35fe..1f4799f7c 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSFileProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java @@ -19,7 +19,9 @@ package org.apache.rat.config.exclusion.fileProcessors; import java.util.ArrayList; -import org.apache.rat.utils.DefaultLog; +import org.apache.rat.config.exclusion.MatcherSet; +import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.utils.ExtendedIterator; import org.junit.jupiter.api.Test; @@ -28,22 +30,29 @@ import java.util.Arrays; import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -public class CVSFileProcessorTest extends AbstractIgnoreProcessorTest { +public class CVSIgnoreBuilderTest extends AbstractIgnoreBuilderTest { @Test public void processExampleFileTest() throws IOException { String[] lines = { "thingone thingtwo", System.lineSeparator(), "one_fish", "two_fish", "", "red_* blue_*"}; - List expected = ExtendedIterator.create(Arrays.asList("thingone", "thingtwo", "one_fish", "two_fish", "red_*", "blue_*").iterator()) - .map(s -> new File(baseDir, s).getPath()).addTo(new ArrayList<>()); + List expected = Arrays.asList("thingone", "thingtwo", "one_fish", "two_fish", "red_fish", "blue_fish"); writeFile(".cvsignore", Arrays.asList(lines)); - CVSFileProcessor processor = new CVSFileProcessor(); - List actual = processor.apply(baseName); - assertEquals(expected, actual); + CVSIgnoreBuilder processor = new CVSIgnoreBuilder(); + MatcherSet matcherSet = processor.build(baseName); + + assertThat(matcherSet.includes()).isPresent(); + assertThat(matcherSet.excludes()).isNotPresent(); + DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + for (String name : expected) { + DocumentName docName = baseName.resolve(name); + assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); + } } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/DescendingFileProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/DescendingFileProcessorTest.java deleted file mode 100644 index e3343c1d5..000000000 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/DescendingFileProcessorTest.java +++ /dev/null @@ -1,70 +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.config.exclusion.fileProcessors; - -import java.util.ArrayList; -import org.apache.rat.document.DocumentName; -import org.apache.rat.utils.ExtendedIterator; -import org.junit.jupiter.api.Test; - -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -public class DescendingFileProcessorTest extends AbstractIgnoreProcessorTest { - - @Test - public void singleDirectoryTest() throws IOException { - String[] lines = {"*.ext", "fname.*", "**/fname.ext"}; - - List expected = ExtendedIterator.create(Arrays.asList(lines).iterator()) - .map(s -> new File(baseDir, s).getPath()).addTo(new ArrayList<>()); - - writeFile("test.txt", Arrays.asList(lines)); - DocumentName documentName = DocumentName.builder(baseDir).build(); - - DescendingFileProcessor processor = new DescendingFileProcessor("test.txt", "#"); - List actual = processor.apply(baseName); - assertThat(actual).isEqualTo(expected); - } - - @Test - public void layeredDirectoryTest() throws IOException { - String[] lines = {"*.ext", "fname.*", "**/fname.ext"}; - - List expected = ExtendedIterator.create(Arrays.asList(lines).iterator()) - .map(s -> new File(baseDir, s).getPath()).addTo(new ArrayList<>()); - - writeFile("test.txt", Arrays.asList(lines)); - - File subdir = new File(baseDir, "subdir"); - assertThat(subdir.mkdirs()).as("Could not make subdirectory").isTrue(); - - writeFile("subdir/test.txt", Collections.singletonList("foo.*")); - expected.add(new File(subdir, "foo.*").getPath()); - - DescendingFileProcessor processor = new DescendingFileProcessor("test.txt", "#"); - List actual = processor.apply(baseName); - assertThat(actual).isEqualTo(expected); - } -} diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessorTest.java deleted file mode 100644 index 3166b4ca7..000000000 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessorTest.java +++ /dev/null @@ -1,118 +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.config.exclusion.fileProcessors; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.stream.Stream; -import org.apache.rat.document.DocumentName; -import org.apache.rat.document.DocumentNameMatcher; -import org.apache.rat.utils.ExtendedIterator; -import org.junit.Ignore; -import org.junit.jupiter.api.Test; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.util.Arrays; -import java.util.List; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import static org.assertj.core.api.Assertions.assertThat; - -public class GitFileProcessorTest extends AbstractIgnoreProcessorTest { - - @Test - public void processExampleFileTest() throws IOException { - String[] lines = { - "# somethings", - "!thingone", "thing*", System.lineSeparator(), - "# some fish", - "**/fish", "*_fish", - "# some colorful directories", - "red/", "blue/*/"}; - - List expected = ExtendedIterator.create(Arrays.asList("**/thing*", "**/fish", "**/*_fish").iterator()) - .map(s -> new File(baseDir, s).getPath()).addTo(new ArrayList<>()); - expected.add(0, "!"+new File(baseDir, "**/thingone").getPath()); - // "thingone", - writeFile(".gitignore", Arrays.asList(lines)); - - GitFileProcessor processor = new GitFileProcessor(); - List actual = processor.apply(baseName); - assertThat(actual).isEqualTo(expected); - - actual.clear(); - processor.customDocumentNameMatchers().forEach(x -> actual.add(x.toString())); - expected.clear(); - ExtendedIterator.create(Arrays.asList("**/red", "blue/*").iterator()) - .map(s -> String.format("and(isDirectory, %s)", s)) - .forEachRemaining(expected::add); - assertThat(actual).isEqualTo(expected); - } - - // see https://git-scm.com/docs/gitignore - @ParameterizedTest - @MethodSource("modifyEntryData") - public void modifyEntryTest(String source, String expected) { - GitFileProcessor underTest = new GitFileProcessor(); - DocumentName testName = DocumentName.builder().setName("GitFileProcessorTest").setBaseName("testDir").build(); - if (source.endsWith("/")) { - assertThat(underTest.modifyEntry(testName, source)).isEqualTo(null); - Iterator iter = underTest.customDocumentNameMatchers().iterator(); - assertThat(iter).hasNext(); - assertThat(iter.next().toString()).isEqualTo(String.format("and(isDirectory, %s)", expected)); - } else { - assertThat(underTest.modifyEntry(testName, source)).isEqualTo(expected); - assertThat(underTest.customDocumentNameMatchers().iterator().hasNext()).isFalse(); - } - } - - private static Stream modifyEntryData() { - List lst = new ArrayList<>(); - - lst.add(Arguments.of("\\#filename", "**/#filename")); - - lst.add(Arguments.of("!#filename", "!**/#filename")); - lst.add(Arguments.of("\\#filename", "**/#filename")); - lst.add(Arguments.of("!#filename", "!**/#filename")); - lst.add(Arguments.of("/filename", "filename")); - lst.add(Arguments.of("file/name", "file/name")); - lst.add(Arguments.of("/file/name", "file/name")); - lst.add(Arguments.of("filename", "**/filename")); - lst.add(Arguments.of("filename/", "**/filename")); - lst.add(Arguments.of("/filename/", "filename")); - - return lst.stream(); - } - - @Test - @Ignore("RAT-335 ") - public void test_RAT_335() { - GitFileProcessor underTest = new GitFileProcessor(); - URL url = GitFileProcessorTest.class.getClassLoader().getResource("RAT_355/src/"); - File file = new File(url.getFile()); - - DocumentName documentName = DocumentName.builder(file).setBaseName(File.separator).build(); - List lst = underTest.apply(documentName); - System.out.println(lst); - } -} diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java new file mode 100644 index 000000000..3156eae19 --- /dev/null +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java @@ -0,0 +1,147 @@ +/* + * 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.config.exclusion.fileProcessors; + +import java.io.File; +import java.util.ArrayList; +import java.util.stream.Stream; +import org.apache.rat.config.exclusion.MatcherSet; +import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.URL; +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.assertj.core.api.Assertions.assertThat; + +public class GitIgnoreBuilderTest extends AbstractIgnoreBuilderTest { + + @Test + public void processExampleFileTest() throws IOException { + String[] lines = { + "# somethings", + "!thingone", "thing*", System.lineSeparator(), + "# some fish", + "**/fish", "*_fish", + "# some colorful directories", + "red/", "blue/*/"}; + + List expected = Arrays.asList("some/things", "some/fish", "another/red_fish"); + + List ignored = Arrays.asList("some/thinggone"); + + // "thingone", + writeFile(".gitignore", Arrays.asList(lines)); + + GitIgnoreBuilder processor = new GitIgnoreBuilder(); + MatcherSet matcherSet = processor.build(baseName); + assertThat(matcherSet.includes()).isPresent(); + assertThat(matcherSet.excludes()).isPresent(); + + DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + for (String name : expected) { + DocumentName docName = baseName.resolve(name); + assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); + } + + matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); + for (String name : ignored) { + DocumentName docName = baseName.resolve(name); + assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); + } + } + + // see https://git-scm.com/docs/gitignore + @ParameterizedTest + @MethodSource("modifyEntryData") + public void modifyEntryTest(String source, String expected) { + GitIgnoreBuilder underTest = new GitIgnoreBuilder(); + DocumentName testName = DocumentName.builder().setName("GitIgnoreBuilderTest").setBaseName("testDir").build(); + if (source.endsWith("/")) { + assertThat(underTest.modifyEntry(testName, source)).isEqualTo(null); + assertThat(underTest.getIncluded().toString()).isEqualTo(expected); + } else { + assertThat(underTest.modifyEntry(testName, source)).isEqualTo(expected); + } + } + + private static Stream modifyEntryData() { + List lst = new ArrayList<>(); + + lst.add(Arguments.of("\\#filename", "**/#filename")); + + lst.add(Arguments.of("!#filename", "!**/#filename")); + lst.add(Arguments.of("\\#filename", "**/#filename")); + lst.add(Arguments.of("!#filename", "!**/#filename")); + lst.add(Arguments.of("/filename", "filename")); + lst.add(Arguments.of("file/name", "file/name")); + lst.add(Arguments.of("/file/name", "file/name")); + lst.add(Arguments.of("filename", "**/filename")); + lst.add(Arguments.of("filename/", "and(isDirectory, **/filename)")); + lst.add(Arguments.of("/filename/", "and(isDirectory, filename)")); + + return lst.stream(); + } + + @Test + public void test_RAT_335() { + GitIgnoreBuilder underTest = new GitIgnoreBuilder(); + URL url = GitIgnoreBuilderTest.class.getClassLoader().getResource("RAT_355/src/"); + File file = new File(url.getFile()); + + DocumentName documentName = DocumentName.builder(file).build(); + MatcherSet matcherSet = underTest.build(documentName); + assertThat(matcherSet.excludes()).isPresent(); + assertThat(matcherSet.includes()).isPresent(); + DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + assertThat(matcher.toString()).isEqualTo("or(/dir1/.gitignore, /.gitignore)"); + + DocumentName name = documentName.resolve("subdir/file1.log" ); + assertThat(matcher.matches(name)).isTrue(); + name = documentName.resolve("subdir/joe.txt" ); + assertThat(matcher.matches(name)).isFalse(); + name = documentName.resolve("subdir/file1.log" ); + assertThat(matcher.matches(name)).isTrue(); + name = documentName.resolve("subdir/joe.md" ); + assertThat(matcher.matches(name)).isTrue(); + + name = documentName.resolve("dir1/joe.txt" ); + assertThat(matcher.matches(name)).isTrue(); + name = documentName.resolve("dir1/file1.md" ); + assertThat(matcher.matches(name)).isTrue(); + + matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); + assertThat(matcher.toString()).isEqualTo("or(/dir1/.gitignore, /.gitignore)"); + + name = documentName.resolve("dir1/dir1.md" ); + assertThat(matcher.matches(name)).isTrue(); + name = documentName.resolve("subdir/dir1.md" ); + assertThat(matcher.matches(name)).isFalse(); + name = documentName.resolve("dir1/file1.log" ); + assertThat(matcher.matches(name)).isTrue(); + name = documentName.resolve("subdir/file1.log" ); + assertThat(matcher.matches(name)).isTrue(); + } +} diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java new file mode 100644 index 000000000..0b23e90d1 --- /dev/null +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java @@ -0,0 +1,82 @@ +/* + * 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.config.exclusion.fileProcessors; + +import java.util.ArrayList; +import org.apache.rat.config.exclusion.MatcherSet; +import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; +import org.apache.rat.utils.ExtendedIterator; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class HgIgnoreBuilderTest extends AbstractIgnoreBuilderTest { + + @Test + public void processExampleFileTest() throws IOException { + String[] lines = { + "# use glob syntax.", "syntax: glob", "*.elc", "*.pyc", "*~", System.lineSeparator(), + "# switch to regexp syntax.", "syntax: regexp", "^\\.pc" }; + + List expected = Arrays.asList("test.elc", "test.pyc", "test.thing~", ".pc"); + + writeFile(".hgignore", Arrays.asList(lines)); + + HgIgnoreBuilder processor = new HgIgnoreBuilder(); + MatcherSet matcherSet = processor.build(baseName); + assertThat(matcherSet.includes()).isPresent(); + assertThat(matcherSet.excludes()).isNotPresent(); + DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + for (String name : expected) { + DocumentName docName = baseName.resolve(name); + assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); + } + } + + @Test + public void processDefaultFileTest() throws IOException { + String[] lines = {"^[A-Z]*\\.txt", "[0-9]*\\.txt"}; + + List expected = Arrays.asList("ABIGNAME.txt", "endsIn9.txt"); + + + List denied = Arrays.asList("asmallName.txt", "endsin.doc"); + writeFile(".hgignore", Arrays.asList(lines)); + + HgIgnoreBuilder processor = new HgIgnoreBuilder(); + MatcherSet matcherSet = processor.build(baseName); + DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + for (String name : expected) { + DocumentName docName = baseName.resolve(name); + assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); + } + for (String name : denied) { + DocumentName docName = DocumentName.builder().setName(name).setBaseName(baseDir).build(); + assertThat(matcher.matches(docName)).as(docName.getName()).isFalse(); + } + } +} diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreProcessorTest.java deleted file mode 100644 index 3085792c5..000000000 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreProcessorTest.java +++ /dev/null @@ -1,66 +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.config.exclusion.fileProcessors; - -import java.util.ArrayList; -import org.apache.rat.utils.ExtendedIterator; -import org.junit.jupiter.api.Test; - -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; - -import static java.lang.String.format; -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class HgIgnoreProcessorTest extends AbstractIgnoreProcessorTest { - - @Test - public void processExampleFileTest() throws IOException { - String[] lines = { - "# use glob syntax.", "syntax: glob", "*.elc", "*.pyc", "*~", System.lineSeparator(), - "# switch to regexp syntax.", "syntax: regexp", "^\\.pc/" }; - - List expected = ExtendedIterator.create(Arrays.asList("*.elc", "*.pyc", "*~").iterator()) - .map(s -> new File(baseDir, s).getPath()).addTo(new ArrayList<>()); - expected.add(format("%%regex[\\Q%s%s\\E%s]", baseDir.getPath(), File.separatorChar, "\\.pc/")); - - writeFile(".hgignore", Arrays.asList(lines)); - - HgIgnoreProcessor processor = new HgIgnoreProcessor(); - List actual = processor.apply(baseName); - assertEquals(expected, actual); - } - - @Test - public void processDefaultFileTest() throws IOException { - String[] lines = {"^[A-Z]*\\.txt", "[0-9]*\\.txt"}; - - List expected = ExtendedIterator.create(Arrays.asList("[A-Z]*\\.txt", ".*[0-9]*\\.txt").iterator()) - .map(s -> format("%%regex[\\Q%s%s\\E%s]", baseDir.getPath(), File.separatorChar, s)) - .addTo(new ArrayList<>()); - - writeFile(".hgignore", Arrays.asList(lines)); - - HgIgnoreProcessor processor = new HgIgnoreProcessor(); - List actual = processor.apply(baseName); - assertEquals(expected, actual); - } -} From 0b9b8b9d58fe92fcc914e615d7f6845359fc449c Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 22 Dec 2024 13:38:09 +0000 Subject: [PATCH 005/123] fixes for RAT-335 --- .../RAT_335/{ignore.txt => commandLine.txt} | 2 - .../ReportTest/RAT_335/src/.gitignore | 7 + .../ReportTest/RAT_335/src/dir1/.gitignore | 3 + .../ReportTest/RAT_335/src/dir1/dir1.txt} | 0 .../ReportTest/RAT_335/src/dir1/file1.log} | 0 .../ReportTest/RAT_335/src/dir2/dir2.md} | 0 .../ReportTest/RAT_335/src/dir3/dir3.log | 1 + .../resources/ReportTest/RAT_335/src/root.md | 1 + .../ReportTest/RAT_335/verify.groovy | 29 +++ .../config/exclusion/ExclusionProcessor.java | 75 ++++-- .../rat/config/exclusion/ExclusionUtils.java | 29 +++ .../rat/config/exclusion/MatcherSet.java | 69 ++---- .../fileProcessors/AbstractBuilder.java | 44 ++++ .../fileProcessors/BazaarIgnoreBuilder.java | 9 +- .../fileProcessors/CVSIgnoreBuilder.java | 6 +- .../fileProcessors/GitIgnoreBuilder.java | 42 ++-- .../fileProcessors/HgIgnoreBuilder.java | 11 +- .../rat/document/DocumentNameMatcher.java | 84 +++++-- .../config/exclusion/FileProcessorTest.java | 2 +- .../BazaarIgnoreBuilderTest.java | 6 +- .../fileProcessors/CVSIgnoreBuilderTest.java | 6 +- .../fileProcessors/GitIgnoreBuilderTest.java | 64 +++-- .../fileProcessors/HgIgnoreBuilderTest.java | 17 +- .../rat/test/AbstractOptionsProvider.java | 219 +++++++++--------- .../commandLine.txt | 0 .../expected-message.txt | 0 .../{RAT_355 => GitIgnoreBuilderTest}/pom.xml | 0 .../src/README.txt | 0 .../GitIgnoreBuilderTest/src/dir1/dir1.md | 1 + .../GitIgnoreBuilderTest/src/dir2/dir2.txt | 1 + .../GitIgnoreBuilderTest/src/dir3/file3.log | 1 + .../src/invoker.properties | 0 .../verify.groovy | 0 .../resources/RAT_355/src/invoker.properties | 16 -- 34 files changed, 446 insertions(+), 299 deletions(-) rename apache-rat-core/src/it/resources/ReportTest/RAT_335/{ignore.txt => commandLine.txt} (63%) create mode 100644 apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore create mode 100644 apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore rename apache-rat-core/src/{test/resources/RAT_355/src/dir1/dir1.md => it/resources/ReportTest/RAT_335/src/dir1/dir1.txt} (100%) rename apache-rat-core/src/{test/resources/RAT_355/src/dir2/dir2.txt => it/resources/ReportTest/RAT_335/src/dir1/file1.log} (100%) rename apache-rat-core/src/{test/resources/RAT_355/src/dir3/file3.log => it/resources/ReportTest/RAT_335/src/dir2/dir2.md} (100%) create mode 100644 apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir3/dir3.log create mode 100644 apache-rat-core/src/it/resources/ReportTest/RAT_335/src/root.md create mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractBuilder.java rename apache-rat-core/src/test/resources/{RAT_355 => GitIgnoreBuilderTest}/commandLine.txt (100%) rename apache-rat-core/src/test/resources/{RAT_355 => GitIgnoreBuilderTest}/expected-message.txt (100%) rename apache-rat-core/src/test/resources/{RAT_355 => GitIgnoreBuilderTest}/pom.xml (100%) rename apache-rat-core/src/test/resources/{RAT_355 => GitIgnoreBuilderTest}/src/README.txt (100%) create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/dir1.md create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir2/dir2.txt create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir3/file3.log rename apache-rat-core/src/{it/resources/ReportTest/RAT_335 => test/resources/GitIgnoreBuilderTest}/src/invoker.properties (100%) rename apache-rat-core/src/test/resources/{RAT_355 => GitIgnoreBuilderTest}/verify.groovy (100%) delete mode 100644 apache-rat-core/src/test/resources/RAT_355/src/invoker.properties diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/ignore.txt b/apache-rat-core/src/it/resources/ReportTest/RAT_335/commandLine.txt similarity index 63% rename from apache-rat-core/src/it/resources/ReportTest/RAT_335/ignore.txt rename to apache-rat-core/src/it/resources/ReportTest/RAT_335/commandLine.txt index df056a6fa..0a6cbd339 100644 --- a/apache-rat-core/src/it/resources/ReportTest/RAT_335/ignore.txt +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/commandLine.txt @@ -1,7 +1,5 @@ --output-style xml ---input-exclude -**/.gitignore --input-exclude-parsed-scm GIT -- diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore new file mode 100644 index 000000000..8855fa805 --- /dev/null +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore @@ -0,0 +1,7 @@ +*.md + +# This makes it ignore dir3/dir3.log and dir3/file3.log +*.log + +# This makes it "unignore" dir3/file3.log +!file*.log diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore new file mode 100644 index 000000000..26fd5c956 --- /dev/null +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore @@ -0,0 +1,3 @@ +*.txt +!dir1.md +file1.log \ No newline at end of file diff --git a/apache-rat-core/src/test/resources/RAT_355/src/dir1/dir1.md b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/dir1.txt similarity index 100% rename from apache-rat-core/src/test/resources/RAT_355/src/dir1/dir1.md rename to apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/dir1.txt diff --git a/apache-rat-core/src/test/resources/RAT_355/src/dir2/dir2.txt b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/file1.log similarity index 100% rename from apache-rat-core/src/test/resources/RAT_355/src/dir2/dir2.txt rename to apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/file1.log diff --git a/apache-rat-core/src/test/resources/RAT_355/src/dir3/file3.log b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir2/dir2.md similarity index 100% rename from apache-rat-core/src/test/resources/RAT_355/src/dir3/file3.log rename to apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir2/dir2.md diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir3/dir3.log b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir3/dir3.log new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir3/dir3.log @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/root.md b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/root.md new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/root.md @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy index 8a3e07657..36da7e7d0 100644 --- a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy @@ -75,6 +75,35 @@ XPath xPath = XPathFactory.newInstance().newXPath() //XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseName[@name='Unknown license']", // mapOf("count", "4" )) + + +//Note the output when running in the real commandline version of git +// +//# Files that must be ignored (dropping the gitignore matches outside of this test tree) +//$ git check-ignore --no-index --verbose $(find . -type f|sort) +// +// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore:2:!dir1.md ./dir1/dir1.md +// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore:1:*.txt ./dir1/dir1.txt +// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore:3:file1.log ./dir1/file1.log +// .gitignore:20:**/.gitignore ./dir1/.gitignore +// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore:1:*.md ./dir2/dir2.md +// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore:4:*.log ./dir3/dir3.log +// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore:7:!file*.log ./dir3/file3.log +// .gitignore:20:**/.gitignore ./.gitignore +// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore:1:*.md ./root.md + +/* list of excluded files: + +./dir1/dir1.txt +./dir1/file1.log +./dir1/.gitignore +./dir2/dir2.md +./dir3/dir3.log +./.gitignore +./root.md + + */ + List ignoredFiles = new ArrayList<>(Arrays.asList( "/dir1/dir1.txt", "/dir1/file1.log", 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 02f529f65..b19fde1c7 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 @@ -26,6 +26,7 @@ import java.util.TreeSet; import java.util.function.Predicate; +import java.util.stream.Collectors; import javax.print.Doc; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; @@ -188,12 +189,10 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { lastMatcherBaseDir = basedir; // add the file processors - final List fileProcessors = extractFileProcessors(basedir, new ArrayList<>()); - + final List fileProcessors = extractFileProcessors(basedir); + final MatcherSet.Builder fromCommandLine = new MatcherSet.Builder(); DocumentName.Builder nameBuilder = DocumentName.builder().setBaseName(basedir); - MatcherSet.Builder fromCommandLine = new MatcherSet.Builder() - .addExcluded(nameBuilder.setName("excludedPatterns").build(), excludedPatterns) - .addIncluded(nameBuilder.setName("includedPatterns").build(), includedPatterns); + extractPatterns(nameBuilder, fromCommandLine); extractCollectionPatterns(nameBuilder, fromCommandLine); extractCollectionMatchers(fromCommandLine); extractPaths(fromCommandLine); @@ -205,7 +204,13 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { return lastMatcher; } - private List extractFileProcessors(final DocumentName basedir, final List fileProcessorList) { + /** + * Extracts the file processors from {@link #fileProcessors}. + * @param basedir The directory to base the file processors on. + * @return a list of MatcherSets that are created for each {@link #fileProcessors} entry. + */ + private List extractFileProcessors(final DocumentName basedir) { + final List fileProcessorList = new ArrayList<>(); for (StandardCollection sc : fileProcessors) { ExtendedIterator iter = sc.fileProcessorBuilder().map(builder -> builder.build(basedir)); if (iter.hasNext()) { @@ -217,14 +222,28 @@ private List extractFileProcessors(final DocumentName basedir, final return fileProcessorList; } - private void extractPatterns(final DocumentName commandLine, final MatcherSet.Builder fromCommandLine) { - fromCommandLine - .addExcluded(commandLine, excludedPatterns) - .addIncluded(commandLine, includedPatterns); + /** + * Extracts {@link #includedPatterns} and {@link #excludedPatterns} into the specified matcherBuilder. + * @param nameBuilder The name builder for the pattern. File names are resolved against the generated name. + * @param matcherBuilder the MatcherSet.Builder to add the patterns to. + */ + private void extractPatterns(DocumentName.Builder nameBuilder, MatcherSet.Builder matcherBuilder) { + DocumentName name = nameBuilder.setName("Patterns").build(); + if (!excludedPatterns.isEmpty()) { + matcherBuilder.addExcluded(name, excludedPatterns.stream().map(s -> ExclusionUtils.localizePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); + } + if (!includedPatterns.isEmpty()) { + + matcherBuilder.addIncluded(name, includedPatterns.stream().map(s -> ExclusionUtils.localizePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); + } } - private void extractCollectionPatterns(final DocumentName.Builder nameBuilder, final MatcherSet.Builder fileProcessorBuilder) { - // add the collection patterns + /** + * Extracts {@link #includedCollections} and {@link #excludedCollections} patterns into the specified matcherBuilder. + * @param nameBuilder the name builder for the pattern names. + * @param matcherBuilder the MatcherSet.Builder to add the collections to. + */ + private void extractCollectionPatterns(final DocumentName.Builder nameBuilder, final MatcherSet.Builder matcherBuilder) { final Set incl = new TreeSet<>(); final Set excl = new TreeSet<>(); for (StandardCollection sc : includedCollections) { @@ -243,41 +262,47 @@ private void extractCollectionPatterns(final DocumentName.Builder nameBuilder, f MatcherSet.Builder.segregateList(excl, incl, sc.patterns()); } } - nameBuilder.setName("collections"); - fileProcessorBuilder - .addExcluded(nameBuilder.setName("excludedCollections").build(), excl) - .addIncluded(nameBuilder.setName("includedCollections").build(), incl); + DocumentName name = nameBuilder.setName("Collections").build(); + matcherBuilder + .addExcluded(name, excl) + .addIncluded(name, incl); } - private void extractCollectionMatchers(final MatcherSet.Builder fromCommandLine) { - // add the matchers + /** + * Extracts {@link #includedCollections} and {@link #excludedCollections} matchers into the specified matcherBuilder. + * @param matcherBuilder the MatcherSet.Builder to add the collections to. + */ + private void extractCollectionMatchers(final MatcherSet.Builder matcherBuilder) { ExtendedIterator.create(includedCollections.iterator()) .map(StandardCollection::staticDocumentNameMatcher) .filter(Objects::nonNull) - .forEachRemaining(fromCommandLine::addIncluded); + .forEachRemaining(matcherBuilder::addIncluded); ExtendedIterator.create(excludedCollections.iterator()) .map(StandardCollection::staticDocumentNameMatcher) .filter(Objects::nonNull) - .forEachRemaining(fromCommandLine::addExcluded); + .forEachRemaining(matcherBuilder::addExcluded); } - private void extractPaths(final MatcherSet.Builder fromCommandLine) { + /** + * Extracts {@link #includedPaths} and {@link #excludedPaths} patterns into the specified matcherBuilder. + * @param matcherBuilder the MatcherSet.Builder to add the collections to. + */ + private void extractPaths(final MatcherSet.Builder matcherBuilder) { if (!includedPaths.isEmpty()) { for (DocumentNameMatcher matcher : includedPaths) { DefaultLog.getInstance().info(format("Including path matcher %s", matcher)); - fromCommandLine.addIncluded(matcher); + matcherBuilder.addIncluded(matcher); } } if (!excludedPaths.isEmpty()) { for (DocumentNameMatcher matcher : excludedPaths) { DefaultLog.getInstance().info(format("Excluding path matcher %s", matcher)); - fromCommandLine.addExcluded(matcher); + matcherBuilder.addExcluded(matcher); } } - } private DocumentNameMatcher createMatcher(List fileProcessors) { @@ -312,7 +337,7 @@ private DocumentNameMatcher createMatcher(List fileProcessors) { } return true; }; - final String name = format("or(%s, not(%s)", included, excluded); + final String name = DocumentNameMatcher.or(included, DocumentNameMatcher.not(excluded)).toString(); return new DocumentNameMatcher(name, pred); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java index 90a8f1a1d..6463be4af 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java @@ -34,6 +34,8 @@ import org.apache.commons.io.LineIterator; import org.apache.commons.lang3.StringUtils; import org.apache.rat.ConfigurationException; +import org.apache.rat.config.exclusion.plexus.MatchPattern; +import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.utils.ExtendedIterator; @@ -188,4 +190,31 @@ private static void verifyFile(final File file) { throw new ConfigurationException(format("%s is not a valid file.", file)); } } + + /** + * Modifies the {@link MatchPattern} formatted {@code pattern} argument by expanding the pattern and + * by adjusting the pattern to include the basename from the {@code documentName} argument. + * @param documentName the name of the file being read. + * @param pattern the pattern to format. + * @return the completely formatted pattern + */ + public static String localizePattern(final DocumentName documentName, final String pattern) { + boolean prefix = pattern.startsWith(NEGATION_PREFIX); + String workingPattern = prefix ? pattern.substring(1) : pattern; + String normalizedPattern = SelectorUtils.extractPattern(workingPattern, documentName.getDirectorySeparator()); + StringBuilder sb = new StringBuilder(); + if (SelectorUtils.isRegexPrefixedPattern(workingPattern)) { + sb.append(prefix ? NEGATION_PREFIX : "") + .append(SelectorUtils.REGEX_HANDLER_PREFIX) + .append("\\Q").append(documentName.getBaseName()) + .append(documentName.getDirectorySeparator()) + .append("\\E").append(normalizedPattern) + .append(SelectorUtils.PATTERN_HANDLER_SUFFIX); + return sb.toString(); + } else { + sb.append(documentName.getBaseName()) + .append(documentName.getDirectorySeparator()).append(normalizedPattern); + return (prefix ? NEGATION_PREFIX : "") + DocumentName.builder(documentName).setName(sb.toString()).build().getName(); + } + } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java index c13b1cee9..73cde5741 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -37,7 +37,6 @@ import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; -import org.apache.rat.utils.ExtendedIterator; /** * The file processor reads the file specified in the DocumentName. @@ -57,34 +56,7 @@ public interface MatcherSet { class Builder { /** A String format pattern to print a regex string */ - public static final String REGEX_FMT = "%%regex[%s]"; - - /** - * Modifies the {@link MatchPattern} formatted {@code pattern} argument by expanding the pattern and - * by adjusting the pattern to include the basename from the {@code documentName} argument. - * @param documentName the name of the file being read. - * @param pattern the pattern to format. - * @return the completely formatted pattern - */ - public static String localizePattern(final DocumentName documentName, final String pattern) { - boolean prefix = pattern.startsWith(ExclusionUtils.NEGATION_PREFIX); - String workingPattern = prefix ? pattern.substring(1) : pattern; - String normalizedPattern = SelectorUtils.extractPattern(workingPattern, documentName.getDirectorySeparator()); - StringBuilder sb = new StringBuilder(); - if (SelectorUtils.isRegexPrefixedPattern(workingPattern)) { - sb.append(prefix ? ExclusionUtils.NEGATION_PREFIX : "") - .append(SelectorUtils.REGEX_HANDLER_PREFIX) - .append("\\Q").append(documentName.getBaseName()) - .append(documentName.getDirectorySeparator()) - .append("\\E").append(normalizedPattern) - .append(SelectorUtils.PATTERN_HANDLER_SUFFIX); - return sb.toString(); - } else { - sb.append(documentName.getBaseName()) - .append(documentName.getDirectorySeparator()).append(normalizedPattern); - return (prefix ? ExclusionUtils.NEGATION_PREFIX : "") + DocumentName.builder(documentName).setName(sb.toString()).build().getName(); - } - } + protected static final String REGEX_FMT = "%%regex[%s]"; /** * Adds to lists of qualified file patterns. Non-matching patterns start with a {@code !}. @@ -118,15 +90,6 @@ public static void segregateList(final Set matching, final Set n commentFilter = StringUtils::isNotBlank; } - /** - * Constructor. - * @param fileName The name of the file to process. - * @param commentPrefix the comment prefix - */ - protected Builder(final String fileName, final String commentPrefix) { - this(fileName, commentPrefix == null ? null : Collections.singletonList(commentPrefix)); - } - /** * Constructor. * @param fileName name of the file to process @@ -144,22 +107,24 @@ protected Builder(final String fileName, final Iterable commentPrefixes) * Default implementation returns the @{code entry} argument. * @param documentName the name of the document that the file was read from. * @param entry the entry from that document. - * @return the modified string or null to skip the string. + * @return the modified string or an empty Optional to skip the string. */ - protected String modifyEntry(final DocumentName documentName, final String entry) { - return entry; + protected Optional modifyEntry(final DocumentName documentName, final String entry) { + return Optional.of(entry); } public Builder addIncluded(DocumentName fromDocument, Set names) { if (!names.isEmpty()) { - addIncluded(new DocumentNameMatcher(fromDocument.localized("/"), MatchPatterns.from(names), fromDocument.getBaseDocumentName())); + String name = String.format("'included %s'", fromDocument.localized("/").substring(1)); + addIncluded(new DocumentNameMatcher(name, MatchPatterns.from(names), fromDocument.getBaseDocumentName())); } return this; } public Builder addExcluded(DocumentName fromDocument, Set names) { if (!names.isEmpty()) { - addExcluded(new DocumentNameMatcher(fromDocument.localized("/"), MatchPatterns.from(names), fromDocument.getBaseDocumentName())); + String name = String.format("'excluded %s'", fromDocument.localized("/").substring(1)); + addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(names), fromDocument.getBaseDocumentName())); } return this; } @@ -179,14 +144,24 @@ public Builder addExcluded(DocumentNameMatcher matcher) { * @param documentName the file to read. */ protected void process(final DocumentName documentName) { - Set included = new HashSet<>(); - Set excluded = new HashSet<>(); List iterable = new ArrayList<>(); ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) - .map(entry -> modifyEntry(documentName, entry)) + .map(entry -> modifyEntry(documentName, entry).orElse(null)) .filter(Objects::nonNull) - .map(entry -> localizePattern(documentName, entry)) + .map(entry -> ExclusionUtils.localizePattern(documentName, entry)) .forEachRemaining(iterable::add); + segregateProcessResult(documentName, iterable); + } + + /** + * Moves properly formatted file names includes, excludes into the proper + * {@link #included} and {@link #excluded} DocumentMatchers. + * @param documentName the nome of the document being processed. + * @param iterable the list of properly formatted include and excludes from the input. + */ + protected void segregateProcessResult(final DocumentName documentName, List iterable) { + Set included = new HashSet<>(); + Set excluded = new HashSet<>(); segregateList(included, excluded, iterable); addExcluded(documentName, excluded); addIncluded(documentName, included); diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractBuilder.java new file mode 100644 index 000000000..59fcfd06f --- /dev/null +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractBuilder.java @@ -0,0 +1,44 @@ +package org.apache.rat.config.exclusion.fileProcessors; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.apache.rat.config.exclusion.MatcherSet; +import org.apache.rat.document.DocumentName; + +public class AbstractBuilder extends MatcherSet.Builder { + + /** + * Constructor. + * @param fileName The name of the file to process. + * @param commentPrefix the comment prefix + */ + protected AbstractBuilder(final String fileName, final String commentPrefix) { + this(fileName, commentPrefix == null ? null : Collections.singletonList(commentPrefix)); + } + + /** + * Constructor. + * @param fileName name of the file to process + * @param commentPrefixes a collection of comment prefixes. + */ + protected AbstractBuilder(final String fileName, final Iterable commentPrefixes) { + super(fileName, commentPrefixes); + } + + /** + * Moves properly formatted file names includes, excludes into the proper + * {@link #included} and {@link #excluded} DocumentMatchers. This differs from the parent implementation + * in that patterns that match the process are excluded. + * @param documentName the nome of the document being processed. + * @param iterable the list of properly formatted include and excludes from the input. + */ + protected void segregateProcessResult(final DocumentName documentName, List iterable) { + Set included = new HashSet<>(); + Set excluded = new HashSet<>(); + segregateList(excluded, included, iterable); + addExcluded(documentName, excluded); + addIncluded(documentName, included); + } +} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java index 315ec99dc..a8b65c960 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java @@ -18,6 +18,7 @@ */ package org.apache.rat.config.exclusion.fileProcessors; +import java.util.Optional; import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; @@ -26,7 +27,7 @@ /** * A processor for {@code .bzrignore} files. */ -public final class BazaarIgnoreBuilder extends MatcherSet.Builder { +public final class BazaarIgnoreBuilder extends AbstractBuilder { /** * Constructor. */ @@ -35,12 +36,12 @@ public BazaarIgnoreBuilder() { } @Override - public String modifyEntry(final DocumentName baseName, final String entry) { + public Optional modifyEntry(final DocumentName baseName, final String entry) { if (entry.startsWith("RE:")) { String line = entry.substring("RE:".length()).trim(); String pattern = line.startsWith("^") ? line.substring(1) : line; - return format(REGEX_FMT, pattern); + return Optional.of(format(REGEX_FMT, pattern)); } - return entry; + return Optional.of(entry); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java index cd308e923..3aae5765e 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java @@ -31,7 +31,7 @@ /** * A file processor for the {@code .csvignore} file. */ -public class CVSIgnoreBuilder extends MatcherSet.Builder { +public class CVSIgnoreBuilder extends AbstractBuilder { /** * The constructor. */ @@ -49,10 +49,10 @@ protected void process(final DocumentName documentName) { String[] parts = line.split("\\s+"); for (String part : parts) { if (!part.isEmpty()) { - result.add(localizePattern(documentName, part)); + result.add(ExclusionUtils.localizePattern(documentName, part)); } } } - addIncluded(documentName.getBaseDocumentName(), result); + addExcluded(documentName, result); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java index 319f2a137..0c931d796 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java @@ -22,10 +22,9 @@ import java.io.FileFilter; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.Objects; -import java.util.Set; +import java.util.Optional; import java.util.SortedMap; import java.util.TreeMap; import java.util.function.Consumer; @@ -42,7 +41,7 @@ * Processes the .gitignore file. * @see .gitignore documentation */ -public class GitIgnoreBuilder extends MatcherSet.Builder { +public class GitIgnoreBuilder extends AbstractBuilder { // create a list of levels that a list of processors at that level. // will return a custom matcher that from an overridden MatcherSet.customDocumentNameMatchers method // build LevelMatcher as a system that returns Include, Exclude or no status for each check. @@ -112,12 +111,24 @@ DocumentNameMatcher getExcluded() { } @Override - public String modifyEntry(final DocumentName documentName, final String entry) { + public Optional modifyEntry(final DocumentName documentName, final String entry) { return modifyEntry(documentName, entry, this::addIncluded, this::addExcluded); } - private static String modifyEntry(final DocumentName documentName, final String entry, Consumer include, - Consumer exclude) { + /** + * Convert the string entry. + * If the string ends with a slash an {@link DocumentNameMatcher#and} is constructed from a directory check and the file + * name matcher. In this case an empty Optional is returned. + * If the string starts with {@link ExclusionUtils#NEGATION_PREFIX} then the entry is placed in the include list, otherwise + * the entry is placed in the exclude list and the name of the check returned. + * @param documentName The name of the document being processed. + * @param entry The entry from the document + * @param include A consumer to accept the included DocumentNameMatchers. + * @param exclude A consumer to accept the excluded DocumentNameMatchers. + * @return and Optional containing the name of the matcher. + */ + private static Optional modifyEntry(final DocumentName documentName, final String entry, Consumer include, + Consumer exclude) { // An optional prefix "!" which negates the pattern; boolean prefix = entry.startsWith(NEGATION_PREFIX); String pattern = prefix || entry.startsWith(ESCAPED_COMMENT) || entry.startsWith(ESCAPED_NEGATION) ? @@ -148,33 +159,28 @@ private static String modifyEntry(final DocumentName documentName, final String } else { include.accept(matcher); } - return null; + return Optional.empty(); } - return prefix ? NEGATION_PREFIX + pattern : pattern; + return Optional.of(prefix ? NEGATION_PREFIX + pattern : pattern); } - private class LevelBuilder extends MatcherSet.Builder { + private static class LevelBuilder extends AbstractBuilder { LevelBuilder(int level) { super(IGNORE_FILE+"-"+level, COMMENT_PREFIX); } - public String modifyEntry(final DocumentName documentName, final String entry) { + public Optional modifyEntry(final DocumentName documentName, final String entry) { return GitIgnoreBuilder.modifyEntry(documentName, entry, this::addIncluded, this::addExcluded); } public void process(DocumentName directory, DocumentName documentName) { - Set included = new HashSet<>(); - Set excluded = new HashSet<>(); List iterable = new ArrayList<>(); ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) - .map(entry -> modifyEntry(documentName, entry)) + .map(entry -> modifyEntry(documentName, entry).orElse(null)) .filter(Objects::nonNull) - .map(entry -> localizePattern(documentName, entry)) + .map(entry -> ExclusionUtils.localizePattern(documentName, entry)) .forEachRemaining(iterable::add); - segregateList(included, excluded, iterable); - addExcluded(directory, excluded); - addIncluded(directory, included); - + segregateProcessResult(directory, iterable); } } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java index 036333ea6..86e8253c0 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java @@ -19,6 +19,7 @@ package org.apache.rat.config.exclusion.fileProcessors; import java.util.Locale; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -30,7 +31,7 @@ /** * A processor for the {@code .hgignore} files. */ -public final class HgIgnoreBuilder extends MatcherSet.Builder { +public final class HgIgnoreBuilder extends AbstractBuilder { /** * The state enumeration for the processor. When processing the file the processor changes * syntax state depending on the input. @@ -62,16 +63,16 @@ protected void process(final DocumentName baseName) { } @Override - public String modifyEntry(final DocumentName baseName, final String entry) { + public Optional modifyEntry(final DocumentName baseName, final String entry) { Matcher m = SYNTAX_CHECK.matcher(entry.toLowerCase(Locale.ROOT)); if (m.matches()) { state = Syntax.valueOf(m.group(1).toUpperCase()); - return null; + return Optional.empty(); } if (state == Syntax.REGEXP) { String pattern = entry.startsWith("^") ? entry.substring(1) : ".*" + entry; - return format(REGEX_FMT, pattern); + return Optional.of(format(REGEX_FMT, pattern)); } - return entry; + return Optional.of(entry); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 043f3b0df..b0620b237 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -23,7 +23,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; import java.util.Set; @@ -65,7 +65,7 @@ public final class DocumentNameMatcher { public DocumentNameMatcher(final String name, final Predicate predicate) { this.name = name; this.predicate = predicate; - this.isCollection = predicate instanceof MatcherPredicate; + this.isCollection = predicate instanceof CollectionPredicate; } /** @@ -85,10 +85,25 @@ public DocumentNameMatcher(final String name, final DocumentNameMatcher delegate */ public DocumentNameMatcher(final String name, final MatchPatterns patterns, final DocumentName basedir) { this(name, (Predicate) documentName -> patterns.matches(documentName.getName(), - MatchPattern.tokenizePathToString(documentName.getName(), basedir.getDirectorySeparator()), + tokenize(documentName.getName(), basedir.getDirectorySeparator()), basedir.isCaseSensitive())); } + /** + * Tokenizes name for faster Matcher processing. + * @param name the name to tokenize + * @param dirSeparator the directory separator + * @return the tokenized name. + */ + private static char[][] tokenize(String name, String dirSeparator) { + String[] tokenizedName = MatchPattern.tokenizePathToString(name, dirSeparator); + char[][] tokenizedNameChar = new char[tokenizedName.length][]; + for (int i = 0; i < tokenizedName.length; i++) { + tokenizedNameChar[i] = tokenizedName[i].toCharArray(); + } + return tokenizedNameChar; + } + /** * Constructs a DocumentNameMatcher from a name and a DocumentName predicate. * @param name the name of the matcher. @@ -185,17 +200,18 @@ public static DocumentNameMatcher or(final Collection match return opt.get(); } - Set myList = new HashSet<>(); + // preserve order + Set workingSet = new LinkedHashSet<>(); for (DocumentNameMatcher matcher : matchers) { - if (matcher.predicate instanceof MatcherPredicate && ((MatcherPredicate)matcher.predicate).matchValue) { - // nested "or" - ((MatcherPredicate)matcher.predicate).matchers.forEach(myList::add); + // check for nested or + if (matcher.predicate instanceof Or) { + ((Or)matcher.predicate).matchers.forEach(workingSet::add); } else { - myList.add(matcher); + workingSet.add(matcher); } } - opt = standardCollectionCheck(matchers, MATCHES_ALL); - return opt.orElseGet(() -> new DocumentNameMatcher(format("or(%s)", join(myList)), new MatcherPredicate(true, myList))); + return standardCollectionCheck(matchers, MATCHES_ALL) + .orElseGet(() -> new DocumentNameMatcher(format("or(%s)", join(workingSet)), new Or(workingSet))); } /** @@ -218,17 +234,18 @@ public static DocumentNameMatcher and(final Collection matc return opt.get(); } - Set myList = new HashSet<>(); + // preserve order + Set workingSet = new LinkedHashSet<>(); for (DocumentNameMatcher matcher : matchers) { - if (matcher.predicate instanceof MatcherPredicate && !((MatcherPredicate)matcher.predicate).matchValue) { - // nested "and" - ((MatcherPredicate)matcher.predicate).matchers.forEach(myList::add); + // check for nexted And + if (matcher.predicate instanceof And) { + ((And)matcher.predicate).matchers.forEach(workingSet::add); } else { - myList.add(matcher); + workingSet.add(matcher); } } opt = standardCollectionCheck(matchers, MATCHES_NONE); - return opt.orElseGet(() -> new DocumentNameMatcher(format("and(%s)", join(myList)), new MatcherPredicate(false, myList))); + return opt.orElseGet(() -> new DocumentNameMatcher(format("and(%s)", join(workingSet)), new And(workingSet))); } /** @@ -240,13 +257,36 @@ public static DocumentNameMatcher and(final DocumentNameMatcher... matchers) { return and(Arrays.asList(matchers)); } - private static class MatcherPredicate implements Predicate { - final Iterable matchers; - final boolean matchValue; + /** + * A marker interface to indicate this predicate contains a collection of matchers. + */ + private interface CollectionPredicate extends Predicate{} + + private static class And implements CollectionPredicate { + + private final Iterable matchers; + + And(final Iterable matchers) { + this.matchers = matchers; + } + + @Override + public boolean test(DocumentName documentName) { + for (DocumentNameMatcher matcher : matchers) { + if (!matcher.matches(documentName)) { + return false; + } + } + return true; + } + } + + private static class Or implements CollectionPredicate { + + private final Iterable matchers; - MatcherPredicate(boolean matchValue, Iterable matchers) { + Or(final Iterable matchers) { this.matchers = matchers; - this.matchValue = matchValue; } @Override @@ -256,7 +296,7 @@ public boolean test(DocumentName documentName) { return true; } } - return !matchValue; + return false; } } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java index 629873401..0421eaa68 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java @@ -35,7 +35,7 @@ public class FileProcessorTest { @ParameterizedTest(name="{index} {1}") @MethodSource("localizePatternData") void localizePatternTest(DocumentName baseName, String pattern, String expectedStr) { - assertThat(MatcherSet.Builder.localizePattern(baseName, pattern)).isEqualTo(expectedStr); + assertThat(ExclusionUtils.localizePattern(baseName, pattern)).isEqualTo(expectedStr); } public static Stream localizePatternData() { diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java index f2a860161..fe5cec339 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java @@ -47,9 +47,9 @@ public void processExampleFileTest() throws IOException { BazaarIgnoreBuilder processor = new BazaarIgnoreBuilder(); MatcherSet matcherSet = processor.build(baseName); - assertThat(matcherSet.includes()).isPresent(); - assertThat(matcherSet.excludes()).isNotPresent(); - DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + assertThat(matcherSet.excludes()).isPresent(); + assertThat(matcherSet.includes()).isNotPresent(); + DocumentNameMatcher matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); for (String name : expected) { DocumentName docName = baseName.resolve(name); assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java index 1f4799f7c..ac5578b62 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java @@ -47,9 +47,9 @@ public void processExampleFileTest() throws IOException { CVSIgnoreBuilder processor = new CVSIgnoreBuilder(); MatcherSet matcherSet = processor.build(baseName); - assertThat(matcherSet.includes()).isPresent(); - assertThat(matcherSet.excludes()).isNotPresent(); - DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + assertThat(matcherSet.excludes()).isPresent(); + assertThat(matcherSet.includes()).isNotPresent(); + DocumentNameMatcher matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); for (String name : expected) { DocumentName docName = baseName.resolve(name); assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java index 3156eae19..d3591967f 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java @@ -35,6 +35,7 @@ import org.junit.jupiter.params.provider.MethodSource; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.not; public class GitIgnoreBuilderTest extends AbstractIgnoreBuilderTest { @@ -48,11 +49,10 @@ public void processExampleFileTest() throws IOException { "# some colorful directories", "red/", "blue/*/"}; - List expected = Arrays.asList("some/things", "some/fish", "another/red_fish"); + List excluded = Arrays.asList("some/things", "some/fish", "another/red_fish"); - List ignored = Arrays.asList("some/thinggone"); + List included = Arrays.asList("some/thingone"); - // "thingone", writeFile(".gitignore", Arrays.asList(lines)); GitIgnoreBuilder processor = new GitIgnoreBuilder(); @@ -61,13 +61,13 @@ public void processExampleFileTest() throws IOException { assertThat(matcherSet.excludes()).isPresent(); DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : expected) { + for (String name : included) { DocumentName docName = baseName.resolve(name); assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); } matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : ignored) { + for (String name : excluded) { DocumentName docName = baseName.resolve(name); assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); } @@ -80,10 +80,10 @@ public void modifyEntryTest(String source, String expected) { GitIgnoreBuilder underTest = new GitIgnoreBuilder(); DocumentName testName = DocumentName.builder().setName("GitIgnoreBuilderTest").setBaseName("testDir").build(); if (source.endsWith("/")) { - assertThat(underTest.modifyEntry(testName, source)).isEqualTo(null); + assertThat(underTest.modifyEntry(testName, source)).isNotPresent(); assertThat(underTest.getIncluded().toString()).isEqualTo(expected); } else { - assertThat(underTest.modifyEntry(testName, source)).isEqualTo(expected); + assertThat(underTest.modifyEntry(testName, source)).contains(expected); } } @@ -105,43 +105,41 @@ private static Stream modifyEntryData() { return lst.stream(); } + private void assertMatches(DocumentName documentName, DocumentNameMatcher matcher, String[] matching, String[] notMatching) { + for (String test : matching) { + DocumentName name = documentName.resolve(test); + assertThat(matcher.matches(name)).as(test).isTrue(); + } + for (String test: notMatching) { + DocumentName name = documentName.resolve(test); + assertThat(matcher.matches(name)).as(test).isFalse(); + } + } + @Test public void test_RAT_335() { GitIgnoreBuilder underTest = new GitIgnoreBuilder(); - URL url = GitIgnoreBuilderTest.class.getClassLoader().getResource("RAT_355/src/"); + URL url = GitIgnoreBuilderTest.class.getClassLoader().getResource("GitIgnoreBuilderTest/src/"); File file = new File(url.getFile()); DocumentName documentName = DocumentName.builder(file).build(); MatcherSet matcherSet = underTest.build(documentName); assertThat(matcherSet.excludes()).isPresent(); assertThat(matcherSet.includes()).isPresent(); + + // includes test DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); - assertThat(matcher.toString()).isEqualTo("or(/dir1/.gitignore, /.gitignore)"); - - DocumentName name = documentName.resolve("subdir/file1.log" ); - assertThat(matcher.matches(name)).isTrue(); - name = documentName.resolve("subdir/joe.txt" ); - assertThat(matcher.matches(name)).isFalse(); - name = documentName.resolve("subdir/file1.log" ); - assertThat(matcher.matches(name)).isTrue(); - name = documentName.resolve("subdir/joe.md" ); - assertThat(matcher.matches(name)).isTrue(); - - name = documentName.resolve("dir1/joe.txt" ); - assertThat(matcher.matches(name)).isTrue(); - name = documentName.resolve("dir1/file1.md" ); - assertThat(matcher.matches(name)).isTrue(); + assertThat(matcher.toString()).isEqualTo("or('included dir1/.gitignore', 'included .gitignore')"); + assertMatches(documentName, matcher, new String[]{"subdir/file1.log", "dir1/dir1.md", "dir1/somedir/dir1.md", + "dir1/file1.log"}, + new String[]{"dir1/joe.txt", "subdir/joe.txt", "subdir/joe.md", "dir1/joe.md" }); + // excludes tests matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); - assertThat(matcher.toString()).isEqualTo("or(/dir1/.gitignore, /.gitignore)"); - - name = documentName.resolve("dir1/dir1.md" ); - assertThat(matcher.matches(name)).isTrue(); - name = documentName.resolve("subdir/dir1.md" ); - assertThat(matcher.matches(name)).isFalse(); - name = documentName.resolve("dir1/file1.log" ); - assertThat(matcher.matches(name)).isTrue(); - name = documentName.resolve("subdir/file1.log" ); - assertThat(matcher.matches(name)).isTrue(); + assertThat(matcher.toString()).isEqualTo("or('excluded dir1/.gitignore', 'excluded .gitignore')"); + assertMatches(documentName, matcher, new String[]{ "dir1/file1.txt", "dir1/somedir/file1.txt", "dir1/file1.log", + "dir1/somedir/file1.log", "subdir/dir1.md", "subdir/some.log"}, + new String[]{"subdir/afile.txt" }); + } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java index 0b23e90d1..a56c26eba 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java @@ -48,9 +48,9 @@ public void processExampleFileTest() throws IOException { HgIgnoreBuilder processor = new HgIgnoreBuilder(); MatcherSet matcherSet = processor.build(baseName); - assertThat(matcherSet.includes()).isPresent(); - assertThat(matcherSet.excludes()).isNotPresent(); - DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + assertThat(matcherSet.excludes()).isPresent(); + assertThat(matcherSet.includes()).isNotPresent(); + DocumentNameMatcher matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); for (String name : expected) { DocumentName docName = baseName.resolve(name); assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); @@ -61,20 +61,19 @@ public void processExampleFileTest() throws IOException { public void processDefaultFileTest() throws IOException { String[] lines = {"^[A-Z]*\\.txt", "[0-9]*\\.txt"}; - List expected = Arrays.asList("ABIGNAME.txt", "endsIn9.txt"); + List match = Arrays.asList("ABIGNAME.txt", "endsIn9.txt"); + List notMatch = Arrays.asList("asmallName.txt", "endsin.doc"); - - List denied = Arrays.asList("asmallName.txt", "endsin.doc"); writeFile(".hgignore", Arrays.asList(lines)); HgIgnoreBuilder processor = new HgIgnoreBuilder(); MatcherSet matcherSet = processor.build(baseName); - DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : expected) { + DocumentNameMatcher matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); + for (String name : match) { DocumentName docName = baseName.resolve(name); assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); } - for (String name : denied) { + for (String name : notMatch) { DocumentName docName = DocumentName.builder().setName(name).setBaseName(baseDir).build(); assertThat(matcher.matches(docName)).as(docName.getName()).isFalse(); } 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 baf44eada..dfad5b43d 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 @@ -64,11 +64,7 @@ import static org.apache.rat.commandline.Arg.HELP_LICENSES; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.Assert.fail; /** * A list of methods that an OptionsProvider in a test case must support. @@ -77,11 +73,13 @@ * Each method in this interface tests an Option in {@link org.apache.rat.OptionCollection}. */ public abstract class AbstractOptionsProvider { - /** A map of test Options to tests */ + /** + * A map of test Options to tests + */ protected final Map testMap = new TreeMap<>(); - protected static final String[] EXCLUDE_ARGS = { "*.foo", "%regex[[A-Z]\\.bar]", "justbaz"}; - protected static final String[] INCLUDE_ARGS = { "B.bar", "justbaz" }; + protected static final String[] EXCLUDE_ARGS = {"*.foo", "%regex[[A-Z]\\.bar]", "justbaz"}; + protected static final String[] INCLUDE_ARGS = {"B.bar", "justbaz"}; /** * The directory to place test data in. * We do not use temp file here as we want the evidence to survive failure. @@ -182,6 +180,7 @@ private void verifyAllMethodsDefinedAndNeeded(Collection unsupportedArgs /** * Create the report configuration from the argument pairs. * There must be at least one arg. It may be `ImmutablePair.nullPair()`. + * * @param args Pairs comprising the argument option and the values for the option. * @return The generated ReportConfiguration. * @throws IOException on error. @@ -193,7 +192,7 @@ protected File writeFile(String name, Iterable lines) { try (PrintWriter writer = new PrintWriter(new FileWriter(file))) { lines.forEach(writer::println); } catch (IOException e) { - fail(e.getMessage(), e); + fail(e.getMessage()); } return file; } @@ -205,18 +204,21 @@ protected DocumentName mkDocName(String name) { /* tests to be implemented */ protected abstract void helpTest(); + private String displayArgAndName(Option option, String fname) { + return String.format("%s %s", option.getLongOpt(), fname); + } // exclude tests private void execExcludeTest(Option option, String[] args) { - String[] notExcluded = { "notbaz", "well._afile" }; - String[] excluded = { "some.foo", "B.bar", "justbaz"}; + String[] notExcluded = {"notbaz", "well._afile"}; + String[] excluded = {"some.foo", "B.bar", "justbaz"}; try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : notExcluded) { - assertTrue(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isTrue(); } for (String fname : excluded) { - assertFalse(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isFalse(); } } catch (IOException e) { fail(e.getMessage()); @@ -225,7 +227,7 @@ private void execExcludeTest(Option option, String[] args) { private void excludeFileTest(Option option) { File outputFile = writeFile("exclude.txt", Arrays.asList(EXCLUDE_ARGS)); - execExcludeTest(option, new String[] {outputFile.getPath()}); + execExcludeTest(option, new String[]{outputFile.getPath()}); } protected void excludeFileTest() { @@ -246,17 +248,17 @@ protected void inputExcludeTest() { protected void inputExcludeStdTest() { Option option = Arg.EXCLUDE_STD.find("input-exclude-std"); - String[] args = { StandardCollection.MISC.name() }; - String[] excluded = { "afile~", ".#afile", "%afile%", "._afile" }; - String[] notExcluded = { "afile~more", "what.#afile", "%afile%withMore", "well._afile" }; + String[] args = {StandardCollection.MISC.name()}; + String[] excluded = {"afile~", ".#afile", "%afile%", "._afile"}; + String[] notExcluded = {"afile~more", "what.#afile", "%afile%withMore", "well._afile"}; try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { - assertFalse(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isFalse(); } for (String fname : notExcluded) { - assertTrue(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -265,7 +267,7 @@ protected void inputExcludeStdTest() { protected void inputExcludeParsedScmTest() { Option option = Arg.EXCLUDE_PARSE_SCM.find("input-exclude-parsed-scm"); - String[] args = { "GIT" }; + String[] args = {"GIT"}; String[] lines = { "# somethings", "!thingone", "thing*", System.lineSeparator(), @@ -273,8 +275,8 @@ protected void inputExcludeParsedScmTest() { "**/fish", "*_fish", "# some colorful directories", "red/", "blue/*/"}; - String[] notExcluded = { "thingone", "dir/fish_two"}; - String[] excluded = { "thingtwo", "dir/fish", "red/fish", "blue/fish" }; + String[] notExcluded = {"thingone", "dir/fish_two"}; + String[] excluded = {"thingtwo", "dir/fish", "red/fish", "blue/fish"}; writeFile(".gitignore", Arrays.asList(lines)); @@ -285,10 +287,10 @@ protected void inputExcludeParsedScmTest() { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { - assertFalse(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isFalse(); } for (String fname : notExcluded) { - assertTrue(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -297,22 +299,22 @@ protected void inputExcludeParsedScmTest() { private void inputExcludeSizeTest() { Option option = Arg.EXCLUDE_SIZE.option(); - String[] args = { "5" }; - writeFile("Hi.txt", Arrays.asList("Hi")); - writeFile("Hello.txt", Arrays.asList("Hello")); - writeFile("HelloWorld.txt", Arrays.asList("HelloWorld")); + String[] args = {"5"}; + writeFile("Hi.txt", Collections.singletonList("Hi")); + writeFile("Hello.txt", Collections.singletonList("Hello")); + writeFile("HelloWorld.txt", Collections.singletonList("HelloWorld")); - String[] notExcluded = { "Hello.txt", "HelloWorld.txt"}; - String[] excluded = { "Hi.txt" }; + String[] notExcluded = {"Hello.txt", "HelloWorld.txt"}; + String[] excluded = {"Hi.txt"}; try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { - assertFalse(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isFalse(); } for (String fname : notExcluded) { - assertTrue(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -329,10 +331,10 @@ private void execIncludeTest(Option option, String[] args) { ImmutablePair.of(excludeOption, EXCLUDE_ARGS)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { - assertFalse(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isFalse(); } for (String fname : notExcluded) { - assertTrue(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -341,7 +343,7 @@ private void execIncludeTest(Option option, String[] args) { private void includeFileTest(Option option) { File outputFile = writeFile("include.txt", Arrays.asList(INCLUDE_ARGS)); - execIncludeTest(option, new String[] {outputFile.getPath()}); + execIncludeTest(option, new String[]{outputFile.getPath()}); } protected void inputIncludeFileTest() { @@ -362,19 +364,19 @@ protected void inputIncludeTest() { protected void inputIncludeStdTest() { ImmutablePair excludes = ImmutablePair.of(Arg.EXCLUDE.find("input-exclude"), - new String[] { "*~more", "*~" }); + new String[]{"*~more", "*~"}); Option option = Arg.INCLUDE_STD.find("input-include-std"); - String[] args = { StandardCollection.MISC.name() }; - String[] excluded = { "afile~more" }; - String[] notExcluded = { "afile~", ".#afile", "%afile%", "._afile", "what.#afile", "%afile%withMore", "well._afile" }; + String[] args = {StandardCollection.MISC.name()}; + String[] excluded = {"afile~more"}; + String[] notExcluded = {"afile~", ".#afile", "%afile%", "._afile", "what.#afile", "%afile%withMore", "well._afile"}; try { ReportConfiguration config = generateConfig(excludes, ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { - assertFalse(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isFalse(); } for (String fname : notExcluded) { - assertTrue(excluder.matches(mkDocName(fname)), () -> option.getKey() + " " + fname); + assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -385,7 +387,7 @@ protected void inputSourceTest() { Option option = Arg.SOURCE.find("input-source"); try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, new String[]{baseDir.getAbsolutePath()})); - assertTrue(config.hasSource()); + assertThat(config.hasSource()).isTrue(); } catch (IOException e) { fail(e.getMessage()); } @@ -393,7 +395,7 @@ protected void inputSourceTest() { // LICENSE tests protected void execLicensesApprovedTest(Option option, String[] args) { - Pair arg1 = ImmutablePair.of(option, args); + Pair arg1 = ImmutablePair.of(option, args); try { ReportConfiguration config = generateConfig(arg1); SortedSet result = config.getLicenseIds(LicenseSetFactory.LicenseFilter.APPROVED); @@ -402,13 +404,13 @@ protected void execLicensesApprovedTest(Option option, String[] args) { fail(e.getMessage()); } - Pair arg2 = ImmutablePair.of( + Pair arg2 = ImmutablePair.of( Arg.CONFIGURATION_NO_DEFAULTS.find("configuration-no-defaults"), null ); try { - ReportConfiguration config = generateConfig(arg1, arg2 ); + ReportConfiguration config = generateConfig(arg1, arg2); SortedSet result = config.getLicenseIds(LicenseSetFactory.LicenseFilter.APPROVED); assertThat(result).containsExactly("one", "two"); } catch (IOException e) { @@ -419,7 +421,7 @@ protected void execLicensesApprovedTest(Option option, String[] args) { protected void helpLicenses() { ByteArrayOutputStream output = new ByteArrayOutputStream(); PrintStream origin = System.out; - try (PrintStream out = new PrintStream(output)){ + try (PrintStream out = new PrintStream(output)) { System.setOut(out); generateConfig(ImmutablePair.of(HELP_LICENSES.option(), null)); } catch (IOException e) { @@ -436,12 +438,12 @@ protected void helpLicenses() { protected void licensesApprovedFileTest() { File outputFile = writeFile("licensesApproved.txt", Arrays.asList("one", "two")); execLicensesApprovedTest(Arg.LICENSES_APPROVED_FILE.find("licenses-approved-file"), - new String[] { outputFile.getPath()}); + new String[]{outputFile.getPath()}); } protected void licensesApprovedTest() { execLicensesApprovedTest(Arg.LICENSES_APPROVED.find("licenses-approved"), - new String[] { "one", "two"}); + new String[]{"one", "two"}); } private void execLicensesDeniedTest(Option option, String[] args) { @@ -456,12 +458,12 @@ private void execLicensesDeniedTest(Option option, String[] args) { } protected void licensesDeniedTest() { - execLicensesDeniedTest(Arg.LICENSES_DENIED.find("licenses-denied"), new String[] {"ILLUMOS"}); + execLicensesDeniedTest(Arg.LICENSES_DENIED.find("licenses-denied"), new String[]{"ILLUMOS"}); } protected void licensesDeniedFileTest() { File outputFile = writeFile("licensesDenied.txt", Collections.singletonList("ILLUMOS")); - execLicensesDeniedTest(Arg.LICENSES_DENIED_FILE.find("licenses-denied-file"), new String[] {outputFile.getPath()}); + execLicensesDeniedTest(Arg.LICENSES_DENIED_FILE.find("licenses-denied-file"), new String[]{outputFile.getPath()}); } private void execLicenseFamiliesApprovedTest(Option option, String[] args) { @@ -488,12 +490,12 @@ private void execLicenseFamiliesApprovedTest(Option option, String[] args) { protected void licenseFamiliesApprovedFileTest() { File outputFile = writeFile("familiesApproved.txt", Collections.singletonList("catz")); execLicenseFamiliesApprovedTest(Arg.FAMILIES_APPROVED_FILE.find("license-families-approved-file"), - new String[] { outputFile.getPath() }); + new String[]{outputFile.getPath()}); } protected void licenseFamiliesApprovedTest() { execLicenseFamiliesApprovedTest(Arg.FAMILIES_APPROVED.find("license-families-approved"), - new String[] {"catz"}); + new String[]{"catz"}); } private void execLicenseFamiliesDeniedTest(Option option, String[] args) { @@ -508,15 +510,15 @@ private void execLicenseFamiliesDeniedTest(Option option, String[] args) { } } - protected void licenseFamiliesDeniedFileTest() { + protected void licenseFamiliesDeniedFileTest() { File outputFile = writeFile("familiesDenied.txt", Collections.singletonList("GPL")); execLicenseFamiliesDeniedTest(Arg.FAMILIES_DENIED_FILE.find("license-families-denied-file"), - new String[] { outputFile.getPath() }); + new String[]{outputFile.getPath()}); } protected void licenseFamiliesDeniedTest() { execLicenseFamiliesDeniedTest(Arg.FAMILIES_DENIED.find("license-families-denied"), - new String[] { "GPL" }); + new String[]{"GPL"}); } protected void counterMaxTest() { @@ -525,17 +527,17 @@ protected void counterMaxTest() { try { ReportConfiguration config = generateConfig(ImmutablePair.nullPair()); - assertEquals(0, config.getClaimValidator().getMax(ClaimStatistic.Counter.UNAPPROVED)); + assertThat(config.getClaimValidator().getMax(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(0); args[0] = "Unapproved:-1"; args[1] = "ignored:1"; config = generateConfig(ImmutablePair.of(option, args)); - assertEquals(Integer.MAX_VALUE, config.getClaimValidator().getMax(ClaimStatistic.Counter.UNAPPROVED)); - assertEquals(1, config.getClaimValidator().getMax(ClaimStatistic.Counter.IGNORED)); + assertThat(config.getClaimValidator().getMax(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(Integer.MAX_VALUE); + assertThat(config.getClaimValidator().getMax(ClaimStatistic.Counter.IGNORED)).isEqualTo(1); args[1] = "unapproved:5"; args[0] = "ignored:0"; config = generateConfig(ImmutablePair.of(option, args)); - assertEquals(5, config.getClaimValidator().getMax(ClaimStatistic.Counter.UNAPPROVED)); - assertEquals(0, config.getClaimValidator().getMax(ClaimStatistic.Counter.IGNORED)); + assertThat(config.getClaimValidator().getMax(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(5); + assertThat(config.getClaimValidator().getMax(ClaimStatistic.Counter.IGNORED)).isEqualTo(0); } catch (IOException e) { fail(e.getMessage()); } @@ -547,17 +549,17 @@ protected void counterMinTest() { try { ReportConfiguration config = generateConfig(ImmutablePair.nullPair()); - assertEquals(0, config.getClaimValidator().getMin(ClaimStatistic.Counter.UNAPPROVED)); + assertThat(config.getClaimValidator().getMin(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(0); args[0] = "Unapproved:1"; args[1] = "ignored:1"; config = generateConfig(ImmutablePair.of(option, args)); - assertEquals(1, config.getClaimValidator().getMin(ClaimStatistic.Counter.UNAPPROVED)); - assertEquals(1, config.getClaimValidator().getMin(ClaimStatistic.Counter.IGNORED)); + assertThat(config.getClaimValidator().getMin(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1); + assertThat(config.getClaimValidator().getMin(ClaimStatistic.Counter.IGNORED)).isEqualTo(1); args[1] = "unapproved:5"; args[0] = "ignored:0"; config = generateConfig(ImmutablePair.of(option, args)); - assertEquals(5, config.getClaimValidator().getMin(ClaimStatistic.Counter.UNAPPROVED)); - assertEquals(0, config.getClaimValidator().getMin(ClaimStatistic.Counter.IGNORED)); + assertThat(config.getClaimValidator().getMin(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(5); + assertThat(config.getClaimValidator().getMin(ClaimStatistic.Counter.IGNORED)).isEqualTo(0); } catch (IOException e) { fail(e.getMessage()); } @@ -569,17 +571,17 @@ private void configTest(Option option) { try { ReportConfiguration config = generateConfig(arg1); SortedSet set = config.getLicenses(LicenseSetFactory.LicenseFilter.ALL); - assertTrue(set.size() > 2); - assertTrue(LicenseSetFactory.search("ONE", "ONE", set).isPresent()); - assertTrue(LicenseSetFactory.search("TWO", "TWO", set).isPresent()); + assertThat(set).hasSizeGreaterThan(2); + assertThat(LicenseSetFactory.search("ONE", "ONE", set)).isPresent(); + assertThat(LicenseSetFactory.search("TWO", "TWO", set)).isPresent(); Pair arg2 = ImmutablePair.of(Arg.CONFIGURATION_NO_DEFAULTS.find("configuration-no-defaults"), null); config = generateConfig(arg1, arg2); set = config.getLicenses(LicenseSetFactory.LicenseFilter.ALL); - assertEquals(2, set.size()); - assertTrue(LicenseSetFactory.search("ONE", "ONE", set).isPresent()); - assertTrue(LicenseSetFactory.search("TWO", "TWO", set).isPresent()); + assertThat(set).hasSize(2); + assertThat(LicenseSetFactory.search("ONE", "ONE", set)).isPresent(); + assertThat(LicenseSetFactory.search("TWO", "TWO", set)).isPresent(); } catch (IOException e) { fail(e.getMessage()); } @@ -596,9 +598,9 @@ protected void configTest() { private void noDefaultsTest(Option arg) { try { ReportConfiguration config = generateConfig(ImmutablePair.of(arg, null)); - assertTrue(config.getLicenses(LicenseSetFactory.LicenseFilter.ALL).isEmpty()); + assertThat(config.getLicenses(LicenseSetFactory.LicenseFilter.ALL)).isEmpty(); config = generateConfig(ImmutablePair.nullPair()); - assertFalse(config.getLicenses(LicenseSetFactory.LicenseFilter.ALL).isEmpty()); + assertThat(config.getLicenses(LicenseSetFactory.LicenseFilter.ALL)).isNotEmpty(); } catch (IOException e) { fail(e.getMessage()); } @@ -615,9 +617,9 @@ protected void configurationNoDefaultsTest() { protected void dryRunTest() { try { ReportConfiguration config = generateConfig(ImmutablePair.of(Arg.DRY_RUN.find("dry-run"), null)); - assertTrue(config.isDryRun()); + assertThat(config.isDryRun()).isTrue(); config = generateConfig(ImmutablePair.nullPair()); - assertFalse(config.isDryRun()); + assertThat(config.isDryRun()).isFalse(); } catch (IOException e) { fail(e.getMessage()); } @@ -627,10 +629,10 @@ private void editCopyrightTest(Option option) { try { Pair arg1 = ImmutablePair.of(option, new String[]{"MyCopyright"}); ReportConfiguration config = generateConfig(arg1); - assertNull(config.getCopyrightMessage(), "Copyright without --edit-license should not work"); + assertThat(config.getCopyrightMessage()).as("Copyright without --edit-license should not work").isNull(); Pair arg2 = ImmutablePair.of(Arg.EDIT_ADD.find("edit-license"), null); config = generateConfig(arg1, arg2); - assertEquals("MyCopyright", config.getCopyrightMessage()); + assertThat(config.getCopyrightMessage()).isEqualTo("MyCopyright"); } catch (IOException e) { fail(e.getMessage()); } @@ -647,9 +649,9 @@ protected void editCopyrightTest() { private void editLicenseTest(Option option) { try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, null)); - assertTrue(config.isAddingLicenses()); + assertThat(config.isAddingLicenses()).isTrue(); config = generateConfig(ImmutablePair.nullPair()); - assertFalse(config.isAddingLicenses()); + assertThat(config.isAddingLicenses()).isFalse(); } catch (IOException e) { fail(e.getMessage()); } @@ -658,6 +660,7 @@ private void editLicenseTest(Option option) { protected void addLicenseTest() { editLicenseTest(Arg.EDIT_ADD.find("addLicense")); } + protected void editLicensesTest() { editLicenseTest(Arg.EDIT_ADD.find("edit-license")); } @@ -666,11 +669,11 @@ private void overwriteTest(Option option) { Pair arg1 = ImmutablePair.of(option, null); try { ReportConfiguration config = generateConfig(arg1); - assertFalse(config.isAddingLicensesForced()); + assertThat(config.isAddingLicensesForced()).isFalse(); Pair arg2 = ImmutablePair.of(Arg.EDIT_ADD.find("edit-license"), null); config = generateConfig(arg1, arg2); - assertTrue(config.isAddingLicensesForced()); + assertThat(config.isAddingLicensesForced()).isTrue(); } catch (IOException e) { fail(e.getMessage()); } @@ -693,7 +696,7 @@ protected void logLevelTest() { try { args[0] = level.name(); generateConfig(ImmutablePair.of(option, args)); - assertEquals(level, DefaultLog.getInstance().getLevel()); + assertThat(DefaultLog.getInstance().getLevel()).isEqualTo(level); } catch (IOException e) { fail(e.getMessage()); } @@ -709,7 +712,7 @@ private void archiveTest(Option option) { for (ReportConfiguration.Processing proc : ReportConfiguration.Processing.values()) { args[0] = proc.name(); ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); - assertEquals(proc, config.getArchiveProcessing()); + assertThat(config.getArchiveProcessing()).isEqualTo(proc); } } catch (IOException e) { fail(e.getMessage()); @@ -726,7 +729,7 @@ private void listFamilies(Option option) { try { args[0] = filter.name(); ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); - assertEquals(filter, config.listFamilies()); + assertThat(config.listFamilies()).isEqualTo(filter); } catch (IOException e) { fail(e.getMessage()); } @@ -752,7 +755,7 @@ private void outTest(Option option) { throw new RuntimeException(e); } try (BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(outFile.toPath())))) { - assertEquals("Hello world", reader.readLine()); + assertThat(reader.readLine()).isEqualTo("Hello world"); } catch (IOException e) { throw new RuntimeException(e); } @@ -775,7 +778,7 @@ private void listLicenses(Option option) { try { args[0] = filter.name(); ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); - assertEquals(filter, config.listLicenses()); + assertThat(config.listLicenses()).isEqualTo(filter); } catch (IOException e) { fail(e.getMessage()); } @@ -791,12 +794,12 @@ protected void outputLicensesTest() { } private void standardTest(Option option) { - String[] args = { null}; + String[] args = {null}; try { for (ReportConfiguration.Processing proc : ReportConfiguration.Processing.values()) { args[0] = proc.name(); ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); - assertEquals(proc, config.getStandardProcessing()); + assertThat(config.getStandardProcessing()).isEqualTo(proc); } } catch (IOException e) { fail(e.getMessage()); @@ -815,7 +818,7 @@ private void styleSheetTest(Option option) { OutputStream out = Files.newOutputStream(file.toPath())) { IOUtils.copy(in, out); } catch (IOException e) { - fail("Could not copy MatcherContainerResource.txt: "+e.getMessage()); + fail("Could not copy MatcherContainerResource.txt: " + e.getMessage()); } // run the test String[] args = {null}; @@ -825,11 +828,11 @@ private void styleSheetTest(Option option) { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); try (InputStream expected = StyleSheets.getStyleSheet(sheet).get(); InputStream actual = config.getStyleSheet().get()) { - assertTrue(IOUtils.contentEquals(expected, actual), () -> String.format("'%s' does not match", sheet)); + assertThat(IOUtils.contentEquals(expected, actual)).as(() -> String.format("'%s' does not match", sheet)).isTrue(); } } } catch (IOException e) { - fail(e.getMessage(), e); + fail(e.getMessage()); } } @@ -845,7 +848,7 @@ protected void scanHiddenDirectoriesTest() { try { ReportConfiguration config = generateConfig(ImmutablePair.of(Arg.INCLUDE_STD.find("scan-hidden-directories"), null)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); - assertTrue(excluder.matches(mkDocName(".file")), ".file"); + assertThat(excluder.matches(mkDocName(".file"))).as(".file").isTrue(); } catch (IOException e) { fail(e.getMessage()); } @@ -856,28 +859,28 @@ protected void xmlTest() { ReportConfiguration config = generateConfig(ImmutablePair.of(Arg.OUTPUT_STYLE.find("xml"), null)); try (InputStream expected = StyleSheets.getStyleSheet("xml").get(); InputStream actual = config.getStyleSheet().get()) { - assertTrue(IOUtils.contentEquals(expected, actual), "'xml' does not match"); + assertThat(IOUtils.contentEquals(expected, actual)).as("'xml' does not match").isTrue(); } } catch (IOException e) { fail(e.getMessage()); } } - final public Stream provideArguments(ExtensionContext context) { - List lst = new ArrayList<>(); - List missingTests = new ArrayList<>(); + final public Stream provideArguments(ExtensionContext context) { + List lst = new ArrayList<>(); + List missingTests = new ArrayList<>(); - for (String key : OptionsList.getKeys()) { - OptionCollectionTest.OptionTest test = testMap.get(key); - if (test == null) { - missingTests.add(key); - } else { - lst.add(Arguments.of(key, test)); - } - } - if (!missingTests.isEmpty()) { - System.out.println("The following tests are excluded: '" + String.join( "', '", missingTests ) + "'"); - } - return lst.stream(); + for (String key : OptionsList.getKeys()) { + OptionCollectionTest.OptionTest test = testMap.get(key); + if (test == null) { + missingTests.add(key); + } else { + lst.add(Arguments.of(key, test)); } + } + if (!missingTests.isEmpty()) { + System.out.println("The following tests are excluded: '" + String.join("', '", missingTests) + "'"); + } + return lst.stream(); + } } diff --git a/apache-rat-core/src/test/resources/RAT_355/commandLine.txt b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/commandLine.txt similarity index 100% rename from apache-rat-core/src/test/resources/RAT_355/commandLine.txt rename to apache-rat-core/src/test/resources/GitIgnoreBuilderTest/commandLine.txt diff --git a/apache-rat-core/src/test/resources/RAT_355/expected-message.txt b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/expected-message.txt similarity index 100% rename from apache-rat-core/src/test/resources/RAT_355/expected-message.txt rename to apache-rat-core/src/test/resources/GitIgnoreBuilderTest/expected-message.txt diff --git a/apache-rat-core/src/test/resources/RAT_355/pom.xml b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/pom.xml similarity index 100% rename from apache-rat-core/src/test/resources/RAT_355/pom.xml rename to apache-rat-core/src/test/resources/GitIgnoreBuilderTest/pom.xml diff --git a/apache-rat-core/src/test/resources/RAT_355/src/README.txt b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/README.txt similarity index 100% rename from apache-rat-core/src/test/resources/RAT_355/src/README.txt rename to apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/README.txt diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/dir1.md b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/dir1.md new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/dir1.md @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir2/dir2.txt b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir2/dir2.txt new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir2/dir2.txt @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir3/file3.log b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir3/file3.log new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir3/file3.log @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/invoker.properties b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/invoker.properties similarity index 100% rename from apache-rat-core/src/it/resources/ReportTest/RAT_335/src/invoker.properties rename to apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/invoker.properties diff --git a/apache-rat-core/src/test/resources/RAT_355/verify.groovy b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/verify.groovy similarity index 100% rename from apache-rat-core/src/test/resources/RAT_355/verify.groovy rename to apache-rat-core/src/test/resources/GitIgnoreBuilderTest/verify.groovy diff --git a/apache-rat-core/src/test/resources/RAT_355/src/invoker.properties b/apache-rat-core/src/test/resources/RAT_355/src/invoker.properties deleted file mode 100644 index 6e8c3479e..000000000 --- a/apache-rat-core/src/test/resources/RAT_355/src/invoker.properties +++ /dev/null @@ -1,16 +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. - -invoker.goals = clean apache-rat:check From 058120d42e2338f38a7449dcf45a81a146c8cea6 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Wed, 25 Dec 2024 15:47:10 +0000 Subject: [PATCH 006/123] fixes for. gitignore and other descending processors --- .../ReportTest/RAT_335/verify.groovy | 24 +- .../config/exclusion/ExclusionProcessor.java | 50 +--- .../rat/config/exclusion/MatcherSet.java | 126 ++-------- .../config/exclusion/StandardCollection.java | 9 +- .../fileProcessors/AbstractBuilder.java | 44 ---- .../AbstractFileProcessorBuilder.java | 235 ++++++++++++++++++ .../fileProcessors/BazaarIgnoreBuilder.java | 7 +- .../fileProcessors/CVSIgnoreBuilder.java | 13 +- .../fileProcessors/GitIgnoreBuilder.java | 104 +------- .../fileProcessors/HgIgnoreBuilder.java | 21 +- .../rat/document/DocumentNameMatcher.java | 94 ++++++- .../apache/rat/ReportConfigurationTest.java | 106 ++++---- .../AbstractIgnoreBuilderTest.java | 44 ++++ .../BazaarIgnoreBuilderTest.java | 18 +- .../fileProcessors/CVSIgnoreBuilderTest.java | 15 +- .../fileProcessors/GitIgnoreBuilderTest.java | 77 +++--- .../fileProcessors/HgIgnoreBuilderTest.java | 33 +-- .../rat/document/DocumentNameMatcherTest.java | 95 +++++++ .../rat/test/AbstractOptionsProvider.java | 19 +- 19 files changed, 649 insertions(+), 485 deletions(-) delete mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractBuilder.java create mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java create mode 100644 apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy index 36da7e7d0..3774f283d 100644 --- a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy @@ -125,30 +125,10 @@ assertThat(ignoredFiles).isEmpty() // Document types XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='IGNORED']", - mapOf("count", "6" )) + mapOf("count", "7" )) XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='NOTICE']", mapOf("count", "1" )) XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='STANDARD']", - mapOf("count", "6" )) - -/* -TextUtils.assertPatternInTarget("^ Approved:\\s+8 ", content) -TextUtils.assertPatternInTarget("^ Archives:\\s+1 ", content) -TextUtils.assertPatternInTarget("^ Binaries:\\s+2 ", content) -TextUtils.assertPatternInTarget("^ Document types:\\s+5 ", content) -TextUtils.assertPatternInTarget("^ Ignored:\\s+1 ", content) -TextUtils.assertPatternInTarget("^ License categories:\\s+4 ", content) -TextUtils.assertPatternInTarget("^ License names:\\s+5", content) -TextUtils.assertPatternInTarget("^ Notices:\\s+2 ", content) -TextUtils.assertPatternInTarget("^ Standards:\\s+8 ", content) -TextUtils.assertPatternInTarget("^ Unapproved:\\s+2 ", content) -TextUtils.assertPatternInTarget("^ Unknown:\\s+2 ", content) - -logOutput = new File(args[1]) -log = logOutput.text - -TextUtils.assertPatternNotInTarget("^ERROR:", log) -TextUtils.assertPatternNotInTarget("^WARN:", log) -*/ + mapOf("count", "3" )) 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 b19fde1c7..0f5e18342 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 @@ -25,17 +25,13 @@ import java.util.Set; import java.util.TreeSet; -import java.util.function.Predicate; import java.util.stream.Collectors; -import javax.print.Doc; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.utils.DefaultLog; import org.apache.rat.utils.ExtendedIterator; import static java.lang.String.format; -import static org.apache.rat.document.DocumentNameMatcher.MATCHES_ALL; -import static org.apache.rat.document.DocumentNameMatcher.MATCHES_NONE; /** * Processes the include and exclude patterns and applies the result against a base directory @@ -189,17 +185,16 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { lastMatcherBaseDir = basedir; // add the file processors - final List fileProcessors = extractFileProcessors(basedir); + final List matchers = extractFileProcessors(basedir); final MatcherSet.Builder fromCommandLine = new MatcherSet.Builder(); DocumentName.Builder nameBuilder = DocumentName.builder().setBaseName(basedir); extractPatterns(nameBuilder, fromCommandLine); extractCollectionPatterns(nameBuilder, fromCommandLine); extractCollectionMatchers(fromCommandLine); extractPaths(fromCommandLine); + matchers.add(fromCommandLine.build()); - fileProcessors.add(fromCommandLine.build(basedir)); - - lastMatcher = createMatcher(fileProcessors); + lastMatcher = MatcherSet.merge(matchers).createMatcher(); } return lastMatcher; } @@ -212,9 +207,9 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { private List extractFileProcessors(final DocumentName basedir) { final List fileProcessorList = new ArrayList<>(); for (StandardCollection sc : fileProcessors) { - ExtendedIterator iter = sc.fileProcessorBuilder().map(builder -> builder.build(basedir)); + ExtendedIterator> iter = sc.fileProcessorBuilder().map(builder -> builder.build(basedir)); if (iter.hasNext()) { - iter.forEachRemaining(fileProcessorList::add); + iter.forEachRemaining(fileProcessorList::addAll); } else { DefaultLog.getInstance().debug(String.format("%s does not have a fileProcessor.", sc)); } @@ -305,40 +300,5 @@ private void extractPaths(final MatcherSet.Builder matcherBuilder) { } } - private DocumentNameMatcher createMatcher(List fileProcessors) { - - List includedList = new ArrayList<>(); - List excludedList = new ArrayList<>(); - - for (MatcherSet processor : fileProcessors) { - if (processor.includes().isPresent()) { - includedList.add(processor.includes().get()); - } - if (processor.excludes().isPresent()) { - excludedList.add(processor.excludes().get()); - } - } - - final DocumentNameMatcher included = includedList.isEmpty() ? MATCHES_NONE : DocumentNameMatcher.or(includedList); - final DocumentNameMatcher excluded = excludedList.isEmpty() ? MATCHES_NONE : DocumentNameMatcher.or(excludedList); - if (excluded == MATCHES_NONE) { - return (included == MATCHES_NONE) ? MATCHES_ALL : included; - } else { - if (included == MATCHES_NONE) { - return DocumentNameMatcher.not(excluded); - } - Predicate pred = documentName -> { - if (included.matches(documentName)) { - return true; - } - if (excluded.matches(documentName)) { - return false; - } - return true; - }; - final String name = DocumentNameMatcher.or(included, DocumentNameMatcher.not(excluded)).toString(); - return new DocumentNameMatcher(name, pred); - } - } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java index 73cde5741..d0f8b94e7 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -18,26 +18,21 @@ */ package org.apache.rat.config.exclusion; -import java.io.File; -import java.io.FileFilter; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; -import org.apache.commons.io.filefilter.DirectoryFileFilter; -import org.apache.commons.io.filefilter.NameFileFilter; -import org.apache.commons.lang3.StringUtils; import org.apache.rat.config.exclusion.plexus.MatchPattern; import org.apache.rat.config.exclusion.plexus.MatchPatterns; import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; +import static org.apache.rat.document.DocumentNameMatcher.MATCHES_ALL; +import static org.apache.rat.document.DocumentNameMatcher.MATCHES_NONE; + /** * The file processor reads the file specified in the DocumentName. * It must return a list of fully qualified strings for the {@link MatchPattern} to process. @@ -49,15 +44,29 @@ public interface MatcherSet { Optional includes(); Optional excludes(); + /** + * Creates a DocumentNameMatcher from an iterable of MatcherSets. + * @return A DocumentNameMatcher that processes the matcher sets. + */ + default DocumentNameMatcher createMatcher() { + return DocumentNameMatcher.matcherSet(includes().orElse(MATCHES_NONE), excludes().orElse(MATCHES_NONE)); + } + + static MatcherSet merge(List matcherSets) { + Builder builder = new Builder(); + for (MatcherSet matcherSet : matcherSets) { + matcherSet.includes().ifPresent(builder::addIncluded); + matcherSet.excludes().ifPresent(builder::addExcluded); + } + return builder.build(); + } + /** * A MatcherSet that assumes the files contain the already formatted strings and just need to be * localized for the fileName. */ class Builder { - /** A String format pattern to print a regex string */ - protected static final String REGEX_FMT = "%%regex[%s]"; - /** * Adds to lists of qualified file patterns. Non-matching patterns start with a {@code !}. * @param matching the list to put matching file patterns into. @@ -75,42 +84,12 @@ public static void segregateList(final Set matching, final Set n }); } - /** The name of the file being processed */ - protected final String fileName; - - /** The predicate that will return {@code false} for any comment line in the file. */ - protected final Predicate commentFilter; - + /** the DocumentNameMatcher that specifies included files */ protected DocumentNameMatcher included; - + /** The DocumentNameMatcher that specifies excluded files */ protected DocumentNameMatcher excluded; - Builder() { - fileName = StringUtils.EMPTY; - commentFilter = StringUtils::isNotBlank; - } - - /** - * Constructor. - * @param fileName name of the file to process - * @param commentPrefixes a collection of comment prefixes. - */ - protected Builder(final String fileName, final Iterable commentPrefixes) { - super(); - this.fileName = fileName; - // null prefixes = check prefix may not be blank. - this.commentFilter = commentPrefixes == null ? StringUtils::isNotBlank : ExclusionUtils.commentFilter(commentPrefixes); - } - - /** - * Allows modification of the file entry to match the {@link MatchPattern} format. - * Default implementation returns the @{code entry} argument. - * @param documentName the name of the document that the file was read from. - * @param entry the entry from that document. - * @return the modified string or an empty Optional to skip the string. - */ - protected Optional modifyEntry(final DocumentName documentName, final String entry) { - return Optional.of(entry); + public Builder() { } public Builder addIncluded(DocumentName fromDocument, Set names) { @@ -139,63 +118,7 @@ public Builder addExcluded(DocumentNameMatcher matcher) { return this; } - /** - * Process by reading the file setting the {@link #included} and {@link #excluded} DocumentMatchers. - * @param documentName the file to read. - */ - protected void process(final DocumentName documentName) { - List iterable = new ArrayList<>(); - ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) - .map(entry -> modifyEntry(documentName, entry).orElse(null)) - .filter(Objects::nonNull) - .map(entry -> ExclusionUtils.localizePattern(documentName, entry)) - .forEachRemaining(iterable::add); - segregateProcessResult(documentName, iterable); - } - - /** - * Moves properly formatted file names includes, excludes into the proper - * {@link #included} and {@link #excluded} DocumentMatchers. - * @param documentName the nome of the document being processed. - * @param iterable the list of properly formatted include and excludes from the input. - */ - protected void segregateProcessResult(final DocumentName documentName, List iterable) { - Set included = new HashSet<>(); - Set excluded = new HashSet<>(); - segregateList(included, excluded, iterable); - addExcluded(documentName, excluded); - addIncluded(documentName, included); - } - - /** - * Create a list of files by applying the filter to the specified directory. - * @param dir the directory. - * @param filter the filter. - * @return an array of files. May be empty but will not be null. - */ - protected File[] listFiles(final File dir, final FileFilter filter) { - File[] result = dir.listFiles(filter); - return result == null ? new File[0] : result; - } - - /** - * Process the directory tree looking for files that match the filter. Call {@link #process} on any matching file. - * @param directory The name of the directory to process. - * @param fileFilter the filter to detect processable files with. - */ - protected void checkDirectory(final DocumentName directory, final FileFilter fileFilter) { - File dirFile = new File(directory.getName()); - for (File f : listFiles(dirFile, fileFilter)) { - process(DocumentName.builder(f).setBaseName(directory.getBaseName()).build()); - } - for (File dir : listFiles(dirFile, DirectoryFileFilter.DIRECTORY)) { - checkDirectory(DocumentName.builder(dir).build(), fileFilter); - } - } - - public MatcherSet build(final DocumentName dir) { - checkDirectory(dir, new NameFileFilter(fileName)); - + public MatcherSet build() { MatcherSet result = new MatcherSet() { final DocumentNameMatcher myIncluded = included; final DocumentNameMatcher myExcluded = excluded; @@ -214,6 +137,5 @@ public Optional excludes() { excluded = null; return result; } - } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java index 9d6874c40..46fe649e0 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java @@ -28,6 +28,7 @@ import java.util.Set; import java.util.function.Predicate; +import org.apache.rat.config.exclusion.fileProcessors.AbstractFileProcessorBuilder; import org.apache.rat.config.exclusion.fileProcessors.BazaarIgnoreBuilder; import org.apache.rat.config.exclusion.fileProcessors.CVSIgnoreBuilder; import org.apache.rat.config.exclusion.fileProcessors.GitIgnoreBuilder; @@ -200,12 +201,12 @@ null, new CVSIgnoreBuilder()), /** A document name matcher supplier to create a document name matcher. May be null */ private final DocumentNameMatcher staticDocumentNameMatcher; /** The MatcherSet to process the exclude file associated with this exclusion. May be null. */ - private final MatcherSet.Builder fileProcessorBuilder; + private final AbstractFileProcessorBuilder fileProcessorBuilder; /** The description of this collection */ private final String desc; StandardCollection(final String desc, final Collection patterns, final DocumentNameMatcher documentNameMatcher, - final MatcherSet.Builder fileProcessorBuilder) { + final AbstractFileProcessorBuilder fileProcessorBuilder) { this.desc = desc; this.patterns = patterns == null ? Collections.emptyList() : new HashSet<>(patterns); this.staticDocumentNameMatcher = documentNameMatcher; @@ -263,8 +264,8 @@ public Set patterns() { * * @return the fileProcessor if it exists, {@code null} otherwise. */ - public ExtendedIterator fileProcessorBuilder() { - List lst = new ArrayList<>(); + public ExtendedIterator fileProcessorBuilder() { + List lst = new ArrayList<>(); for (StandardCollection sc : getCollections()) { if (sc.fileProcessorBuilder != null) { lst.add(sc.fileProcessorBuilder); diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractBuilder.java deleted file mode 100644 index 59fcfd06f..000000000 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractBuilder.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.apache.rat.config.exclusion.fileProcessors; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import org.apache.rat.config.exclusion.MatcherSet; -import org.apache.rat.document.DocumentName; - -public class AbstractBuilder extends MatcherSet.Builder { - - /** - * Constructor. - * @param fileName The name of the file to process. - * @param commentPrefix the comment prefix - */ - protected AbstractBuilder(final String fileName, final String commentPrefix) { - this(fileName, commentPrefix == null ? null : Collections.singletonList(commentPrefix)); - } - - /** - * Constructor. - * @param fileName name of the file to process - * @param commentPrefixes a collection of comment prefixes. - */ - protected AbstractBuilder(final String fileName, final Iterable commentPrefixes) { - super(fileName, commentPrefixes); - } - - /** - * Moves properly formatted file names includes, excludes into the proper - * {@link #included} and {@link #excluded} DocumentMatchers. This differs from the parent implementation - * in that patterns that match the process are excluded. - * @param documentName the nome of the document being processed. - * @param iterable the list of properly formatted include and excludes from the input. - */ - protected void segregateProcessResult(final DocumentName documentName, List iterable) { - Set included = new HashSet<>(); - Set excluded = new HashSet<>(); - segregateList(excluded, included, iterable); - addExcluded(documentName, excluded); - addIncluded(documentName, included); - } -} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java new file mode 100644 index 000000000..b3e703aa6 --- /dev/null +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java @@ -0,0 +1,235 @@ +/* + * 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.config.exclusion.fileProcessors; + +import java.io.File; +import java.io.FileFilter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import org.apache.commons.io.filefilter.DirectoryFileFilter; +import org.apache.commons.io.filefilter.NameFileFilter; +import org.apache.commons.lang3.StringUtils; +import org.apache.rat.config.exclusion.ExclusionUtils; +import org.apache.rat.config.exclusion.MatcherSet; +import org.apache.rat.config.exclusion.plexus.MatchPattern; +import org.apache.rat.config.exclusion.plexus.MatchPatterns; +import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; + +/** + * // create a list of levels that a list of processors at that level. + * // will return a custom matcher that from an overridden MatcherSet.customDocumentNameMatchers method + * // build LevelMatcher as a system that returns Include, Exclude or no status for each check. + * // put the level matcher in an array with other level matchers at the specific level below the root + * // When searching start at the lowest level and work up the tree. + */ +public abstract class AbstractFileProcessorBuilder { + /** A String format pattern to print a regex string */ + protected static final String REGEX_FMT = "%%regex[%s]"; + + /** The name of the file being processed */ + protected final String fileName; + + /** The predicate that will return {@code false} for any comment line in the file. */ + protected final Predicate commentFilter; + + private final SortedMap levelBuilders; + + private final boolean includeProcessorFile; + + /** + * Constructor for multiple comment prefixes. + * @param fileName The name of the file being read. + * @param commentPrefixes the collection of comment prefixes. + */ + protected AbstractFileProcessorBuilder(final String fileName, final Iterable commentPrefixes, final boolean includeProcessorFile) { + this(fileName, commentPrefixes == null ? StringUtils::isNotBlank : ExclusionUtils.commentFilter(commentPrefixes), includeProcessorFile); + } + + /** + * Constructor for single comment prefix + * @param fileName The name of the file to process. + * @param commentPrefix the comment prefix + */ + protected AbstractFileProcessorBuilder(final String fileName, final String commentPrefix, final boolean includeProcessorFile) { + this(fileName, commentPrefix == null ? null : Collections.singletonList(commentPrefix), includeProcessorFile); + } + + /** + * Constructor for single comment prefix + * @param fileName The name of the file to process. + * @param commentFilter the comment prefix filter. + */ + protected AbstractFileProcessorBuilder(final String fileName, final Predicate commentFilter, final boolean includeProcessorFile) { + this.levelBuilders = new TreeMap<>(); + this.fileName = fileName; + this.commentFilter = commentFilter; + this.includeProcessorFile = includeProcessorFile; + } + + private List createMatcherSetList(DocumentName dir) { + List keys = new ArrayList<>(levelBuilders.keySet()); + keys.sort((a, b) -> -1 * Integer.compare(a, b)); + return keys.stream().map( key -> levelBuilders.get(key).asMatcherSet(dir)).collect(Collectors.toList()); + } + + public final List build(final DocumentName dir) { + if (includeProcessorFile) { + String name = String.format("**/%s", fileName); + String pattern = ExclusionUtils.localizePattern(dir, name); + MatcherSet matcherSet = new MatcherSet.Builder() + .addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(Collections.singletonList(pattern)), dir)) + .build(); + LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(0, LevelBuilder::new); + levelBuilder.add(matcherSet); + } + + checkDirectory(0, dir, new NameFileFilter(fileName)); + + List result = null; + if (levelBuilders.size() == 1) { + result = Collections.singletonList(levelBuilders.get(0).asMatcherSet(dir)); + } else { + result = createMatcherSetList(dir); + } + levelBuilders.clear(); + return result; + } + + /** + * Process by reading the file, creating a MatcherSet, and adding it to the + * matcherSets. + * @param documentName the file to read. + */ + protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName dirBasedName, final DocumentName documentName) { + final MatcherSet.Builder matcherSetBuilder = new MatcherSet.Builder(); + final List iterable = new ArrayList<>(); + ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) + .map(entry -> modifyEntry(matcherSetConsumer, documentName, entry).orElse(null)) + .filter(Objects::nonNull) + .map(entry -> ExclusionUtils.localizePattern(documentName, entry)) + .forEachRemaining(iterable::add); + + Set included = new HashSet<>(); + Set excluded = new HashSet<>(); + MatcherSet.Builder.segregateList(excluded, included, iterable); + matcherSetBuilder.addExcluded(dirBasedName, excluded); + matcherSetBuilder.addIncluded(dirBasedName, included); + return matcherSetBuilder.build(); + } + + /** + * Process the directory tree looking for files that match the filter. Call {@link #process} on any matching file. + * @param directory The name of the directory to process. + * @param fileFilter the filter to detect processable files with. + */ + private void checkDirectory(final int level, final DocumentName directory, final FileFilter fileFilter) { + File dirFile = new File(directory.getName()); + for (File f : listFiles(dirFile, fileFilter)) { + LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(level, LevelBuilder::new); + DocumentName dirBasedName = DocumentName.builder(f).setBaseName(directory.getBaseName()).build(); + levelBuilder.add(process(levelBuilder::add, dirBasedName, DocumentName.builder(f).setBaseName(directory.getName()).build())); + } + for (File dir : listFiles(dirFile, DirectoryFileFilter.DIRECTORY)) { + checkDirectory(level + 1, DocumentName.builder(dir).setBaseName(directory.getBaseName()).build(), fileFilter); + } + } + + /** + * Allows modification of the file entry to match the {@link MatchPattern} format. + * Default implementation returns the @{code entry} argument. + * @param documentName the name of the document that the file was read from. + * @param entry the entry from that document. + * @return the modified string or an empty Optional to skip the string. + */ + protected Optional modifyEntry(final Consumer matcherSetConsumer, final DocumentName documentName, final String entry) { + return Optional.of(entry); + } + + /** + * Create a list of files by applying the filter to the specified directory. + * @param dir the directory. + * @param filter the filter. + * @return an array of files. May be empty but will not be null. + */ + protected File[] listFiles(final File dir, final FileFilter filter) { + File[] result = dir.listFiles(filter); + return result == null ? new File[0] : result; + } + + protected static class FileProcessorPredicate implements Predicate { + private final Collection matcherSets; + FileProcessorPredicate(Collection matcherSets) { + this.matcherSets = matcherSets; + } + + public Collection getMatcherSets() { + return matcherSets; + } + + @Override + public boolean test(DocumentName documentName) { + for (MatcherSet matcherSet : matcherSets) { + if (matcherSet.includes().orElse(DocumentNameMatcher.MATCHES_NONE).matches(documentName)) { + return true; + } + if (matcherSet.excludes().orElse(DocumentNameMatcher.MATCHES_NONE).matches(documentName)) { + return false; + } + } + return true; + } + } + + static class LevelBuilder { + /** + * The list of MatcherSets that this builder produced. + */ + private final MatcherSet.Builder builder; + + public LevelBuilder(Integer integer) { + int level = integer; + builder = new MatcherSet.Builder(); + } + + public void add(MatcherSet matcherSet) { + if (matcherSet.includes().isPresent()) { + builder.addIncluded(matcherSet.includes().get()); + } + if (matcherSet.excludes().isPresent()) { + builder.addExcluded(matcherSet.excludes().get()); + } + } + + public MatcherSet asMatcherSet(DocumentName dir) { + return builder.build(); + } + } +} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java index a8b65c960..787564d35 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java @@ -19,6 +19,7 @@ package org.apache.rat.config.exclusion.fileProcessors; import java.util.Optional; +import java.util.function.Consumer; import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; @@ -27,16 +28,16 @@ /** * A processor for {@code .bzrignore} files. */ -public final class BazaarIgnoreBuilder extends AbstractBuilder { +public final class BazaarIgnoreBuilder extends AbstractFileProcessorBuilder { /** * Constructor. */ public BazaarIgnoreBuilder() { - super(".bzrignore", "#"); + super(".bzrignore", "#", true); } @Override - public Optional modifyEntry(final DocumentName baseName, final String entry) { + public Optional modifyEntry(final Consumer matcherSetConsumer, final DocumentName baseName, final String entry) { if (entry.startsWith("RE:")) { String line = entry.substring("RE:".length()).trim(); String pattern = line.startsWith("^") ? line.substring(1) : line; diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java index 3aae5765e..69e6aba3a 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java @@ -23,6 +23,7 @@ import java.util.Iterator; import java.util.Set; +import java.util.function.Consumer; import org.apache.commons.lang3.StringUtils; import org.apache.rat.config.exclusion.ExclusionUtils; import org.apache.rat.config.exclusion.MatcherSet; @@ -30,17 +31,21 @@ /** * A file processor for the {@code .csvignore} file. + * @see Ignoring files via cvsignore + *

    + * The patterns found in .cvsignore are only valid for the directory that contains them, not for any sub-directories. + *

    */ -public class CVSIgnoreBuilder extends AbstractBuilder { +public class CVSIgnoreBuilder extends AbstractFileProcessorBuilder { /** * The constructor. */ public CVSIgnoreBuilder() { - super(".cvsignore", (String) null); + super(".cvsignore", (String) null, true); } @Override - protected void process(final DocumentName documentName) { + protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName dirBasedName, final DocumentName documentName) { final File dir = new File(documentName.getName()); Set result = new HashSet<>(); Iterator iter = ExclusionUtils.asIterator(dir, StringUtils::isNotBlank); @@ -53,6 +58,6 @@ protected void process(final DocumentName documentName) { } } } - addExcluded(documentName, result); + return new MatcherSet.Builder().addExcluded(documentName, result).build(); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java index 0c931d796..af5545e67 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java @@ -20,15 +20,8 @@ import java.io.File; -import java.io.FileFilter; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; import java.util.Optional; -import java.util.SortedMap; -import java.util.TreeMap; import java.util.function.Consumer; -import org.apache.commons.io.filefilter.DirectoryFileFilter; import org.apache.rat.config.exclusion.ExclusionUtils; import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.config.exclusion.plexus.MatchPatterns; @@ -41,78 +34,18 @@ * Processes the .gitignore file. * @see .gitignore documentation */ -public class GitIgnoreBuilder extends AbstractBuilder { - // create a list of levels that a list of processors at that level. - // will return a custom matcher that from an overridden MatcherSet.customDocumentNameMatchers method - // build LevelMatcher as a system that returns Include, Exclude or no status for each check. - // put the level matcher in an array with other level matchers at the specific level below the root - // When searching start at the lowest level and work up the tree. - +public class GitIgnoreBuilder extends AbstractFileProcessorBuilder { private static final String IGNORE_FILE = ".gitignore"; private static final String COMMENT_PREFIX = "#"; private static final String ESCAPED_COMMENT = "\\#"; private static final String ESCAPED_NEGATION = "\\!"; private static final String SLASH = "/"; - private SortedMap levelBuilders = new TreeMap<>(); - - /** * Constructs a file processor that processes a .gitignore file and ignores any lines starting with "#". */ public GitIgnoreBuilder() { - super(IGNORE_FILE, COMMENT_PREFIX); - } - - /** - * Process the directory tree looking for files that match the filter. Process any matching file and return - * a list of fully qualified patterns. - * @param directory The name of the directory to process. - * @param fileFilter the filter to detect processable files with. - * @return the list of fully qualified file patterns. - */ - protected void checkDirectory(final DocumentName directory, final FileFilter fileFilter) { - checkDirectory(0, directory, fileFilter); - List keys = new ArrayList<>(levelBuilders.keySet()); - keys.sort( (a, b) -> -1 * a.compareTo(b)); - for (int level : keys) { - LevelBuilder levelBuilder = levelBuilders.get(level); - MatcherSet fileProcessor = levelBuilder.build(directory); - fileProcessor.excludes().ifPresent(this::addExcluded); - fileProcessor.includes().ifPresent(this::addIncluded); - } - } - - private void checkDirectory(final int level, final DocumentName directory, final FileFilter fileFilter) { - File dirFile = new File(directory.getName()); - for (File f : listFiles(dirFile, fileFilter)) { - LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(level, LevelBuilder::new); - DocumentName dirBasedName = DocumentName.builder(f).setBaseName(directory.getBaseName()).build(); - levelBuilder.process(dirBasedName, DocumentName.builder(f).setBaseName(directory.getName()).build()); - } - for (File dir : listFiles(dirFile, DirectoryFileFilter.DIRECTORY)) { - checkDirectory(level + 1, DocumentName.builder(dir).setBaseName(directory.getBaseName()).build(), fileFilter); - } - } - /** - * package private for testing. - * @return the included DocumentNameMatcher. - */ - DocumentNameMatcher getIncluded() { - return included; - } - - /** - * package private for testing. - * @return the excluded DocumentNameMatcher. - */ - DocumentNameMatcher getExcluded() { - return excluded; - } - - @Override - public Optional modifyEntry(final DocumentName documentName, final String entry) { - return modifyEntry(documentName, entry, this::addIncluded, this::addExcluded); + super(IGNORE_FILE, COMMENT_PREFIX, true); } /** @@ -123,12 +56,10 @@ public Optional modifyEntry(final DocumentName documentName, final Strin * the entry is placed in the exclude list and the name of the check returned. * @param documentName The name of the document being processed. * @param entry The entry from the document - * @param include A consumer to accept the included DocumentNameMatchers. - * @param exclude A consumer to accept the excluded DocumentNameMatchers. * @return and Optional containing the name of the matcher. */ - private static Optional modifyEntry(final DocumentName documentName, final String entry, Consumer include, - Consumer exclude) { + @Override + protected Optional modifyEntry(final Consumer matcherSetConsumer, final DocumentName documentName, final String entry) { // An optional prefix "!" which negates the pattern; boolean prefix = entry.startsWith(NEGATION_PREFIX); String pattern = prefix || entry.startsWith(ESCAPED_COMMENT) || entry.startsWith(ESCAPED_NEGATION) ? @@ -154,33 +85,16 @@ private static Optional modifyEntry(final DocumentName documentName, fin .build(); DocumentNameMatcher matcher = DocumentNameMatcher.and(new DocumentNameMatcher("isDirectory", File::isDirectory), new DocumentNameMatcher(name, MatchPatterns.from(matcherPattern.localized(SLASH)))); + + MatcherSet.Builder builder = new MatcherSet.Builder(); if (prefix) { - exclude.accept(matcher); + builder.addIncluded(matcher); } else { - include.accept(matcher); + builder.addExcluded(matcher); } + matcherSetConsumer.accept(builder.build()); return Optional.empty(); } return Optional.of(prefix ? NEGATION_PREFIX + pattern : pattern); } - - private static class LevelBuilder extends AbstractBuilder { - LevelBuilder(int level) { - super(IGNORE_FILE+"-"+level, COMMENT_PREFIX); - } - - public Optional modifyEntry(final DocumentName documentName, final String entry) { - return GitIgnoreBuilder.modifyEntry(documentName, entry, this::addIncluded, this::addExcluded); - } - - public void process(DocumentName directory, DocumentName documentName) { - List iterable = new ArrayList<>(); - ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) - .map(entry -> modifyEntry(documentName, entry).orElse(null)) - .filter(Objects::nonNull) - .map(entry -> ExclusionUtils.localizePattern(documentName, entry)) - .forEachRemaining(iterable::add); - segregateProcessResult(directory, iterable); - } - } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java index 86e8253c0..ca8ca1344 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java @@ -20,6 +20,7 @@ import java.util.Locale; import java.util.Optional; +import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -30,8 +31,10 @@ /** * A processor for the {@code .hgignore} files. + * @see Mecurial how to ignore files + * @see syntax for Mercurial ignore files */ -public final class HgIgnoreBuilder extends AbstractBuilder { +public final class HgIgnoreBuilder extends AbstractFileProcessorBuilder { /** * The state enumeration for the processor. When processing the file the processor changes * syntax state depending on the input. @@ -52,26 +55,34 @@ enum Syntax { * Constructs the .hgignore processor. */ public HgIgnoreBuilder() { - super(".hgignore", "#"); + super(".hgignore", "#", true); state = Syntax.REGEXP; } @Override - protected void process(final DocumentName baseName) { + protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName dirBasedName, final DocumentName documentName) { state = Syntax.REGEXP; - super.process(baseName); + return super.process(matcherSetConsumer, dirBasedName, documentName); } @Override - public Optional modifyEntry(final DocumentName baseName, final String entry) { + public Optional modifyEntry(final Consumer matcherSetConsumer, final DocumentName documentName, final String entry) { Matcher m = SYNTAX_CHECK.matcher(entry.toLowerCase(Locale.ROOT)); if (m.matches()) { state = Syntax.valueOf(m.group(1).toUpperCase()); return Optional.empty(); } + /* + Neither glob nor regexp patterns are rooted. A glob-syntax pattern of the form *.c will match a file ending in .c + in any directory, and a regexp pattern of the form \.c$ will do the same. To root a regexp pattern, start it with ^. + */ if (state == Syntax.REGEXP) { String pattern = entry.startsWith("^") ? entry.substring(1) : ".*" + entry; return Optional.of(format(REGEX_FMT, pattern)); + } else { + if (entry.startsWith("*")) { + return Optional.of("**/"+entry); + } } return Optional.of(entry); } diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index b0620b237..5ce63d587 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; @@ -134,6 +135,13 @@ public boolean isCollection() { return isCollection; } + /** + * Returns the predicate that this DocumentNameMatcher is using. + * @return The predicate that this DocumentNameMatcher is using. + */ + public Predicate getPredicate() { + return predicate; + } @Override public String toString() { return name; @@ -205,7 +213,7 @@ public static DocumentNameMatcher or(final Collection match for (DocumentNameMatcher matcher : matchers) { // check for nested or if (matcher.predicate instanceof Or) { - ((Or)matcher.predicate).matchers.forEach(workingSet::add); + ((Or)matcher.predicate).getMatchers().forEach(workingSet::add); } else { workingSet.add(matcher); } @@ -239,7 +247,7 @@ public static DocumentNameMatcher and(final Collection matc for (DocumentNameMatcher matcher : matchers) { // check for nexted And if (matcher.predicate instanceof And) { - ((And)matcher.predicate).matchers.forEach(workingSet::add); + ((And)matcher.predicate).getMatchers().forEach(workingSet::add); } else { workingSet.add(matcher); } @@ -248,6 +256,28 @@ public static DocumentNameMatcher and(final Collection matc return opt.orElseGet(() -> new DocumentNameMatcher(format("and(%s)", join(workingSet)), new And(workingSet))); } + /** + * A particular matcher that will not match any excluded unless they are listed in the includes. + * @param includes the DocumentNameMatcher to match the includes. + * @param excludes the DocumentNameMatcher to match the excludes. + * @return a DocumentNameMatcher with the specified logic. + */ + public static DocumentNameMatcher matcherSet(final DocumentNameMatcher includes, + final DocumentNameMatcher excludes) { + if (excludes == MATCHES_NONE) { + return MATCHES_ALL; + } else { + if (includes == MATCHES_NONE) { + return not(excludes); + } + } + if (includes == MATCHES_ALL) { + return MATCHES_ALL; + } + List workingSet = Arrays.asList(includes, excludes); + return new DocumentNameMatcher(format("matcherSet(%s)", join(workingSet)), new MatcherPredicate(workingSet)); + } + /** * Performs a logical {@code AND} across the collection of matchers. * @param matchers the matchers to check. @@ -260,19 +290,32 @@ public static DocumentNameMatcher and(final DocumentNameMatcher... matchers) { /** * A marker interface to indicate this predicate contains a collection of matchers. */ - private interface CollectionPredicate extends Predicate{} + // package private for testing access + abstract static class CollectionPredicate implements Predicate { + // package private for testing acess. + private final Iterable matchers; - private static class And implements CollectionPredicate { + protected CollectionPredicate(Iterable matchers) { + this.matchers = matchers; + } - private final Iterable matchers; + public Iterable getMatchers() { + return matchers; + } + } + /** + * An implementation of "and" logic across a collection of DocumentNameMatchers. + */ + // package private for testing access + static class And extends CollectionPredicate { And(final Iterable matchers) { - this.matchers = matchers; + super(matchers); } @Override public boolean test(DocumentName documentName) { - for (DocumentNameMatcher matcher : matchers) { + for (DocumentNameMatcher matcher : getMatchers()) { if (!matcher.matches(documentName)) { return false; } @@ -281,17 +324,18 @@ public boolean test(DocumentName documentName) { } } - private static class Or implements CollectionPredicate { - - private final Iterable matchers; - + /** + * An implementation of "or" logic across a collection of DocumentNameMatchers. + */ + // package private for testing access + static class Or extends CollectionPredicate { Or(final Iterable matchers) { - this.matchers = matchers; + super(matchers); } @Override public boolean test(DocumentName documentName) { - for (DocumentNameMatcher matcher : matchers) { + for (DocumentNameMatcher matcher : getMatchers()) { if (matcher.matches(documentName)) { return true; } @@ -299,4 +343,28 @@ public boolean test(DocumentName documentName) { return false; } } + + /** + * An implementation of "or" logic across a collection of DocumentNameMatchers. + */ + // package private for testing access + static class MatcherPredicate extends CollectionPredicate { + MatcherPredicate(final Iterable matchers) { + super(matchers); + } + + @Override + public boolean test(final DocumentName documentName) { + Iterator iter = getMatchers().iterator(); + // included + if (iter.next().matches(documentName)) { + return true; + } + // excluded + if (iter.next().matches(documentName)) { + return false; + } + return true; + } + } } 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 11a8ce013..581d474b5 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 @@ -19,10 +19,7 @@ package org.apache.rat; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -91,11 +88,13 @@ public void cleanup() { public void testAddIncludedFilter() { DocumentName dirName = DocumentName.builder(tempDir).build(); underTest.addExcludedFilter(DirectoryFileFilter.INSTANCE); - DocumentNameMatcher exlcuder = underTest.getDocumentExcluder(dirName); - assertEquals("not(DirectoryFileFilter)", exlcuder.toString()); - assertFalse(exlcuder.matches(DocumentName.builder(tempDir).build())); + DocumentNameMatcher matcher = underTest.getDocumentExcluder(dirName); + + assertThat(matcher.toString()).isEqualTo("not(DirectoryFileFilter)"); + assertThat(matcher.matches(DocumentName.builder(tempDir).build())).isFalse(); + File f = new File(tempDir, "foo.txt"); - assertTrue(exlcuder.matches(DocumentName.builder(f).build())); + assertThat(exlcuder.matches(DocumentName.builder(f).build())).isTrue(); } @Test @@ -104,17 +103,16 @@ public void testAddFamilies() { ILicenseFamily fam2 = ILicenseFamily.builder().setLicenseFamilyCategory("BAR").setLicenseFamilyName("big and round").build(); underTest.addFamilies(Arrays.asList(fam1, fam2)); SortedSet result = underTest.getLicenseIds(LicenseFilter.ALL); - assertTrue(result.contains(ILicenseFamily.makeCategory("FOO")), "Missing FOO"); - assertTrue(result.contains(ILicenseFamily.makeCategory("BAR")), "Missing BAR"); - assertEquals(2, result.size()); + assertThat(result).contains(ILicenseFamily.makeCategory("FOO")); + assertThat(result).contains(ILicenseFamily.makeCategory("BAR")); + assertThat(result).hasSize(2); } @Test public void testAddApprovedLicenseId() { underTest.addApprovedLicenseId("FOO"); SortedSet result = underTest.getLicenseIds(LicenseFilter.APPROVED); - assertTrue(result.contains("FOO")); - assertEquals(1, result.size()); + assertThat(result).hasSize(1).contains("FOO"); } @Test public void testAddAndRemoveApproveLicenseCategories() { @@ -367,27 +365,28 @@ DocumentName mkDocumentName(File f) { @Test public void exclusionTest() { DocumentName baseDir = DocumentName.builder(tempDir).build(); - assertTrue(underTest.getDocumentExcluder(baseDir).matches(mkDocumentName(new File(tempDir,"foo")))); - assertTrue(underTest.getDocumentExcluder(baseDir).matches(mkDocumentName(new File("foo")))); + DocumentName foo = mkDocumentName(new File(tempDir,"foo")); + assertThat(underTest.getDocumentExcluder(baseDir).matches(foo)).isTrue(); underTest.setFrom(Defaults.builder().build()); File f = new File(tempDir, ".hiddenDir"); - assertTrue(f.mkdir(), () -> "Could not create directory " + f); - - assertFalse(underTest.getDocumentExcluder(baseDir).matches(mkDocumentName(new File(tempDir, ".hiddenDir")))); + assertThat(f.mkdir()).as(() -> "Could not create directory " + f).isTrue(); + DocumentName hiddenDir = mkDocumentName(new File(tempDir, ".hiddenDir")); + DocumentNameMatcher excluder = underTest.getDocumentExcluder(baseDir); + assertThat(excluder.matches(hiddenDir)).isFalse(); underTest.addIncludedCollection(StandardCollection.HIDDEN_DIR); - assertTrue(underTest.getDocumentExcluder(baseDir).matches(mkDocumentName(new File(tempDir, ".hiddenDir")))); + assertThat(underTest.getDocumentExcluder(baseDir).matches(hiddenDir)).isTrue(); underTest.addExcludedCollection(StandardCollection.HIDDEN_DIR); - assertTrue(underTest.getDocumentExcluder(baseDir).matches(mkDocumentName(new File(tempDir, ".hiddenDir")))); + assertThat(underTest.getDocumentExcluder(baseDir).matches(hiddenDir)).isTrue(); underTest.addExcludedFilter(DirectoryFileFilter.DIRECTORY); File file = new File(tempDir, "newDir"); - assertTrue(file.mkdirs(), () -> "Could not create directory " + file); - assertFalse(underTest.getDocumentExcluder(baseDir).matches(mkDocumentName(file))); + assertThat(file.mkdirs()).as(() -> "Could not create directory " + file).isTrue(); + assertThat(underTest.getDocumentExcluder(baseDir).matches(mkDocumentName(file))).isFalse(); } @Test @@ -472,8 +471,8 @@ public void reportableTest() { IReportable reportable = mock(IReportable.class); underTest.addSource(reportable); assertThat(underTest.hasSource()).isTrue(); - Exception thrown = assertThrows(ConfigurationException.class, () -> underTest.addSource((IReportable)null)); - assertThat(thrown.getMessage()).contains("Reportable may not be null."); + assertThatThrownBy(() -> underTest.addSource((IReportable)null)).isExactlyInstanceOf(ConfigurationException.class) + .hasMessageContaining("Reportable may not be null."); } @Test @@ -518,18 +517,17 @@ public void testFlags() { public void testValidate() { final StringBuilder sb = new StringBuilder(); String msg = "At least one source must be specified"; - Exception thrown = assertThrows(ConfigurationException.class, - () -> underTest.validate(sb::append)); - assertThat(thrown.getMessage()).isEqualTo(msg); + assertThatThrownBy(() -> underTest.validate(sb::append)).isExactlyInstanceOf(ConfigurationException.class) + .hasMessageContaining(msg); assertThat(sb.toString()).isEqualTo(msg); sb.setLength(0); msg = "You must specify at least one license"; underTest.addSource(mock(IReportable.class)); - thrown = assertThrows(ConfigurationException.class, - () -> underTest.validate(sb::append)); - assertThat(thrown.getMessage()).isEqualTo(msg); + + assertThatThrownBy(() -> underTest.validate(sb::append)).isExactlyInstanceOf(ConfigurationException.class) + .hasMessageContaining(msg); assertThat(sb.toString()).isEqualTo(msg); sb.setLength(0); @@ -559,45 +557,48 @@ public void testSetOut() throws IOException { public void logFamilyCollisionTest() { // setup underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name")); - assertFalse(log.getCaptured().contains("CAT")); + assertThat(log.getCaptured()).doesNotContain("CAT"); // verify default collision logs WARNING underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name2")); - assertTrue(log.getCaptured().contains("WARN"), "default value not WARN"); - assertTrue(log.getCaptured().contains("CAT"), "'CAT' not found"); + assertThat(log.getCaptured().contains("WARN")).as("default value not WARN").isTrue(); + assertThat(log.getCaptured().contains("CAT")).as("'CAT' not found").isTrue(); // verify level setting works. for (Level l : Level.values()) { log.clear(); underTest.logFamilyCollisions(l); underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name2")); - assertTrue(log.getCaptured().contains("CAT"), "'CAT' not found"); - assertTrue(log.getCaptured().contains(l.name()), "logging not set to "+l); + assertThat(log.getCaptured().contains("CAT")).as("'CAT' not found").isTrue(); + assertThat(log.getCaptured().contains(l.name())).as("logging not set to "+l).isTrue(); } } @Test public void familyDuplicateOptionsTest() { underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name")); - assertFalse(log.getCaptured().contains("CAT")); + assertThat(log.getCaptured()).doesNotContain("CAT"); // verify default second setting ignores change underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name2")); - assertTrue(log.getCaptured().contains("CAT")); - assertEquals("name", underTest.getLicenseFamilies(LicenseFilter.ALL).stream() - .filter(s -> s.getFamilyCategory().equals("CAT ")).map(ILicenseFamily::getFamilyName).findFirst().get()); + assertThat(log.getCaptured()).contains("CAT"); + assertThat(underTest.getLicenseFamilies(LicenseFilter.ALL).stream() + .filter(s -> s.getFamilyCategory().equals("CAT ")).map(ILicenseFamily::getFamilyName).findFirst()) + .contains("name"); underTest.familyDuplicateOption(Options.OVERWRITE); // verify second setting ignores change underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name2")); - assertTrue(log.getCaptured().contains("CAT")); - assertEquals("name2", underTest.getLicenseFamilies(LicenseFilter.ALL).stream() - .filter(s -> s.getFamilyCategory().equals("CAT ")).map(ILicenseFamily::getFamilyName).findFirst().get()); + assertThat(log.getCaptured()).contains("CAT"); + assertThat(underTest.getLicenseFamilies(LicenseFilter.ALL).stream() + .filter(s -> s.getFamilyCategory().equals("CAT ")).map(ILicenseFamily::getFamilyName).findFirst()) + .contains("name2"); // verify fail throws exception underTest.familyDuplicateOption(Options.FAIL); - assertThrows( IllegalArgumentException.class, ()->underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name2"))); - + assertThatThrownBy(()->underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name2"))) + .isExactlyInstanceOf(IllegalArgumentException.class); + underTest.familyDuplicateOption(Options.IGNORE); } @@ -617,7 +618,7 @@ public void logLicenseCollisionTest() { underTest.addLicense(ILicense.builder().setId("ID").setName("license name2").setFamily(family.getFamilyCategory()) .setMatcher( matcher ).setLicenseFamilies(underTest.getLicenseFamilies(LicenseFilter.ALL)) .build()); - assertTrue(log.getCaptured().contains("WARN")); + assertThat(log.getCaptured()).contains("WARN"); log.clear(); underTest.logLicenseCollisions(Level.ERROR); @@ -626,7 +627,7 @@ public void logLicenseCollisionTest() { underTest.addLicense(ILicense.builder().setId("ID").setName("license name2").setFamily(family.getFamilyCategory()) .setMatcher( matcher ).setLicenseFamilies(underTest.getLicenseFamilies(LicenseFilter.ALL)) .build()); - assertTrue(log.getCaptured().contains("ERROR")); + assertThat(log.getCaptured()).contains("ERROR"); } @Test @@ -644,18 +645,19 @@ public void licenseDuplicateOptionsTest() { // verify default second setting ignores change underTest.addLicense(makeLicense.apply("license name2")); - assertTrue(log.getCaptured().contains("WARN")); - assertEquals("license name", - underTest.getLicenses(LicenseFilter.ALL).stream().map(ILicense::getName).findFirst().get()); + assertThat(log.getCaptured()).contains("WARN"); + assertThat(underTest.getLicenses(LicenseFilter.ALL).stream().map(ILicense::getName).findFirst()) + .contains("license name"); underTest.licenseDuplicateOption(Options.OVERWRITE); underTest.addLicense(makeLicense.apply("license name2")); - assertEquals("license name2", - underTest.getLicenses(LicenseFilter.ALL).stream().map(ILicense::getName).findFirst().get()); + assertThat(underTest.getLicenses(LicenseFilter.ALL).stream().map(ILicense::getName).findFirst()) + .contains("license name2"); // verify fail throws exception underTest.licenseDuplicateOption(Options.FAIL); - assertThrows( IllegalArgumentException.class, ()-> underTest.addLicense(makeLicense.apply("another name"))); + assertThatThrownBy(()-> underTest.addLicense(makeLicense.apply("another name"))) + .isExactlyInstanceOf(IllegalArgumentException.class); } /** diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java index 9a9e3898c..44338358c 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java @@ -18,7 +18,10 @@ */ package org.apache.rat.config.exclusion.fileProcessors; +import java.util.List; +import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.condition.EnabledOnOs; @@ -30,6 +33,12 @@ import java.io.IOException; import java.io.PrintWriter; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * The base class for FileProcessor builder tests. + * Provides supporting methods for creating test files and for validating results. + */ public class AbstractIgnoreBuilderTest { @TempDir @@ -51,6 +60,13 @@ void cleanUp() { System.gc(); } + /** + * Writes a text file to the baseDir directory. + * @param name the name of the file. + * @param lines the lines to write to the file. + * @return the File that was written. + * @throws IOException if file cannot be created. + */ protected File writeFile(String name, Iterable lines) throws IOException { File file = new File(baseDir, name); try (PrintWriter writer = new PrintWriter(new FileWriter(file))) { @@ -59,4 +75,32 @@ protected File writeFile(String name, Iterable lines) throws IOException return file; } + /** + * Asserts the correctness of the exlcuder. An excluder returns false if the document name is matched. + * @param builder An FileProcessorBuilder that will create the excluder. + * @param matching the matching strings. + * @param notMatching the non-matching strings. + */ + protected void assertCorrect(AbstractFileProcessorBuilder builder, Iterable matching, Iterable notMatching) { + assertCorrect(builder.build(baseName), baseName, matching, notMatching); + } + + /** + * Asserts the correctness of the excluder. An excluder returns false if the document name is matched. + * @param matcherSets the list of matchers to create the DocumentNameMatcher from. + * @param baseDir the base directory for the excluder test. + * @param matching the matching strings. + * @param notMatching the non-matching strings. + */ + protected void assertCorrect(List matcherSets, DocumentName baseDir, Iterable matching, Iterable notMatching) { + DocumentNameMatcher excluder = MatcherSet.merge(matcherSets).createMatcher(); + for (String name : matching) { + DocumentName docName = baseDir.resolve(name); + assertThat(excluder.matches(docName)).as(docName.getName()).isFalse(); + } + for (String name : notMatching) { + DocumentName docName = baseDir.resolve(name); + assertThat(excluder.matches(docName)).as(docName.getName()).isTrue(); + } + } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java index fe5cec339..820e798e7 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java @@ -18,17 +18,12 @@ */ package org.apache.rat.config.exclusion.fileProcessors; -import java.util.ArrayList; -import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; -import org.apache.rat.utils.ExtendedIterator; import org.junit.jupiter.api.Test; -import java.io.File; import java.io.IOException; import java.util.Arrays; -import java.util.Collections; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -41,19 +36,12 @@ public void processExampleFileTest() throws IOException { "# a comment", "*.elc", "*.pyc", "*~", System.lineSeparator(), "# switch to regexp syntax.", "RE:^\\.pc" }; - List expected = Arrays.asList("test.elc", "test.pyc", "test.thing~", ".pc"); + List matching = Arrays.asList("test.elc", "test.pyc", "test.thing~", ".pc"); + List notMatching = Arrays.asList("test.foo", ".pc/stuff", "subidr/test.elc"); writeFile(".bzrignore", Arrays.asList(lines)); - BazaarIgnoreBuilder processor = new BazaarIgnoreBuilder(); - MatcherSet matcherSet = processor.build(baseName); - assertThat(matcherSet.excludes()).isPresent(); - assertThat(matcherSet.includes()).isNotPresent(); - DocumentNameMatcher matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : expected) { - DocumentName docName = baseName.resolve(name); - assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); - } + assertCorrect(new BazaarIgnoreBuilder(), matching, notMatching); } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java index ac5578b62..9319bbfc2 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java @@ -40,19 +40,14 @@ public void processExampleFileTest() throws IOException { String[] lines = { "thingone thingtwo", System.lineSeparator(), "one_fish", "two_fish", "", "red_* blue_*"}; - List expected = Arrays.asList("thingone", "thingtwo", "one_fish", "two_fish", "red_fish", "blue_fish"); + List matching = Arrays.asList("thingone", "thingtwo", "one_fish", "two_fish", "red_fish", "blue_fish"); + List notMatching = Arrays.asList("thing", "two", "fish_red", "subdir/two_fish", "subdir/red_fish", "subdir/blue_fish"); writeFile(".cvsignore", Arrays.asList(lines)); CVSIgnoreBuilder processor = new CVSIgnoreBuilder(); - MatcherSet matcherSet = processor.build(baseName); - - assertThat(matcherSet.excludes()).isPresent(); - assertThat(matcherSet.includes()).isNotPresent(); - DocumentNameMatcher matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : expected) { - DocumentName docName = baseName.resolve(name); - assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); - } + DocumentNameMatcher matcher = MatcherSet.merge(processor.build(baseName)).createMatcher(); + + assertCorrect(new CVSIgnoreBuilder(), matching, notMatching); } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java index d3591967f..5527e5623 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java @@ -20,10 +20,16 @@ import java.io.File; import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.stream.Stream; import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; +import org.apache.rat.document.DocumentNameMatcherTest; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -36,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.not; +import static org.assertj.core.api.Fail.fail; public class GitIgnoreBuilderTest extends AbstractIgnoreBuilderTest { @@ -49,28 +56,13 @@ public void processExampleFileTest() throws IOException { "# some colorful directories", "red/", "blue/*/"}; - List excluded = Arrays.asList("some/things", "some/fish", "another/red_fish"); + List matches = Arrays.asList("some/things", "some/fish", "another/red_fish"); - List included = Arrays.asList("some/thingone"); + List notMatches = Arrays.asList("some/thingone", "thingone"); writeFile(".gitignore", Arrays.asList(lines)); - GitIgnoreBuilder processor = new GitIgnoreBuilder(); - MatcherSet matcherSet = processor.build(baseName); - assertThat(matcherSet.includes()).isPresent(); - assertThat(matcherSet.excludes()).isPresent(); - - DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : included) { - DocumentName docName = baseName.resolve(name); - assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); - } - - matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : excluded) { - DocumentName docName = baseName.resolve(name); - assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); - } + assertCorrect(new GitIgnoreBuilder(), matches, notMatches); } // see https://git-scm.com/docs/gitignore @@ -79,11 +71,17 @@ public void processExampleFileTest() throws IOException { public void modifyEntryTest(String source, String expected) { GitIgnoreBuilder underTest = new GitIgnoreBuilder(); DocumentName testName = DocumentName.builder().setName("GitIgnoreBuilderTest").setBaseName("testDir").build(); + List matcherSets = new ArrayList<>(); + Optional entry = underTest.modifyEntry(matcherSets::add, testName, source); + + if (source.endsWith("/")) { - assertThat(underTest.modifyEntry(testName, source)).isNotPresent(); - assertThat(underTest.getIncluded().toString()).isEqualTo(expected); + assertThat(entry).isNotPresent(); + assertThat(matcherSets).hasSize(1); + DocumentNameMatcher matcher = matcherSets.get(0).createMatcher(); + assertThat(matcher.toString()).isEqualTo(expected); } else { - assertThat(underTest.modifyEntry(testName, source)).contains(expected); + assertThat(entry.get()).isEqualTo(expected); } } @@ -99,8 +97,10 @@ private static Stream modifyEntryData() { lst.add(Arguments.of("file/name", "file/name")); lst.add(Arguments.of("/file/name", "file/name")); lst.add(Arguments.of("filename", "**/filename")); - lst.add(Arguments.of("filename/", "and(isDirectory, **/filename)")); - lst.add(Arguments.of("/filename/", "and(isDirectory, filename)")); + lst.add(Arguments.of("filename/", "not(and(isDirectory, **/filename))")); + lst.add(Arguments.of("/filename/", "not(and(isDirectory, filename))")); + // inclusion by itself becomes nothing. + lst.add(Arguments.of("!filename/", "TRUE")); return lst.stream(); } @@ -123,23 +123,20 @@ public void test_RAT_335() { File file = new File(url.getFile()); DocumentName documentName = DocumentName.builder(file).build(); - MatcherSet matcherSet = underTest.build(documentName); - assertThat(matcherSet.excludes()).isPresent(); - assertThat(matcherSet.includes()).isPresent(); - - // includes test - DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); - assertThat(matcher.toString()).isEqualTo("or('included dir1/.gitignore', 'included .gitignore')"); - assertMatches(documentName, matcher, new String[]{"subdir/file1.log", "dir1/dir1.md", "dir1/somedir/dir1.md", - "dir1/file1.log"}, - new String[]{"dir1/joe.txt", "subdir/joe.txt", "subdir/joe.md", "dir1/joe.md" }); - - // excludes tests - matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); - assertThat(matcher.toString()).isEqualTo("or('excluded dir1/.gitignore', 'excluded .gitignore')"); - assertMatches(documentName, matcher, new String[]{ "dir1/file1.txt", "dir1/somedir/file1.txt", "dir1/file1.log", - "dir1/somedir/file1.log", "subdir/dir1.md", "subdir/some.log"}, - new String[]{"subdir/afile.txt" }); + List matcherSets = underTest.build(documentName); + DocumentNameMatcher matcher = MatcherSet.merge(matcherSets).createMatcher(); + + DocumentName candidate = DocumentName.builder() + .setName("/home/claude/apache/creadur-rat/apache-rat-core/target/test-classes/GitIgnoreBuilderTest/src/dir1/file1.log") + .setBaseName("home/claude/apache/creadur-rat/apache-rat-core/target/test-classes/GitIgnoreBuilderTest/src/").build(); + DocumentNameMatcherTest.decompose(matcher, candidate); + + assertThat(matcher.toString()).isEqualTo("matcherSet(or('included dir1/.gitignore', 'included .gitignore'), or('excluded dir1/.gitignore', **/.gitignore, 'excluded .gitignore'))"); + + List notMatching = Arrays.asList("README.txt", "dir1/dir1.md", "dir2/dir2.txt", "dir3/file3.log", "dir1/file1.log"); + + List matching = Arrays.asList(".gitignore", "root.md", "dir1/.gitignore", "dir1/dir1.txt", "dir2/dir2.md", "dir3/dir3.log"); + assertCorrect(matcherSets, documentName.getBaseDocumentName(), matching, notMatching); } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java index a56c26eba..d5b9edcb7 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java @@ -39,43 +39,26 @@ public class HgIgnoreBuilderTest extends AbstractIgnoreBuilderTest { @Test public void processExampleFileTest() throws IOException { String[] lines = { - "# use glob syntax.", "syntax: glob", "*.elc", "*.pyc", "*~", System.lineSeparator(), + "# use glob syntax.", "syntax: glob", "*.elc", "*.pyc", "*~", "*.c", System.lineSeparator(), "# switch to regexp syntax.", "syntax: regexp", "^\\.pc" }; - List expected = Arrays.asList("test.elc", "test.pyc", "test.thing~", ".pc"); + List matching = Arrays.asList("test.elc", "test.pyc", "subdir/test.pyc", "test.thing~", ".pc", "foo.c", "/subdir/foo.c" ); + List notMatching = Arrays.asList("test.foo", "test.thing~/subdir", ".pc/subdir"); writeFile(".hgignore", Arrays.asList(lines)); - HgIgnoreBuilder processor = new HgIgnoreBuilder(); - MatcherSet matcherSet = processor.build(baseName); - assertThat(matcherSet.excludes()).isPresent(); - assertThat(matcherSet.includes()).isNotPresent(); - DocumentNameMatcher matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : expected) { - DocumentName docName = baseName.resolve(name); - assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); - } + assertCorrect(new HgIgnoreBuilder(), matching, notMatching); } @Test public void processDefaultFileTest() throws IOException { - String[] lines = {"^[A-Z]*\\.txt", "[0-9]*\\.txt"}; + String[] lines = {"^[A-Z]*\\.txt", "[0-9]+\\.txt"}; - List match = Arrays.asList("ABIGNAME.txt", "endsIn9.txt"); - List notMatch = Arrays.asList("asmallName.txt", "endsin.doc"); + List matching = Arrays.asList("ABIGNAME.txt", "endsIn9.txt"); + List notMatching = Arrays.asList("asmallName.txt", "endsin.doc"); writeFile(".hgignore", Arrays.asList(lines)); - HgIgnoreBuilder processor = new HgIgnoreBuilder(); - MatcherSet matcherSet = processor.build(baseName); - DocumentNameMatcher matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : match) { - DocumentName docName = baseName.resolve(name); - assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); - } - for (String name : notMatch) { - DocumentName docName = DocumentName.builder().setName(name).setBaseName(baseDir).build(); - assertThat(matcher.matches(docName)).as(docName.getName()).isFalse(); - } + assertCorrect(new HgIgnoreBuilder(), matching, notMatching); } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java new file mode 100644 index 000000000..7c33064b0 --- /dev/null +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java @@ -0,0 +1,95 @@ +package org.apache.rat.document; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.apache.rat.document.DocumentNameMatcher.MATCHES_ALL; +import static org.apache.rat.document.DocumentNameMatcher.MATCHES_NONE; + +public class DocumentNameMatcherTest { + + private final static DocumentNameMatcher TRUE = new DocumentNameMatcher("T", (Predicate)name -> true); + private final static DocumentNameMatcher FALSE = new DocumentNameMatcher("F", (Predicate)name -> false); + private final static DocumentNameMatcher SOME = new DocumentNameMatcher("X", (Predicate)name -> false); + private final static DocumentName testName = DocumentName.builder().setName("testName").setBaseName("/").build(); + + @Test + public void orTest() { + assertThat(DocumentNameMatcher.or(TRUE, FALSE).matches(testName)).as("T,F").isTrue(); + assertThat(DocumentNameMatcher.or(FALSE, TRUE).matches(testName)).as("F,T").isTrue(); + assertThat(DocumentNameMatcher.or(TRUE, TRUE).matches(testName)).as("T,T").isTrue(); + assertThat(DocumentNameMatcher.or(FALSE, FALSE).matches(testName)).as("F,F").isFalse(); + } + + @Test + public void andTest() { + assertThat(DocumentNameMatcher.and(TRUE, FALSE).matches(testName)).as("T,F").isFalse(); + assertThat(DocumentNameMatcher.and(FALSE, TRUE).matches(testName)).as("F,T").isFalse(); + assertThat(DocumentNameMatcher.and(TRUE, TRUE).matches(testName)).as("T,T").isTrue(); + assertThat(DocumentNameMatcher.and(FALSE, FALSE).matches(testName)).as("F,F").isFalse(); + } + + @Test + public void matcherSetTest() { + assertThat(DocumentNameMatcher.matcherSet(TRUE, FALSE).matches(testName)).as("T,F").isTrue(); + assertThat(DocumentNameMatcher.matcherSet(FALSE, TRUE).matches(testName)).as("F,T").isFalse(); + assertThat(DocumentNameMatcher.matcherSet(TRUE, TRUE).matches(testName)).as("T,T").isTrue(); + assertThat(DocumentNameMatcher.matcherSet(FALSE, FALSE).matches(testName)).as("F,F").isTrue(); + + assertThat(DocumentNameMatcher.matcherSet(MATCHES_ALL, MATCHES_ALL)).as("All,All").isEqualTo(MATCHES_ALL); + assertThat(DocumentNameMatcher.matcherSet(MATCHES_ALL, MATCHES_NONE)).as("All,None").isEqualTo(MATCHES_ALL); + assertThat(DocumentNameMatcher.matcherSet(MATCHES_ALL, SOME)).as("All,X").isEqualTo(MATCHES_ALL); + + assertThat(DocumentNameMatcher.matcherSet(MATCHES_NONE, MATCHES_ALL)).as("None,All").isEqualTo(MATCHES_NONE); + assertThat(DocumentNameMatcher.matcherSet(MATCHES_NONE, MATCHES_NONE)).as("None,None").isEqualTo(MATCHES_ALL); + assertThat(DocumentNameMatcher.matcherSet(MATCHES_NONE, SOME).toString()).as("None,X").isEqualTo("not(X)"); + + assertThat(DocumentNameMatcher.matcherSet(SOME, MATCHES_ALL).toString()).as("X,All").isEqualTo("matcherSet(X, TRUE)"); + assertThat(DocumentNameMatcher.matcherSet(SOME, MATCHES_NONE)).as("X,None").isEqualTo(MATCHES_ALL); + assertThat(DocumentNameMatcher.matcherSet(SOME, SOME).toString()).as("X,X").isEqualTo("matcherSet(X, X)"); + } + + public static void decompose(DocumentNameMatcher matcher, DocumentName candidate) { + List result = new ArrayList<>(); + + decompose(0, matcher, candidate, result); + System.out.println("Decomposition for "+candidate); + for (DecomposeData d : result) { + System.out.println(d); + } + } + private static void decompose(int level, DocumentNameMatcher matcher, DocumentName candidate, List result) { + Predicate pred = matcher.getPredicate(); + result.add(new DecomposeData(level, matcher.toString(), pred.test(candidate))); + if (pred instanceof DocumentNameMatcher.CollectionPredicate) { + DocumentNameMatcher.CollectionPredicate collection = (DocumentNameMatcher.CollectionPredicate) pred; + for(DocumentNameMatcher subMatcher : collection.getMatchers()) { + decompose(level + 1, subMatcher, candidate, result); + } + } + } + + public static class DecomposeData { + int level; + String name;; + boolean result; + + DecomposeData(int level, String name, boolean result) { + this.level = level; + this.name = name; + this.result = result; + } + + @Override + public String toString() { + char[] chars = new char[level*2]; + Arrays.fill(chars, ' '); + String fill = new String(chars); + return String.format("%s%s : %s", fill, name, result); + } + } +} 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 dfad5b43d..91b3ec9dc 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 @@ -29,6 +29,7 @@ import org.apache.rat.commandline.StyleSheets; import org.apache.rat.config.exclusion.StandardCollection; import org.apache.rat.document.DocumentNameMatcher; +import org.apache.rat.document.DocumentNameMatcherTest; import org.apache.rat.document.DocumentName; import org.apache.rat.license.ILicense; import org.apache.rat.license.ILicenseFamily; @@ -37,7 +38,6 @@ import org.apache.rat.testhelpers.TextUtils; import org.apache.rat.utils.DefaultLog; import org.apache.rat.utils.Log.Level; -import org.apache.rat.utils.ExtendedIterator; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.provider.Arguments; @@ -204,9 +204,11 @@ protected DocumentName mkDocName(String name) { /* tests to be implemented */ protected abstract void helpTest(); + /** Displayd the option and value under test */ private String displayArgAndName(Option option, String fname) { return String.format("%s %s", option.getLongOpt(), fname); } + // exclude tests private void execExcludeTest(Option option, String[] args) { String[] notExcluded = {"notbaz", "well._afile"}; @@ -275,17 +277,22 @@ protected void inputExcludeParsedScmTest() { "**/fish", "*_fish", "# some colorful directories", "red/", "blue/*/"}; - String[] notExcluded = {"thingone", "dir/fish_two"}; - String[] excluded = {"thingtwo", "dir/fish", "red/fish", "blue/fish"}; + + String[] notExcluded = {"thingone", "dir/fish_two", "some/thingone", "blue/fish/dory" }; + String[] excluded = {"thingtwo", "some/things", "dir/fish", "red/fish", "blue/fish", "some/fish", "another/red_fish"}; writeFile(".gitignore", Arrays.asList(lines)); + File dir = new File(baseDir, "red"); + dir.mkdirs(); + dir = new File(baseDir, "blue"); + dir = new File(dir, "fish"); + dir.mkdirs(); + - List expected = ExtendedIterator.create(Arrays.asList("thing*", "**/fish", "*_fish", "red/**", "blue/*/**").iterator()) - .map(s -> new File(baseDir, s).getPath()).addTo(new ArrayList<>()); - expected.add(0, "!" + new File(baseDir, "thingone").getPath()); try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); + DocumentNameMatcherTest.decompose(excluder, mkDocName("thingone")); for (String fname : excluded) { assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isFalse(); } From b3990be37542883118c74ba718063351becf0531 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Wed, 25 Dec 2024 16:35:55 +0000 Subject: [PATCH 007/123] cleaned up checkstyle issues --- .../ReportTest/RAT_335/verify.groovy | 1 - .../config/exclusion/ExclusionProcessor.java | 11 +- .../rat/config/exclusion/MatcherSet.java | 48 ++++++-- .../AbstractFileProcessorBuilder.java | 110 ++++++++---------- .../fileProcessors/BazaarIgnoreBuilder.java | 1 + .../fileProcessors/CVSIgnoreBuilder.java | 2 +- .../fileProcessors/GitIgnoreBuilder.java | 7 +- .../fileProcessors/HgIgnoreBuilder.java | 2 +- .../rat/document/DocumentNameMatcher.java | 31 +++-- .../rat/document/DocumentNameMatcherTest.java | 18 +++ 10 files changed, 141 insertions(+), 90 deletions(-) diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy index 3774f283d..07db17902 100644 --- a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy @@ -106,7 +106,6 @@ XPath xPath = XPathFactory.newInstance().newXPath() List ignoredFiles = new ArrayList<>(Arrays.asList( "/dir1/dir1.txt", - "/dir1/file1.log", "/dir1/.gitignore", "/dir2/dir2.md", "/dir3/dir3.log", 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 0f5e18342..76e595fe7 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 @@ -24,8 +24,8 @@ import java.util.Objects; import java.util.Set; import java.util.TreeSet; - import java.util.stream.Collectors; + import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.utils.DefaultLog; @@ -222,14 +222,15 @@ private List extractFileProcessors(final DocumentName basedir) { * @param nameBuilder The name builder for the pattern. File names are resolved against the generated name. * @param matcherBuilder the MatcherSet.Builder to add the patterns to. */ - private void extractPatterns(DocumentName.Builder nameBuilder, MatcherSet.Builder matcherBuilder) { + private void extractPatterns(final DocumentName.Builder nameBuilder, final MatcherSet.Builder matcherBuilder) { DocumentName name = nameBuilder.setName("Patterns").build(); if (!excludedPatterns.isEmpty()) { - matcherBuilder.addExcluded(name, excludedPatterns.stream().map(s -> ExclusionUtils.localizePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); + matcherBuilder.addExcluded(name, excludedPatterns.stream() + .map(s -> ExclusionUtils.localizePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); } if (!includedPatterns.isEmpty()) { - - matcherBuilder.addIncluded(name, includedPatterns.stream().map(s -> ExclusionUtils.localizePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); + matcherBuilder.addIncluded(name, includedPatterns.stream() + .map(s -> ExclusionUtils.localizePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java index d0f8b94e7..b5369c7ba 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -18,19 +18,16 @@ */ package org.apache.rat.config.exclusion; -import java.util.ArrayList; import java.util.List; import java.util.Optional; - import java.util.Set; -import java.util.function.Predicate; + import org.apache.rat.config.exclusion.plexus.MatchPattern; import org.apache.rat.config.exclusion.plexus.MatchPatterns; import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; -import static org.apache.rat.document.DocumentNameMatcher.MATCHES_ALL; import static org.apache.rat.document.DocumentNameMatcher.MATCHES_NONE; /** @@ -63,7 +60,7 @@ static MatcherSet merge(List matcherSets) { /** * A MatcherSet that assumes the files contain the already formatted strings and just need to be - * localized for the fileName. + * localized for the fileName. When {@link #build()} is called the builder is reset to the initial state. */ class Builder { @@ -92,7 +89,14 @@ public static void segregateList(final Set matching, final Set n public Builder() { } - public Builder addIncluded(DocumentName fromDocument, Set names) { + /** + * Adds included file names from the specified document. File names are resolved relative to the directory + * of the {@code fromDocument}. + * @param fromDocument the document the names were read from. + * @param names the names that were read from the document. + * @return this + */ + public Builder addIncluded(final DocumentName fromDocument, final Set names) { if (!names.isEmpty()) { String name = String.format("'included %s'", fromDocument.localized("/").substring(1)); addIncluded(new DocumentNameMatcher(name, MatchPatterns.from(names), fromDocument.getBaseDocumentName())); @@ -100,7 +104,14 @@ public Builder addIncluded(DocumentName fromDocument, Set names) { return this; } - public Builder addExcluded(DocumentName fromDocument, Set names) { + /** + * Adds excluded file names from the specified document. File names are resolved relative to the directory + * of the {@code fromDocument}. + * @param fromDocument the document the names were read from. + * @param names the names that were read from the document. + * @return this + */ + public Builder addExcluded(final DocumentName fromDocument, final Set names) { if (!names.isEmpty()) { String name = String.format("'excluded %s'", fromDocument.localized("/").substring(1)); addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(names), fromDocument.getBaseDocumentName())); @@ -108,20 +119,35 @@ public Builder addExcluded(DocumentName fromDocument, Set names) { return this; } - public Builder addIncluded(DocumentNameMatcher matcher) { + + /** + * Adds specified DocumentNameMatcher to the included matchers. + * @param matcher A document name matcher to add to the included set. + * @return this + */ + public Builder addIncluded(final DocumentNameMatcher matcher) { this.included = this.included == null ? matcher : DocumentNameMatcher.or(this.included, matcher); return this; } - public Builder addExcluded(DocumentNameMatcher matcher) { + /** + * Adds specified DocumentNameMatcher to the excluded matchers. + * @param matcher A document name matcher to add to the excluded set. + * @return this + */ + public Builder addExcluded(final DocumentNameMatcher matcher) { this.excluded = this.excluded == null ? matcher : DocumentNameMatcher.or(this.excluded, matcher); return this; } + /** + * Builds a MatcherSet. When {@link #build()} is called the builder is reset to the initial state. + * @return the MatcherSet based upon the included and excluded matchers. + */ public MatcherSet build() { MatcherSet result = new MatcherSet() { - final DocumentNameMatcher myIncluded = included; - final DocumentNameMatcher myExcluded = excluded; + private final DocumentNameMatcher myIncluded = included; + private final DocumentNameMatcher myExcluded = excluded; @Override public Optional includes() { diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java index b3e703aa6..42278f97c 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java @@ -21,7 +21,6 @@ import java.io.File; import java.io.FileFilter; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -33,6 +32,7 @@ import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Collectors; + import org.apache.commons.io.filefilter.DirectoryFileFilter; import org.apache.commons.io.filefilter.NameFileFilter; import org.apache.commons.lang3.StringUtils; @@ -44,24 +44,32 @@ import org.apache.rat.document.DocumentNameMatcher; /** - * // create a list of levels that a list of processors at that level. - * // will return a custom matcher that from an overridden MatcherSet.customDocumentNameMatchers method - * // build LevelMatcher as a system that returns Include, Exclude or no status for each check. - * // put the level matcher in an array with other level matchers at the specific level below the root - * // When searching start at the lowest level and work up the tree. + * Creates a List of {@link MatcherSet}s that represent the inclusions and exclusions of this file processor. + *

    + * By default this processor: + *

    + *
      + *
    • Creates a list of levels that correspond the depth of the directories where the specific include/exclude file is located. + * Directory depth is relative to the initially discovered include/exclude file.
    • + *
    • A MatcherSet is created for each include/exclude file located, and the MatcherSet is added to the proper level.
    • + *
    • During the build: + *
        + *
      • Each level creates a MatcherSet for the level.
      • + *
      • The MatcherSet for each level is returned in reverse order (deepest first). This ensures that most include/exclude + * files will be properly handled.
      • + *
    • + *
    */ public abstract class AbstractFileProcessorBuilder { /** A String format pattern to print a regex string */ protected static final String REGEX_FMT = "%%regex[%s]"; - /** The name of the file being processed */ protected final String fileName; - /** The predicate that will return {@code false} for any comment line in the file. */ protected final Predicate commentFilter; - + /** the collection of level builders */ private final SortedMap levelBuilders; - + /** if {@code true} then the processor file name will be included in the list of files to ignore */ private final boolean includeProcessorFile; /** @@ -94,12 +102,22 @@ protected AbstractFileProcessorBuilder(final String fileName, final Predicate createMatcherSetList(DocumentName dir) { + /** + * Creates the MatcherSet from each level and returns them in a list in reverse order. + * @return a list of MatcherSet + */ + + private List createMatcherSetList() { List keys = new ArrayList<>(levelBuilders.keySet()); keys.sort((a, b) -> -1 * Integer.compare(a, b)); - return keys.stream().map( key -> levelBuilders.get(key).asMatcherSet(dir)).collect(Collectors.toList()); + return keys.stream().map(key -> levelBuilders.get(key).asMatcherSet()).collect(Collectors.toList()); } + /** + * Builder the list of MatcherSet that define the inclusions/exclusions for the file processor. + * @param dir the directory agains which name resolution should be made. + * @return the List of MatcherSet that represent this file processor. + */ public final List build(final DocumentName dir) { if (includeProcessorFile) { String name = String.format("**/%s", fileName); @@ -107,18 +125,14 @@ public final List build(final DocumentName dir) { MatcherSet matcherSet = new MatcherSet.Builder() .addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(Collections.singletonList(pattern)), dir)) .build(); - LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(0, LevelBuilder::new); + LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(0, k -> new LevelBuilder()); levelBuilder.add(matcherSet); } checkDirectory(0, dir, new NameFileFilter(fileName)); - List result = null; - if (levelBuilders.size() == 1) { - result = Collections.singletonList(levelBuilders.get(0).asMatcherSet(dir)); - } else { - result = createMatcherSetList(dir); - } + List result = levelBuilders.size() == 1 ? Collections.singletonList(levelBuilders.get(0).asMatcherSet()) + : createMatcherSetList(); levelBuilders.clear(); return result; } @@ -153,7 +167,7 @@ protected MatcherSet process(final Consumer matcherSetConsumer, fina private void checkDirectory(final int level, final DocumentName directory, final FileFilter fileFilter) { File dirFile = new File(directory.getName()); for (File f : listFiles(dirFile, fileFilter)) { - LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(level, LevelBuilder::new); + LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(level, k -> new LevelBuilder()); DocumentName dirBasedName = DocumentName.builder(f).setBaseName(directory.getBaseName()).build(); levelBuilder.add(process(levelBuilder::add, dirBasedName, DocumentName.builder(f).setBaseName(directory.getName()).build())); } @@ -184,51 +198,29 @@ protected File[] listFiles(final File dir, final FileFilter filter) { return result == null ? new File[0] : result; } - protected static class FileProcessorPredicate implements Predicate { - private final Collection matcherSets; - FileProcessorPredicate(Collection matcherSets) { - this.matcherSets = matcherSets; - } - - public Collection getMatcherSets() { - return matcherSets; - } - - @Override - public boolean test(DocumentName documentName) { - for (MatcherSet matcherSet : matcherSets) { - if (matcherSet.includes().orElse(DocumentNameMatcher.MATCHES_NONE).matches(documentName)) { - return true; - } - if (matcherSet.excludes().orElse(DocumentNameMatcher.MATCHES_NONE).matches(documentName)) { - return false; - } - } - return true; - } - } - - static class LevelBuilder { + /** + * Manages the merging of {@link MatcherSet}s for the specified level. + */ + private static class LevelBuilder { /** * The list of MatcherSets that this builder produced. */ - private final MatcherSet.Builder builder; + private final MatcherSet.Builder builder = new MatcherSet.Builder(); - public LevelBuilder(Integer integer) { - int level = integer; - builder = new MatcherSet.Builder(); - } - - public void add(MatcherSet matcherSet) { - if (matcherSet.includes().isPresent()) { - builder.addIncluded(matcherSet.includes().get()); - } - if (matcherSet.excludes().isPresent()) { - builder.addExcluded(matcherSet.excludes().get()); - } + /** + * Adds a MatcherSet to this level. + * @param matcherSet the matcher set to add. + */ + public void add(final MatcherSet matcherSet) { + matcherSet.includes().ifPresent(builder::addIncluded); + matcherSet.excludes().ifPresent(builder::addExcluded); } - public MatcherSet asMatcherSet(DocumentName dir) { + /** + * Constructs the MatcherSet for this level. + * @return the MatcherSet. + */ + public MatcherSet asMatcherSet() { return builder.build(); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java index 787564d35..2be97f983 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java @@ -20,6 +20,7 @@ import java.util.Optional; import java.util.function.Consumer; + import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java index 69e6aba3a..0f2ff1047 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java @@ -21,9 +21,9 @@ import java.io.File; import java.util.HashSet; import java.util.Iterator; - import java.util.Set; import java.util.function.Consumer; + import org.apache.commons.lang3.StringUtils; import org.apache.rat.config.exclusion.ExclusionUtils; import org.apache.rat.config.exclusion.MatcherSet; diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java index af5545e67..6c70fb736 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java @@ -19,9 +19,9 @@ package org.apache.rat.config.exclusion.fileProcessors; import java.io.File; - import java.util.Optional; import java.util.function.Consumer; + import org.apache.rat.config.exclusion.ExclusionUtils; import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.config.exclusion.plexus.MatchPatterns; @@ -35,10 +35,15 @@ * @see .gitignore documentation */ public class GitIgnoreBuilder extends AbstractFileProcessorBuilder { + /** The name of the file we read from */ private static final String IGNORE_FILE = ".gitignore"; + /** The comment prefix */ private static final String COMMENT_PREFIX = "#"; + /** An escaped comment in the .gitignore file. (Not a comment) */ private static final String ESCAPED_COMMENT = "\\#"; + /** An escaped negation in the .gitignore file. (Not a negation) */ private static final String ESCAPED_NEGATION = "\\!"; + /** The slash string */ private static final String SLASH = "/"; /** diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java index ca8ca1344..d7d0ad05b 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java @@ -81,7 +81,7 @@ public Optional modifyEntry(final Consumer matcherSetConsume return Optional.of(format(REGEX_FMT, pattern)); } else { if (entry.startsWith("*")) { - return Optional.of("**/"+entry); + return Optional.of("**/" + entry); } } return Optional.of(entry); diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 5ce63d587..be6bafb8c 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -45,7 +45,7 @@ public final class DocumentNameMatcher { private final Predicate predicate; /** The name of this matcher. */ private final String name; - + /** {@code true} this this matcher is a collection of matchers */ private final boolean isCollection; /** @@ -96,7 +96,7 @@ public DocumentNameMatcher(final String name, final MatchPatterns patterns, fina * @param dirSeparator the directory separator * @return the tokenized name. */ - private static char[][] tokenize(String name, String dirSeparator) { + private static char[][] tokenize(final String name, final String dirSeparator) { String[] tokenizedName = MatchPattern.tokenizePathToString(name, dirSeparator); char[][] tokenizedNameChar = new char[tokenizedName.length][]; for (int i = 0; i < tokenizedName.length; i++) { @@ -184,7 +184,8 @@ private static String join(final Collection matchers) { return String.join(", ", children); } - private static Optional standardCollectionCheck(Collection matchers, DocumentNameMatcher override) { + private static Optional standardCollectionCheck(final Collection matchers, + final DocumentNameMatcher override) { if (matchers.isEmpty()) { throw new ConfigurationException("Empty matcher collection"); } @@ -213,7 +214,7 @@ public static DocumentNameMatcher or(final Collection match for (DocumentNameMatcher matcher : matchers) { // check for nested or if (matcher.predicate instanceof Or) { - ((Or)matcher.predicate).getMatchers().forEach(workingSet::add); + ((Or) matcher.predicate).getMatchers().forEach(workingSet::add); } else { workingSet.add(matcher); } @@ -247,7 +248,7 @@ public static DocumentNameMatcher and(final Collection matc for (DocumentNameMatcher matcher : matchers) { // check for nexted And if (matcher.predicate instanceof And) { - ((And)matcher.predicate).getMatchers().forEach(workingSet::add); + ((And) matcher.predicate).getMatchers().forEach(workingSet::add); } else { workingSet.add(matcher); } @@ -292,13 +293,21 @@ public static DocumentNameMatcher and(final DocumentNameMatcher... matchers) { */ // package private for testing access abstract static class CollectionPredicate implements Predicate { - // package private for testing acess. - private final Iterable matchers; - - protected CollectionPredicate(Iterable matchers) { + /** The collection for matchers that make up this predicate */ + private final Iterable matchers; + + /** + * Constructs a collecton predicate from the collection of matchers + * @param matchers the colleciton of matchers to use. + */ + protected CollectionPredicate(final Iterable matchers) { this.matchers = matchers; } + /** + * Gets the internal matchers. + * @return an iterable over the internal matchers. + */ public Iterable getMatchers() { return matchers; } @@ -314,7 +323,7 @@ static class And extends CollectionPredicate { } @Override - public boolean test(DocumentName documentName) { + public boolean test(final DocumentName documentName) { for (DocumentNameMatcher matcher : getMatchers()) { if (!matcher.matches(documentName)) { return false; @@ -334,7 +343,7 @@ static class Or extends CollectionPredicate { } @Override - public boolean test(DocumentName documentName) { + public boolean test(final DocumentName documentName) { for (DocumentNameMatcher matcher : getMatchers()) { if (matcher.matches(documentName)) { return true; diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java index 7c33064b0..e586a1de9 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java @@ -1,3 +1,21 @@ +/* + * 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.util.ArrayList; From 26b881d23e54f88f37f3b1978f1d4dfa2f0cf539 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Wed, 25 Dec 2024 16:36:46 +0000 Subject: [PATCH 008/123] cleaned up checkstyle issues --- .../src/it/resources/ReportTest/RAT_335/verify.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy index 07db17902..d660f59fd 100644 --- a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy @@ -124,10 +124,10 @@ assertThat(ignoredFiles).isEmpty() // Document types XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='IGNORED']", - mapOf("count", "7" )) + mapOf("count", "6" )) XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='NOTICE']", mapOf("count", "1" )) XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='STANDARD']", - mapOf("count", "3" )) + mapOf("count", "4" )) From ae25ee2b5a2f4d092102446eef95681bbfd5ac58 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Thu, 26 Dec 2024 00:09:53 +0000 Subject: [PATCH 009/123] fixed and cleaned up plugin tests --- .../config/exclusion/ExclusionProcessor.java | 2 +- .../org/apache/rat/OptionCollectionTest.java | 34 +- .../rat/test/AbstractOptionsProvider.java | 22 +- .../org/apache/rat/test/utils/Resources.java | 20 +- .../org/apache/rat/testhelpers/XmlUtils.java | 24 +- .../org/apache/rat/mp/OptionMojoTest.java | 26 +- .../org/apache/rat/mp/RatCheckMojoTest.java | 322 +++++++++--------- .../unit/RAT-335-GitIgnore/.gitignore | 7 - .../unit/RAT-335-GitIgnore/dir1/.gitignore | 3 - .../unit/RAT-335-GitIgnore/dir1/dir1.txt | 1 - .../unit/RAT-335-GitIgnore/dir1/file1.log | 1 - .../unit/RAT-335-GitIgnore/dir2/dir2.md | 1 - .../unit/RAT-335-GitIgnore/dir3/dir3.log | 1 - .../unit/RAT-335-GitIgnore/invoker.properties | 16 - .../resources/unit/RAT-335-GitIgnore/root.md | 1 - .../{RAT-335-GitIgnore => RAT-335}/README.txt | 0 .../dir1/dir1.md | 0 .../dir2/dir2.txt | 0 .../dir3/file3.log | 0 .../{RAT-335-GitIgnore => RAT-335}/pom.xml | 0 .../unit/RAT-362-GitIgnore/.gitignore | 2 - .../resources/unit/RAT-362-GitIgnore/foo.md | 1 - .../unit/RAT-362-GitIgnore/invoker.properties | 16 - .../{RAT-362-GitIgnore => RAT-362}/bar.md | 0 .../{RAT-362-GitIgnore => RAT-362}/pom.xml | 1 + .../src/test/resources/unit/it3/pom.xml | 1 + .../apache/rat/anttasks/ReportOptionTest.java | 28 +- 27 files changed, 276 insertions(+), 254 deletions(-) delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/.gitignore delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/.gitignore delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.txt delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/file1.log delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.md delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/dir3.log delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/invoker.properties delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/root.md rename apache-rat-plugin/src/test/resources/unit/{RAT-335-GitIgnore => RAT-335}/README.txt (100%) rename apache-rat-plugin/src/test/resources/unit/{RAT-335-GitIgnore => RAT-335}/dir1/dir1.md (100%) rename apache-rat-plugin/src/test/resources/unit/{RAT-335-GitIgnore => RAT-335}/dir2/dir2.txt (100%) rename apache-rat-plugin/src/test/resources/unit/{RAT-335-GitIgnore => RAT-335}/dir3/file3.log (100%) rename apache-rat-plugin/src/test/resources/unit/{RAT-335-GitIgnore => RAT-335}/pom.xml (100%) delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/.gitignore delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/foo.md delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/invoker.properties rename apache-rat-plugin/src/test/resources/unit/{RAT-362-GitIgnore => RAT-362}/bar.md (100%) rename apache-rat-plugin/src/test/resources/unit/{RAT-362-GitIgnore => RAT-362}/pom.xml (97%) 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 76e595fe7..1e88e86bb 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 @@ -253,7 +253,7 @@ private void extractCollectionPatterns(final DocumentName.Builder nameBuilder, f for (StandardCollection sc : excludedCollections) { Set patterns = sc.patterns(); if (patterns.isEmpty()) { - DefaultLog.getInstance().info(String.format("%s does not have a defined collection for exclusion.", sc)); + DefaultLog.getInstance().debug(String.format("%s does not have a defined collection for exclusion.", sc)); } else { MatcherSet.Builder.segregateList(excl, incl, sc.patterns()); } 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 ab1ce763a..5f3feaf94 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 @@ -18,6 +18,7 @@ */ package org.apache.rat; +import java.nio.file.Path; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.Option; @@ -29,10 +30,12 @@ import org.apache.rat.testhelpers.TestingLog; import org.apache.rat.utils.DefaultLog; import org.apache.rat.utils.Log; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.api.condition.OS; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; @@ -54,20 +57,12 @@ import static org.junit.jupiter.api.Assertions.fail; public class OptionCollectionTest { + @TempDir + static Path testPath; - /** - * The base directory for the test. - * We do not use TempFile because we want the evidence of the run - * to exist after a failure. - */ - private final File baseDir; - - /** - * Constructor. - */ - public OptionCollectionTest() { - baseDir = new File("target/optionTools"); - baseDir.mkdirs(); + @AfterAll + static void preserveData() { + AbstractOptionsProvider.preserveData(testPath.toFile(), "optionTest"); } /** @@ -118,7 +113,7 @@ public void testDirOptionCapturesDirectoryToScan() throws IOException { ReportConfiguration config; try { DefaultLog.setInstance(log); - String[] args = {"--dir", baseDir.getAbsolutePath()}; + String[] args = {"--dir", testPath.toFile().getAbsolutePath()}; config = OptionCollection.parseCommands(args, (o) -> { }, true); } finally { @@ -161,7 +156,7 @@ public void getReportableTest(String fName) throws IOException { * @param test the option test to execute. */ @ParameterizedTest - @ArgumentsSource(OptionsProvider.class) + @ArgumentsSource(CliOptionsProvider.class) public void testOptionsUpdateConfig(String name, OptionTest test) { DefaultLog.getInstance().log(Log.Level.INFO, "Running test for: " + name); test.test(); @@ -170,7 +165,7 @@ public void testOptionsUpdateConfig(String name, OptionTest test) { /** * A class to provide the Options and tests to the testOptionsUpdateConfig. */ - static class OptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { + static class CliOptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { /** A flag to determine if help was called */ final AtomicBoolean helpCalled = new AtomicBoolean(false); @@ -190,8 +185,8 @@ public void helpTest() { /** * Constructor. Sets the baseDir and loads the testMap. */ - public OptionsProvider() { - super(Collections.emptyList()); + public CliOptionsProvider() { + super(Collections.emptyList(), testPath.toFile()); } /** @@ -201,7 +196,8 @@ public OptionsProvider() { * @return A ReportConfiguration * @throws IOException on critical error. */ - protected ReportConfiguration generateConfig(Pair... args) throws IOException { + @SafeVarargs + protected final ReportConfiguration generateConfig(Pair... args) throws IOException { helpCalled.set(false); List sArgs = new ArrayList<>(); for (Pair pair : args) { 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 91b3ec9dc..ae91b43a0 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 @@ -18,7 +18,10 @@ */ package org.apache.rat.test; +import java.nio.file.FileSystems; +import java.nio.file.Path; import org.apache.commons.cli.Option; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; @@ -82,18 +85,25 @@ public abstract class AbstractOptionsProvider { protected static final String[] INCLUDE_ARGS = {"B.bar", "justbaz"}; /** * The directory to place test data in. - * We do not use temp file here as we want the evidence to survive failure. */ - protected final File baseDir; + protected File baseDir; + + public static void preserveData(File baseDir, String targetDir) { + final Path recordPath = FileSystems.getDefault().getPath("target", targetDir); + recordPath.toFile().mkdirs(); + try { + FileUtils.copyDirectory(baseDir, recordPath.toFile()); + } catch (IOException e) { + System.err.format("Unable to copy data from %s to %s%n", baseDir, recordPath); + } + } protected DocumentName baseName() { return DocumentName.builder(baseDir).build(); } - protected AbstractOptionsProvider(Collection unsupportedArgs) { - baseDir = new File("target/optionTools"); - baseDir.mkdirs(); - + protected AbstractOptionsProvider(Collection unsupportedArgs, File baseDir) { + this.baseDir = baseDir; testMap.put("addLicense", this::addLicenseTest); testMap.put("config", this::configTest); testMap.put("configuration-no-defaults", this::configurationNoDefaultsTest); diff --git a/apache-rat-core/src/test/java/org/apache/rat/test/utils/Resources.java b/apache-rat-core/src/test/java/org/apache/rat/test/utils/Resources.java index fda2b5897..67a96afd9 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/test/utils/Resources.java +++ b/apache-rat-core/src/test/java/org/apache/rat/test/utils/Resources.java @@ -50,7 +50,22 @@ private Resources() { * Locates a test resource file in the class path. */ public static File getResourceFile(String pResource) throws IOException { - return getResourceFromBase(TEST_RESOURCE_BASE_PATH, pResource); + File f = getResourceFromBase(TEST_RESOURCE_BASE_PATH, pResource); + if (!f.isFile()) { + throw new FileNotFoundException("Unable to locate resource file: " + pResource); + } + return f; + } + + /** + * Locates a test resource directory in the class path. + */ + public static File getResourceDirectory(String pResource) throws IOException { + File f = getResourceFromBase(TEST_RESOURCE_BASE_PATH, pResource); + if (!f.isDirectory()) { + throw new FileNotFoundException("Unable to locate resource file: " + pResource); + } + return f; } @@ -71,9 +86,6 @@ public static File getExampleResource(String pResource) { */ private static File getResourceFromBase(File baseDir, String pResource) throws IOException { File f = new File(baseDir, pResource); - if (!f.isFile()) { - throw new FileNotFoundException("Unable to locate resource file: " + pResource); - } return f.getCanonicalFile(); } 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 67a9c0c70..429364a0c 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 @@ -30,6 +30,7 @@ import java.lang.reflect.UndeclaredThrowableException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -98,7 +99,8 @@ public static NodeList getNodeList(Object source, XPath xPath, String xpath) thr } public static boolean isPresent(Object source, XPath xPath, String xpath) throws XPathExpressionException { - return !xPath.compile(xpath).evaluate(source).equals("null"); + Object node = xPath.compile(xpath).evaluate(source, XPathConstants.NODE); + return node != null; } public static List getNodes(Object source, XPath xPath, String xpath) throws XPathExpressionException { @@ -177,6 +179,18 @@ public static String getAttribute(Object source, XPath xPath, String xpath, Stri return node.getNodeValue(); } + public static Map mapOf(String... parts) { + Map map = new HashMap<>(); + for (int i=0; i attributes) throws XPathExpressionException { Node node = XmlUtils.getNode(source, xPath, xpath); NamedNodeMap attr = node.getAttributes(); @@ -186,4 +200,12 @@ public static void assertAttributes(Object source, XPath xPath, String xpath, Ma assertThat(node.getNodeValue()).as(() -> entry.getKey() + " on " + xpath).isEqualTo(entry.getValue()); } } + + public static void assertIsPresent(Object source, XPath xPath, String xpath) throws XPathExpressionException { + assertThat(isPresent(source, xPath, xpath)).isTrue(); + } + + public static void assertIsNotPresent(Object source, XPath xPath, String xpath) throws XPathExpressionException { + assertThat(isPresent(source, xPath, xpath)).isFalse(); + } } diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java index 07c461dae..d80269729 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java @@ -19,6 +19,7 @@ package org.apache.rat.mp; import org.apache.commons.cli.Option; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.maven.plugin.MojoExecutionException; @@ -30,8 +31,10 @@ import org.apache.rat.ReportConfiguration; import org.apache.rat.plugin.BaseRatMojo; import org.codehaus.plexus.component.configurator.ComponentConfigurationException; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; @@ -41,7 +44,6 @@ import java.io.IOException; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystems; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -51,26 +53,34 @@ public class OptionMojoTest { - static final Path testPath = FileSystems.getDefault().getPath("target", "optionTest"); + + @TempDir + static Path testPath; + static String POM_FMT; @BeforeAll public static void makeDirs() throws IOException { - testPath.toFile().mkdirs(); POM_FMT = IOUtils.resourceToString("/optionTest/pom.tpl", StandardCharsets.UTF_8); } + @AfterAll + static void preserveData() { + AbstractOptionsProvider.preserveData(testPath.toFile(), "optionTest"); + } + @ParameterizedTest - @ArgumentsSource(OptionsProvider.class) - public void testOptionsUpdateConfig(String name, OptionCollectionTest.OptionTest test) { + @ArgumentsSource(MojoOptionsProvider.class) + void testOptionsUpdateConfig(String name, OptionCollectionTest.OptionTest test) { test.test(); } - public static class OptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { + static class MojoOptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { private RatCheckMojo mojo = null; - public OptionsProvider() { - super(BaseRatMojo.unsupportedArgs()); + + public MojoOptionsProvider() { + super(BaseRatMojo.unsupportedArgs(), testPath.toFile()); } private RatCheckMojo generateMojo(Pair... args) throws IOException { diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java index c104bf7ca..9b28a2582 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java @@ -16,17 +16,18 @@ */ package org.apache.rat.mp; +import static java.lang.String.format; import static java.nio.charset.StandardCharsets.UTF_8; import static org.apache.rat.mp.RatTestHelpers.ensureRatReportIsCorrect; -import static org.apache.rat.mp.RatTestHelpers.getSourceDirectory; -import static org.apache.rat.mp.RatTestHelpers.newArtifactFactory; -import static org.apache.rat.mp.RatTestHelpers.newArtifactRepository; -import static org.apache.rat.mp.RatTestHelpers.newSiteRenderer; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Fail.fail; import java.io.File; import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -44,70 +45,93 @@ import org.apache.rat.license.LicenseSetFactory; import org.apache.rat.license.LicenseSetFactory.LicenseFilter; import org.apache.rat.report.claim.ClaimStatistic; +import org.apache.rat.test.AbstractOptionsProvider; +import org.apache.rat.test.utils.Resources; import org.apache.rat.testhelpers.TextUtils; import org.apache.rat.testhelpers.XmlUtils; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NodeList; /** * Test case for the {@link RatCheckMojo} and {@link RatReportMojo}. */ -public class RatCheckMojoTest extends BetterAbstractMojoTestCase { - /** - * Creates a new instance of {@link RatCheckMojo}. - * - * @param pDir The directory, where to look for a pom.xml file. - * @return The configured Mojo. - * @throws Exception An error occurred while creating the Mojo. - */ - private RatCheckMojo newRatCheckMojo(String pDir) throws Exception { - Arg.reset(); - return (RatCheckMojo) newRatMojo(pDir, "check", false); +public class RatCheckMojoTest { //extends BetterAbstractMojoTestCase { + + @TempDir + static Path tempDir; + + private static XPath xPath = XPathFactory.newInstance().newXPath(); + + @AfterAll + static void preserveData() { + AbstractOptionsProvider.preserveData(tempDir.toFile(), "unit"); + } + + + private RatCheckMojo getMojo(File pomFile) throws IOException { + try { + final RatCheckMojo mojo = new OptionMojoTest.SimpleMojoTestcase() { + }.getMojo(pomFile); + Assertions.assertNotNull(mojo); + return mojo; + } catch (IOException e) { + throw e; + } catch (Exception e) { + throw new IOException(format("Unable to generate mojo for %s", pomFile), e); + } } /** * Creates a new instance of {@link AbstractRatMojo}. * - * @param pDir The directory, where to look for a pom.xml file. - * @param pGoal The goal, which the Mojo must implement. - * @param pCreateCopy if {@code true} copy the directory contents and return the + * @param testDir The directory, where to look for a pom.xml file. * copy location. * @return The configured Mojo. * @throws Exception An error occurred while creating the Mojo. */ - private AbstractRatMojo newRatMojo(String pDir, String pGoal, boolean pCreateCopy) throws Exception { - final File baseDir = new File(getBasedir()); - final File testBaseDir = getSourceDirectory(getBasedir(), pDir, pCreateCopy, baseDir); - final File testPom = new File(testBaseDir, "pom.xml"); - final File buildDirectory = new File(new File(baseDir, "target/test"), pDir); - AbstractRatMojo mojo = (AbstractRatMojo) lookupConfiguredMojo(testPom, pGoal); - assertNotNull(mojo); - - assertNotNull("The mojo is missing its MavenProject, which will result in an NPE during RAT runs.", - mojo.getProject()); - - if (mojo instanceof RatReportMojo) { - setVariableValueToObject(mojo, "localRepository", newArtifactRepository(getContainer())); - setVariableValueToObject(mojo, "factory", newArtifactFactory()); - setVariableValueToObject(mojo, "siteRenderer", newSiteRenderer(getContainer())); - } else if (mojo instanceof RatCheckMojo) { - final File ratTxtFile = new File(buildDirectory, "rat.txt"); - FileUtils.write(ratTxtFile, "", UTF_8); // Ensure the output file exists and is empty (rerunning the test will append) - mojo.setOutputFile(ratTxtFile.getAbsolutePath()); - } + private RatCheckMojo newRatMojo(String testDir) throws Exception { + Arg.reset(); + final File pomFile = Resources.getResourceFile(format("unit/%s/pom.xml", testDir)); + final File sourceDir = pomFile.getParentFile(); + final File baseDir = tempDir.resolve(testDir).toFile(); + FileUtils.copyDirectory(sourceDir, baseDir); + + RatCheckMojo mojo = getMojo(pomFile); + assertThat(mojo).isNotNull(); + assertThat(mojo.getProject()) + .as("The mojo is missing its MavenProject, which will result in an NPE during RAT runs.") + .isNotNull(); + +// if (mojo instanceof RatReportMojo) { +// setVariableValueToObject(mojo, "localRepository", newArtifactRepository(getContainer())); +// setVariableValueToObject(mojo, "factory", newArtifactFactory()); +// setVariableValueToObject(mojo, "siteRenderer", newSiteRenderer(getContainer())); +// } else if (mojo instanceof RatCheckMojo) { + File buildDirectory = new File(baseDir, "target"); + buildDirectory.mkdirs(); + final File ratTxtFile = new File(buildDirectory, "rat.txt"); + FileUtils.write(ratTxtFile, "", UTF_8); // Ensure the output file exists and is empty (rerunning the test will append) + mojo.setOutputFile(ratTxtFile.getAbsolutePath()); +// } return mojo; } private String getDir(RatCheckMojo mojo) { - return mojo.getProject().getBasedir().getAbsolutePath().replace("\\","/") + "/"; + return mojo.getProject().getBasedir().getAbsolutePath().replace("\\", "/") + "/"; } + /** * Runs a check, which should expose no problems. * * @throws Exception The test failed. */ - public void testIt1() throws Exception { - final RatCheckMojo mojo = newRatCheckMojo("it1"); + @Test + void it1() throws Exception { + final RatCheckMojo mojo = newRatMojo("it1"); final File ratTxtFile = mojo.getRatTxtFile(); ReportConfiguration config = mojo.getConfiguration(); @@ -127,7 +151,7 @@ public void testIt1() throws Exception { data.put(ClaimStatistic.Counter.UNAPPROVED, "0"); data.put(ClaimStatistic.Counter.UNKNOWN, "0"); - org.w3c.dom.Document document = XmlUtils.toDom(new FileInputStream(ratTxtFile)); + org.w3c.dom.Document document = XmlUtils.toDom(Files.newInputStream(ratTxtFile.toPath())); XPath xPath = XPathFactory.newInstance().newXPath(); for (ClaimStatistic.Counter counter : ClaimStatistic.Counter.values()) { @@ -146,8 +170,8 @@ public void testIt1() throws Exception { private static Map mapOf(String... parts) { Map map = new HashMap<>(); - for (int i=0; i mapOf(String... parts) { * * @throws Exception The test failed. */ - public void testIt2() throws Exception { - final RatCheckMojo mojo = newRatCheckMojo("it2"); + @Test + void it2() throws Exception { + final RatCheckMojo mojo = newRatMojo("it2"); final File ratTxtFile = mojo.getRatTxtFile(); final String[] expected = { "^Files with unapproved licenses\\s+\\*+\\s+\\Q/src.txt\\E\\s+", @@ -170,17 +195,19 @@ public void testIt2() throws Exception { ReporterTestUtils.apacheLicenseVersion2(1), ReporterTestUtils.unknownLicense(1), ReporterTestUtils.documentOut(false, Document.Type.STANDARD, "/src.txt") + - ReporterTestUtils.UNKNOWN_LICENSE, + ReporterTestUtils.UNKNOWN_LICENSE, ReporterTestUtils.documentOut(true, Document.Type.STANDARD, "/pom.xml") + - ReporterTestUtils.APACHE_LICENSE - }; + ReporterTestUtils.APACHE_LICENSE + }; try { mojo.execute(); fail("Expected RatCheckException"); } catch (RatCheckException e) { final String msg = e.getMessage(); - assertTrue("report filename was not contained in '" + msg + "'", msg.contains(ratTxtFile.getName())); - assertFalse("no null allowed in '" + msg + "'", (msg.toUpperCase().contains("NULL"))); + assertThat(msg.contains(ratTxtFile.getName())).as(() -> format("report filename was not contained in '%s'", msg)) + .isTrue(); + assertThat(msg.toUpperCase()).contains("UNAPPROVED EXCEEDED MINIMUM"); + ensureRatReportIsCorrect(ratTxtFile, expected, TextUtils.EMPTY); } } @@ -188,8 +215,9 @@ public void testIt2() throws Exception { /** * Tests adding license headers. */ - public void testIt3() throws Exception { - final RatCheckMojo mojo = (RatCheckMojo) newRatMojo("it3", "check", true); + @Test + void it3() throws Exception { + final RatCheckMojo mojo = newRatMojo("it3"); final File ratTxtFile = mojo.getRatTxtFile(); final String[] expected = { "^Files with unapproved licenses\\s+\\*+\\s+\\Q/src.apt\\E\\s+", @@ -201,37 +229,58 @@ public void testIt3() throws Exception { ReporterTestUtils.apacheLicenseVersion2(1), ReporterTestUtils.unknownLicense(1), ReporterTestUtils.documentOut(false, Document.Type.STANDARD, "/src.apt") + - ReporterTestUtils.UNKNOWN_LICENSE, + ReporterTestUtils.UNKNOWN_LICENSE, ReporterTestUtils.documentOut(true, Document.Type.STANDARD, "/pom.xml") + - ReporterTestUtils.APACHE_LICENSE + ReporterTestUtils.APACHE_LICENSE }; ReportConfiguration config = mojo.getConfiguration(); - assertTrue("should be adding licenses", config.isAddingLicenses()); - + assertThat(config.isAddingLicenses()).as("should be adding licenses").isTrue(); mojo.execute(); - - ensureRatReportIsCorrect(ratTxtFile, expected, TextUtils.EMPTY); + org.w3c.dom.Document document = XmlUtils.toDom(Files.newInputStream(ratTxtFile.toPath())); + + XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/pom.xml']", "type", + "STANDARD"); + XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/src.apt']", "type", + "STANDARD"); + XmlUtils.assertIsPresent(document, xPath, "/rat-report/resource[@name='/src.apt']/license[@approval='false']"); + + XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/src.apt']", "type", + "STANDARD"); + XmlUtils.assertIsPresent(document, xPath, "/rat-report/resource[@name='/src.apt.new']/license[@approval='true']"); + + XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='STANDARD']", "count", + "3"); + + for (Document.Type type : Document.Type.values()) { + if (type == Document.Type.STANDARD) { + XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='STANDARD']", "count", + "3"); + } else { + XmlUtils.assertIsNotPresent(document, xPath, format("/rat-report/statistics/documentType[@name='%s']", type)); + } + } } /** * Tests defining licenses in configuration */ - public void testIt5() throws Exception { - final RatCheckMojo mojo = (RatCheckMojo) newRatMojo("it5", "check", true); + @Test + void it5() throws Exception { + final RatCheckMojo mojo = newRatMojo("it5"); final File ratTxtFile = mojo.getRatTxtFile(); ReportConfiguration config = mojo.getConfiguration(); - assertFalse("Should not be adding licenses", config.isAddingLicenses()); - assertFalse("Should not be forcing licenses", config.isAddingLicensesForced()); + assertThat(config.isAddingLicenses()).as("Should not be adding licenses").isFalse(); + assertThat(config.isAddingLicensesForced()).as("Should not be forcing licenses").isFalse(); ReportConfigurationTest.validateDefaultApprovedLicenses(config); - assertFalse(config.getLicenseCategories(LicenseFilter.APPROVED).contains(ILicenseFamily.makeCategory("YAL"))); + assertThat(config.getLicenseCategories(LicenseFilter.APPROVED)).doesNotContain(ILicenseFamily.makeCategory("YAL")); ReportConfigurationTest.validateDefaultLicenseFamilies(config, "YAL"); - assertNotNull(LicenseSetFactory.familySearch("YAL", config.getLicenseFamilies(LicenseFilter.ALL))); + assertThat(LicenseSetFactory.familySearch("YAL", config.getLicenseFamilies(LicenseFilter.ALL))).isNotNull(); ReportConfigurationTest.validateDefaultLicenses(config, "MyLicense", "CpyrT", "RegxT", "SpdxT", "TextT", "Not", "All", "Any"); - assertTrue(LicenseSetFactory.search("YAL", "MyLicense", config.getLicenses(LicenseFilter.ALL)).isPresent()); + assertThat(LicenseSetFactory.search("YAL", "MyLicense", config.getLicenses(LicenseFilter.ALL))).isPresent(); try { mojo.execute(); fail("Should have thrown exception"); @@ -279,14 +328,15 @@ public void testIt5() throws Exception { XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/pom.xml']/license[@id='TextT']", mapOf("approval", "false", "family", "YAL ", "name", "Text with tag")); } - + /** * Runs a check, which should expose no problems. * * @throws Exception The test failed. */ - public void testRAT_343() throws Exception { - final RatCheckMojo mojo = newRatCheckMojo("RAT-343"); + @Test + void rat343() throws Exception { + final RatCheckMojo mojo = newRatMojo("RAT-343"); final File ratTxtFile = mojo.getRatTxtFile(); // POM reports AL, BSD and CC BYas BSD because it contains the BSD and CC BY strings final String[] expected = { @@ -313,7 +363,7 @@ public void testRAT_343() throws Exception { assertThat(config.isAddingLicensesForced()).isFalse(); assertThat(config.getCopyrightMessage()).isNull(); assertThat(config.getStyleSheet()).withFailMessage("Stylesheet should not be null").isNotNull(); - + ReportConfigurationTest.validateDefaultApprovedLicenses(config, 1); ReportConfigurationTest.validateDefaultLicenseFamilies(config, "BSD", "CC BY"); ReportConfigurationTest.validateDefaultLicenses(config, "BSD", "CC BY"); @@ -325,37 +375,20 @@ public void testRAT_343() throws Exception { /** * Tests verifying gitignore parsing */ - public void /*test*/RAT_335GitIgnoreParsing() throws Exception { - final RatCheckMojo mojo = newRatCheckMojo("RAT-335-GitIgnore"); + @Test + void rat335() throws Exception { + final RatCheckMojo mojo = newRatMojo("RAT-335"); final File ratTxtFile = mojo.getRatTxtFile(); -// final String[] expected = { -// ReporterTestUtils.counterText(ClaimStatistic.Counter.NOTICES, 1, false), -// ReporterTestUtils.counterText(ClaimStatistic.Counter.BINARIES, 0, false), -// ReporterTestUtils.counterText(ClaimStatistic.Counter.ARCHIVES, 0, false), -// ReporterTestUtils.counterText(ClaimStatistic.Counter.STANDARDS, 6, false), -// ReporterTestUtils.counterText(ClaimStatistic.Counter.IGNORED, 0, false), -// ReporterTestUtils.counterText(ClaimStatistic.Counter.UNKNOWN, 4, false), -// ReporterTestUtils.apacheLicenseVersion2(2), -// ReporterTestUtils.unknownLicense(4), -// ReporterTestUtils.documentOut(true, Document.Type.STANDARD, "/pom.xml") + -// ReporterTestUtils.APACHE_LICENSE, -// ReporterTestUtils.documentOut(false, Document.Type.STANDARD, "/dir1/dir1.md") + -// ReporterTestUtils.UNKNOWN_LICENSE, -// ReporterTestUtils.documentOut(false, Document.Type.STANDARD, "/dir2/dir2.txt") + -// ReporterTestUtils.UNKNOWN_LICENSE, -// ReporterTestUtils.documentOut(false, Document.Type.STANDARD, "/dir3/file3.log") + -// ReporterTestUtils.UNKNOWN_LICENSE, -// }; try { mojo.execute(); fail("Expected RatCheckException"); } catch (RatCheckException e) { final String msg = e.getMessage(); - assertTrue("report filename was not contained in '" + msg + "'", msg.contains(ratTxtFile.getName())); - assertFalse("no null allowed in '" + msg + "'", (msg.toUpperCase().contains("NULL"))); + assertThat(msg).contains(ratTxtFile.getName()); + assertThat(msg).contains("UNAPPROVED exceeded minimum"); Map data = new HashMap<>(); - data.put(ClaimStatistic.Counter.APPROVED, "2"); + data.put(ClaimStatistic.Counter.APPROVED, "1"); data.put(ClaimStatistic.Counter.ARCHIVES, "0"); data.put(ClaimStatistic.Counter.BINARIES, "0"); data.put(ClaimStatistic.Counter.DOCUMENT_TYPES, "3"); @@ -363,12 +396,11 @@ public void testRAT_343() throws Exception { data.put(ClaimStatistic.Counter.LICENSE_CATEGORIES, "2"); data.put(ClaimStatistic.Counter.LICENSE_NAMES, "2"); data.put(ClaimStatistic.Counter.NOTICES, "1"); - data.put(ClaimStatistic.Counter.STANDARDS, "6"); + data.put(ClaimStatistic.Counter.STANDARDS, "5"); data.put(ClaimStatistic.Counter.UNAPPROVED, "4"); data.put(ClaimStatistic.Counter.UNKNOWN, "4"); - org.w3c.dom.Document document = XmlUtils.toDom(new FileInputStream(ratTxtFile)); - XPath xPath = XPathFactory.newInstance().newXPath(); + org.w3c.dom.Document document = XmlUtils.toDom(Files.newInputStream(ratTxtFile.toPath())); for (ClaimStatistic.Counter counter : ClaimStatistic.Counter.values()) { String xpath = String.format("/rat-report/statistics/statistic[@name='%s']", counter.displayName()); @@ -381,31 +413,30 @@ public void testRAT_343() throws Exception { // license categories XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseCategory[@name='?????']", - mapOf("count", "4" )); + mapOf("count", "4")); XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseCategory[@name='AL ']", - mapOf("count", "2" )); + mapOf("count", "1")); // license names XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseName[@name='Apache License Version 2.0']", - mapOf("count", "2" )); + mapOf("count", "1")); XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseName[@name='Unknown license']", - mapOf("count", "4" )); + mapOf("count", "4")); // Document types XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='IGNORED']", - mapOf("count", "6" )); + mapOf("count", "6")); XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='NOTICE']", - mapOf("count", "1" )); + mapOf("count", "1")); XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='STANDARD']", - mapOf("count", "6" )); + mapOf("count", "5")); List ignoredFiles = new ArrayList<>(Arrays.asList( "/dir1/dir1.txt", - "/dir1/file1.log", "/dir1/.gitignore", "/dir2/dir2.md", "/dir3/dir3.log", @@ -413,7 +444,7 @@ public void testRAT_343() throws Exception { "/root.md")); NodeList nodeList = XmlUtils.getNodeList(document, xPath, "/rat-report/resource[@type='IGNORED']"); - for (int i=0;i< nodeList.getLength(); i++) { + for (int i = 0; i < nodeList.getLength(); i++) { NamedNodeMap attr = nodeList.item(i).getAttributes(); String s = attr.getNamedItem("name").getNodeValue(); assertThat(ignoredFiles).contains(s); @@ -430,62 +461,45 @@ public void testRAT_343() throws Exception { * So for this test we must create such a file which is specific for the current * working directory. */ - public void /*test*/RAT362GitIgnore() throws Exception { - final RatCheckMojo mojo = newRatCheckMojo("RAT-362-GitIgnore"); + @Test + void rat362() throws Exception { + final RatCheckMojo mojo = newRatMojo("RAT-362"); final File ratTxtFile = mojo.getRatTxtFile(); - final String dirStr = getDir(mojo); - - if (dirStr.contains(":")) { - // The problem this is testing for cannot happen if there is - // a Windows drive letter in the name of the directory. - // Any duplication of a ':' will make it all fail always. - // So there is no point in continuing this test. - return; - } - File dir = new File(dirStr); - - // Make the target directory for the test file - assertTrue(dir.isDirectory()); - - // Create the test file with a content on which it must fail - File barFile = new File(dir, "bar.md"); - assertThat(barFile).exists(); - final String[] expected = { - ReporterTestUtils.counterText(ClaimStatistic.Counter.NOTICES, 0, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.BINARIES, 0, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.ARCHIVES, 0, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.STANDARDS, 3, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.IGNORED, 0, false), - ReporterTestUtils.apacheLicenseVersion2(2), - ReporterTestUtils.unknownLicense(1), - ReporterTestUtils.documentOut(false, Document.Type.STANDARD, "/bar.md") + - ReporterTestUtils.UNKNOWN_LICENSE - }; try { mojo.execute(); - fail("Expected RatCheckException: This check should have failed on the invalid test file"); + fail("Expected RatCheckException"); } catch (RatCheckException e) { final String msg = e.getMessage(); - assertTrue("report filename was not contained in '" + msg + "'", msg.contains(ratTxtFile.getName())); - assertFalse("no null allowed in '" + msg + "'", (msg.toUpperCase().contains("NULL"))); - ensureRatReportIsCorrect(ratTxtFile, expected, TextUtils.EMPTY); + assertThat(msg).contains(ratTxtFile.getName()); + assertThat(msg).contains("UNAPPROVED exceeded minimum"); + + org.w3c.dom.Document document = XmlUtils.toDom(Files.newInputStream(ratTxtFile.toPath())); + // Document types + XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='IGNORED']", + "count", "2"); + + XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/bar.md']", + "type", "STANDARD"); + XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/foo.md']", + "type", "IGNORED"); } } /** - * Tests implicit excludes apply to submodules too - */ - public void testRAT_107() throws Exception { - final RatCheckMojo mojo = (RatCheckMojo) newRatMojo("RAT-107", "check", true); - final File ratTxtFile = mojo.getRatTxtFile(); - final String[] expected = {}; - final String[] notExpected = {}; - setVariableValueToObject(mojo, "excludeSubProjects", Boolean.FALSE); - mojo.setInputExcludeParsedScm("MAVEN"); - mojo.setInputExcludeParsedScm("idea"); - mojo.setInputExcludeParsedScm("eclipse"); - mojo.execute(); - - ensureRatReportIsCorrect(ratTxtFile, expected, notExpected); - } + * Tests implicit excludes apply to submodules too + */ + @Test + void rat107() throws Exception { + final RatCheckMojo mojo = newRatMojo("RAT-107"); + final File ratTxtFile = mojo.getRatTxtFile(); + final String[] expected = {}; + final String[] notExpected = {}; + //setVariableValueToObject(mojo, "excludeSubProjects", Boolean.FALSE); + mojo.setInputExcludeParsedScm("MAVEN"); + mojo.setInputExcludeParsedScm("idea"); + mojo.setInputExcludeParsedScm("eclipse"); + mojo.execute(); + + ensureRatReportIsCorrect(ratTxtFile, expected, notExpected); + } } diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/.gitignore b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/.gitignore deleted file mode 100644 index 8855fa805..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -*.md - -# This makes it ignore dir3/dir3.log and dir3/file3.log -*.log - -# This makes it "unignore" dir3/file3.log -!file*.log diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/.gitignore b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/.gitignore deleted file mode 100644 index 26fd5c956..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.txt -!dir1.md -file1.log \ No newline at end of file diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.txt b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.txt deleted file mode 100644 index a31cbc897..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.txt +++ /dev/null @@ -1 +0,0 @@ -File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/file1.log b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/file1.log deleted file mode 100644 index a31cbc897..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/file1.log +++ /dev/null @@ -1 +0,0 @@ -File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.md b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.md deleted file mode 100644 index a31cbc897..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.md +++ /dev/null @@ -1 +0,0 @@ -File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/dir3.log b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/dir3.log deleted file mode 100644 index a31cbc897..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/dir3.log +++ /dev/null @@ -1 +0,0 @@ -File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/invoker.properties b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/invoker.properties deleted file mode 100644 index 6e8c3479e..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/invoker.properties +++ /dev/null @@ -1,16 +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. - -invoker.goals = clean apache-rat:check diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/root.md b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/root.md deleted file mode 100644 index a31cbc897..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/root.md +++ /dev/null @@ -1 +0,0 @@ -File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/README.txt b/apache-rat-plugin/src/test/resources/unit/RAT-335/README.txt similarity index 100% rename from apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/README.txt rename to apache-rat-plugin/src/test/resources/unit/RAT-335/README.txt diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.md b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/dir1.md similarity index 100% rename from apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.md rename to apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/dir1.md diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.txt b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir2/dir2.txt similarity index 100% rename from apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.txt rename to apache-rat-plugin/src/test/resources/unit/RAT-335/dir2/dir2.txt diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/file3.log b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir3/file3.log similarity index 100% rename from apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/file3.log rename to apache-rat-plugin/src/test/resources/unit/RAT-335/dir3/file3.log diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/pom.xml b/apache-rat-plugin/src/test/resources/unit/RAT-335/pom.xml similarity index 100% rename from apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/pom.xml rename to apache-rat-plugin/src/test/resources/unit/RAT-335/pom.xml diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/.gitignore b/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/.gitignore deleted file mode 100644 index 4912996bc..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/foo.md -target \ No newline at end of file diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/foo.md b/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/foo.md deleted file mode 100644 index a31cbc897..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/foo.md +++ /dev/null @@ -1 +0,0 @@ -File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/invoker.properties b/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/invoker.properties deleted file mode 100644 index 6e8c3479e..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/invoker.properties +++ /dev/null @@ -1,16 +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. - -invoker.goals = clean apache-rat:check diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/bar.md b/apache-rat-plugin/src/test/resources/unit/RAT-362/bar.md similarity index 100% rename from apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/bar.md rename to apache-rat-plugin/src/test/resources/unit/RAT-362/bar.md diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/pom.xml b/apache-rat-plugin/src/test/resources/unit/RAT-362/pom.xml similarity index 97% rename from apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/pom.xml rename to apache-rat-plugin/src/test/resources/unit/RAT-362/pom.xml index 71669aa32..af34ad819 100644 --- a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/pom.xml +++ b/apache-rat-plugin/src/test/resources/unit/RAT-362/pom.xml @@ -27,6 +27,7 @@ apache-rat-plugin @pom.version@ + xml **/.gitignore diff --git a/apache-rat-plugin/src/test/resources/unit/it3/pom.xml b/apache-rat-plugin/src/test/resources/unit/it3/pom.xml index f6982e399..1188a2d28 100644 --- a/apache-rat-plugin/src/test/resources/unit/it3/pom.xml +++ b/apache-rat-plugin/src/test/resources/unit/it3/pom.xml @@ -29,6 +29,7 @@ 1 true + xml diff --git a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java index 6b2432c0b..1ba32129e 100644 --- a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java +++ b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java @@ -16,6 +16,7 @@ */ package org.apache.rat.anttasks; +import java.nio.file.Path; import org.apache.commons.cli.Option; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; @@ -25,7 +26,9 @@ import org.apache.rat.testhelpers.TestingLog; import org.apache.rat.utils.DefaultLog; import org.apache.rat.utils.Log; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; @@ -43,17 +46,18 @@ * Tests to ensure the option setting works correctly. */ public class ReportOptionTest { - // devhint: we do want to keep data in case of test failures, thus do not use TempDir here - static final File baseDir = new File("target/optionTest"); + @TempDir + static Path testPath; + static ReportConfiguration reportConfiguration; - @BeforeAll - public static void makeDirs() { - baseDir.mkdirs(); + @AfterAll + static void preserveData() { + AbstractOptionsProvider.preserveData(testPath.toFile(), "optionTest"); } @ParameterizedTest - @ArgumentsSource(OptionsProvider.class) + @ArgumentsSource(AntOptionsProvider.class) public void testOptionsUpdateConfig(String name, OptionCollectionTest.OptionTest test) { test.test(); } @@ -68,15 +72,16 @@ public void execute() { } } - static class OptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { + final class AntOptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { final AtomicBoolean helpCalled = new AtomicBoolean(false); - public OptionsProvider() { - super(BaseAntTask.unsupportedArgs()); + public AntOptionsProvider() { + super(BaseAntTask.unsupportedArgs(), testPath.toFile()); } - protected ReportConfiguration generateConfig(Pair... args) { + @SafeVarargs + protected final ReportConfiguration generateConfig(Pair... args) { BuildTask task = args[0].getKey() == null ? new BuildTask() : new BuildTask(args[0].getKey()); task.setUp(args); task.buildRule.executeTarget(task.name); @@ -118,7 +123,8 @@ private class BuildTask extends AbstractRatAntTaskTest { antFile = new File(baseDir, name + ".xml"); } - public void setUp(Pair... args) { + @SafeVarargs + public final void setUp(Pair... args) { StringBuilder childElements = new StringBuilder(); StringBuilder attributes = new StringBuilder(); if (args[0].getKey() != null) { From 53be57e82489905e1a86ac1a037ea3c867780ea2 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Thu, 26 Dec 2024 00:10:58 +0000 Subject: [PATCH 010/123] fixed and cleaned up plugin tests --- apache-rat-plugin/src/test/resources/unit/RAT-362/.gitignore | 2 ++ apache-rat-plugin/src/test/resources/unit/RAT-362/foo.md | 1 + 2 files changed, 3 insertions(+) create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-362/.gitignore create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-362/foo.md diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-362/.gitignore b/apache-rat-plugin/src/test/resources/unit/RAT-362/.gitignore new file mode 100644 index 000000000..4912996bc --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-362/.gitignore @@ -0,0 +1,2 @@ +/foo.md +target \ No newline at end of file diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-362/foo.md b/apache-rat-plugin/src/test/resources/unit/RAT-362/foo.md new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-362/foo.md @@ -0,0 +1 @@ +File without a valid license From eba23cb40bdfcf7bfc28711a2f99bc3d9b18e6f5 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Thu, 26 Dec 2024 00:12:05 +0000 Subject: [PATCH 011/123] fixed and cleaned up plugin tests --- .../src/test/resources/unit/RAT-335/.gitignore | 7 +++++++ .../src/test/resources/unit/RAT-335/dir1/.gitignore | 3 +++ .../src/test/resources/unit/RAT-335/dir1/dir1.txt | 1 + .../src/test/resources/unit/RAT-335/dir1/file1.log | 1 + .../src/test/resources/unit/RAT-335/dir2/dir2.md | 1 + .../src/test/resources/unit/RAT-335/dir3/dir3.log | 1 + apache-rat-plugin/src/test/resources/unit/RAT-335/root.md | 1 + 7 files changed, 15 insertions(+) create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335/.gitignore create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/.gitignore create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/dir1.txt create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/file1.log create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335/dir2/dir2.md create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335/dir3/dir3.log create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335/root.md diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335/.gitignore b/apache-rat-plugin/src/test/resources/unit/RAT-335/.gitignore new file mode 100644 index 000000000..8855fa805 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-335/.gitignore @@ -0,0 +1,7 @@ +*.md + +# This makes it ignore dir3/dir3.log and dir3/file3.log +*.log + +# This makes it "unignore" dir3/file3.log +!file*.log diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/.gitignore b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/.gitignore new file mode 100644 index 000000000..26fd5c956 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/.gitignore @@ -0,0 +1,3 @@ +*.txt +!dir1.md +file1.log \ No newline at end of file diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/dir1.txt b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/dir1.txt new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/dir1.txt @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/file1.log b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/file1.log new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/file1.log @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335/dir2/dir2.md b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir2/dir2.md new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir2/dir2.md @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335/dir3/dir3.log b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir3/dir3.log new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir3/dir3.log @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335/root.md b/apache-rat-plugin/src/test/resources/unit/RAT-335/root.md new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-335/root.md @@ -0,0 +1 @@ +File without a valid license From b6a5ce261c5f104fff704112eb8571b3c5df7097 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Thu, 26 Dec 2024 00:14:37 +0000 Subject: [PATCH 012/123] fixed and cleaned up plugin tests --- .../test/resources/unit/RAT-107/.classpath | 1 + .../src/test/resources/unit/RAT-107/.project | 1 + .../resources/unit/RAT-107/.settings/dummy | 0 .../src/test/resources/unit/RAT-107/dummy.ipr | 1 + .../unit/RAT-107/submodule/.classpath | 1 + .../resources/unit/RAT-107/submodule/.project | 1 + .../unit/RAT-107/submodule/.settings/dummy | 0 .../unit/RAT-107/submodule/dummy.iml | 1 + .../unit/RAT-107/submodule/dummy.ipr | 1 + .../unit/RAT-107/submodule/dummy.iws | 1 + .../src/test/resources/unit/it5/.bzrignore | 5 - .../src/test/resources/unit/it5/pom.xml | 97 ------------------- 12 files changed, 8 insertions(+), 102 deletions(-) create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/.classpath create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/.project create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/.settings/dummy create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/dummy.ipr create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.classpath create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.project create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.settings/dummy create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.iml create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.ipr create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.iws delete mode 100644 apache-rat-plugin/src/test/resources/unit/it5/.bzrignore delete mode 100644 apache-rat-plugin/src/test/resources/unit/it5/pom.xml diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/.classpath b/apache-rat-plugin/src/test/resources/unit/RAT-107/.classpath new file mode 100644 index 000000000..b77e339f2 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-107/.classpath @@ -0,0 +1 @@ +This file intentionally has no Apache License Header. diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/.project b/apache-rat-plugin/src/test/resources/unit/RAT-107/.project new file mode 100644 index 000000000..b77e339f2 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-107/.project @@ -0,0 +1 @@ +This file intentionally has no Apache License Header. diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/.settings/dummy b/apache-rat-plugin/src/test/resources/unit/RAT-107/.settings/dummy new file mode 100644 index 000000000..e69de29bb diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/dummy.ipr b/apache-rat-plugin/src/test/resources/unit/RAT-107/dummy.ipr new file mode 100644 index 000000000..b77e339f2 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-107/dummy.ipr @@ -0,0 +1 @@ +This file intentionally has no Apache License Header. diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.classpath b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.classpath new file mode 100644 index 000000000..b77e339f2 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.classpath @@ -0,0 +1 @@ +This file intentionally has no Apache License Header. diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.project b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.project new file mode 100644 index 000000000..b77e339f2 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.project @@ -0,0 +1 @@ +This file intentionally has no Apache License Header. diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.settings/dummy b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.settings/dummy new file mode 100644 index 000000000..e69de29bb diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.iml b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.iml new file mode 100644 index 000000000..b77e339f2 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.iml @@ -0,0 +1 @@ +This file intentionally has no Apache License Header. diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.ipr b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.ipr new file mode 100644 index 000000000..b77e339f2 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.ipr @@ -0,0 +1 @@ +This file intentionally has no Apache License Header. diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.iws b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.iws new file mode 100644 index 000000000..b77e339f2 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.iws @@ -0,0 +1 @@ +This file intentionally has no Apache License Header. diff --git a/apache-rat-plugin/src/test/resources/unit/it5/.bzrignore b/apache-rat-plugin/src/test/resources/unit/it5/.bzrignore deleted file mode 100644 index f59acc081..000000000 --- a/apache-rat-plugin/src/test/resources/unit/it5/.bzrignore +++ /dev/null @@ -1,5 +0,0 @@ -## RAT-171: Add rubbish and ensure that the plugin behaves properly -DoesNotExistAtALL/** -*\IllegalStuffNotExisting -Lets-See*+?!OrWhat -\\nDoesThatWorkAsWell\/ diff --git a/apache-rat-plugin/src/test/resources/unit/it5/pom.xml b/apache-rat-plugin/src/test/resources/unit/it5/pom.xml deleted file mode 100644 index 9cb1327b1..000000000 --- a/apache-rat-plugin/src/test/resources/unit/it5/pom.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - 4.0.0 - org.codehaus.mojo.rat.test - it1 - 1.0 - - - - org.apache.rat - apache-rat-plugin - @pom.version@ - - xml - - - YAL - Yet another license - - - YAL - - - MyLicense - YAL - Yet Another License - - - YAL - CpyrT - Copyright with tags - - - 1990 - 1991 - foo - - - - YAL - RegxT - Regex with tag - - regex tag - - - YAL - SpdxT - Spdx with tag - - spxd-tag - - - YAL - TextT - Text with tag - - text-tag - - - YAL - Not - Not testing - - - not test text - - - - YAL - All - All testing - - - all test text - all spdx text - - - - YAL - Any - Any testing - - - any test text - any spdx text - - - - - src.apt - - - - - - From ab8e00aa827f760478c97d3d9c1bbfe3cabecd17 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Fri, 27 Dec 2024 00:28:03 +0000 Subject: [PATCH 013/123] updated and fixed plugin tests --- .../resources/ReportTest/RAT_14/verify.groovy | 2 +- .../java/org/apache/rat/OptionCollection.java | 34 ++-- .../src/main/java/org/apache/rat/Report.java | 4 +- .../java/org/apache/rat/commandline/Arg.java | 27 +-- .../rat/commandline/ArgumentContext.java | 41 ++++- .../config/exclusion/ExclusionProcessor.java | 2 + .../rat/config/exclusion/ExclusionUtils.java | 17 +- .../rat/config/exclusion/MatcherSet.java | 3 + .../configuration/XMLConfigurationReader.java | 162 +++++++++++------- .../rat/document/DocumentNameMatcher.java | 49 ++++++ .../rat/report/xml/writer/XmlWriter.java | 4 +- .../main/java/org/apache/rat/utils/Log.java | 14 +- .../org/apache/rat/OptionCollectionTest.java | 19 +- .../java/org/apache/rat/ReporterTest.java | 17 +- .../org/apache/rat/commandline/ArgTests.java | 2 +- .../fileProcessors/GitIgnoreBuilderTest.java | 7 +- .../rat/document/DocumentNameMatcherTest.java | 43 ----- .../rat/test/AbstractOptionsProvider.java | 23 ++- .../org/apache/rat/testhelpers/XmlUtils.java | 4 +- apache-rat-plugin/.gitignore | 1 + apache-rat-plugin/pom.xml | 14 +- .../it/CustomLicense/.rat/customConfig.xml | 17 ++ .../src/it/CustomLicense/invoker.properties | 2 +- .../src/it/CustomLicense/pom.xml | 28 +-- apache-rat-plugin/src/it/RAT-268/pom.xml | 10 +- .../org/apache/rat/mp/AbstractRatMojo.java | 21 ++- .../org/apache/rat/mp/OptionMojoTest.java | 70 +------- .../org/apache/rat/mp/RatCheckMojoTest.java | 104 +++++------ .../resources/unit/it5/.rat/customConfig.xml | 23 +++ .../src/test/resources/unit/it5/pom.xml | 41 +++++ .../java/nl/basjes/something/Something.java | 26 +++ .../apache/rat/anttasks/ReportOptionTest.java | 12 +- .../org/apache/rat/tools/Documentation.java | 3 +- 33 files changed, 507 insertions(+), 339 deletions(-) create mode 100644 apache-rat-plugin/src/it/CustomLicense/.rat/customConfig.xml create mode 100644 apache-rat-plugin/src/test/resources/unit/it5/.rat/customConfig.xml create mode 100644 apache-rat-plugin/src/test/resources/unit/it5/pom.xml create mode 100644 apache-rat-plugin/src/test/resources/unit/it5/src/main/java/nl/basjes/something/Something.java diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_14/verify.groovy b/apache-rat-core/src/it/resources/ReportTest/RAT_14/verify.groovy index 431b0b046..226394df0 100644 --- a/apache-rat-core/src/it/resources/ReportTest/RAT_14/verify.groovy +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_14/verify.groovy @@ -64,7 +64,7 @@ myArgs[1] = "UNAPPROVED:-1" myArgs[2] = "--" myArgs[3] = src.getAbsolutePath() -ReportConfiguration configuration = OptionCollection.parseCommands(myArgs, { opts -> }) +ReportConfiguration configuration = OptionCollection.parseCommands(src, myArgs, { opts -> }) assertNotNull(configuration) configuration.validate(DefaultLog.getInstance().&error) Reporter reporter = new Reporter(configuration) diff --git a/apache-rat-core/src/main/java/org/apache/rat/OptionCollection.java b/apache-rat-core/src/main/java/org/apache/rat/OptionCollection.java index dca321c9c..7dc33fd88 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/OptionCollection.java +++ b/apache-rat-core/src/main/java/org/apache/rat/OptionCollection.java @@ -132,25 +132,28 @@ private static String asString(final Object[] args) { /** * Parses the standard options to create a ReportConfiguration. * + * @param workingDirectory The directory to resolve relative file names against. * @param args the arguments to parse * @param helpCmd the help command to run when necessary. * @return a ReportConfiguration or null if Help was printed. * @throws IOException on error. */ - public static ReportConfiguration parseCommands(final String[] args, final Consumer helpCmd) throws IOException { - return parseCommands(args, helpCmd, false); + public static ReportConfiguration parseCommands(final File workingDirectory, final String[] args, final Consumer helpCmd) throws IOException { + return parseCommands(workingDirectory, args, helpCmd, false); } /** * Parses the standard options to create a ReportConfiguration. * + * @param workingDirectory The directory to resolve relative file names against. * @param args the arguments to parse * @param helpCmd the help command to run when necessary. * @param noArgs If true then the commands do not need extra arguments * @return a ReportConfiguration or {@code null} if Help was printed. * @throws IOException on error. */ - public static ReportConfiguration parseCommands(final String[] args, final Consumer helpCmd, final boolean noArgs) throws IOException { + public static ReportConfiguration parseCommands(final File workingDirectory, final String[] args, + final Consumer helpCmd, final boolean noArgs) throws IOException { Options opts = buildOptions(); CommandLine commandLine; try { @@ -166,27 +169,23 @@ public static ReportConfiguration parseCommands(final String[] args, final Consu Arg.processLogLevel(commandLine); + ArgumentContext argumentContext = new ArgumentContext(workingDirectory, commandLine); if (commandLine.hasOption(HELP)) { helpCmd.accept(opts); return null; } if (commandLine.hasOption(HELP_LICENSES)) { - new Licenses(createConfiguration(commandLine), new PrintWriter(System.out)).printHelp(); - return null; - } - - if (commandLine.hasOption(HELP_LICENSES)) { - new Licenses(createConfiguration(commandLine), new PrintWriter(System.out)).printHelp(); + new Licenses(createConfiguration(argumentContext), new PrintWriter(System.out)).printHelp(); return null; } if (commandLine.hasOption(Arg.HELP_LICENSES.option())) { - new Licenses(createConfiguration(commandLine), new PrintWriter(System.out)).printHelp(); + new Licenses(createConfiguration(argumentContext), new PrintWriter(System.out)).printHelp(); return null; } - ReportConfiguration configuration = createConfiguration(commandLine); + ReportConfiguration configuration = createConfiguration(argumentContext); if (!noArgs && !configuration.hasSource()) { String msg = "No directories or files specified for scanning. Did you forget to close a multi-argument option?"; DefaultLog.getInstance().error(msg); @@ -201,14 +200,15 @@ public static ReportConfiguration parseCommands(final String[] args, final Consu * Create the report configuration. * Note: this method is package private for testing. * You probably want one of the {@code ParseCommands} methods. - * @param commandLine the parsed command line. + * @param argumentContext The context to execute in. * @return a ReportConfiguration - * @see #parseCommands(String[], Consumer) - * @see #parseCommands(String[], Consumer, boolean) + * @see #parseCommands(File, String[], Consumer) + * @see #parseCommands(File, String[], Consumer, boolean) */ - static ReportConfiguration createConfiguration(final CommandLine commandLine) { - final ReportConfiguration configuration = new ReportConfiguration(); - new ArgumentContext(configuration, commandLine).processArgs(); + static ReportConfiguration createConfiguration(final ArgumentContext argumentContext) { + argumentContext.processArgs(); + final ReportConfiguration configuration = argumentContext.getConfiguration(); + final CommandLine commandLine = argumentContext.getCommandLine(); if (Arg.DIR.isSelected()) { try { configuration.addSource(getReportable(commandLine.getParsedOptionValue(Arg.DIR.getSelected()), configuration)); diff --git a/apache-rat-core/src/main/java/org/apache/rat/Report.java b/apache-rat-core/src/main/java/org/apache/rat/Report.java index 6a7847e5b..ff4103c4c 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/Report.java +++ b/apache-rat-core/src/main/java/org/apache/rat/Report.java @@ -18,6 +18,8 @@ */ package org.apache.rat; +import java.io.File; + import org.apache.commons.cli.Options; import org.apache.rat.document.RatDocumentAnalysisException; import org.apache.rat.help.Help; @@ -39,7 +41,7 @@ public final class Report { */ public static void main(final String[] args) throws Exception { DefaultLog.getInstance().info(new VersionInfo().toString()); - ReportConfiguration configuration = OptionCollection.parseCommands(args, Report::printUsage); + ReportConfiguration configuration = OptionCollection.parseCommands(new File("."), args, Report::printUsage); if (configuration != null) { configuration.validate(DefaultLog.getInstance()::error); Reporter reporter = new Reporter(configuration); 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 3ba85b95a..b975e4150 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 @@ -586,7 +586,8 @@ private static void processConfigurationArgs(final ArgumentContext context) thro Defaults.Builder defaultBuilder = Defaults.builder(); if (CONFIGURATION.isSelected()) { for (String fn : context.getCommandLine().getOptionValues(CONFIGURATION.getSelected())) { - defaultBuilder.add(fn); + File file = context.resolve(fn); + defaultBuilder.add(file); } } if (CONFIGURATION_NO_DEFAULTS.isSelected()) { @@ -603,11 +604,12 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (FAMILIES_APPROVED_FILE.isSelected()) { try { - File f = context.getCommandLine().getParsedOptionValue(FAMILIES_APPROVED_FILE.getSelected()); + String fileName = context.getCommandLine().getOptionValue(FAMILIES_APPROVED_FILE.getSelected()); + File f = context.resolve(fileName); try (InputStream in = Files.newInputStream(f.toPath())) { context.getConfiguration().addApprovedLicenseCategories(IOUtils.readLines(in, StandardCharsets.UTF_8)); } - } catch (IOException | ParseException e) { + } catch (IOException e) { throw new ConfigurationException(e); } } @@ -618,11 +620,12 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (FAMILIES_DENIED_FILE.isSelected()) { try { - File f = context.getCommandLine().getParsedOptionValue(FAMILIES_DENIED_FILE.getSelected()); + String fileName = context.getCommandLine().getOptionValue(FAMILIES_DENIED_FILE.getSelected()); + File f = context.resolve(fileName); try (InputStream in = Files.newInputStream(f.toPath())) { context.getConfiguration().removeApprovedLicenseCategories(IOUtils.readLines(in, StandardCharsets.UTF_8)); } - } catch (IOException | ParseException e) { + } catch (IOException e) { throw new ConfigurationException(e); } } @@ -634,11 +637,12 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (LICENSES_APPROVED_FILE.isSelected()) { try { - File f = context.getCommandLine().getParsedOptionValue(LICENSES_APPROVED_FILE.getSelected()); - try (InputStream in = Files.newInputStream(f.toPath())) { + String fileName = context.getCommandLine().getOptionValue(LICENSES_APPROVED_FILE.getSelected()); + File file = context.resolve(fileName); + try (InputStream in = Files.newInputStream(file.toPath())) { context.getConfiguration().addApprovedLicenseIds(IOUtils.readLines(in, StandardCharsets.UTF_8)); } - } catch (IOException | ParseException e) { + } catch (IOException e) { throw new ConfigurationException(e); } } @@ -649,11 +653,12 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (LICENSES_DENIED_FILE.isSelected()) { try { - File f = context.getCommandLine().getParsedOptionValue(LICENSES_DENIED_FILE.getSelected()); - try (InputStream in = Files.newInputStream(f.toPath())) { + String fileName = context.getCommandLine().getOptionValue(LICENSES_DENIED_FILE.getSelected()); + File file = context.resolve(fileName); + try (InputStream in = Files.newInputStream(file.toPath())) { context.getConfiguration().removeApprovedLicenseIds(IOUtils.readLines(in, StandardCharsets.UTF_8)); } - } catch (IOException | ParseException e) { + } catch (IOException e) { throw new ConfigurationException(e); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java b/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java index 31abfd073..bc8b1c2e9 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java +++ b/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java @@ -18,10 +18,13 @@ */ package org.apache.rat.commandline; +import java.io.File; + import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Option; import org.apache.commons.cli.ParseException; import org.apache.rat.ReportConfiguration; +import org.apache.rat.document.DocumentName; import org.apache.rat.utils.DefaultLog; import static java.lang.String.format; @@ -35,17 +38,30 @@ public class ArgumentContext { private final ReportConfiguration configuration; /** The command line that is building the configuration */ private final CommandLine commandLine; + /** The directory from which relative file names will be resolved */ + private final DocumentName workingDirectory; /** - * Constructor. + * Creates a context with the specified configuration. + * @param workingDirectory the directory from which relative file names will be resolved. * @param configuration The configuration that is being built. * @param commandLine The command line that is building the configuration. */ - public ArgumentContext(final ReportConfiguration configuration, final CommandLine commandLine) { + public ArgumentContext(final File workingDirectory, final ReportConfiguration configuration, final CommandLine commandLine) { + this.workingDirectory = DocumentName.builder().setName(workingDirectory.getAbsoluteFile()).build(); this.commandLine = commandLine; this.configuration = configuration; } + /** + * Creates a context with an emtpy configuration. + * @param workingDirectory The directory from which to resolve relative file names. + * @param commandLine The command line. + */ + public ArgumentContext(final File workingDirectory, final CommandLine commandLine) { + this(workingDirectory, new ReportConfiguration(), commandLine); + } + /** * Process the arguments specified in this context. */ @@ -69,6 +85,27 @@ public CommandLine getCommandLine() { return commandLine; } + /** + * Gets the directory name from which releative file names will be resolved. + * @return The directory name from which releative file names will be resolved. + */ + public DocumentName getWorkingDirectory() { + return workingDirectory; + } + + /** + * Resolves the file name to the working directory if necessayr. + * @param fileName the file name to resolve. + * @return the file name string. + */ + public File resolve(final String fileName) { + if (!fileName.startsWith("/")) { + DocumentName fn = DocumentName.builder().setName(fileName).setBaseName("/").build(); + return new File(workingDirectory.resolve(fn.localized()).getName()); + } + return new File(fileName); + } + /** * Logs a ParseException as a warning. * @param exception the parse exception to log 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 1e88e86bb..eb000f4c2 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 @@ -195,6 +195,8 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { matchers.add(fromCommandLine.build()); lastMatcher = MatcherSet.merge(matchers).createMatcher(); + DefaultLog.getInstance().debug(format("Created matcher set for %s%n%s", basedir.getName(), + lastMatcher)); } return lastMatcher; } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java index 6463be4af..b1366f43e 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java @@ -38,7 +38,9 @@ import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; +import org.apache.rat.utils.DefaultLog; import org.apache.rat.utils.ExtendedIterator; +import org.apache.rat.utils.Log; import static java.lang.String.format; @@ -117,7 +119,20 @@ public static Predicate commentFilter(final String commentPrefix) { * @return a FileFilter. */ public static FileFilter asFileFilter(final DocumentName parent, final DocumentNameMatcher nameMatcher) { - return file -> nameMatcher.matches(DocumentName.builder(file).setBaseName(parent.getBaseName()).build()); + return file -> { + DocumentName candidate = DocumentName.builder(file).setBaseName(parent.getBaseName()).build(); + boolean result = nameMatcher.matches(candidate); + Log log = DefaultLog.getInstance(); + if (log.isEnabled(Log.Level.DEBUG)) { + log.debug(format("FILTER TEST for %s -> %s", file, result)); + if (!result) { + List< DocumentNameMatcher.DecomposeData> data = nameMatcher.decompose(candidate); + log.debug("Decomposition for " + candidate); + data.forEach(log::debug); + } + } + return result; + }; } /** diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java index b5369c7ba..81188cc7c 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -41,6 +41,9 @@ public interface MatcherSet { Optional includes(); Optional excludes(); + default String getDescription() { + return String.format("MatcherSet: include [%s] exclude [%s]", includes().orElse(MATCHES_NONE), excludes().orElse(MATCHES_NONE)); + } /** * Creates a DocumentNameMatcher from an iterable of MatcherSets. * @return A DocumentNameMatcher that processes the matcher sets. diff --git a/apache-rat-core/src/main/java/org/apache/rat/configuration/XMLConfigurationReader.java b/apache-rat-core/src/main/java/org/apache/rat/configuration/XMLConfigurationReader.java index 0bf2dda8d..bab5d7f1a 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/configuration/XMLConfigurationReader.java +++ b/apache-rat-core/src/main/java/org/apache/rat/configuration/XMLConfigurationReader.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; @@ -126,6 +127,21 @@ public SortedSet licenseFamilies() { }; } + /** + * Creates textual representation of a node for display. + * @param node the node to create the textual representation of. + * @return The textual representation of the node for display. + */ + private String nodeText(final Node node) { + StringWriter stringWriter = new StringWriter().append("<").append(node.getNodeName()); + NamedNodeMap attr = node.getAttributes(); + for (int i = 0; i < attr.getLength(); i++) { + Node n = attr.item(i); + stringWriter.append(String.format(" %s='%s'", n.getNodeName(), n.getNodeValue())); + } + return stringWriter.append(">").toString(); + } + @Override public void addLicenses(final URI uri) { read(uri); @@ -327,22 +343,27 @@ private void setValue(final Description description, final Description childDesc */ private Pair> processChildNodes(final Description description, final Node parent, final BiPredicate childProcessor) { - boolean foundChildren = false; - List children = new ArrayList<>(); - // check XML child nodes. - if (parent.hasChildNodes()) { - - nodeListConsumer(parent.getChildNodes(), n -> { - if (n.getNodeType() == Node.ELEMENT_NODE) { - children.add(n); + try { + boolean foundChildren = false; + List children = new ArrayList<>(); + // check XML child nodes. + if (parent.hasChildNodes()) { + + nodeListConsumer(parent.getChildNodes(), n -> { + if (n.getNodeType() == Node.ELEMENT_NODE) { + children.add(n); + } + }); + foundChildren = !children.isEmpty(); + if (foundChildren) { + processChildren(description, children, childProcessor); } - }); - foundChildren = !children.isEmpty(); - if (foundChildren) { - processChildren(description, children, childProcessor); } + return new ImmutablePair<>(foundChildren, children); + } catch (RuntimeException exception) { + DefaultLog.getInstance().error(String.format("Child node extraction error in: '%s'", nodeText(parent))); + throw exception; } - return new ImmutablePair<>(foundChildren, children); } /** @@ -408,6 +429,7 @@ private AbstractBuilder parseMatcher(final Node matcherNode) { } } catch (DOMException e) { + DefaultLog.getInstance().error(String.format("Matcher error in: '%s'", nodeText(matcherNode))); throw new ConfigurationException(e); } return builder.hasId() ? new IDRecordingBuilder(matchers, builder) : builder; @@ -445,34 +467,39 @@ private BiPredicate licenseChildNodeProcessor(final ILicense. * @return the License definition. */ private ILicense parseLicense(final Node licenseNode) { - ILicense.Builder builder = ILicense.builder(); - // get the description for the builder - Description description = builder.getDescription(); - // set the BUILDER_PARAM options from the description - processBuilderParams(description, builder); - // set the children from attributes. - description.setChildren(builder, attributes(licenseNode)); - // set children from the child nodes - Pair> pair = processChildNodes(description, licenseNode, - licenseChildNodeProcessor(builder, description)); - List children = pair.getRight(); - - // check for inline nodes that can accept child nodes. - List childDescriptions = description.getChildren().values().stream() - .filter(d -> XMLConfig.isLicenseInline(d.getCommonName())).collect(Collectors.toList()); - for (Description childDescription : childDescriptions) { - Iterator iter = children.iterator(); - while (iter.hasNext()) { - callSetter(childDescription, builder, parseMatcher(iter.next())); - iter.remove(); + try { + ILicense.Builder builder = ILicense.builder(); + // get the description for the builder + Description description = builder.getDescription(); + // set the BUILDER_PARAM options from the description + processBuilderParams(description, builder); + // set the children from attributes. + description.setChildren(builder, attributes(licenseNode)); + // set children from the child nodes + Pair> pair = processChildNodes(description, licenseNode, + licenseChildNodeProcessor(builder, description)); + List children = pair.getRight(); + + // check for inline nodes that can accept child nodes. + List childDescriptions = description.getChildren().values().stream() + .filter(d -> XMLConfig.isLicenseInline(d.getCommonName())).collect(Collectors.toList()); + for (Description childDescription : childDescriptions) { + Iterator iter = children.iterator(); + while (iter.hasNext()) { + callSetter(childDescription, builder, parseMatcher(iter.next())); + iter.remove(); + } } - } - if (!children.isEmpty()) { - children.forEach(n -> DefaultLog.getInstance().warn(String.format("unrecognised child node '%s' in node '%s'%n", - n.getNodeName(), licenseNode.getNodeName()))); + if (!children.isEmpty()) { + children.forEach(n -> DefaultLog.getInstance().warn(String.format("unrecognised child node '%s' in node '%s'%n", + n.getNodeName(), licenseNode.getNodeName()))); + } + return builder.build(); + } catch (RuntimeException exception) { + DefaultLog.getInstance().error(String.format("License error in: '%s'", nodeText(licenseNode))); + throw exception; } - return builder.build(); } @Override @@ -519,12 +546,17 @@ private ILicenseFamily parseFamily(final Map attributes) { */ private void parseFamily(final Node familyNode) { if (XMLConfig.FAMILY.equals(familyNode.getNodeName())) { - ILicenseFamily result = parseFamily(attributes(familyNode)); - if (result == null) { - throw new ConfigurationException( - String.format("families/family tag requires %s attribute", XMLConfig.ATT_ID)); + try { + ILicenseFamily result = parseFamily(attributes(familyNode)); + if (result == null) { + throw new ConfigurationException( + String.format("families/family tag requires %s attribute", XMLConfig.ATT_ID)); + } + licenseFamilies.add(result); + } catch (RuntimeException exception) { + DefaultLog.getInstance().error(String.format("Family error in: '%s'", nodeText(familyNode))); + throw exception; } - licenseFamilies.add(result); } } @@ -535,21 +567,26 @@ private void parseFamily(final Node familyNode) { */ private void parseApproved(final Node approvedNode) { if (XMLConfig.FAMILY.equals(approvedNode.getNodeName())) { - Map attributes = attributes(approvedNode); - if (attributes.containsKey(XMLConfig.ATT_LICENSE_REF)) { - approvedFamilies.add(attributes.get(XMLConfig.ATT_LICENSE_REF)); - } else if (attributes.containsKey(XMLConfig.ATT_ID)) { - ILicenseFamily target = parseFamily(attributes); - if (target != null) { - licenseFamilies.add(target); - String familyCategory = target.getFamilyCategory(); - if (StringUtils.isNotBlank(familyCategory)) { - approvedFamilies.add(familyCategory); + try { + Map attributes = attributes(approvedNode); + if (attributes.containsKey(XMLConfig.ATT_LICENSE_REF)) { + approvedFamilies.add(attributes.get(XMLConfig.ATT_LICENSE_REF)); + } else if (attributes.containsKey(XMLConfig.ATT_ID)) { + ILicenseFamily target = parseFamily(attributes); + if (target != null) { + licenseFamilies.add(target); + String familyCategory = target.getFamilyCategory(); + if (StringUtils.isNotBlank(familyCategory)) { + approvedFamilies.add(familyCategory); + } } + } else { + throw new ConfigurationException(String.format("family tag requires %s or %s attribute", + XMLConfig.ATT_LICENSE_REF, XMLConfig.ATT_ID)); } - } else { - throw new ConfigurationException(String.format("family tag requires %s or %s attribute", - XMLConfig.ATT_LICENSE_REF, XMLConfig.ATT_ID)); + } catch (RuntimeException exception) { + DefaultLog.getInstance().error(String.format("Approved error in: '%s'", nodeText(approvedNode))); + throw exception; } } } @@ -569,11 +606,16 @@ public SortedSet approvedLicenseId() { } private void parseMatcherBuilder(final Node classNode) { - Map attributes = attributes(classNode); - if (attributes.get(XMLConfig.ATT_CLASS_NAME) == null) { - throw new ConfigurationException("matcher must have a " + XMLConfig.ATT_CLASS_NAME + " attribute"); + try { + Map attributes = attributes(classNode); + if (attributes.get(XMLConfig.ATT_CLASS_NAME) == null) { + throw new ConfigurationException("matcher must have a " + XMLConfig.ATT_CLASS_NAME + " attribute"); + } + MatcherBuilderTracker.addBuilder(attributes.get(XMLConfig.ATT_CLASS_NAME), attributes.get(XMLConfig.ATT_NAME)); + } catch (RuntimeException exception) { + DefaultLog.getInstance().error(String.format("Matcher error in: '%s'", nodeText(classNode))); + throw exception; } - MatcherBuilderTracker.addBuilder(attributes.get(XMLConfig.ATT_CLASS_NAME), attributes.get(XMLConfig.ATT_NAME)); } @Override diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index be6bafb8c..d788d35c6 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -142,11 +142,34 @@ public boolean isCollection() { public Predicate getPredicate() { return predicate; } + @Override public String toString() { return name; } + /** + * Decomposes the matcher execution against the candidate. + * @param candidate the candiate to check. + * @return a list of {@link DecomposeData} for each evaluation in the matcher. + */ + public List decompose(final DocumentName candidate) { + final List result = new ArrayList<>(); + decompose(0, this, candidate, result); + return result; + } + + private void decompose(final int level, final DocumentNameMatcher matcher, final DocumentName candidate, final List result) { + final Predicate pred = matcher.getPredicate(); + result.add(new DecomposeData(level, matcher.toString(), pred.test(candidate))); + if (pred instanceof DocumentNameMatcher.CollectionPredicate) { + final DocumentNameMatcher.CollectionPredicate collection = (DocumentNameMatcher.CollectionPredicate) pred; + for (DocumentNameMatcher subMatcher : collection.getMatchers()) { + decompose(level + 1, subMatcher, candidate, result); + } + } + } + /** * Performs the match against the DocumentName. * @param documentName the document name to check. @@ -376,4 +399,30 @@ public boolean test(final DocumentName documentName) { return true; } } + + /** + * Data from a {@link DocumentNameMatcher#decompose(DocumentName)} call. + */ + public static final class DecomposeData { + /** the level this data was generated at */ + private final int level; + /** The name of the DocumentNameMatcher that created this result */ + private final String name;; + /** The result of the check. */ + private final boolean result; + + private DecomposeData(final int level, final String name, final boolean result) { + this.level = level; + this.name = name; + this.result = result; + } + + @Override + public String toString() { + final char[] chars = new char[level * 2]; + Arrays.fill(chars, ' '); + final String fill = new String(chars); + return String.format("%s%s : %s", fill, name, result); + } + } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/report/xml/writer/XmlWriter.java b/apache-rat-core/src/main/java/org/apache/rat/report/xml/writer/XmlWriter.java index 53a0dfb61..128f32f6f 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/report/xml/writer/XmlWriter.java +++ b/apache-rat-core/src/main/java/org/apache/rat/report/xml/writer/XmlWriter.java @@ -482,7 +482,7 @@ public IXmlWriter comment(final CharSequence text) throws IOException { /** * Writes an attribute of an element. Note that this is only allowed directly - * after {@link #openElement(CharSequence)} or {@link #attribute}. + * after {@link #openElement(CharSequence)} or a previous {@code attribute} call. * * @param name the attribute name, not null * @param value the attribute value, not null @@ -717,7 +717,7 @@ private boolean isValidNameBody(final char character) { } @Override - public void close() throws Exception { + public void close() throws IOException { closeDocument(); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/utils/Log.java b/apache-rat-core/src/main/java/org/apache/rat/utils/Log.java index d12db3e6c..9a9461c7f 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/utils/Log.java +++ b/apache-rat-core/src/main/java/org/apache/rat/utils/Log.java @@ -184,6 +184,15 @@ default void error(Object message, Throwable throwable) { * @return the Writer backed by this log. */ default Writer asWriter() { + return asWriter(Level.INFO); + } + + /** + * Returns a Writer backed by this log. All messages are logged at "INFO" level. + * @return the Writer backed by this log. + * @param level the Log level to write at. + */ + default Writer asWriter(Level level) { return new Writer() { private StringBuilder sb = new StringBuilder(); @@ -195,7 +204,7 @@ public void write(final char[] cbuf, final int off, final int len) { sb.append(txt); } else { while (pos > -1) { - Log.this.info(sb.append(txt, 0, pos).toString()); + Log.this.log(level, sb.append(txt, 0, pos).toString()); sb.delete(0, sb.length()); txt = txt.substring(pos + 1); pos = txt.indexOf(System.lineSeparator()); @@ -207,7 +216,7 @@ public void write(final char[] cbuf, final int off, final int len) { @Override public void flush() { if (sb.length() > 0) { - Log.this.info(sb.toString()); + Log.this.log(level, sb.toString()); } sb = new StringBuilder(); } @@ -218,4 +227,5 @@ public void close() throws IOException { } }; } + } 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 5f3feaf94..a1d21ea99 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 @@ -24,6 +24,7 @@ import org.apache.commons.cli.Option; import org.apache.commons.cli.ParseException; import org.apache.commons.lang3.tuple.Pair; +import org.apache.rat.commandline.ArgumentContext; import org.apache.rat.license.LicenseSetFactory; import org.apache.rat.report.IReportable; import org.apache.rat.test.AbstractOptionsProvider; @@ -98,7 +99,7 @@ public void testDeprecatedUseLogged() throws IOException { try { DefaultLog.setInstance(log); String[] args = {"--dir", "target", "-a"}; - ReportConfiguration config = OptionCollection.parseCommands(args, o -> fail("Help printed"), true); + ReportConfiguration config = OptionCollection.parseCommands(testPath.toFile(), args, o -> fail("Help printed"), true); assertThat(config).isNotNull(); } finally { DefaultLog.setInstance(null); @@ -114,7 +115,7 @@ public void testDirOptionCapturesDirectoryToScan() throws IOException { try { DefaultLog.setInstance(log); String[] args = {"--dir", testPath.toFile().getAbsolutePath()}; - config = OptionCollection.parseCommands(args, (o) -> { + config = OptionCollection.parseCommands(testPath.toFile(), args, (o) -> { }, true); } finally { DefaultLog.setInstance(null); @@ -126,7 +127,7 @@ public void testDirOptionCapturesDirectoryToScan() throws IOException { @Test public void testShortenedOptions() throws IOException { String[] args = {"--output-lic", "ALL"}; - ReportConfiguration config = OptionCollection.parseCommands(args, (o) -> { + ReportConfiguration config = OptionCollection.parseCommands(testPath.toFile(), args, (o) -> { }, true); assertThat(config).isNotNull(); assertThat(config.listLicenses()).isEqualTo(LicenseSetFactory.LicenseFilter.ALL); @@ -136,7 +137,8 @@ public void testShortenedOptions() throws IOException { public void testDefaultConfiguration() throws ParseException { String[] empty = {}; CommandLine cl = new DefaultParser().parse(OptionCollection.buildOptions(), empty); - ReportConfiguration config = OptionCollection.createConfiguration(cl); + ArgumentContext context = new ArgumentContext(new File("."), cl); + ReportConfiguration config = OptionCollection.createConfiguration(context); ReportConfigurationTest.validateDefault(config); } @@ -144,7 +146,7 @@ public void testDefaultConfiguration() throws ParseException { @ValueSource(strings = { ".", "./", "target", "./target" }) public void getReportableTest(String fName) throws IOException { File expected = new File(fName); - ReportConfiguration config = OptionCollection.parseCommands(new String[]{fName}, o -> fail("Help called"), false); + ReportConfiguration config = OptionCollection.parseCommands(testPath.toFile(), new String[]{fName}, o -> fail("Help called"), false); IReportable reportable = OptionCollection.getReportable(expected, config); assertNotNull(reportable, () -> format("'%s' returned null", fName)); assertThat(reportable.getName().getName()).isEqualTo(expected.getAbsolutePath()); @@ -174,7 +176,7 @@ static class CliOptionsProvider extends AbstractOptionsProvider implements Argum public void helpTest() { String[] args = {longOpt(OptionCollection.HELP)}; try { - ReportConfiguration config = OptionCollection.parseCommands(args, o -> helpCalled.set(true), true); + ReportConfiguration config = OptionCollection.parseCommands(testPath.toFile(), args, o -> helpCalled.set(true), true); assertNull(config, "Should not have config"); assertTrue(helpCalled.get(), "Help was not called"); } catch (IOException e) { @@ -196,8 +198,7 @@ public CliOptionsProvider() { * @return A ReportConfiguration * @throws IOException on critical error. */ - @SafeVarargs - protected final ReportConfiguration generateConfig(Pair... args) throws IOException { + protected final ReportConfiguration generateConfig(List> args) throws IOException { helpCalled.set(false); List sArgs = new ArrayList<>(); for (Pair pair : args) { @@ -209,7 +210,7 @@ protected final ReportConfiguration generateConfig(Pair... arg } } } - ReportConfiguration config = OptionCollection.parseCommands(sArgs.toArray(new String[0]), o -> helpCalled.set(true), true); + ReportConfiguration config = OptionCollection.parseCommands(testPath.toFile(), sArgs.toArray(new String[0]), o -> helpCalled.set(true), true); assertFalse(helpCalled.get(), "Help was called"); return config; } 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 725174420..5e64a6b62 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 @@ -52,6 +52,7 @@ import org.apache.commons.io.FileUtils; import org.apache.rat.api.Document.Type; import org.apache.rat.api.RatException; +import org.apache.rat.commandline.ArgumentContext; import org.apache.rat.commandline.StyleSheets; import org.apache.rat.document.FileDocument; import org.apache.rat.document.DocumentName; @@ -84,7 +85,8 @@ public void testExecute() throws RatException, ParseException { File output = new File(tempDirectory, "testExecute"); CommandLine cl = new DefaultParser().parse(OptionCollection.buildOptions(), new String[]{"--output-style", "xml", "--output-file", output.getPath(), basedir}); - ReportConfiguration config = OptionCollection.createConfiguration(cl); + ArgumentContext ctxt = new ArgumentContext(new File("."), cl); + ReportConfiguration config = OptionCollection.createConfiguration(ctxt); ClaimStatistic statistic = new Reporter(config).execute(); assertThat(statistic.getCounter(Type.ARCHIVE)).isEqualTo(1); @@ -137,7 +139,9 @@ public void testExecute() throws RatException, ParseException { public void testOutputOption() throws Exception { File output = new File(tempDirectory, "test"); CommandLine commandLine = new DefaultParser().parse(OptionCollection.buildOptions(), new String[]{"-o", output.getCanonicalPath(), basedir}); - ReportConfiguration config = OptionCollection.createConfiguration(commandLine); + ArgumentContext ctxt = new ArgumentContext(new File("."), commandLine); + + ReportConfiguration config = OptionCollection.createConfiguration(ctxt); new Reporter(config).output(); assertThat(output.exists()).isTrue(); String content = FileUtils.readFileToString(output, StandardCharsets.UTF_8); @@ -154,7 +158,9 @@ public void testDefaultOutput() throws Exception { try (PrintStream out = new PrintStream(output)) { System.setOut(out); CommandLine commandLine = new DefaultParser().parse(OptionCollection.buildOptions(), new String[]{basedir}); - ReportConfiguration config = OptionCollection.createConfiguration(commandLine); + ArgumentContext ctxt = new ArgumentContext(new File("."), commandLine); + + ReportConfiguration config = OptionCollection.createConfiguration(ctxt); new Reporter(config).output(); } finally { System.setOut(origin); @@ -204,9 +210,10 @@ public void testXMLOutput() throws Exception { "type", "STANDARD")); File output = new File(tempDirectory, "testXMLOutput"); - CommandLine commandLine = new DefaultParser().parse(OptionCollection.buildOptions(), new String[]{"--output-style", "xml", "--output-file", output.getPath(), basedir}); - ReportConfiguration config = OptionCollection.createConfiguration(commandLine); + ArgumentContext ctxt = new ArgumentContext(new File("."), commandLine); + + ReportConfiguration config = OptionCollection.createConfiguration(ctxt); new Reporter(config).output(); assertThat(output).exists(); diff --git a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java index 88079ec68..fc4c980f9 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java +++ b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java @@ -56,7 +56,7 @@ public void setOut(File file) { CommandLine commandLine = createCommandLine(new String[] {"--output-file", name}); OutputFileConfig configuration = new OutputFileConfig(); - ArgumentContext ctxt = new ArgumentContext(configuration, commandLine); + ArgumentContext ctxt = new ArgumentContext(new File("."), configuration, commandLine); Arg.processArgs(ctxt); assertEquals(expected.getAbsolutePath(), configuration.actual.getAbsolutePath()); } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java index 5527e5623..f372f129f 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java @@ -20,16 +20,11 @@ import java.io.File; import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; import java.util.Optional; -import java.util.function.Consumer; -import java.util.function.Predicate; import java.util.stream.Stream; import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; -import org.apache.rat.document.DocumentNameMatcherTest; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -129,7 +124,7 @@ public void test_RAT_335() { DocumentName candidate = DocumentName.builder() .setName("/home/claude/apache/creadur-rat/apache-rat-core/target/test-classes/GitIgnoreBuilderTest/src/dir1/file1.log") .setBaseName("home/claude/apache/creadur-rat/apache-rat-core/target/test-classes/GitIgnoreBuilderTest/src/").build(); - DocumentNameMatcherTest.decompose(matcher, candidate); + System.out.println("Decomposition for "+candidate); assertThat(matcher.toString()).isEqualTo("matcherSet(or('included dir1/.gitignore', 'included .gitignore'), or('excluded dir1/.gitignore', **/.gitignore, 'excluded .gitignore'))"); diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java index e586a1de9..4c2e04ba8 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java @@ -18,9 +18,6 @@ */ package org.apache.rat.document; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import java.util.function.Predicate; import org.junit.jupiter.api.Test; @@ -70,44 +67,4 @@ public void matcherSetTest() { assertThat(DocumentNameMatcher.matcherSet(SOME, MATCHES_NONE)).as("X,None").isEqualTo(MATCHES_ALL); assertThat(DocumentNameMatcher.matcherSet(SOME, SOME).toString()).as("X,X").isEqualTo("matcherSet(X, X)"); } - - public static void decompose(DocumentNameMatcher matcher, DocumentName candidate) { - List result = new ArrayList<>(); - - decompose(0, matcher, candidate, result); - System.out.println("Decomposition for "+candidate); - for (DecomposeData d : result) { - System.out.println(d); - } - } - private static void decompose(int level, DocumentNameMatcher matcher, DocumentName candidate, List result) { - Predicate pred = matcher.getPredicate(); - result.add(new DecomposeData(level, matcher.toString(), pred.test(candidate))); - if (pred instanceof DocumentNameMatcher.CollectionPredicate) { - DocumentNameMatcher.CollectionPredicate collection = (DocumentNameMatcher.CollectionPredicate) pred; - for(DocumentNameMatcher subMatcher : collection.getMatchers()) { - decompose(level + 1, subMatcher, candidate, result); - } - } - } - - public static class DecomposeData { - int level; - String name;; - boolean result; - - DecomposeData(int level, String name, boolean result) { - this.level = level; - this.name = name; - this.result = result; - } - - @Override - public String toString() { - char[] chars = new char[level*2]; - Arrays.fill(chars, ' '); - String fill = new String(chars); - return String.format("%s%s : %s", fill, name, result); - } - } } 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 ae91b43a0..79dc5f9b3 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 @@ -32,12 +32,12 @@ import org.apache.rat.commandline.StyleSheets; import org.apache.rat.config.exclusion.StandardCollection; import org.apache.rat.document.DocumentNameMatcher; -import org.apache.rat.document.DocumentNameMatcherTest; import org.apache.rat.document.DocumentName; import org.apache.rat.license.ILicense; import org.apache.rat.license.ILicenseFamily; import org.apache.rat.license.LicenseSetFactory; import org.apache.rat.report.claim.ClaimStatistic; +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; @@ -102,8 +102,18 @@ protected DocumentName baseName() { return DocumentName.builder(baseDir).build(); } + public static File setup(File baseDir) { + try { + final File sourceDir = Resources.getResourceDirectory("OptionTools"); + FileUtils.copyDirectory(sourceDir, new File(baseDir,"/src/test/resources/OptionTools")); + } catch (IOException e) { + DefaultLog.getInstance().error("Can not copy 'OptionTools' to " + baseDir, e); + } + return baseDir; + } + protected AbstractOptionsProvider(Collection unsupportedArgs, File baseDir) { - this.baseDir = baseDir; + this.baseDir = setup(baseDir); testMap.put("addLicense", this::addLicenseTest); testMap.put("config", this::configTest); testMap.put("configuration-no-defaults", this::configurationNoDefaultsTest); @@ -187,6 +197,12 @@ private void verifyAllMethodsDefinedAndNeeded(Collection unsupportedArgs unsupportedArgs.forEach(testMap::remove); } + @SafeVarargs + protected final ReportConfiguration generateConfig(Pair... args) throws IOException { + List> options = Arrays.asList(args); + return generateConfig(options); + } + /** * Create the report configuration from the argument pairs. * There must be at least one arg. It may be `ImmutablePair.nullPair()`. @@ -195,7 +211,7 @@ private void verifyAllMethodsDefinedAndNeeded(Collection unsupportedArgs * @return The generated ReportConfiguration. * @throws IOException on error. */ - protected abstract ReportConfiguration generateConfig(Pair... args) throws IOException; + protected abstract ReportConfiguration generateConfig(List> args) throws IOException; protected File writeFile(String name, Iterable lines) { File file = new File(baseDir, name); @@ -302,7 +318,6 @@ protected void inputExcludeParsedScmTest() { try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); - DocumentNameMatcherTest.decompose(excluder, mkDocName("thingone")); for (String fname : excluded) { assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isFalse(); } 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 429364a0c..69b2b00b0 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 @@ -202,10 +202,10 @@ public static void assertAttributes(Object source, XPath xPath, String xpath, Ma } public static void assertIsPresent(Object source, XPath xPath, String xpath) throws XPathExpressionException { - assertThat(isPresent(source, xPath, xpath)).isTrue(); + assertThat(isPresent(source, xPath, xpath)).as("Presence of "+xpath).isTrue(); } public static void assertIsNotPresent(Object source, XPath xPath, String xpath) throws XPathExpressionException { - assertThat(isPresent(source, xPath, xpath)).isFalse(); + assertThat(isPresent(source, xPath, xpath)).as("Non-presence of "+xpath).isFalse(); } } diff --git a/apache-rat-plugin/.gitignore b/apache-rat-plugin/.gitignore index d302b51b5..47d015ffc 100644 --- a/apache-rat-plugin/.gitignore +++ b/apache-rat-plugin/.gitignore @@ -1,3 +1,4 @@ /target/ +/invoker_target/ /src/site/apt/argument_types.txt /invoker_target/ diff --git a/apache-rat-plugin/pom.xml b/apache-rat-plugin/pom.xml index cabee5ccf..9bd8a2962 100644 --- a/apache-rat-plugin/pom.xml +++ b/apache-rat-plugin/pom.xml @@ -99,6 +99,7 @@ src/it/CustomLicense/src/**/ **/.bzrignore + invoker_target/** src/test/resources/XmlOutputExamples/**/* @@ -246,7 +247,7 @@ org.apache.maven.plugins maven-invoker-plugin - ${project.build.directory}/invoker + ${project.basedir}/invoker_target ${project.build.directory}/local-repo true src/it/settings.xml @@ -262,6 +263,17 @@ + + maven-clean-plugin + + + + invoker_target + false + + + + org.apache.maven.plugins maven-checkstyle-plugin diff --git a/apache-rat-plugin/src/it/CustomLicense/.rat/customConfig.xml b/apache-rat-plugin/src/it/CustomLicense/.rat/customConfig.xml new file mode 100644 index 000000000..9f0ab7fb9 --- /dev/null +++ b/apache-rat-plugin/src/it/CustomLicense/.rat/customConfig.xml @@ -0,0 +1,17 @@ + + + + " + + + + + Attribution-NonCommercial-NoDerivatives + + + + + + + diff --git a/apache-rat-plugin/src/it/CustomLicense/invoker.properties b/apache-rat-plugin/src/it/CustomLicense/invoker.properties index 6e8c3479e..123118983 100644 --- a/apache-rat-plugin/src/it/CustomLicense/invoker.properties +++ b/apache-rat-plugin/src/it/CustomLicense/invoker.properties @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -invoker.goals = clean apache-rat:check +invoker.goals = -X clean apache-rat:check diff --git a/apache-rat-plugin/src/it/CustomLicense/pom.xml b/apache-rat-plugin/src/it/CustomLicense/pom.xml index 4a03c4872..474872128 100644 --- a/apache-rat-plugin/src/it/CustomLicense/pom.xml +++ b/apache-rat-plugin/src/it/CustomLicense/pom.xml @@ -27,31 +27,13 @@ apache-rat-plugin @pom.version@ - false - - - CC - Creative Commons - - - - - CC - CC-BY-NC-ND - - Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International - - Attribution-NonCommercial-NoDerivatives - - - - - CC - - + xml + .rat/customConfig.xml + + .rat/** pom.xml invoker.properties - + diff --git a/apache-rat-plugin/src/it/RAT-268/pom.xml b/apache-rat-plugin/src/it/RAT-268/pom.xml index 2084bef08..9a42f6d02 100644 --- a/apache-rat-plugin/src/it/RAT-268/pom.xml +++ b/apache-rat-plugin/src/it/RAT-268/pom.xml @@ -33,12 +33,12 @@ apache-rat-plugin @pom.version@ - - STANDARDS:0 - - + + STANDARDS:0 + + **/src.apt - + diff --git a/apache-rat-plugin/src/main/java/org/apache/rat/mp/AbstractRatMojo.java b/apache-rat-plugin/src/main/java/org/apache/rat/mp/AbstractRatMojo.java index 2603c50ae..ff9f2165f 100644 --- a/apache-rat-plugin/src/main/java/org/apache/rat/mp/AbstractRatMojo.java +++ b/apache-rat-plugin/src/main/java/org/apache/rat/mp/AbstractRatMojo.java @@ -255,6 +255,10 @@ public void setAddDefaultLicenses(final boolean addDefaultLicenses) { @Parameter(defaultValue = "${project}", required = true, readonly = true) protected MavenProject project; + protected AbstractRatMojo() { + DefaultLog.setInstance(makeLog()); + } + /** * @return the Maven project. */ @@ -349,10 +353,9 @@ protected void removeKey(final Arg arg) { private org.apache.rat.utils.Log makeLog() { return new org.apache.rat.utils.Log() { - private final org.apache.maven.plugin.logging.Log log = getLog(); - @Override public Level getLevel() { + final org.apache.maven.plugin.logging.Log log = getLog(); if (log.isDebugEnabled()) { return Level.DEBUG; } @@ -370,6 +373,7 @@ public Level getLevel() { @Override public void log(final Level level, final String message, final Throwable throwable) { + final org.apache.maven.plugin.logging.Log log = getLog(); switch (level) { case DEBUG: if (throwable != null) { @@ -406,6 +410,7 @@ public void log(final Level level, final String message, final Throwable throwab @Override public void log(final Level level, final String msg) { + final org.apache.maven.plugin.logging.Log log = getLog(); switch (level) { case DEBUG: log.debug(msg); @@ -459,10 +464,9 @@ private void setIncludeExclude() { } protected ReportConfiguration getConfiguration() throws MojoExecutionException { + Log log = DefaultLog.getInstance(); if (reportConfiguration == null) { - DefaultLog.setInstance(makeLog()); try { - Log log = DefaultLog.getInstance(); if (super.getLog().isDebugEnabled()) { log.debug("Start BaseRatMojo Configuration options"); for (Map.Entry> entry : args.entrySet()) { @@ -476,7 +480,8 @@ protected ReportConfiguration getConfiguration() throws MojoExecutionException { setIncludeExclude(); - ReportConfiguration config = OptionCollection.parseCommands(args().toArray(new String[0]), + getLog().warn("Basedir is : " + basedir); + ReportConfiguration config = OptionCollection.parseCommands(basedir, args().toArray(new String[0]), o -> getLog().warn("Help option not supported"), true); reportDeprecatedProcessing(); @@ -498,7 +503,7 @@ protected ReportConfiguration getConfiguration() throws MojoExecutionException { } } if (families != null || getDeprecatedConfigs().findAny().isPresent()) { - if (super.getLog().isDebugEnabled()) { + if (log.isEnabled(Log.Level.DEBUG)) { log.debug(format("%s license families loaded from pom", families.length)); } Consumer logger = super.getLog().isDebugEnabled() ? l -> log.debug(format("Family: %s", l)) @@ -519,10 +524,10 @@ protected ReportConfiguration getConfiguration() throws MojoExecutionException { } if (licenses != null) { - if (super.getLog().isDebugEnabled()) { + if (log.isEnabled(Log.Level.DEBUG)) { log.debug(format("%s licenses loaded from pom", licenses.length)); } - Consumer logger = super.getLog().isDebugEnabled() ? l -> log.debug(format("License: %s", l)) + Consumer logger = log.isEnabled(Log.Level.DEBUG) ? l -> log.debug(format("License: %s", l)) : l -> { }; Consumer addApproved = (approvedLicenses == null || approvedLicenses.length == 0) diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java index d80269729..67b71126d 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java @@ -19,7 +19,6 @@ package org.apache.rat.mp; import org.apache.commons.cli.Option; -import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.maven.plugin.MojoExecutionException; @@ -83,8 +82,10 @@ public MojoOptionsProvider() { super(BaseRatMojo.unsupportedArgs(), testPath.toFile()); } - private RatCheckMojo generateMojo(Pair... args) throws IOException { - MavenOption keyOption = new MavenOption(args[0].getKey() == null ? Option.builder().longOpt("no-option").build() : args[0].getKey()); + private RatCheckMojo generateMojo(List> args) throws IOException { + MavenOption keyOption = new MavenOption(args.get(0).getKey() == null ? + Option.builder().longOpt("no-option").build() : + args.get(0).getKey()); List mavenOptions = new ArrayList<>(); for (Pair pair : args) { if (pair.getKey() != null) { @@ -94,7 +95,6 @@ private RatCheckMojo generateMojo(Pair... args) throws IOExcept mavenOptions.add(new MavenOption(pair.getKey()).xmlNode(value)); } } else { - MavenOption mavenOption = new MavenOption(pair.getKey()); mavenOptions.add(new MavenOption(pair.getKey()).xmlNode("true")); } } @@ -121,9 +121,10 @@ private RatCheckMojo generateMojo(Pair... args) throws IOExcept } @Override - protected ReportConfiguration generateConfig(Pair... args) throws IOException { + protected final ReportConfiguration generateConfig(List> args) throws IOException { try { this.mojo = generateMojo(args); + AbstractOptionsProvider.setup(this.mojo.getProject().getBasedir()); return mojo.getConfiguration(); } catch (MojoExecutionException e) { throw new IOException(e.getMessage(), e); @@ -134,65 +135,6 @@ protected ReportConfiguration generateConfig(Pair... args) thr protected void helpTest() { fail("Should not call help"); } - -/* - private void execExcludeTest(Option option, String[] args) { - - try { - ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); - File workingDir = mojo.getProject().getBasedir(); - for (String fn : new String[] {"some.foo", "B.bar", "justbaz", "notbaz"}) { - try (FileOutputStream fos = new FileOutputStream(new File(workingDir, fn))) { - fos.write("Hello world".getBytes()); - } - } - - assertThat(ds.getExcludedList()).contains("some.foo"); - assertThat(ds.getExcludedList()).contains("B.bar"); - assertThat(ds.getExcludedList()).contains("justbaz"); - assertThat(ds.getIncludedList()).contains("notbaz"); - } catch (IOException | MojoExecutionException e) { - fail(e.getMessage(), e); - } - } - - @Override - protected void excludeTest() { - String[] args = { "*.foo", "*.bar", "justbaz"}; - execExcludeTest(Arg.EXCLUDE.find("exclude"), args); - } - - @Override - protected void inputExcludeTest() { - String[] args = { "*.foo", "*.bar", "justbaz"}; - execExcludeTest(Arg.EXCLUDE.find("input-exclude"), args); - } - - private void excludeFileTest(Option option) { - File outputFile = new File(baseDir, "exclude.txt"); - try (FileWriter fw = new FileWriter(outputFile)) { - fw.write("*.foo"); - fw.write(System.lineSeparator()); - fw.write("*.bar"); - fw.write(System.lineSeparator()); - fw.write("justbaz"); - fw.write(System.lineSeparator()); - } catch (IOException e) { - throw new RuntimeException(e); - } - execExcludeTest(option, new String[] {outputFile.getPath()}); - } - - protected void excludeFileTest() { - excludeFileTest(Arg.EXCLUDE_FILE.find("exclude-file")); - } - - - protected void inputExcludeFileTest() { - excludeFileTest(Arg.EXCLUDE_FILE.find("input-exclude-file")); - } - - */ } public abstract static class SimpleMojoTestcase extends BetterAbstractMojoTestCase { diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java index 9b28a2582..1e8c6c1e4 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java @@ -24,7 +24,6 @@ import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -64,7 +63,7 @@ public class RatCheckMojoTest { //extends BetterAbstractMojoTestCase { @TempDir static Path tempDir; - private static XPath xPath = XPathFactory.newInstance().newXPath(); + private final static XPath xPath = XPathFactory.newInstance().newXPath(); @AfterAll static void preserveData() { @@ -95,35 +94,24 @@ private RatCheckMojo getMojo(File pomFile) throws IOException { */ private RatCheckMojo newRatMojo(String testDir) throws Exception { Arg.reset(); - final File pomFile = Resources.getResourceFile(format("unit/%s/pom.xml", testDir)); - final File sourceDir = pomFile.getParentFile(); + final File sourceDir = Resources.getResourceDirectory(format("unit/%s", testDir)); final File baseDir = tempDir.resolve(testDir).toFile(); FileUtils.copyDirectory(sourceDir, baseDir); - + final File pomFile = new File(baseDir, "pom.xml"); RatCheckMojo mojo = getMojo(pomFile); assertThat(mojo).isNotNull(); assertThat(mojo.getProject()) .as("The mojo is missing its MavenProject, which will result in an NPE during RAT runs.") .isNotNull(); -// if (mojo instanceof RatReportMojo) { -// setVariableValueToObject(mojo, "localRepository", newArtifactRepository(getContainer())); -// setVariableValueToObject(mojo, "factory", newArtifactFactory()); -// setVariableValueToObject(mojo, "siteRenderer", newSiteRenderer(getContainer())); -// } else if (mojo instanceof RatCheckMojo) { File buildDirectory = new File(baseDir, "target"); - buildDirectory.mkdirs(); + assertThat(buildDirectory.mkdirs()).isTrue(); final File ratTxtFile = new File(buildDirectory, "rat.txt"); FileUtils.write(ratTxtFile, "", UTF_8); // Ensure the output file exists and is empty (rerunning the test will append) mojo.setOutputFile(ratTxtFile.getAbsolutePath()); -// } return mojo; } - private String getDir(RatCheckMojo mojo) { - return mojo.getProject().getBasedir().getAbsolutePath().replace("\\", "/") + "/"; - } - /** * Runs a check, which should expose no problems. * @@ -143,7 +131,7 @@ void it1() throws Exception { data.put(ClaimStatistic.Counter.APPROVED, "1"); data.put(ClaimStatistic.Counter.BINARIES, "0"); data.put(ClaimStatistic.Counter.DOCUMENT_TYPES, "2"); - data.put(ClaimStatistic.Counter.IGNORED, "1"); + data.put(ClaimStatistic.Counter.IGNORED, "2"); data.put(ClaimStatistic.Counter.LICENSE_CATEGORIES, "1"); data.put(ClaimStatistic.Counter.LICENSE_NAMES, "1"); data.put(ClaimStatistic.Counter.NOTICES, "0"); @@ -191,7 +179,7 @@ void it2() throws Exception { ReporterTestUtils.counterText(ClaimStatistic.Counter.BINARIES, 0, false), ReporterTestUtils.counterText(ClaimStatistic.Counter.ARCHIVES, 0, false), ReporterTestUtils.counterText(ClaimStatistic.Counter.STANDARDS, 2, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.IGNORED, 0, false), + ReporterTestUtils.counterText(ClaimStatistic.Counter.IGNORED, 1, false), ReporterTestUtils.apacheLicenseVersion2(1), ReporterTestUtils.unknownLicense(1), ReporterTestUtils.documentOut(false, Document.Type.STANDARD, "/src.txt") + @@ -219,20 +207,6 @@ void it2() throws Exception { void it3() throws Exception { final RatCheckMojo mojo = newRatMojo("it3"); final File ratTxtFile = mojo.getRatTxtFile(); - final String[] expected = { - "^Files with unapproved licenses\\s+\\*+\\s+\\Q/src.apt\\E\\s+", - ReporterTestUtils.counterText(ClaimStatistic.Counter.NOTICES, 0, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.BINARIES, 0, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.ARCHIVES, 0, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.STANDARDS, 2, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.IGNORED, 0, false), - ReporterTestUtils.apacheLicenseVersion2(1), - ReporterTestUtils.unknownLicense(1), - ReporterTestUtils.documentOut(false, Document.Type.STANDARD, "/src.apt") + - ReporterTestUtils.UNKNOWN_LICENSE, - ReporterTestUtils.documentOut(true, Document.Type.STANDARD, "/pom.xml") + - ReporterTestUtils.APACHE_LICENSE - }; ReportConfiguration config = mojo.getConfiguration(); assertThat(config.isAddingLicenses()).as("should be adding licenses").isTrue(); @@ -256,6 +230,9 @@ void it3() throws Exception { if (type == Document.Type.STANDARD) { XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='STANDARD']", "count", "3"); + } else if (type == Document.Type.IGNORED) { + XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='IGNORED']", "count", + "1"); } else { XmlUtils.assertIsNotPresent(document, xPath, format("/rat-report/statistics/documentType[@name='%s']", type)); } @@ -274,59 +251,58 @@ void it5() throws Exception { assertThat(config.isAddingLicenses()).as("Should not be adding licenses").isFalse(); assertThat(config.isAddingLicensesForced()).as("Should not be forcing licenses").isFalse(); - ReportConfigurationTest.validateDefaultApprovedLicenses(config); - assertThat(config.getLicenseCategories(LicenseFilter.APPROVED)).doesNotContain(ILicenseFamily.makeCategory("YAL")); - ReportConfigurationTest.validateDefaultLicenseFamilies(config, "YAL"); + ReportConfigurationTest.validateDefaultApprovedLicenses(config, 1); + assertThat(config.getLicenseCategories(LicenseFilter.APPROVED)).doesNotContain(ILicenseFamily.makeCategory("YAL")) + .contains(ILicenseFamily.makeCategory("CC")); + ReportConfigurationTest.validateDefaultLicenseFamilies(config, "YAL", "CC"); + assertThat(LicenseSetFactory.familySearch("YAL", config.getLicenseFamilies(LicenseFilter.APPROVED))).isNull(); assertThat(LicenseSetFactory.familySearch("YAL", config.getLicenseFamilies(LicenseFilter.ALL))).isNotNull(); - ReportConfigurationTest.validateDefaultLicenses(config, "MyLicense", "CpyrT", "RegxT", "SpdxT", "TextT", - "Not", "All", "Any"); - assertThat(LicenseSetFactory.search("YAL", "MyLicense", config.getLicenses(LicenseFilter.ALL))).isPresent(); - try { + assertThat(LicenseSetFactory.familySearch("CC", config.getLicenseFamilies(LicenseFilter.APPROVED))).isNotNull(); + assertThat(LicenseSetFactory.familySearch("CC", config.getLicenseFamilies(LicenseFilter.ALL))).isNotNull(); + + ReportConfigurationTest.validateDefaultLicenses(config, "CC-BY-NC-ND", "YAL"); + assertThat(LicenseSetFactory.search("YAL", "YAL", config.getLicenses(LicenseFilter.ALL))).isPresent(); + //try { mojo.execute(); - fail("Should have thrown exception"); - } catch (RatCheckException e) { - assertThat(e.getMessage()).contains("UNAPPROVED"); - } + // fail("Should have thrown exception"); +// } catch (RatCheckException e) { +// assertThat(e.getMessage()).contains("LICENSE_CATEGORIES, LICENSE_NAMES, STANDARDS exceeded"); +// } Map data = new HashMap<>(); - data.put(ClaimStatistic.Counter.APPROVED, "0"); + data.put(ClaimStatistic.Counter.APPROVED, "1"); data.put(ClaimStatistic.Counter.ARCHIVES, "0"); data.put(ClaimStatistic.Counter.BINARIES, "0"); data.put(ClaimStatistic.Counter.DOCUMENT_TYPES, "2"); - data.put(ClaimStatistic.Counter.IGNORED, "1"); + data.put(ClaimStatistic.Counter.IGNORED, "3"); data.put(ClaimStatistic.Counter.LICENSE_CATEGORIES, "1"); - data.put(ClaimStatistic.Counter.LICENSE_NAMES, "4"); + data.put(ClaimStatistic.Counter.LICENSE_NAMES, "1"); data.put(ClaimStatistic.Counter.NOTICES, "0"); data.put(ClaimStatistic.Counter.STANDARDS, "1"); - data.put(ClaimStatistic.Counter.UNAPPROVED, "4"); + data.put(ClaimStatistic.Counter.UNAPPROVED, "0"); data.put(ClaimStatistic.Counter.UNKNOWN, "0"); - org.w3c.dom.Document document = XmlUtils.toDom(new FileInputStream(ratTxtFile)); + org.w3c.dom.Document document = XmlUtils.toDom(Files.newInputStream(ratTxtFile.toPath())); XPath xPath = XPathFactory.newInstance().newXPath(); for (ClaimStatistic.Counter counter : ClaimStatistic.Counter.values()) { String xpath = String.format("/rat-report/statistics/statistic[@name='%s']", counter.displayName()); Map map = mapOf("approval", - counter == ClaimStatistic.Counter.UNAPPROVED ? "false" : "true", + "true", "count", data.get(counter), "description", counter.getDescription()); XmlUtils.assertAttributes(document, xPath, xpath, map); } - XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/.bzrignore']", - mapOf("mediaType", "application/octet-stream", "type", "IGNORED")); - + XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/.rat']", + "mediaType", "application/octet-stream", "type", "IGNORED", "isDirectory", "true"); XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/pom.xml']", - mapOf("mediaType", "application/xml", "type", "STANDARD", "encoding", "ISO-8859-1")); - - XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/pom.xml']/license[@id='Any']", - mapOf("approval", "false", "family", "YAL ", "name", "Any testing")); - XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/pom.xml']/license[@id='MyLicense']", - mapOf("approval", "false", "family", "YAL ", "name", "Yet another license")); - XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/pom.xml']/license[@id='RegxT']", - mapOf("approval", "false", "family", "YAL ", "name", "Regex with tag")); - XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/pom.xml']/license[@id='TextT']", - mapOf("approval", "false", "family", "YAL ", "name", "Text with tag")); + "mediaType", "application/xml", "type", "IGNORED", "isDirectory", "false"); + XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/src/main/java/nl/basjes/something/Something.java']", + "mediaType", "text/x-java-source", "type", "STANDARD", "encoding", "ISO-8859-1"); + XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/src/main/java/nl/basjes/something/Something.java']/license", + "approval", "true", "family", ILicenseFamily.makeCategory("CC"), "id", "CC-BY-NC-ND", "name", + "Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International"); } /** @@ -348,7 +324,7 @@ void rat343() throws Exception { ReporterTestUtils.counterText(ClaimStatistic.Counter.BINARIES, 0, false), ReporterTestUtils.counterText(ClaimStatistic.Counter.ARCHIVES, 0, false), ReporterTestUtils.counterText(ClaimStatistic.Counter.STANDARDS, 1, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.IGNORED, 0, false), + ReporterTestUtils.counterText(ClaimStatistic.Counter.IGNORED, 1, false), ReporterTestUtils.apacheLicenseVersion2(1), "^BSD: 1 ", "^Creative Commons Attribution: 1 ", @@ -476,7 +452,7 @@ void rat362() throws Exception { org.w3c.dom.Document document = XmlUtils.toDom(Files.newInputStream(ratTxtFile.toPath())); // Document types XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='IGNORED']", - "count", "2"); + "count", "3"); XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/bar.md']", "type", "STANDARD"); diff --git a/apache-rat-plugin/src/test/resources/unit/it5/.rat/customConfig.xml b/apache-rat-plugin/src/test/resources/unit/it5/.rat/customConfig.xml new file mode 100644 index 000000000..6eea4db67 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/it5/.rat/customConfig.xml @@ -0,0 +1,23 @@ + + + + " + " + + + + Attribution-NonCommercial-NoDerivatives + + + + Yet another license + + + + + + + + diff --git a/apache-rat-plugin/src/test/resources/unit/it5/pom.xml b/apache-rat-plugin/src/test/resources/unit/it5/pom.xml new file mode 100644 index 000000000..474872128 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/it5/pom.xml @@ -0,0 +1,41 @@ + + + + 4.0.0 + org.apache.rat.test + custom-license + 1.0 + + + + org.apache.rat + apache-rat-plugin + @pom.version@ + + xml + .rat/customConfig.xml + + .rat/** + pom.xml + invoker.properties + + + + + + diff --git a/apache-rat-plugin/src/test/resources/unit/it5/src/main/java/nl/basjes/something/Something.java b/apache-rat-plugin/src/test/resources/unit/it5/src/main/java/nl/basjes/something/Something.java new file mode 100644 index 000000000..4a7f38d95 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/it5/src/main/java/nl/basjes/something/Something.java @@ -0,0 +1,26 @@ +/* + * *********************************************************************** + * Ok, this file is really Apache _ licensed but it has a fake header + * that does not match the Apache rules to test custom license validation. + * *********************************************************************** + * + * Something toolkit + * Copyright (C) 2019-2024 Niels Basjes + * + * This work is licensed under the Creative Commons + * Attribution-NonCommercial-NoDerivatives 4.0 International License. + * + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by-nc-nd/4.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. + */ +package nl.basjes.something; + +public class Something { + private static final String something = "No real code"; +} diff --git a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java index 1ba32129e..c201502d3 100644 --- a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java +++ b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java @@ -17,6 +17,7 @@ package org.apache.rat.anttasks; import java.nio.file.Path; +import java.util.List; import org.apache.commons.cli.Option; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; @@ -80,9 +81,8 @@ public AntOptionsProvider() { super(BaseAntTask.unsupportedArgs(), testPath.toFile()); } - @SafeVarargs - protected final ReportConfiguration generateConfig(Pair... args) { - BuildTask task = args[0].getKey() == null ? new BuildTask() : new BuildTask(args[0].getKey()); + protected final ReportConfiguration generateConfig(List> args) { + BuildTask task = args.get(0).getKey() == null ? new BuildTask() : new BuildTask(args.get(0).getKey()); task.setUp(args); task.buildRule.executeTarget(task.name); return reportConfiguration; @@ -99,6 +99,8 @@ public void helpLicenses() { Log oldLog = DefaultLog.setInstance(testLog); try { ReportConfiguration config = generateConfig(ImmutablePair.of(HELP_LICENSES.option(), null)); + } catch (IOException e) { + throw new RuntimeException(e); } finally { DefaultLog.setInstance(oldLog); } @@ -124,10 +126,10 @@ private class BuildTask extends AbstractRatAntTaskTest { } @SafeVarargs - public final void setUp(Pair... args) { + public final void setUp(List> args) { StringBuilder childElements = new StringBuilder(); StringBuilder attributes = new StringBuilder(); - if (args[0].getKey() != null) { + if (args.get(0).getKey() != null) { for (Pair pair : args) { AntOption argOption = new AntOption(pair.getKey()); diff --git a/apache-rat-tools/src/main/java/org/apache/rat/tools/Documentation.java b/apache-rat-tools/src/main/java/org/apache/rat/tools/Documentation.java index a96fe9ae2..0ebfc3d81 100644 --- a/apache-rat-tools/src/main/java/org/apache/rat/tools/Documentation.java +++ b/apache-rat-tools/src/main/java/org/apache/rat/tools/Documentation.java @@ -18,6 +18,7 @@ */ package org.apache.rat.tools; +import java.io.File; import java.io.IOException; import java.io.Writer; @@ -45,7 +46,7 @@ private Documentation() { * @throws IOException on error */ public static void main(final String[] args) throws IOException { - ReportConfiguration config = OptionCollection.parseCommands(args, Documentation::printUsage, true); + ReportConfiguration config = OptionCollection.parseCommands(new File("."), args, Documentation::printUsage, true); if (config != null) { try (Writer writer = config.getWriter().get()) { new Licenses(config, writer).output(); From 5fb0fdf4bcd9b2cd158d824e27d8f3a047888a5a Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Fri, 27 Dec 2024 00:40:54 +0000 Subject: [PATCH 014/123] fixed last tests in plugin module --- apache-rat-plugin/src/it/CustomLicense/invoker.properties | 2 +- .../src/test/java/org/apache/rat/mp/RatCheckMojoTest.java | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/apache-rat-plugin/src/it/CustomLicense/invoker.properties b/apache-rat-plugin/src/it/CustomLicense/invoker.properties index 123118983..6e8c3479e 100644 --- a/apache-rat-plugin/src/it/CustomLicense/invoker.properties +++ b/apache-rat-plugin/src/it/CustomLicense/invoker.properties @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -invoker.goals = -X clean apache-rat:check +invoker.goals = clean apache-rat:check diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java index 1e8c6c1e4..c10b10bb6 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java @@ -221,15 +221,11 @@ void it3() throws Exception { XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/src.apt']", "type", "STANDARD"); - XmlUtils.assertIsPresent(document, xPath, "/rat-report/resource[@name='/src.apt.new']/license[@approval='true']"); - - XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='STANDARD']", "count", - "3"); for (Document.Type type : Document.Type.values()) { if (type == Document.Type.STANDARD) { XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='STANDARD']", "count", - "3"); + "2"); } else if (type == Document.Type.IGNORED) { XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='IGNORED']", "count", "1"); From 4b564ba67ae5d775729ec1dcb6e7f779e9cbe279 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Fri, 27 Dec 2024 00:49:26 +0000 Subject: [PATCH 015/123] fixed Ant task issues --- .../src/main/java/org/apache/rat/anttasks/Report.java | 2 +- .../test/java/org/apache/rat/anttasks/ReportOptionTest.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apache-rat-tasks/src/main/java/org/apache/rat/anttasks/Report.java b/apache-rat-tasks/src/main/java/org/apache/rat/anttasks/Report.java index 493b032cd..156d7779a 100644 --- a/apache-rat-tasks/src/main/java/org/apache/rat/anttasks/Report.java +++ b/apache-rat-tasks/src/main/java/org/apache/rat/anttasks/Report.java @@ -352,7 +352,7 @@ public ReportConfiguration getConfiguration() { boolean helpLicenses = !getValues(Arg.HELP_LICENSES).isEmpty(); removeKey(Arg.HELP_LICENSES); - final ReportConfiguration configuration = OptionCollection.parseCommands(args().toArray(new String[0]), + final ReportConfiguration configuration = OptionCollection.parseCommands(new File("."), args().toArray(new String[0]), o -> DefaultLog.getInstance().warn("Help option not supported"), true); if (getValues(Arg.OUTPUT_FILE).isEmpty()) { diff --git a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java index c201502d3..966c0ee02 100644 --- a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java +++ b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java @@ -73,7 +73,7 @@ public void execute() { } } - final class AntOptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { + final static class AntOptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { final AtomicBoolean helpCalled = new AtomicBoolean(false); @@ -125,7 +125,6 @@ private class BuildTask extends AbstractRatAntTaskTest { antFile = new File(baseDir, name + ".xml"); } - @SafeVarargs public final void setUp(List> args) { StringBuilder childElements = new StringBuilder(); StringBuilder attributes = new StringBuilder(); From 0e40a8b926883dfc589b97715b54cff9dd240272 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Fri, 27 Dec 2024 15:22:20 +0000 Subject: [PATCH 016/123] added missing files --- .../exclusion/fileProcessors/GitIgnoreBuilderTest.java | 3 --- .../src/test/resources/GitIgnoreBuilderTest/src/.gitignore | 7 +++++++ .../resources/GitIgnoreBuilderTest/src/dir1/.gitignore | 3 +++ .../test/resources/GitIgnoreBuilderTest/src/dir1/dir1.txt | 1 + .../test/resources/GitIgnoreBuilderTest/src/dir1/file1.log | 1 + .../test/resources/GitIgnoreBuilderTest/src/dir2/dir2.md | 1 + .../test/resources/GitIgnoreBuilderTest/src/dir3/dir3.log | 1 + .../src/test/resources/GitIgnoreBuilderTest/src/root.md | 1 + 8 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/.gitignore create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/.gitignore create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/dir1.txt create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/file1.log create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir2/dir2.md create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir3/dir3.log create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/root.md diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java index f372f129f..b98c446e7 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java @@ -36,8 +36,6 @@ import org.junit.jupiter.params.provider.MethodSource; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.not; -import static org.assertj.core.api.Fail.fail; public class GitIgnoreBuilderTest extends AbstractIgnoreBuilderTest { @@ -69,7 +67,6 @@ public void modifyEntryTest(String source, String expected) { List matcherSets = new ArrayList<>(); Optional entry = underTest.modifyEntry(matcherSets::add, testName, source); - if (source.endsWith("/")) { assertThat(entry).isNotPresent(); assertThat(matcherSets).hasSize(1); diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/.gitignore b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/.gitignore new file mode 100644 index 000000000..8855fa805 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/.gitignore @@ -0,0 +1,7 @@ +*.md + +# This makes it ignore dir3/dir3.log and dir3/file3.log +*.log + +# This makes it "unignore" dir3/file3.log +!file*.log diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/.gitignore b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/.gitignore new file mode 100644 index 000000000..26fd5c956 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/.gitignore @@ -0,0 +1,3 @@ +*.txt +!dir1.md +file1.log \ No newline at end of file diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/dir1.txt b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/dir1.txt new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/dir1.txt @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/file1.log b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/file1.log new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/file1.log @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir2/dir2.md b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir2/dir2.md new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir2/dir2.md @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir3/dir3.log b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir3/dir3.log new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir3/dir3.log @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/root.md b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/root.md new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/root.md @@ -0,0 +1 @@ +File without a valid license From 528e46a3e9d2f58f645d98520c08a55dd9438948 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Fri, 27 Dec 2024 17:01:19 +0000 Subject: [PATCH 017/123] fixed tests on Windows --- .../apache/rat/config/exclusion/plexus/MatchPattern.java | 2 +- .../src/main/java/org/apache/rat/document/DocumentName.java | 3 +-- .../exclusion/fileProcessors/AbstractIgnoreBuilderTest.java | 6 ++++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java index c43836ecd..1229cc4e9 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java @@ -141,7 +141,7 @@ static char[][] tokenizePathToCharArray(final String path, final String separato return tokenizedNameChar; } - public static MatchPattern fromString(final String source) { + public static MatchPattern fromString(final String source) { return new MatchPattern(source, File.separator); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java index e71bed85b..c56609071 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java @@ -69,7 +69,7 @@ public final class DocumentName implements Comparable { // determine the case sensitivity of the file system we are operating on. static { - boolean fsSensitive = true; + boolean fsSensitive; File f = null; try { Path p = Files.createTempDirectory("NameSet"); @@ -96,7 +96,6 @@ public final class DocumentName implements Comparable { ROOTS.add(name); } } - } /** diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java index 44338358c..4c4f03e8d 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java @@ -19,7 +19,9 @@ package org.apache.rat.config.exclusion.fileProcessors; import java.util.List; +import org.apache.rat.config.exclusion.ExclusionUtils; import org.apache.rat.config.exclusion.MatcherSet; +import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; import org.junit.jupiter.api.AfterEach; @@ -95,11 +97,11 @@ protected void assertCorrect(AbstractFileProcessorBuilder builder, Iterable matcherSets, DocumentName baseDir, Iterable matching, Iterable notMatching) { DocumentNameMatcher excluder = MatcherSet.merge(matcherSets).createMatcher(); for (String name : matching) { - DocumentName docName = baseDir.resolve(name); + DocumentName docName = baseDir.resolve(SelectorUtils.extractPattern(name, File.separator)); assertThat(excluder.matches(docName)).as(docName.getName()).isFalse(); } for (String name : notMatching) { - DocumentName docName = baseDir.resolve(name); + DocumentName docName = baseDir.resolve(SelectorUtils.extractPattern(name, File.separator)); assertThat(excluder.matches(docName)).as(docName.getName()).isTrue(); } } From 52f0589c4de1a1451f5cb565ea2f591d1dd27005 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Fri, 27 Dec 2024 17:12:19 +0000 Subject: [PATCH 018/123] turned on mvn debugging --- .github/workflows/maven.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 593c3afa0..91c518dd3 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -62,7 +62,7 @@ jobs: cache: 'maven' - name: Build with Maven - run: ./mvnw -e -B -V -ntp clean install + run: ./mvnw -X -e -B -V -ntp clean install - name: Generate javadoc run: ./mvnw -e -B -V -ntp javadoc:javadoc From 0741f3a5f195352d9e1f1c75174c032afe90e3c1 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 28 Dec 2024 09:42:29 +0000 Subject: [PATCH 019/123] Fixed command line file name processing --- .../java/org/apache/rat/commandline/Arg.java | 23 ++++---- .../rat/commandline/ArgumentContext.java | 24 ++++----- .../apache/rat/commandline/Converters.java | 53 ++++++++++++++++++- .../org/apache/rat/commandline/ArgTests.java | 7 +-- .../rat/test/AbstractOptionsProvider.java | 30 ++++++++--- 5 files changed, 103 insertions(+), 34 deletions(-) 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 b975e4150..f916e3843 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 @@ -119,10 +119,14 @@ public enum Arg { CONFIGURATION(new OptionGroup() .addOption(Option.builder().longOpt("config").hasArgs().argName("File") .desc("File names for system configuration.") + .converter(Converters.FILE_CONVERTER) + .type(File.class) .build()) .addOption(Option.builder().longOpt("licenses").hasArgs().argName("File") .desc("File names for system configuration.") .deprecated(DeprecatedAttributes.builder().setSince("0.17").setForRemoval(true).setDescription(StdMsgs.useMsg("--config")).get()) + .converter(Converters.FILE_CONVERTER) + .type(File.class) .build())), /** @@ -186,7 +190,6 @@ public enum Arg { .hasArg().argName("File").type(File.class) .converter(Converters.FILE_CONVERTER) .desc("Name of file containing the denied license IDs.") - .converter(Converters.FILE_CONVERTER) .build())), /** @@ -234,6 +237,7 @@ public enum Arg { "File names must use linux directory separator ('/') or none at all. " + "File names that do not start with '/' are relative to the directory where the " + "argument is located.") + .converter(Converters.FILE_CONVERTER) .type(File.class) .build())), @@ -585,8 +589,8 @@ private static void processConfigurationArgs(final ArgumentContext context) thro try { Defaults.Builder defaultBuilder = Defaults.builder(); if (CONFIGURATION.isSelected()) { - for (String fn : context.getCommandLine().getOptionValues(CONFIGURATION.getSelected())) { - File file = context.resolve(fn); + File[] files = CONFIGURATION.getParsedOptionValues(context.getCommandLine()); + for (File file : files) { defaultBuilder.add(file); } } @@ -604,8 +608,7 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (FAMILIES_APPROVED_FILE.isSelected()) { try { - String fileName = context.getCommandLine().getOptionValue(FAMILIES_APPROVED_FILE.getSelected()); - File f = context.resolve(fileName); + File f = context.getCommandLine().getParsedOptionValue(FAMILIES_APPROVED_FILE.getSelected()); try (InputStream in = Files.newInputStream(f.toPath())) { context.getConfiguration().addApprovedLicenseCategories(IOUtils.readLines(in, StandardCharsets.UTF_8)); } @@ -620,8 +623,7 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (FAMILIES_DENIED_FILE.isSelected()) { try { - String fileName = context.getCommandLine().getOptionValue(FAMILIES_DENIED_FILE.getSelected()); - File f = context.resolve(fileName); + File f = context.getCommandLine().getParsedOptionValue(FAMILIES_DENIED_FILE.getSelected()); try (InputStream in = Files.newInputStream(f.toPath())) { context.getConfiguration().removeApprovedLicenseCategories(IOUtils.readLines(in, StandardCharsets.UTF_8)); } @@ -637,8 +639,7 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (LICENSES_APPROVED_FILE.isSelected()) { try { - String fileName = context.getCommandLine().getOptionValue(LICENSES_APPROVED_FILE.getSelected()); - File file = context.resolve(fileName); + File file = context.getCommandLine().getParsedOptionValue(LICENSES_APPROVED_FILE.getSelected()); try (InputStream in = Files.newInputStream(file.toPath())) { context.getConfiguration().addApprovedLicenseIds(IOUtils.readLines(in, StandardCharsets.UTF_8)); } @@ -653,8 +654,7 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (LICENSES_DENIED_FILE.isSelected()) { try { - String fileName = context.getCommandLine().getOptionValue(LICENSES_DENIED_FILE.getSelected()); - File file = context.resolve(fileName); + File file = context.getCommandLine().getParsedOptionValue(LICENSES_DENIED_FILE.getSelected()); try (InputStream in = Files.newInputStream(file.toPath())) { context.getConfiguration().removeApprovedLicenseIds(IOUtils.readLines(in, StandardCharsets.UTF_8)); } @@ -800,6 +800,7 @@ public static void processLogLevel(final CommandLine commandLine) { * @throws ConfigurationException on error */ public static void processArgs(final ArgumentContext context) throws ConfigurationException { + Converters.FILE_CONVERTER.setWorkingDirectory(context.getWorkingDirectory()); processOutputArgs(context); processEditArgs(context); processInputArgs(context); diff --git a/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java b/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java index bc8b1c2e9..3fb4f94fb 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java +++ b/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java @@ -93,18 +93,18 @@ public DocumentName getWorkingDirectory() { return workingDirectory; } - /** - * Resolves the file name to the working directory if necessayr. - * @param fileName the file name to resolve. - * @return the file name string. - */ - public File resolve(final String fileName) { - if (!fileName.startsWith("/")) { - DocumentName fn = DocumentName.builder().setName(fileName).setBaseName("/").build(); - return new File(workingDirectory.resolve(fn.localized()).getName()); - } - return new File(fileName); - } +// /** +// * Resolves the file name to the working directory if necessayr. +// * @param fileName the file name to resolve. +// * @return the file name string. +// */ +// public File resolve(final String fileName) { +// if (!fileName.startsWith("/")) { +// DocumentName fn = DocumentName.builder().setName(fileName).setBaseName("/").build(); +// return new File(workingDirectory.resolve(fn.localized()).getName()); +// } +// return new File(fileName); +// } /** * Logs a ParseException as a warning. 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 197703f93..61f27cdbe 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 @@ -19,10 +19,12 @@ package org.apache.rat.commandline; import java.io.File; +import java.io.IOException; import org.apache.commons.cli.Converter; import org.apache.commons.lang3.tuple.Pair; import org.apache.rat.ConfigurationException; +import org.apache.rat.document.DocumentName; import org.apache.rat.report.claim.ClaimStatistic; import static java.lang.String.format; @@ -39,7 +41,8 @@ private Converters() { /** * Creates a File with fully qualified name */ - public static final Converter FILE_CONVERTER = s -> new File(s).getAbsoluteFile(); + public static final FileConverter FILE_CONVERTER = new FileConverter(); + /** * converts the Converter pattern into a Converter, count pair. */ @@ -55,4 +58,52 @@ private Converters() { throw new ConfigurationException(format("'%s' is not a valid Counter", parts[0]), e); } }; + + /** + * A converter that can handle relative or absolute files. + */ + public static final class FileConverter implements Converter { + /** The working directory to resolve relative files agains */ + private DocumentName workingDirectory; + + /** + * The constructor. + */ + private FileConverter() { + // private construction only. + } + + /** + * Sets the working directory for the conversion. + * @param workingDirectory + */ + public void setWorkingDirectory(final DocumentName workingDirectory) { + this.workingDirectory = workingDirectory; + } + + /** + * Applies the conversion function to the specified file name. + * @param fileName the file name to create a file from. + * @return a File. + * @throws NullPointerException if {@code fileName} is null. + */ + public File apply(final String fileName) throws NullPointerException { + File file = new File(fileName); + // is this a relative file? + if (!fileName.startsWith(File.separator)) { + // check for a root provided (e.g. C:\\)" + DocumentName.Builder builder = DocumentName.builder(file); + final DocumentName name = builder.build(); + if (name.getRoot().isEmpty()) { + // no root, resolve against workingDirectory + file = new File(workingDirectory.resolve(fileName).getName()).getAbsoluteFile(); + } + } + try { + return file.getCanonicalFile(); + } catch (IOException e) { + return file.getAbsoluteFile(); + } + } + } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java index fc4c980f9..c40941028 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java +++ b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java @@ -18,6 +18,7 @@ */ package org.apache.rat.commandline; +import java.io.IOException; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.Options; @@ -31,7 +32,7 @@ import java.io.File; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; public class ArgTests { @@ -43,7 +44,7 @@ private CommandLine createCommandLine(String[] args) throws ParseException { @ParameterizedTest @ValueSource(strings = { "rat.txt", "./rat.txt", "/rat.txt", "target/rat.test" }) - public void outputFleNameNoDirectoryTest(String name) throws ParseException { + public void outputFleNameNoDirectoryTest(String name) throws ParseException, IOException { class OutputFileConfig extends ReportConfiguration { private File actual = null; @Override @@ -58,6 +59,6 @@ public void setOut(File file) { OutputFileConfig configuration = new OutputFileConfig(); ArgumentContext ctxt = new ArgumentContext(new File("."), configuration, commandLine); Arg.processArgs(ctxt); - assertEquals(expected.getAbsolutePath(), configuration.actual.getAbsolutePath()); + assertThat(configuration.actual.getAbsolutePath()).isEqualTo(expected.getCanonicalPath()); } } 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 79dc5f9b3..e1f0748b6 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 @@ -80,14 +80,20 @@ public abstract class AbstractOptionsProvider { * A map of test Options to tests */ protected final Map testMap = new TreeMap<>(); - + /** The list of exclude args */ protected static final String[] EXCLUDE_ARGS = {"*.foo", "%regex[[A-Z]\\.bar]", "justbaz"}; + /** the list of include args */ protected static final String[] INCLUDE_ARGS = {"B.bar", "justbaz"}; /** * The directory to place test data in. */ protected File baseDir; + /** + * Copy the runtime data to the "target" directory. + * @param baseDir the base directory to copy to. + * @param targetDir the directory relative to the base directory to copy to. + */ public static void preserveData(File baseDir, String targetDir) { final Path recordPath = FileSystems.getDefault().getPath("target", targetDir); recordPath.toFile().mkdirs(); @@ -98,10 +104,19 @@ public static void preserveData(File baseDir, String targetDir) { } } + /** + * Gets the document name based on the baseDir. + * @return The document name based on the baseDir. + */ protected DocumentName baseName() { return DocumentName.builder(baseDir).build(); } + /** + * Copies the test data to the specified directory. + * @param baseDir the directory to copy the /src/test/resources to. + * @return the {@code baseDir} argument. + */ public static File setup(File baseDir) { try { final File sourceDir = Resources.getResourceDirectory("OptionTools"); @@ -255,7 +270,7 @@ private void execExcludeTest(Option option, String[] args) { private void excludeFileTest(Option option) { File outputFile = writeFile("exclude.txt", Arrays.asList(EXCLUDE_ARGS)); - execExcludeTest(option, new String[]{outputFile.getPath()}); + execExcludeTest(option, new String[]{outputFile.getAbsolutePath()}); } protected void excludeFileTest() { @@ -375,7 +390,7 @@ private void execIncludeTest(Option option, String[] args) { private void includeFileTest(Option option) { File outputFile = writeFile("include.txt", Arrays.asList(INCLUDE_ARGS)); - execIncludeTest(option, new String[]{outputFile.getPath()}); + execIncludeTest(option, new String[]{outputFile.getAbsolutePath()}); } protected void inputIncludeFileTest() { @@ -470,7 +485,7 @@ protected void helpLicenses() { protected void licensesApprovedFileTest() { File outputFile = writeFile("licensesApproved.txt", Arrays.asList("one", "two")); execLicensesApprovedTest(Arg.LICENSES_APPROVED_FILE.find("licenses-approved-file"), - new String[]{outputFile.getPath()}); + new String[]{outputFile.getAbsolutePath()}); } protected void licensesApprovedTest() { @@ -495,7 +510,8 @@ protected void licensesDeniedTest() { protected void licensesDeniedFileTest() { File outputFile = writeFile("licensesDenied.txt", Collections.singletonList("ILLUMOS")); - execLicensesDeniedTest(Arg.LICENSES_DENIED_FILE.find("licenses-denied-file"), new String[]{outputFile.getPath()}); + execLicensesDeniedTest(Arg.LICENSES_DENIED_FILE.find("licenses-denied-file"), + new String[]{outputFile.getAbsolutePath()}); } private void execLicenseFamiliesApprovedTest(Option option, String[] args) { @@ -522,7 +538,7 @@ private void execLicenseFamiliesApprovedTest(Option option, String[] args) { protected void licenseFamiliesApprovedFileTest() { File outputFile = writeFile("familiesApproved.txt", Collections.singletonList("catz")); execLicenseFamiliesApprovedTest(Arg.FAMILIES_APPROVED_FILE.find("license-families-approved-file"), - new String[]{outputFile.getPath()}); + new String[]{outputFile.getAbsolutePath()}); } protected void licenseFamiliesApprovedTest() { @@ -545,7 +561,7 @@ private void execLicenseFamiliesDeniedTest(Option option, String[] args) { protected void licenseFamiliesDeniedFileTest() { File outputFile = writeFile("familiesDenied.txt", Collections.singletonList("GPL")); execLicenseFamiliesDeniedTest(Arg.FAMILIES_DENIED_FILE.find("license-families-denied-file"), - new String[]{outputFile.getPath()}); + new String[]{outputFile.getAbsolutePath()}); } protected void licenseFamiliesDeniedTest() { From e6c723ac3d720161431a2f58abb04abe81a34781 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 28 Dec 2024 12:11:22 +0000 Subject: [PATCH 020/123] added test failure info --- .github/workflows/maven.yml | 2 +- .../org/apache/rat/OptionCollectionTest.java | 14 ++--- .../exclusion/ExclusionProcessorTest.java | 8 ++- .../rat/test/AbstractOptionsProvider.java | 52 ++++++++++++++----- 4 files changed, 51 insertions(+), 25 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 91c518dd3..593c3afa0 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -62,7 +62,7 @@ jobs: cache: 'maven' - name: Build with Maven - run: ./mvnw -X -e -B -V -ntp clean install + run: ./mvnw -e -B -V -ntp clean install - name: Generate javadoc run: ./mvnw -e -B -V -ntp javadoc:javadoc 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 a1d21ea99..bd31ea1f9 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 @@ -51,11 +51,7 @@ import static java.lang.String.format; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; +import static org.assertj.core.api.Fail.fail; public class OptionCollectionTest { @TempDir @@ -148,7 +144,7 @@ public void getReportableTest(String fName) throws IOException { File expected = new File(fName); ReportConfiguration config = OptionCollection.parseCommands(testPath.toFile(), new String[]{fName}, o -> fail("Help called"), false); IReportable reportable = OptionCollection.getReportable(expected, config); - assertNotNull(reportable, () -> format("'%s' returned null", fName)); + assertThat(reportable).as(() -> format("'%s' returned null", fName)).isNotNull(); assertThat(reportable.getName().getName()).isEqualTo(expected.getAbsolutePath()); } @@ -177,8 +173,8 @@ public void helpTest() { String[] args = {longOpt(OptionCollection.HELP)}; try { ReportConfiguration config = OptionCollection.parseCommands(testPath.toFile(), args, o -> helpCalled.set(true), true); - assertNull(config, "Should not have config"); - assertTrue(helpCalled.get(), "Help was not called"); + assertThat(config).as("Should not have config").isNull(); + assertThat(helpCalled.get()).as("Help was not called").isTrue(); } catch (IOException e) { fail(e.getMessage()); } @@ -211,7 +207,7 @@ protected final ReportConfiguration generateConfig(List> } } ReportConfiguration config = OptionCollection.parseCommands(testPath.toFile(), sArgs.toArray(new String[0]), o -> helpCalled.set(true), true); - assertFalse(helpCalled.get(), "Help was called"); + assertThat(helpCalled.get()).as("Help was called").isFalse(); return config; } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/ExclusionProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/ExclusionProcessorTest.java index 580d10849..f8535a90b 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/ExclusionProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/ExclusionProcessorTest.java @@ -51,7 +51,13 @@ public void setup() { } private void testParseExclusion(DocumentNameMatcher nameMatcher, DocumentName name, boolean expected) { - assertThat(nameMatcher.matches(name)).as(() -> format("Failed on [%s %s]", basedir, name)).isEqualTo(expected); + assertThat(nameMatcher.matches(name)).as(() -> format("Failed on [%s %s]%n%s", basedir, name, dump(nameMatcher, name))).isEqualTo(expected); + } + + private String dump(DocumentNameMatcher nameMatcher, DocumentName name) { + StringBuilder sb = new StringBuilder(); + nameMatcher.decompose(name).forEach(s -> sb.append(s).append("\n")); + return sb.toString(); } private DocumentName mkName(String pth) { 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 e1f0748b6..4d8ff6de2 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 @@ -64,10 +64,11 @@ import java.util.SortedSet; import java.util.TreeMap; import java.util.stream.Stream; +import org.junit.jupiter.params.provider.ArgumentsProvider; import static org.apache.rat.commandline.Arg.HELP_LICENSES; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; +import static org.assertj.core.api.Fail.fail; /** * A list of methods that an OptionsProvider in a test case must support. @@ -75,7 +76,7 @@ * 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 { +public abstract class AbstractOptionsProvider implements ArgumentsProvider { /** * A map of test Options to tests */ @@ -250,6 +251,16 @@ private String displayArgAndName(Option option, String fname) { return String.format("%s %s", option.getLongOpt(), fname); } + private String dump(DocumentNameMatcher nameMatcher, DocumentName name) { + StringBuilder sb = new StringBuilder(); + nameMatcher.decompose(name).forEach(s -> sb.append(s).append("\n")); + return sb.toString(); + } + + private String dump(Option option, String fname, DocumentNameMatcher matcher, DocumentName name) { + return String.format("%s%n%s", displayArgAndName(option, fname), dump(matcher, name)); + } + // exclude tests private void execExcludeTest(Option option, String[] args) { String[] notExcluded = {"notbaz", "well._afile"}; @@ -258,10 +269,12 @@ private void execExcludeTest(Option option, String[] args) { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : notExcluded) { - assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isTrue(); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); } for (String fname : excluded) { - assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isFalse(); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); } } catch (IOException e) { fail(e.getMessage()); @@ -298,10 +311,12 @@ protected void inputExcludeStdTest() { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { - assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isFalse(); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); } for (String fname : notExcluded) { - assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isTrue(); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -334,10 +349,12 @@ protected void inputExcludeParsedScmTest() { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { - assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isFalse(); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isFalse(); } for (String fname : notExcluded) { - assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isTrue(); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -358,10 +375,12 @@ private void inputExcludeSizeTest() { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { - assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isFalse(); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); } for (String fname : notExcluded) { - assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isTrue(); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -378,10 +397,12 @@ private void execIncludeTest(Option option, String[] args) { ImmutablePair.of(excludeOption, EXCLUDE_ARGS)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { - assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isFalse(); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); } for (String fname : notExcluded) { - assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isTrue(); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -420,10 +441,12 @@ protected void inputIncludeStdTest() { ReportConfiguration config = generateConfig(excludes, ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { - assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isFalse(); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); } for (String fname : notExcluded) { - assertThat(excluder.matches(mkDocName(fname))).as(() -> displayArgAndName(option, fname)).isTrue(); + DocumentName docName = mkDocName(fname); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -914,6 +937,7 @@ protected void xmlTest() { } } + @Override final public Stream provideArguments(ExtensionContext context) { List lst = new ArrayList<>(); List missingTests = new ArrayList<>(); From 7e9c7dd277974f4abd6516033ffe783966a8bb7a Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 28 Dec 2024 13:15:32 +0000 Subject: [PATCH 021/123] Added more info to decompose messages --- .../rat/document/DocumentNameMatcher.java | 103 ++++++++++++++++-- .../rat/document/DocumentNameMatcherTest.java | 3 + 2 files changed, 94 insertions(+), 12 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index d788d35c6..4b24f6dd7 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -85,9 +85,7 @@ public DocumentNameMatcher(final String name, final DocumentNameMatcher delegate * @param basedir the base directory for the scanning. */ public DocumentNameMatcher(final String name, final MatchPatterns patterns, final DocumentName basedir) { - this(name, (Predicate) documentName -> patterns.matches(documentName.getName(), - tokenize(documentName.getName(), basedir.getDirectorySeparator()), - basedir.isCaseSensitive())); + this(name, new MatchPatternsPredicate(basedir, patterns)); } /** @@ -120,7 +118,7 @@ public DocumentNameMatcher(final String name, final MatchPatterns matchers) { * @param fileFilter the file filter to execute. */ public DocumentNameMatcher(final String name, final FileFilter fileFilter) { - this(name, (Predicate) documentName -> fileFilter.accept(new File(documentName.getName()))); + this(name, new FileFilterPredicate(fileFilter)); } /** @@ -161,7 +159,7 @@ public List decompose(final DocumentName candidate) { private void decompose(final int level, final DocumentNameMatcher matcher, final DocumentName candidate, final List result) { final Predicate pred = matcher.getPredicate(); - result.add(new DecomposeData(level, matcher.toString(), pred.test(candidate))); + result.add(new DecomposeData(level, matcher, pred.test(candidate))); if (pred instanceof DocumentNameMatcher.CollectionPredicate) { final DocumentNameMatcher.CollectionPredicate collection = (DocumentNameMatcher.CollectionPredicate) pred; for (DocumentNameMatcher subMatcher : collection.getMatchers()) { @@ -192,8 +190,7 @@ public static DocumentNameMatcher not(final DocumentNameMatcher nameMatcher) { return MATCHES_ALL; } - return new DocumentNameMatcher(format("not(%s)", nameMatcher), - (Predicate) documentName -> !nameMatcher.matches(documentName)); + return new DocumentNameMatcher(format("not(%s)", nameMatcher), new NotPredicate(nameMatcher)); } /** @@ -311,10 +308,80 @@ public static DocumentNameMatcher and(final DocumentNameMatcher... matchers) { return and(Arrays.asList(matchers)); } + /** + * A DocumentName predicate that uses MatchPatterns. + */ + public static final class MatchPatternsPredicate implements Predicate { + /** The base diirectory for the pattern matches */ + private final DocumentName basedir; + /** The patter matchers */ + private final MatchPatterns patterns; + + private MatchPatternsPredicate(final DocumentName basedir, final MatchPatterns patterns) { + this.basedir = basedir; + this.patterns = patterns; + } + + @Override + public boolean test(final DocumentName documentName) { + return patterns.matches(documentName.getName(), + tokenize(documentName.getName(), basedir.getDirectorySeparator()), + basedir.isCaseSensitive()); + } + + @Override + public String toString() { + return patterns.toString(); + } + } + + /** + * A DocumentName predicate reverses another DocumentNameMatcher + */ + public static final class NotPredicate implements Predicate { + /** The document name matcher to reverse */ + private final DocumentNameMatcher nameMatcher; + + private NotPredicate(final DocumentNameMatcher nameMatcher) { + this.nameMatcher = nameMatcher; + } + + @Override + public boolean test(final DocumentName documentName) { + return !nameMatcher.matches(documentName); + } + + @Override + public String toString() { + return nameMatcher.predicate.toString(); + } + } + + /** + * A DocumentName predicate that uses FileFilter. + */ + public static final class FileFilterPredicate implements Predicate { + /** The file filter */ + private final FileFilter fileFilter; + + private FileFilterPredicate(final FileFilter fileFilter) { + this.fileFilter = fileFilter; + } + + @Override + public boolean test(final DocumentName documentName) { + return fileFilter.accept(new File(documentName.getName())); + } + + @Override + public String toString() { + return fileFilter.toString(); + } + } + /** * A marker interface to indicate this predicate contains a collection of matchers. */ - // package private for testing access abstract static class CollectionPredicate implements Predicate { /** The collection for matchers that make up this predicate */ private final Iterable matchers; @@ -334,6 +401,14 @@ protected CollectionPredicate(final Iterable matchers) { public Iterable getMatchers() { return matchers; } + + public String toString() { + StringBuilder builder = new StringBuilder(); + for (DocumentNameMatcher matcher : matchers) { + builder.append(matcher.predicate.toString()).append(System.lineSeparator()); + } + return builder.toString(); + } } /** @@ -407,13 +482,13 @@ public static final class DecomposeData { /** the level this data was generated at */ private final int level; /** The name of the DocumentNameMatcher that created this result */ - private final String name;; + private final DocumentNameMatcher matcher; /** The result of the check. */ private final boolean result; - private DecomposeData(final int level, final String name, final boolean result) { + private DecomposeData(final int level, final DocumentNameMatcher matcher, final boolean result) { this.level = level; - this.name = name; + this.matcher = matcher; this.result = result; } @@ -422,7 +497,11 @@ public String toString() { final char[] chars = new char[level * 2]; Arrays.fill(chars, ' '); final String fill = new String(chars); - return String.format("%s%s : %s", fill, name, result); + return fill + + matcher.toString() + " : " + result + + System.lineSeparator() + + fill + " " + + matcher.predicate.toString(); } } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java index 4c2e04ba8..6b7c3e374 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java @@ -18,7 +18,10 @@ */ package org.apache.rat.document; +import java.io.File; +import java.io.FileFilter; import java.util.function.Predicate; +import org.apache.commons.io.filefilter.NameFileFilter; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; From 07ca02a421f187f7876960d6c1420e9c6e3dd375 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Wed, 1 Jan 2025 15:12:26 +0000 Subject: [PATCH 022/123] updated some tests --- apache-rat-core/pom.xml | 5 + .../rat/commandline/ArgumentContext.java | 2 +- .../config/exclusion/ExclusionProcessor.java | 16 +- .../rat/config/exclusion/ExclusionUtils.java | 45 +- .../rat/config/exclusion/MatcherSet.java | 4 +- .../config/exclusion/StandardCollection.java | 30 +- .../AbstractFileProcessorBuilder.java | 32 +- .../fileProcessors/CVSIgnoreBuilder.java | 2 +- .../fileProcessors/HgIgnoreBuilder.java | 4 +- .../config/exclusion/plexus/MatchPattern.java | 5 +- .../exclusion/plexus/MatchPatterns.java | 12 +- .../org/apache/rat/document/DocumentName.java | 425 +++++++++++------- .../rat/document/DocumentNameMatcher.java | 12 +- .../org/apache/rat/walker/ArchiveWalker.java | 9 +- .../org/apache/rat/walker/FileListWalker.java | 20 +- .../exclusion/ExclusionProcessorTest.java | 161 ++++--- .../config/exclusion/FileProcessorTest.java | 56 ++- .../rat/document/DocumentNameBuilderTest.java | 322 +++++++++++++ .../apache/rat/document/DocumentNameTest.java | 258 +++++++---- .../org/apache/rat/document/FSInfoTest.java | 60 +++ .../rat/document/guesser/NoteGuesserTest.java | 32 +- .../rat/testhelpers/TestingDocument.java | 4 +- .../apache/rat/walker/FileListWalkerTest.java | 12 +- pom.xml | 6 + 24 files changed, 1118 insertions(+), 416 deletions(-) create mode 100644 apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java create mode 100644 apache-rat-core/src/test/java/org/apache/rat/document/FSInfoTest.java diff --git a/apache-rat-core/pom.xml b/apache-rat-core/pom.xml index 8ac00d1e3..844a7efc5 100644 --- a/apache-rat-core/pom.xml +++ b/apache-rat-core/pom.xml @@ -281,5 +281,10 @@ groovy-all test + + com.google.jimfs + jimfs + test + diff --git a/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java b/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java index 3fb4f94fb..dfa7be71e 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java +++ b/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java @@ -48,7 +48,7 @@ public class ArgumentContext { * @param commandLine The command line that is building the configuration. */ public ArgumentContext(final File workingDirectory, final ReportConfiguration configuration, final CommandLine commandLine) { - this.workingDirectory = DocumentName.builder().setName(workingDirectory.getAbsoluteFile()).build(); + this.workingDirectory = DocumentName.builder(workingDirectory).build(); this.commandLine = commandLine; this.configuration = configuration; } 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 eb000f4c2..48d5eddc3 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 @@ -187,7 +187,7 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { // add the file processors final List matchers = extractFileProcessors(basedir); final MatcherSet.Builder fromCommandLine = new MatcherSet.Builder(); - DocumentName.Builder nameBuilder = DocumentName.builder().setBaseName(basedir); + DocumentName.Builder nameBuilder = DocumentName.builder(basedir).setBaseName(basedir); extractPatterns(nameBuilder, fromCommandLine); extractCollectionPatterns(nameBuilder, fromCommandLine); extractCollectionMatchers(fromCommandLine); @@ -219,6 +219,10 @@ private List extractFileProcessors(final DocumentName basedir) { return fileProcessorList; } + private String preparePattern(DocumentName documentName, String pattern) { + return ExclusionUtils.localizePattern(documentName, + ExclusionUtils.convertSeparator(pattern, "/", documentName.getDirectorySeparator())); + } /** * Extracts {@link #includedPatterns} and {@link #excludedPatterns} into the specified matcherBuilder. * @param nameBuilder The name builder for the pattern. File names are resolved against the generated name. @@ -228,11 +232,12 @@ private void extractPatterns(final DocumentName.Builder nameBuilder, final Match DocumentName name = nameBuilder.setName("Patterns").build(); if (!excludedPatterns.isEmpty()) { matcherBuilder.addExcluded(name, excludedPatterns.stream() - .map(s -> ExclusionUtils.localizePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); + .map(s -> preparePattern(name, s)) + .collect(Collectors.toSet())); } if (!includedPatterns.isEmpty()) { matcherBuilder.addIncluded(name, includedPatterns.stream() - .map(s -> ExclusionUtils.localizePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); + .map(s -> preparePattern(name, s)).collect(Collectors.toSet())); } } @@ -262,9 +267,8 @@ private void extractCollectionPatterns(final DocumentName.Builder nameBuilder, f } DocumentName name = nameBuilder.setName("Collections").build(); matcherBuilder - .addExcluded(name, excl) - .addIncluded(name, incl); - + .addExcluded(name, excl.stream().map(s -> preparePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())) + .addIncluded(name, incl.stream().map(s -> preparePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); } /** diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java index b1366f43e..772526d67 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java @@ -192,12 +192,20 @@ protected boolean isValidLine(final String line) { /** * Returns {@code true} if the file name represents a hidden file - * @param f the file to check. + * @param file the file to check. * @return true if it is the name of a hidden file. */ - public static boolean isHidden(final File f) { - String s = f.getName(); - return s.startsWith(".") && !(s.equals(".") || s.equals("..")); + public static boolean isHidden(final File file) { + return isHidden(file.getName()); + } + + /** + * Returns {@code true} if the filename represents a hidden file + * @param fileName the file to check. + * @return true if it is the name of a hidden file. + */ + public static boolean isHidden(final String fileName) { + return fileName.startsWith(".") && !(fileName.equals(".") || fileName.equals("..")); } private static void verifyFile(final File file) { @@ -217,19 +225,30 @@ public static String localizePattern(final DocumentName documentName, final Stri boolean prefix = pattern.startsWith(NEGATION_PREFIX); String workingPattern = prefix ? pattern.substring(1) : pattern; String normalizedPattern = SelectorUtils.extractPattern(workingPattern, documentName.getDirectorySeparator()); - StringBuilder sb = new StringBuilder(); - if (SelectorUtils.isRegexPrefixedPattern(workingPattern)) { - sb.append(prefix ? NEGATION_PREFIX : "") + + String result = SelectorUtils.isRegexPrefixedPattern(workingPattern) ? + new StringBuilder(prefix ? NEGATION_PREFIX : "") .append(SelectorUtils.REGEX_HANDLER_PREFIX) .append("\\Q").append(documentName.getBaseName()) .append(documentName.getDirectorySeparator()) .append("\\E").append(normalizedPattern) - .append(SelectorUtils.PATTERN_HANDLER_SUFFIX); - return sb.toString(); - } else { - sb.append(documentName.getBaseName()) - .append(documentName.getDirectorySeparator()).append(normalizedPattern); - return (prefix ? NEGATION_PREFIX : "") + DocumentName.builder(documentName).setName(sb.toString()).build().getName(); + .append(SelectorUtils.PATTERN_HANDLER_SUFFIX) + .toString() + : documentName.getBaseDocumentName().resolve(normalizedPattern).getName(); + return (prefix ? NEGATION_PREFIX : "") + result; + } + + /** + * Tokenizes the string based on the directory separator. + * @param source the source to tokenize + * @param from the directory separator for the source. + * @param to the directory separator for the result. + * @return the source string with the separators converted. + */ + public static String convertSeparator(final String source, final String from, final String to) { + if (StringUtils.isEmpty(source) || from.equals(to)) { + return source; } + return String.join(to, source.split("\\Q" + from + "\\E")); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java index 81188cc7c..da6ed194e 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -102,7 +102,7 @@ public Builder() { public Builder addIncluded(final DocumentName fromDocument, final Set names) { if (!names.isEmpty()) { String name = String.format("'included %s'", fromDocument.localized("/").substring(1)); - addIncluded(new DocumentNameMatcher(name, MatchPatterns.from(names), fromDocument.getBaseDocumentName())); + addIncluded(new DocumentNameMatcher(name, MatchPatterns.from("/", names), fromDocument.getBaseDocumentName())); } return this; } @@ -117,7 +117,7 @@ public Builder addIncluded(final DocumentName fromDocument, final Set na public Builder addExcluded(final DocumentName fromDocument, final Set names) { if (!names.isEmpty()) { String name = String.format("'excluded %s'", fromDocument.localized("/").substring(1)); - addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(names), fromDocument.getBaseDocumentName())); + addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(fromDocument.getDirectorySeparator(), names), fromDocument.getBaseDocumentName())); } return this; } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java index 46fe649e0..5921ecaa7 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java @@ -101,20 +101,34 @@ null, new CVSIgnoreBuilder()), */ HIDDEN_DIR("The hidden directories. Directories with names that start with '.'", null, - new DocumentNameMatcher("HIDDEN_DIR", (Predicate) documentName -> { - File f = new File(documentName.getName()); - return f.isDirectory() && ExclusionUtils.isHidden(f); - }), null + new DocumentNameMatcher("HIDDEN_DIR", new Predicate() { + @Override + public boolean test(DocumentName documentName) { + File file = documentName.asFile(); + return file.isDirectory() && ExclusionUtils.isHidden(documentName.getShortName()); + } + @Override + public String toString() { + return "HIDDEN_DIR"; + } + }), null ), /** * The hidden files. Directories with names that start with '.' */ HIDDEN_FILE("The hidden files. Directories with names that start with '.'", null, - new DocumentNameMatcher("HIDDEN_FILE", (Predicate) documentName -> { - File f = new File(documentName.getName()); - return f.isFile() && ExclusionUtils.isHidden(f); - }), null + new DocumentNameMatcher("HIDDEN_FILE", new Predicate() { + @Override + public boolean test(DocumentName documentName) { + File file = documentName.asFile(); + return file.isFile() && ExclusionUtils.isHidden(documentName.getShortName()); + } + @Override + public String toString() { + return "HIDDEN_FILE"; + } + }), null ), /** * The files and directories created by an IDEA IDE based tool. diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java index 42278f97c..c5f7470e9 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java @@ -115,21 +115,21 @@ private List createMatcherSetList() { /** * Builder the list of MatcherSet that define the inclusions/exclusions for the file processor. - * @param dir the directory agains which name resolution should be made. + * @param root the directory against which name resolution should be made. * @return the List of MatcherSet that represent this file processor. */ - public final List build(final DocumentName dir) { + public final List build(final DocumentName root) { if (includeProcessorFile) { String name = String.format("**/%s", fileName); - String pattern = ExclusionUtils.localizePattern(dir, name); + String pattern = ExclusionUtils.localizePattern(root, name); MatcherSet matcherSet = new MatcherSet.Builder() - .addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(Collections.singletonList(pattern)), dir)) + .addExcluded(new DocumentNameMatcher(name, MatchPatterns.from("/", Collections.singletonList(pattern)), root)) .build(); LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(0, k -> new LevelBuilder()); levelBuilder.add(matcherSet); } - checkDirectory(0, dir, new NameFileFilter(fileName)); + checkDirectory(0, root, root, new NameFileFilter(fileName)); List result = levelBuilders.size() == 1 ? Collections.singletonList(levelBuilders.get(0).asMatcherSet()) : createMatcherSetList(); @@ -140,9 +140,12 @@ public final List build(final DocumentName dir) { /** * Process by reading the file, creating a MatcherSet, and adding it to the * matcherSets. + * @param matcherSetConsumer the consumer to add the custom matcher sets to. + * @param root The root against which to resolve names. * @param documentName the file to read. + * @return A matcher set based on the strings in the file. */ - protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName dirBasedName, final DocumentName documentName) { + protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName root, final DocumentName documentName) { final MatcherSet.Builder matcherSetBuilder = new MatcherSet.Builder(); final List iterable = new ArrayList<>(); ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) @@ -154,25 +157,26 @@ protected MatcherSet process(final Consumer matcherSetConsumer, fina Set included = new HashSet<>(); Set excluded = new HashSet<>(); MatcherSet.Builder.segregateList(excluded, included, iterable); - matcherSetBuilder.addExcluded(dirBasedName, excluded); - matcherSetBuilder.addIncluded(dirBasedName, included); + matcherSetBuilder.addExcluded(root, excluded); + matcherSetBuilder.addIncluded(root, included); return matcherSetBuilder.build(); } /** * Process the directory tree looking for files that match the filter. Call {@link #process} on any matching file. + * @param level the level being precessed + * @param root the directory against which names should be resolved. * @param directory The name of the directory to process. * @param fileFilter the filter to detect processable files with. */ - private void checkDirectory(final int level, final DocumentName directory, final FileFilter fileFilter) { - File dirFile = new File(directory.getName()); - for (File f : listFiles(dirFile, fileFilter)) { + private void checkDirectory(final int level, final DocumentName root, final DocumentName directory, final FileFilter fileFilter) { + File dirFile = directory.asFile(); + for (File file : listFiles(dirFile, fileFilter)) { LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(level, k -> new LevelBuilder()); - DocumentName dirBasedName = DocumentName.builder(f).setBaseName(directory.getBaseName()).build(); - levelBuilder.add(process(levelBuilder::add, dirBasedName, DocumentName.builder(f).setBaseName(directory.getName()).build())); + levelBuilder.add(process(levelBuilder::add, root, DocumentName.builder(file).build())); } for (File dir : listFiles(dirFile, DirectoryFileFilter.DIRECTORY)) { - checkDirectory(level + 1, DocumentName.builder(dir).setBaseName(directory.getBaseName()).build(), fileFilter); + checkDirectory(level + 1, root, DocumentName.builder(dir).setBaseName(directory.getBaseName()).build(), fileFilter); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java index 0f2ff1047..0f6a7b26d 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java @@ -45,7 +45,7 @@ public CVSIgnoreBuilder() { } @Override - protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName dirBasedName, final DocumentName documentName) { + protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName root, final DocumentName documentName) { final File dir = new File(documentName.getName()); Set result = new HashSet<>(); Iterator iter = ExclusionUtils.asIterator(dir, StringUtils::isNotBlank); diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java index d7d0ad05b..ec238090c 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java @@ -60,9 +60,9 @@ public HgIgnoreBuilder() { } @Override - protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName dirBasedName, final DocumentName documentName) { + protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName root, final DocumentName documentName) { state = Syntax.REGEXP; - return super.process(matcherSetConsumer, dirBasedName, documentName); + return super.process(matcherSetConsumer, root, documentName); } @Override diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java index 1229cc4e9..9715b99ec 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java @@ -49,7 +49,7 @@ public final class MatchPattern { private final char[][] tokenizedChar; - private MatchPattern(final String source, final String separator) { + public MatchPattern(final String source, final String separator) { regexPattern = SelectorUtils.isRegexPrefixedPattern(source) ? source.substring( SelectorUtils.REGEX_HANDLER_PREFIX.length(), @@ -141,7 +141,4 @@ static char[][] tokenizePathToCharArray(final String path, final String separato return tokenizedNameChar; } - public static MatchPattern fromString(final String source) { - return new MatchPattern(source, File.separator); - } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java index 454ba304e..88f4aa77c 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java @@ -96,23 +96,23 @@ public boolean matchesPatternStart(final String name, final boolean isCaseSensit return false; } - public static MatchPatterns from(final String... sources) { + public static MatchPatterns from(final String separator, final String... sources) { final int length = sources.length; MatchPattern[] result = new MatchPattern[length]; for (int i = 0; i < length; i++) { - result[i] = MatchPattern.fromString(sources[i]); + result[i] = new MatchPattern(sources[i], separator); } return new MatchPatterns(result); } - public static MatchPatterns from(final Iterable strings) { - return new MatchPatterns(getMatchPatterns(strings)); + public static MatchPatterns from(final String separator, final Iterable strings) { + return new MatchPatterns(getMatchPatterns(separator, strings)); } - private static MatchPattern[] getMatchPatterns(final Iterable items) { + private static MatchPattern[] getMatchPatterns(final String separator, final Iterable items) { List result = new ArrayList<>(); for (String string : items) { - result.add(MatchPattern.fromString(string)); + result.add(new MatchPattern(string, separator)); } return result.toArray(new MatchPattern[0]); } diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java index c56609071..1c7d50625 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java @@ -20,19 +20,24 @@ import java.io.File; import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.Objects; -import java.util.Set; +import java.util.Optional; -import org.apache.commons.io.FileUtils; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.builder.CompareToBuilder; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; -import org.apache.rat.utils.DefaultLog; /** * The name for a document. The {@code DocumentName} is an immutable structure that handles all the intricacies of file @@ -51,51 +56,50 @@ * within an archive. When representing a file in an archive the baseName is the name of the enclosing archive document. *

    */ -public final class DocumentName implements Comparable { - /** The list of all roots on the file system. */ - static final Set ROOTS = new HashSet<>(); - /** {@code True} if the file system on which we are operating is case-sensitive. */ - public static final boolean FS_IS_CASE_SENSITIVE; +public class DocumentName implements Comparable { /** The full name for the document. */ private final String name; /** The name of the base directory for the document. */ - private final String baseName; - /** The directory separator for this document. */ - private final String dirSeparator; - /** The case-sensitive flag */ - private final boolean isCaseSensitive; + //private final String baseName; + private final DocumentName baseName; + /** The file system info for this document. */ + private final FSInfo fsInfo; /** The root for the DocumentName. May be empty but not null. */ private final String root; - // determine the case sensitivity of the file system we are operating on. - static { - boolean fsSensitive; - File f = null; + private static final FSInfo DEFAULT_FSINFO = new FSInfo(FileSystems.getDefault()); + + private static boolean isCaseSensitive(FileSystem fs) { + boolean isCaseSensitive = false; + Path nameSet = null; + Path filea = null; + Path fileA = null; try { - Path p = Files.createTempDirectory("NameSet"); - f = p.toFile(); - fsSensitive = !new File(f, "a").equals(new File(f, "A")); - } catch (IOException e) { - fsSensitive = true; - } finally { - if (f != null) { - try { - FileUtils.deleteDirectory(f); - } catch (IOException e) { - DefaultLog.getInstance().warn("Unable to delete temporary directory: " + f, e); + try { + Path root = fs.getPath(""); + nameSet = Files.createTempDirectory(root, "NameSet"); + filea = nameSet.resolve("a"); + fileA = nameSet.resolve("A"); + Files.createFile(filea); + Files.createFile(fileA); + isCaseSensitive = true; + } catch (IOException e) { + // do nothing + } finally { + if (filea != null) { + Files.deleteIfExists(filea); + } + if (fileA != null) { + Files.deleteIfExists(fileA); + } + if (nameSet != null) { + Files.deleteIfExists(nameSet); } } + } catch (IOException e) { + // do nothing. } - FS_IS_CASE_SENSITIVE = fsSensitive; - - // determine all the roots on the file system(s). - File[] roots = File.listRoots(); - if (roots != null) { - for (File root : roots) { - String name = root.getPath(); - ROOTS.add(name); - } - } + return isCaseSensitive; } /** @@ -103,13 +107,20 @@ public final class DocumentName implements Comparable { * @return the Builder. */ public static Builder builder() { - return new Builder(); + return new Builder(DEFAULT_FSINFO); + } + + public static Builder builder(FSInfo fsInfo) { + return new Builder(fsInfo); + } + + public static Builder builder(FileSystem fileSystem) { + return new Builder(fileSystem); } /** * Creates a builder from a File. The {@link #baseName} is set to the file name if it is a directory otherwise - * it is set to the directory containing the file. The {@link #dirSeparator} is set from the file and - * case sensitivity based on the local file system. + * it is set to the directory containing the file. * @param file The file to set defaults from. * @return the Builder. */ @@ -132,24 +143,56 @@ public static Builder builder(final DocumentName documentName) { */ private DocumentName(final Builder builder) { this.name = builder.name; - this.baseName = builder.baseName; - this.dirSeparator = builder.dirSeparator; - this.isCaseSensitive = builder.isCaseSensitive; + this.fsInfo = builder.fsInfo; this.root = builder.root; + this.baseName = builder.sameNameFlag ? this : builder.baseName; + } + + public File asFile() { + return new File(getName()); + } + + public Path asPath() { + return Paths.get(name); } /** - * Creates a new DocumentName by adding the child to the current name. + * Creates a new DocumentName by adding the child to the current name. Resulting documentName will + * have the same base name. * @param child the child to add (must use directory separator from this document name). - * @return the new document name with the same {@link #baseName}, {@link #dirSeparator} and case sensitivity as + * @return the new document name with the same {@link #baseName}, directory sensitivity and case sensitivity as * this one. */ public DocumentName resolve(final String child) { - List parts = new ArrayList<>(); - parts.addAll(Arrays.asList(tokenize(name))); - parts.addAll(Arrays.asList(tokenize(child))); - String newName = String.join(dirSeparator, parts); - return new Builder(this).setName(newName).build(); + if (StringUtils.isBlank(child)) { + return this; + } + String separator = getDirectorySeparator(); + String pattern = separator.equals("/") ? child.replace('\\', '/') : + child.replace('/', '\\'); + + if (!pattern.startsWith(separator)) { + pattern = name + separator + pattern; + } + + return new Builder(this).setName(normalize(pattern)).build(); + } + + private String normalize(String pattern) { + List parts = new ArrayList<>(Arrays.asList(tokenize(pattern))); + for (int i=0; i{ + private final String separator; + private final boolean isCaseSensitive; + private final List roots; + + public FSInfo(FileSystem fileSystem) { + this.separator = fileSystem.getSeparator(); + this.isCaseSensitive = DocumentName.isCaseSensitive(fileSystem); + roots = new ArrayList<>(); + fileSystem.getRootDirectories().forEach(r -> roots.add(r.toString())); + } + + public String dirSeparator() { + return separator; + } + + public boolean isCaseSensitive() { + return isCaseSensitive; + } + + public Optional rootFor(String workingName) { + for (String sysRoot : roots) { + if (workingName.startsWith(sysRoot)) { + return Optional.of(sysRoot); + } + } + return Optional.empty(); + } + + @Override + public int compareTo(FSInfo other) { + return CompareToBuilder.reflectionCompare(this, other); + } + + @Override + public boolean equals(Object other) { + return EqualsBuilder.reflectionEquals(this, other); + } + + @Override + public int hashCode() { + return HashCodeBuilder.reflectionHashCode(this); + } } /** @@ -285,20 +376,31 @@ public static final class Builder { /** The name for the document */ private String name; /** The base name for the document */ - private String baseName; - /** The directory separator */ - private String dirSeparator; - /** The case sensitivity flag */ - private boolean isCaseSensitive; + private DocumentName baseName; + /** The file system info */ + private final FSInfo fsInfo; /** The file system root */ private String root; + /** A flag for baseName same as this */ + private boolean sameNameFlag; + private Builder() { + fsInfo = DEFAULT_FSINFO; + root = ""; + } /** * Create with default settings. */ - private Builder() { - isCaseSensitive = FS_IS_CASE_SENSITIVE; - dirSeparator = File.separator; + private Builder(FSInfo fsInfo) { + this.fsInfo = fsInfo; + root = ""; + } + + /** + * Create with default settings. + */ + private Builder(FileSystem fileSystem) { + fsInfo = fileSystem.equals(FileSystems.getDefault()) ? DEFAULT_FSINFO : new FSInfo(fileSystem); root = ""; } @@ -307,10 +409,18 @@ private Builder() { * @param file the file to base the builder on. */ private Builder(final File file) { - this(); + this(DEFAULT_FSINFO); + setName(file); + } + + /** + * Used in testing + * @param fsInfo the FSInfo for the file. + * @param file the file to process + */ + Builder(final FSInfo fsInfo, final File file) { + this(fsInfo); setName(file); - isCaseSensitive = FS_IS_CASE_SENSITIVE; - dirSeparator = File.separator; } /** @@ -321,21 +431,29 @@ private Builder(final DocumentName documentName) { this.root = documentName.root; this.name = documentName.name; this.baseName = documentName.baseName; - this.isCaseSensitive = documentName.isCaseSensitive; - this.dirSeparator = documentName.dirSeparator; + this.fsInfo = documentName.fsInfo; } + /** + * Get the directory separator for this builder. + * @return the directory separator fo this builder. + */ + public String directorySeparator() { + return fsInfo.dirSeparator(); + } /** * Verify that the builder will build a proper DocumentName. */ private void verify() { Objects.requireNonNull(name, "Name cannot be null"); - Objects.requireNonNull(baseName, "Basename cannot be null"); - if (name.startsWith(dirSeparator)) { - name = name.substring(dirSeparator.length()); + if (name.startsWith(fsInfo.dirSeparator())) { + name = name.substring(fsInfo.dirSeparator().length()); } - if (baseName.startsWith(dirSeparator)) { - baseName = baseName.substring(dirSeparator.length()); + if (!sameNameFlag) { + Objects.requireNonNull(baseName, "Basename cannot be null"); + if (!name.startsWith(baseName.name)) { + throw new IllegalArgumentException(String.format("name '%s' must start with baseName '%s'", name, baseName.name)); + } } } @@ -345,58 +463,54 @@ private void verify() { * @return this. */ public Builder setRoot(final String root) { - this.root = root; + this.root = StringUtils.defaultIfBlank(root, ""); return this; } /** - * Sets the name for this DocumentName. Will reset the root to the empty string. + * Sets the name for this DocumentName relative to the baseName. If the {@code name} is null + * an empty string is used. *

    - * To correctly parse the string it must either be the directory separator specified by - * {@link File#separator} or must have been explicitly set by calling {@link #setDirSeparator(String)} - * before making this call. + * To correctly parse the string it must use the directory separator specified by + * this Document. *

    - * @param name the name for this Document name. + * @param name the name for this Document name. Will be made relative to the baseName * @return this */ public Builder setName(final String name) { - Pair pair = splitRoot(name, dirSeparator); + Pair pair = splitRoot(StringUtils.defaultIfEmpty(name, "")); if (this.root.isEmpty()) { this.root = pair.getLeft(); } this.name = pair.getRight(); + if (this.baseName != null && !baseName.name.isEmpty()) { + if (!this.name.startsWith(baseName.name)) { + this.name = this.name.isEmpty() ? baseName.name : + baseName.name + fsInfo.dirSeparator() + this.name; + } + } return this; } - /** - * Extracts the root/name pair from a file. - * @param file the file to extract the root/name pair from. - * @return the root/name pair. - */ - static Pair splitRoot(final File file) { - return splitRoot(file.getAbsolutePath(), File.separator); - } - /** * Extracts the root/name pair from a name string. *

    * Package private for testing. *

    * @param name the name to extract the root/name pair from. - * @param dirSeparator the directory separator. * @return the root/name pair. */ - static Pair splitRoot(final String name, final String dirSeparator) { + Pair splitRoot(final String name) { String workingName = name; - String root = ""; - for (String sysRoot : ROOTS) { - if (workingName.startsWith(sysRoot)) { - workingName = workingName.substring(sysRoot.length()); - if (!workingName.startsWith(dirSeparator)) { - if (sysRoot.endsWith(dirSeparator)) { - root = sysRoot.substring(0, sysRoot.length() - dirSeparator.length()); + Optional maybeRoot = fsInfo.rootFor(name); + String root = maybeRoot.orElse(""); + if (!root.isEmpty()) { + if (workingName.startsWith(root)) { + workingName = workingName.substring(root.length()); + if (!workingName.startsWith(fsInfo.dirSeparator())) { + if (root.endsWith(fsInfo.dirSeparator())) { + root = root.substring(0, root.length() - fsInfo.dirSeparator().length()); } - return ImmutablePair.of(root, workingName); } } } @@ -414,18 +528,17 @@ private void setEmptyRoot(final String root) { } /** - * Sets the properties from the file. This method sets the {@link #root} if it is empty, and resets {@link #name}, - * {@link #dirSeparator} and {@link #baseName}. + * Sets the properties from the file. Will reset the baseName appropraitly. * @param file the file to set the properties from. * @return this. */ public Builder setName(final File file) { - Pair pair = splitRoot(file); + Pair pair = splitRoot(file.getAbsolutePath()); setEmptyRoot(pair.getLeft()); this.name = pair.getRight(); - this.dirSeparator = File.separator; - this.baseName = name; - if (!file.isDirectory()) { + if (file.isDirectory()) { + sameNameFlag = true; + } else { File p = file.getParentFile(); if (p != null) { setBaseName(p); @@ -438,17 +551,15 @@ public Builder setName(final File file) { * Sets the baseName. * Will set the root if it is not set. *

    - * To correctly parse the string it must either be the directory separator specified by - * {@link File#separator} or must have been explicitly set by calling {@link #setDirSeparator(String)} - * before making this call. + * To correctly parse the string it must use the directory separator specified by this builder. *

    * @param baseName the basename to use. * @return this. */ public Builder setBaseName(final String baseName) { - Pair pair = splitRoot(baseName, dirSeparator); - setEmptyRoot(pair.getLeft()); - this.baseName = pair.getRight(); + DocumentName.Builder builder = DocumentName.builder(fsInfo).setName(baseName); + builder.sameNameFlag = true; + setBaseName(builder); return this; } @@ -459,7 +570,7 @@ public Builder setBaseName(final String baseName) { * @return this. */ public Builder setBaseName(final DocumentName baseName) { - this.baseName = baseName.getName(); + this.baseName = baseName; if (!baseName.getRoot().isEmpty()) { this.root = baseName.getRoot(); } @@ -467,36 +578,24 @@ public Builder setBaseName(final DocumentName baseName) { } /** - * Sets the basename from a File. Sets {@link #root} and the {@link #baseName} - * Will set the root. - * @param file the file to set the base name from. - * @return this. - */ - public Builder setBaseName(final File file) { - Pair pair = splitRoot(file); - this.root = pair.getLeft(); - this.baseName = pair.getRight(); - return this; - } - - /** - * Sets the directory separator. - * @param dirSeparator the directory separator to use. - * @return this. + * Executes the builder, sets the base name and clears the sameName flag. + * @param builder the builder for the base name. */ - public Builder setDirSeparator(final String dirSeparator) { - Objects.requireNonNull(dirSeparator, "Directory separator cannot be null"); - this.dirSeparator = dirSeparator; - return this; + private void setBaseName(DocumentName.Builder builder) { + this.baseName = builder.build(); + this.sameNameFlag = false; } /** - * Sets the {@link #isCaseSensitive} flag. - * @param isCaseSensitive the expected state of the flag. + * Sets the basename from a File. Sets {@link #root} and the {@link #baseName} + * Will set the root. + * @param file the file to set the base name from. * @return this. */ - public Builder setCaseSensitive(final boolean isCaseSensitive) { - this.isCaseSensitive = isCaseSensitive; + public Builder setBaseName(final File file) { + DocumentName.Builder builder = DocumentName.builder(fsInfo).setName(file); + builder.sameNameFlag = true; + setBaseName(builder); return this; } diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 4b24f6dd7..4a8925594 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -160,12 +160,12 @@ public List decompose(final DocumentName candidate) { private void decompose(final int level, final DocumentNameMatcher matcher, final DocumentName candidate, final List result) { final Predicate pred = matcher.getPredicate(); result.add(new DecomposeData(level, matcher, pred.test(candidate))); - if (pred instanceof DocumentNameMatcher.CollectionPredicate) { - final DocumentNameMatcher.CollectionPredicate collection = (DocumentNameMatcher.CollectionPredicate) pred; - for (DocumentNameMatcher subMatcher : collection.getMatchers()) { - decompose(level + 1, subMatcher, candidate, result); - } - } +// if (pred instanceof DocumentNameMatcher.CollectionPredicate) { +// final DocumentNameMatcher.CollectionPredicate collection = (DocumentNameMatcher.CollectionPredicate) pred; +// for (DocumentNameMatcher subMatcher : collection.getMatchers()) { +// decompose(level + 1, subMatcher, candidate, result); +// } +// } } /** 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 d9148701e..7ad4ca23c 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 @@ -24,6 +24,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -82,19 +83,19 @@ private InputStream createInputStream() throws IOException { */ public Collection getDocuments() throws RatException { List result = new ArrayList<>(); + //DocumentName.FSInfo archiveInfo = new DocumentName.FSInfo(true, Arrays.asList("/"), "/"); try (ArchiveInputStream input = new ArchiveStreamFactory().createArchiveInputStream(createInputStream())) { ArchiveEntry entry = null; while ((entry = input.getNextEntry()) != null) { if (!entry.isDirectory() && input.canReadEntryData(entry)) { - DocumentName innerName = DocumentName.builder().setDirSeparator("/").setName(entry.getName()) - .setBaseName(".").setCaseSensitive(true).build(); + DocumentName innerName = DocumentName.builder().setName(entry.getName()) + .setBaseName(".").build(); if (this.getDocument().getNameExcluder().matches(innerName)) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); IOUtils.copy(input, baos); DocumentName archiveName = getDocument().getName(); String outerNameStr = format("%s#%s", archiveName.getName(), entry.getName()); - DocumentName outerName = DocumentName.builder(archiveName).setName(outerNameStr) - .setCaseSensitive(true).build(); + DocumentName outerName = DocumentName.builder(archiveName).setName(outerNameStr).build(); result.add(new ArchiveEntryDocument(outerName, baos.toByteArray(), getDocument().getNameExcluder())); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/walker/FileListWalker.java b/apache-rat-core/src/main/java/org/apache/rat/walker/FileListWalker.java index 6e6c50e5a..5aa48852d 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/walker/FileListWalker.java +++ b/apache-rat-core/src/main/java/org/apache/rat/walker/FileListWalker.java @@ -25,6 +25,7 @@ import org.apache.commons.io.IOUtils; import org.apache.rat.api.RatException; import org.apache.rat.commandline.Arg; +import org.apache.rat.config.exclusion.ExclusionUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.document.FileDocument; @@ -40,9 +41,9 @@ public class FileListWalker implements IReportable { /** The source document name */ private final FileDocument source; /** The root document name */ - private final FileDocument rootDoc; + private final DocumentName rootDoc; /** the base directory for the source document */ - private final FileDocument baseDoc; + private final DocumentName baseDoc; /** * Constructor. @@ -51,22 +52,21 @@ public class FileListWalker implements IReportable { public FileListWalker(final FileDocument source) { this.source = source; File baseDir = source.getFile().getParentFile().getAbsoluteFile(); - this.baseDoc = new FileDocument(baseDir, DocumentNameMatcher.MATCHES_ALL); + this.baseDoc = DocumentName.builder(baseDir).build(); File p = baseDir; while (p.getParentFile() != null) { p = p.getParentFile(); } - File rootDir = p; - rootDoc = new FileDocument(rootDir, DocumentNameMatcher.MATCHES_ALL); + this.rootDoc = DocumentName.builder(p).build(); } private FileDocument createDocument(final String unixFileName) { DocumentName sourceName = source.getName(); - String finalName = "/".equals(sourceName.getDirectorySeparator()) ? unixFileName : - unixFileName.replace("/", sourceName.getDirectorySeparator()); - FileDocument documentBase = unixFileName.startsWith("/") ? rootDoc : baseDoc; - File documentFile = new File(documentBase.getFile(), finalName); - return new FileDocument(rootDoc.getName(), documentFile, DocumentNameMatcher.MATCHES_ALL); + String finalName = ExclusionUtils.convertSeparator(unixFileName, "/", sourceName.getDirectorySeparator()); + DocumentName documentBase = unixFileName.startsWith("/") ? rootDoc : baseDoc; + DocumentName documentName = documentBase.resolve(finalName); + File documentFile = documentName.asFile(); + return new FileDocument(documentBase, documentFile, DocumentNameMatcher.MATCHES_ALL); } @Override diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/ExclusionProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/ExclusionProcessorTest.java index f8535a90b..96d059c74 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/ExclusionProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/ExclusionProcessorTest.java @@ -18,9 +18,20 @@ */ package org.apache.rat.config.exclusion; +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; import org.apache.commons.io.FileUtils; +import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.document.DocumentName; +import org.apache.rat.document.FSInfoTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -31,26 +42,29 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mockito; import static java.lang.String.format; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Fail.fail; +import static org.apache.rat.document.FSInfoTest.OSX; +import static org.apache.rat.document.FSInfoTest.UNIX; +import static org.apache.rat.document.FSInfoTest.WINDOWS; + public class ExclusionProcessorTest { final private static DocumentNameMatcher TRUE = DocumentNameMatcher.MATCHES_ALL; final private static DocumentNameMatcher FALSE = DocumentNameMatcher.MATCHES_NONE; - /** The base directory for the test. */ + @TempDir - private File basedirFile; - private DocumentName basedir; + private static Path tempDir; - @BeforeEach - public void setup() { - basedir = DocumentName.builder(basedirFile).build(); - } - private void testParseExclusion(DocumentNameMatcher nameMatcher, DocumentName name, boolean expected) { + private void testParseExclusion(DocumentName basedir, DocumentNameMatcher nameMatcher, DocumentName name, boolean expected) { assertThat(nameMatcher.matches(name)).as(() -> format("Failed on [%s %s]%n%s", basedir, name, dump(nameMatcher, name))).isEqualTo(expected); } @@ -60,48 +74,63 @@ private String dump(DocumentNameMatcher nameMatcher, DocumentName name) { return sb.toString(); } - private DocumentName mkName(String pth) { - File f = new File(basedirFile, pth); - try { - FileUtils.cleanDirectory(basedirFile); - FileUtils.touch(f); - } catch (IOException e) { - fail(e); + private DocumentName mkName(DocumentName baseDir, String pth) throws IOException { + DocumentName result = baseDir.resolve(ExclusionUtils.convertSeparator(pth, "/", baseDir.getDirectorySeparator())); + DocumentName mocked = Mockito.spy(result); + + String fn = result.localized(FileSystems.getDefault().getSeparator()); + File file = tempDir.resolve(fn.substring(1)).toFile(); + File parent = file.getParentFile(); + if (parent.exists() && !parent.isDirectory()) { + parent.delete(); } - return DocumentName.builder(f).setBaseName(basedir.getBaseName()).build(); + parent.mkdirs(); + if (file.exists()) { + if (file.isDirectory()) { + FileUtils.deleteDirectory(file); + } else { + FileUtils.delete(file); + } + } + file.createNewFile(); + Mockito.when(mocked.asFile()).thenReturn(file); + return mocked; } - @Test - public void defaultTest() { + @ParameterizedTest + @MethodSource("getDocumentNames") + void defaultTest(DocumentName basedir) throws IOException { ExclusionProcessor p = new ExclusionProcessor(); - testParseExclusion(p.getNameMatcher(basedir), mkName("hello"), true); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, "hello"), true); } - @Test - public void addExcludedCollectionTest() { + @ParameterizedTest + @MethodSource("getDocumentNames") + void addExcludedCollectionTest(DocumentName basedir) throws IOException { ExclusionProcessor p = new ExclusionProcessor().addExcludedCollection(StandardCollection.MISC); // "**/*~", "**/#*#", "**/.#*", "**/%*%", "**/._*" - testParseExclusion(p.getNameMatcher(basedir), mkName("hello"), true); - testParseExclusion(p.getNameMatcher(basedir), mkName("hello~"), false); - testParseExclusion(p.getNameMatcher(basedir), mkName("#hello#"), false); - testParseExclusion(p.getNameMatcher(basedir), mkName(".#hello"), false); - testParseExclusion(p.getNameMatcher(basedir), mkName("%hello%"), false); - testParseExclusion(p.getNameMatcher(basedir), mkName("._hello"), false); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir,"hello"), true); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir,"hello~"), false); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, "#hello#"), false); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, ".#hello"), false); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, "%hello%"), false); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, "._hello"), false); } - @Test - public void addExcludedAndIncludedCollectionTest() { + @ParameterizedTest + @MethodSource("getDocumentNames") + void addExcludedAndIncludedCollectionTest(DocumentName basedir) throws IOException { ExclusionProcessor p = new ExclusionProcessor().addExcludedCollection(StandardCollection.MISC) .addIncludedCollection(StandardCollection.HIDDEN_FILE); - testParseExclusion(p.getNameMatcher(basedir), mkName("hello"), true); - testParseExclusion(p.getNameMatcher(basedir), mkName("hello~"), false); - testParseExclusion(p.getNameMatcher(basedir), mkName("#hello#"), false); - testParseExclusion(p.getNameMatcher(basedir), mkName(".#hello"), true); - testParseExclusion(p.getNameMatcher(basedir), mkName("%hello%"), false); - testParseExclusion(p.getNameMatcher(basedir), mkName("._hello"), true); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir,"hello"), true); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, "hello~"), false); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, "#hello#"), false); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, ".#hello"), true); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, "%hello%"), false); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, "._hello"), true); } - private void assertExclusions(String pattern, Map expectedMap) { + private void assertExclusions(DocumentName basedir, String pattern, Map expectedMap) throws IOException { String[] paths = {"a/b/foo", "b/foo", "foo", "foo/x", "foo/x/y", "b/foo/x", "b/foo/x/y", "a/b/foo/x", "a/b/foo/x/y"}; ExclusionProcessor p = new ExclusionProcessor().addExcludedPatterns(Collections.singletonList(pattern)); @@ -111,13 +140,13 @@ private void assertExclusions(String pattern, Map expectedMap) { if (expected == null) { throw new RuntimeException("Missing expected value for " + pth + " in pattern " + pattern); } - DocumentName dn = mkName(pth); - testParseExclusion(pathMatcher, mkName(pth), expected); + testParseExclusion(basedir, pathMatcher, mkName(basedir, pth), expected); } } - @Test - public void addExcludedPatternsTest() { + @ParameterizedTest + @MethodSource("getDocumentNames") + void addExcludedPatternsTest(DocumentName basedir) throws IOException { Map expectedMap = new HashMap<>(); expectedMap.put("a/b/foo", true); @@ -129,7 +158,7 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", true); expectedMap.put("a/b/foo/x", true); expectedMap.put("a/b/foo/x/y",true); - assertExclusions("foo", expectedMap); + assertExclusions(basedir, "foo", expectedMap); expectedMap.clear(); expectedMap.put("a/b/foo", true); @@ -141,7 +170,7 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", true); expectedMap.put("a/b/foo/x", true); expectedMap.put("a/b/foo/x/y",true); - assertExclusions("foo/*", expectedMap); + assertExclusions(basedir, "foo/*", expectedMap); expectedMap.clear(); expectedMap.put("a/b/foo", true); @@ -153,7 +182,7 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", true); expectedMap.put("a/b/foo/x", true); expectedMap.put("a/b/foo/x/y",true); - assertExclusions("foo/**", expectedMap); + assertExclusions(basedir, "foo/**", expectedMap); expectedMap.clear(); expectedMap.put("a/b/foo", true); @@ -165,7 +194,7 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", true); expectedMap.put("a/b/foo/x", true); expectedMap.put("a/b/foo/x/y",true); - assertExclusions("*/foo", expectedMap); + assertExclusions(basedir, "*/foo", expectedMap); expectedMap.clear(); expectedMap.put("a/b/foo", true); @@ -177,7 +206,7 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", true); expectedMap.put("a/b/foo/x", true); expectedMap.put("a/b/foo/x/y",true); - assertExclusions("*/foo/*", expectedMap); + assertExclusions(basedir, "*/foo/*", expectedMap); expectedMap.clear(); expectedMap.put("a/b/foo", true); @@ -189,7 +218,7 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", false); expectedMap.put("a/b/foo/x", true); expectedMap.put("a/b/foo/x/y",true); - assertExclusions("*/foo/**", expectedMap); + assertExclusions(basedir, "*/foo/**", expectedMap); expectedMap.clear(); expectedMap.put("a/b/foo", false); @@ -201,7 +230,7 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", true); expectedMap.put("a/b/foo/x", true); expectedMap.put("a/b/foo/x/y",true); - assertExclusions("**/foo", expectedMap); + assertExclusions(basedir, "**/foo", expectedMap); expectedMap.clear(); expectedMap.put("a/b/foo", true); @@ -213,7 +242,7 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", true); expectedMap.put("a/b/foo/x", false); expectedMap.put("a/b/foo/x/y",true); - assertExclusions("**/foo/*", expectedMap); + assertExclusions(basedir, "**/foo/*", expectedMap); expectedMap.clear(); expectedMap.put("a/b/foo", false); @@ -225,11 +254,12 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", false); expectedMap.put("a/b/foo/x", false); expectedMap.put("a/b/foo/x/y",false); - assertExclusions("**/foo/**", expectedMap); + assertExclusions(basedir, "**/foo/**", expectedMap); } - @Test - public void orTest() { + @ParameterizedTest + @MethodSource("getDocumentNames") + void orTest(DocumentName basedir) { ExclusionProcessor underTest = new ExclusionProcessor(); assertThat(DocumentNameMatcher.or(Arrays.asList(TRUE, FALSE)).matches(basedir)).isTrue(); assertThat(DocumentNameMatcher.or(Arrays.asList(FALSE, TRUE)).matches(basedir)).isTrue(); @@ -237,8 +267,9 @@ public void orTest() { assertThat(DocumentNameMatcher.or(Arrays.asList(FALSE, FALSE)).matches(basedir)).isFalse(); } - @Test - public void andTest() { + @ParameterizedTest + @MethodSource("getDocumentNames") + void andTest(DocumentName basedir) { ExclusionProcessor underTest = new ExclusionProcessor(); assertThat(DocumentNameMatcher.and(TRUE, FALSE).matches(basedir)).isFalse(); assertThat(DocumentNameMatcher.and(FALSE, TRUE).matches(basedir)).isFalse(); @@ -246,10 +277,30 @@ public void andTest() { assertThat(DocumentNameMatcher.and(FALSE, FALSE).matches(basedir)).isFalse(); } - @Test - public void notTest() { + @ParameterizedTest + @MethodSource("getDocumentNames") + void notTest(DocumentName basedir) { ExclusionProcessor underTest = new ExclusionProcessor(); assertThat(DocumentNameMatcher.not(TRUE).matches(basedir)).isFalse(); assertThat(DocumentNameMatcher.not(FALSE).matches(basedir)).isTrue(); } + + private static Stream getDocumentNames() throws IOException { + List lst = new ArrayList<>(); + + DocumentName.Builder builder = DocumentName.builder().setName("default"); + lst.add(Arguments.of(builder.setBaseName(builder.directorySeparator()).build())); + + builder = DocumentName.builder(WINDOWS).setName("windows"); + lst.add(Arguments.of(builder.setBaseName(builder.directorySeparator()).build())); + + builder = DocumentName.builder(UNIX).setName("unix"); + lst.add(Arguments.of(builder.setBaseName(builder.directorySeparator()).build())); + + builder = DocumentName.builder(OSX).setName("osx"); + lst.add(Arguments.of(builder.setBaseName(builder.directorySeparator()).build())); + + + return lst.stream(); + } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java index 0421eaa68..2deba2c9b 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java @@ -18,18 +18,29 @@ */ package org.apache.rat.config.exclusion; +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import java.io.IOException; +import java.nio.file.FileSystem; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Stream; import org.apache.rat.document.DocumentName; +import org.apache.rat.document.FSInfoTest; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import static org.assertj.core.api.Assertions.assertThat; +import static org.apache.rat.document.FSInfoTest.OSX; +import static org.apache.rat.document.FSInfoTest.UNIX; +import static org.apache.rat.document.FSInfoTest.WINDOWS; public class FileProcessorTest { + private static final String BACKSLASH = "\\"; FileProcessorTest() {} @ParameterizedTest(name="{index} {1}") @@ -38,24 +49,39 @@ void localizePatternTest(DocumentName baseName, String pattern, String expectedS assertThat(ExclusionUtils.localizePattern(baseName, pattern)).isEqualTo(expectedStr); } - public static Stream localizePatternData() { - List lst = new ArrayList<>(); - DocumentName baseName = DocumentName.builder().setName("fileBeingRead").setBaseName("baseDir").setDirSeparator("/").build(); + public static Stream localizePatternData() throws IOException { + List lst = new ArrayList<>(); + Map patterns = new HashMap<>(); + patterns.put("file", "%1$sbaseDir%1$sfile"); + patterns.put("!file", "!%1$sbaseDir%1$sfile"); + patterns.put("%regex[file]", "%%regex[\\Q%1$sbaseDir%1$s\\Efile]"); + patterns.put("!%regex[file]", "!%%regex[\\Q%1$sbaseDir%1$s\\Efile]"); + patterns.put("%ant[file]", "%1$sbaseDir%1$sfile"); + patterns.put("!%ant[file]", "!%1$sbaseDir%1$sfile"); - lst.add(Arguments.of(baseName, "file", "/baseDir/file")); - lst.add(Arguments.of(baseName, "!file", "!/baseDir/file")); - lst.add(Arguments.of(baseName, "%regex[file]", "%regex[\\Q/baseDir/\\Efile]")); - lst.add(Arguments.of(baseName, "!%regex[file]", "!%regex[\\Q/baseDir/\\Efile]")); - lst.add(Arguments.of(baseName, "%ant[file]", "/baseDir/file")); - lst.add(Arguments.of(baseName, "!%ant[file]", "!/baseDir/file")); + patterns.put("file/**", "%1$sbaseDir%1$sfile%1$s**"); + patterns.put("!file/**", "!%1$sbaseDir%1$sfile%1$s**"); + patterns.put("%regex[file/.*]", "%%regex[\\Q%1$sbaseDir%1$s\\Efile/.*]"); + patterns.put("!%regex[file/.*]", "!%%regex[\\Q%1$sbaseDir%1$s\\Efile/.*]"); + patterns.put("%ant[file/**]", "%1$sbaseDir%1$sfile%1$s**"); + patterns.put("!%ant[file/**]", "!%1$sbaseDir%1$sfile%1$s**"); - lst.add(Arguments.of(baseName, "file/**", "/baseDir/file/**")); - lst.add(Arguments.of(baseName, "!file/**", "!/baseDir/file/**")); - lst.add(Arguments.of(baseName, "%regex[file/.*]", "%regex[\\Q/baseDir/\\Efile/.*]")); - lst.add(Arguments.of(baseName, "!%regex[file/.*]", "!%regex[\\Q/baseDir/\\Efile/.*]")); - lst.add(Arguments.of(baseName, "%ant[file/**]", "/baseDir/file/**")); - lst.add(Arguments.of(baseName, "!%ant[file/**]", "!/baseDir/file/**")); + DocumentName baseName = DocumentName.builder(FSInfoTest.UNIX).setName("fileBeingRead").setBaseName("baseDir").build(); + for (Map.Entry pattern : patterns.entrySet()) { + lst.add(Arguments.of(baseName, pattern.getKey(), String.format(pattern.getValue(), UNIX.dirSeparator()))); + } + + + baseName = DocumentName.builder(FSInfoTest.WINDOWS).setName("fileBeingRead").setBaseName("baseDir").build(); + for (Map.Entry pattern : patterns.entrySet()) { + lst.add(Arguments.of(baseName, pattern.getKey(), String.format(pattern.getValue(), WINDOWS.dirSeparator()))); + } + + baseName = DocumentName.builder(FSInfoTest.OSX).setName("fileBeingRead").setBaseName("baseDir").build(); + for (Map.Entry pattern : patterns.entrySet()) { + lst.add(Arguments.of(baseName, pattern.getKey(), String.format(pattern.getValue(), OSX.dirSeparator()))); + } return lst.stream(); } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java new file mode 100644 index 000000000..0531897da --- /dev/null +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java @@ -0,0 +1,322 @@ +/* + * 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 com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.FileStore; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.builder.CompareToBuilder; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.rat.utils.DefaultLog; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.apache.rat.document.FSInfoTest.OSX; +import static org.apache.rat.document.FSInfoTest.UNIX; +import static org.apache.rat.document.FSInfoTest.WINDOWS; + + +public class DocumentNameBuilderTest { + + @ParameterizedTest(name="{0}") + @MethodSource("buildTestData") + void buildTest(String testName, DocumentName documentName, String name, String shortName, String baseName, String root, + String directorySeparator, Boolean isCaseSensitive, String localized, String localizedArg) { + assertThat(documentName.getName()).as("Invalid name").isEqualTo(name); + assertThat(documentName.getShortName()).as("Invalid short name").isEqualTo(shortName); + assertThat(documentName.getBaseName()).as("Invalid base name").isEqualTo(baseName); + assertThat(documentName.getRoot()).as("Invalid root").isEqualTo(root); + assertThat(documentName.getDirectorySeparator()).as("Invalid directory separator").isEqualTo(directorySeparator); + if (isCaseSensitive) { + assertThat(documentName.isCaseSensitive()).as("Invalid case sensitivity").isTrue(); + } else { + assertThat(documentName.isCaseSensitive()).as("Invalid case sensitivity").isFalse(); + } + assertThat(documentName.localized()).as("Invalid localized ").isEqualTo(localized); + final String sep = documentName.getDirectorySeparator().equals("/") ? "\\" : "/"; + assertThat(documentName.localized(sep)).as(() -> String.format("Invalid localized('%s')", sep)).isEqualTo(localizedArg); + } + + + static Stream buildTestData() throws IOException { + List lst = new ArrayList<>(); + + // + String testName = "windows\\foo direct"; + DocumentName documentName = DocumentName.builder(WINDOWS).setName("C:\\\\windows\\foo").setBaseName("C:\\\\windows").build(); + lst.add(Arguments.of( testName, documentName, "C:\\\\windows\\foo", "foo", "C:\\\\windows", "C:\\", "\\", false, + "\\foo", "/foo")); + DocumentName baseName = documentName; + + // + testName = "builder(docName)"; + documentName = DocumentName.builder(baseName).build(); + lst.add(Arguments.of( testName, documentName, "C:\\\\windows\\foo", "foo", "C:\\\\windows", "C:\\", "\\", false, + "\\foo", "/foo")); + + // + testName = "windows\\foo\\bar by resolve"; + documentName = baseName.resolve("bar"); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows", "C:\\", "\\", false, + "\\foo\\bar", "/foo/bar")); + + // + testName = "windows\\foo\\direct by basename"; + documentName = DocumentName.builder(baseName).setName("windows\\foo\\direct").build(); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\direct", "direct", "C:\\\\windows", "C:\\", "\\", false, + "\\foo\\direct", "/foo/direct")); + + // + testName = "windows\\foo\\bar by file"; + File file = mock(File.class); + File parent = mock(File.class); + when(file.getAbsolutePath()).thenReturn("C:\\\\windows\\foo\\bar"); + when(file.getParentFile()).thenReturn(parent); + when(file.isDirectory()).thenReturn(false); + when(parent.getAbsolutePath()).thenReturn("C:\\\\windows\\foo"); + when(parent.isDirectory()).thenReturn(true); + documentName = new DocumentName.Builder(WINDOWS, file).build(); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows\\foo", "C:\\", "\\", false, + "\\bar", "/bar")); + + // + testName = "windows\\foo\\bar by directory"; + file = mock(File.class); + parent = mock(File.class); + when(file.getAbsolutePath()).thenReturn("C:\\\\windows\\foo\\bar"); + when(file.getParentFile()).thenReturn(parent); + when(file.isDirectory()).thenReturn(true); + when(parent.getAbsolutePath()).thenReturn("C:\\\\windows\\foo"); + when(parent.isDirectory()).thenReturn(true); + documentName = new DocumentName.Builder(WINDOWS, file).build(); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows\\foo\\bar", "C:\\", "\\", false, + "\\", "/")); + + // + testName = "windows setRoot"; + documentName = DocumentName.builder(baseName).setRoot("D:\\").build(); + lst.add(Arguments.of(testName, documentName, "D:\\\\windows\\foo", "foo", "C:\\\\windows", "D:\\", "\\", false, + "D:\\\\windows\\foo", "D://windows/foo")); + + testName = "windows setRoot(null)"; + documentName = DocumentName.builder(baseName).setRoot(null).build(); + lst.add(Arguments.of(testName, documentName, "\\windows\\foo", "foo", "C:\\\\windows", "", "\\", false, + "\\windows\\foo", "/windows/foo")); + + testName = "windows setRoot('')"; + documentName = DocumentName.builder(baseName).setRoot("").build(); + lst.add(Arguments.of(testName, documentName, "\\windows\\foo", "foo", "C:\\\\windows", "", "\\", false, + "\\windows\\foo", "/windows/foo")); + + // + testName = "windows setName('baz')"; + documentName = DocumentName.builder(baseName).setName("baz").build(); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\baz", "baz", "C:\\\\windows", "C:\\", "\\", false, + "\\baz", "/baz")); + + testName = "windows setName((String)null)"; + documentName = DocumentName.builder(baseName).setName((String)null).build(); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows", "windows", "C:\\\\windows", "C:\\", "\\", false, + "\\", "/")); + + testName = "windows setName('')"; + documentName = DocumentName.builder(baseName).setName("").build(); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows", "windows", "C:\\\\windows", "C:\\", "\\", false, + "\\", "/")); + + file = mock(File.class); + parent = mock(File.class); + when(file.getAbsolutePath()).thenReturn("C:\\\\windows\\foo\\bar"); + when(file.getParentFile()).thenReturn(parent); + when(file.isDirectory()).thenReturn(false); + when(parent.getAbsolutePath()).thenReturn("C:\\\\windows\\foo"); + when(parent.isDirectory()).thenReturn(true); + testName = "windows setName(file)"; + documentName = DocumentName.builder(baseName).setName(file).build(); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows\\foo", "C:\\", "\\", false, + "\\bar", "/bar")); + + file = mock(File.class); + parent = mock(File.class); + when(file.getAbsolutePath()).thenReturn("C:\\\\windows\\foo\\bar"); + when(file.getParentFile()).thenReturn(parent); + when(file.isDirectory()).thenReturn(true); + when(parent.getAbsolutePath()).thenReturn("C:\\\\windows\\foo"); + when(parent.isDirectory()).thenReturn(true); + testName = "windows setName(directory)"; + documentName = DocumentName.builder(baseName).setName(file).build(); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows\\foo\\bar", "C:\\", "\\", false, + "\\", "/")); + + return lst.stream(); + + +// +// /** +// * Sets the baseName. +// * Will set the root if it is not set. +// *

    +// * To correctly parse the string it must use the directory separator specified by this builder. +// *

    +// * @param baseName the basename to use. +// * @return this. +// */ +// public DocumentName.Builder setBaseName(final String baseName) { +// DocumentName.Builder builder = DocumentName.builder(fsInfo).setName(baseName); +// builder.sameNameFlag = true; +// setBaseName(builder); +// return this; +// } +// +// /** +// * Sets the basename from the {@link #name} of the specified DocumentName. +// * Will set the root the baseName has the root set. +// * @param baseName the DocumentName to set the basename from. +// * @return this. +// */ +// public DocumentName.Builder setBaseName(final DocumentName baseName) { +// this.baseName = baseName; +// if (!baseName.getRoot().isEmpty()) { +// this.root = baseName.getRoot(); +// } +// return this; +// } +// +// /** +// * Executes the builder, sets the base name and clears the sameName flag. +// * @param builder the builder for the base name. +// */ +// private void setBaseName(DocumentName.Builder builder) { +// this.baseName = builder.build(); +// this.sameNameFlag = false; +// } +// +// /** +// * Sets the basename from a File. Sets {@link #root} and the {@link #baseName} +// * Will set the root. +// * @param file the file to set the base name from. +// * @return this. +// */ +// public DocumentName.Builder setBaseName(final File file) { +// DocumentName.Builder builder = DocumentName.builder(fsInfo).setName(file); +// builder.sameNameFlag = true; +// setBaseName(builder); +// return this; +// } +// +// /** +// * Build a DocumentName from this builder. +// * @return A new DocumentName. +// */ +// public DocumentName build() { +// verify(); +// return new DocumentName(this); +// } + +// +// assertThat(documentName.getName()).isEqualTo("C:\\\\windows\\foo") +// +// +// assertThat(documentName.getRoot()).isEqualTo("C:\\"); +// assertThat(documentName.isCaseSensitive()).isFalse(); +// assertThat(documentName.getShortName()).isEqualTo("foo"); +// assertThat(documentName.localized("/")).isEqualTo("/windows/foo"); +// assertThat(documentName.getBaseName()).isEqualTo("C:\\\\windows"); +// documentName.getBaseDocumentName(); +// documentName.getDirectorySeparator(); +// +// +// public String getName() +// +// +// public String getBaseName() +// +// +// public String getRoot() +// +// +// public DocumentName getBaseDocumentName +// +// public String getDirectorySeparator( +// +// +// public String localized() +// +// public String localized(final String dirSeparator) +// +// +// public String[] tokenize(final String source) { +// // return source.split("\\Q" + fsInfo.dirSeparator() + "\\E"); +// +// +// +// public String getShortName() +// +// public boolean isCaseSensitive() + + +/* + @Override + public int compareTo(final DocumentName other) { + return CompareToBuilder.reflectionCompare(this, other); + } + + @Override + public boolean equals(final Object other) { + return EqualsBuilder.reflectionEquals(this, other); + } + + @Override + public int hashCode() { + return HashCodeBuilder.reflectionHashCode(this); + } + +*/ + + } + + +} diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java index def6ec447..457362f29 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java @@ -18,7 +18,11 @@ */ package org.apache.rat.document; +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; import java.io.File; +import java.io.IOException; +import java.nio.file.FileSystem; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -33,28 +37,110 @@ import static java.lang.String.format; import static org.assertj.core.api.Assertions.assertThat; +import static org.apache.rat.document.FSInfoTest.OSX; +import static org.apache.rat.document.FSInfoTest.UNIX; +import static org.apache.rat.document.FSInfoTest.WINDOWS; public class DocumentNameTest { + @ParameterizedTest(name = "{index} {0} {2}") + @MethodSource("resolveTestData") + void resolveTest(String testName, DocumentName base, String toResolve, DocumentName expected) { + DocumentName actual = base.resolve(toResolve); + assertThat(actual).isEqualTo(expected); + } + + + private static Stream resolveTestData() { + List lst = new ArrayList<>(); + + DocumentName base = DocumentName.builder(UNIX).setName("/dir/unix").setBaseName("/").build(); + + DocumentName expected = DocumentName.builder(UNIX).setName("/dir/unix/relative").setBaseName("/").build(); + lst.add(Arguments.of("unix", base, "relative", expected)); + + expected = DocumentName.builder(UNIX).setName("/from/root").setBaseName("/").build(); + lst.add(Arguments.of("unix", base, "/from/root", expected)); + + expected = DocumentName.builder(UNIX).setName("dir/up/and/down").setBaseName("/").build(); + lst.add(Arguments.of("unix", base, "../up/and/down", expected)); + + expected = DocumentName.builder(UNIX).setName("/from/root").setBaseName("/").build(); + lst.add(Arguments.of("unix", base, "\\from\\root", expected)); + + expected = DocumentName.builder(UNIX).setName("dir/up/and/down").setBaseName("/").build(); + lst.add(Arguments.of("unix", base, "..\\up\\and\\down", expected)); + + // WINDOWS + base = DocumentName.builder(WINDOWS).setName("\\dir\\windows").setBaseName("C:\\\\").build(); + + expected = DocumentName.builder(WINDOWS).setName("\\dir\\windows\\relative").setBaseName("C:\\\\").build(); + lst.add(Arguments.of("windows", base, "relative", expected)); + + expected = DocumentName.builder(WINDOWS).setName("\\from\\root").setBaseName("C:\\\\").build(); + lst.add(Arguments.of("windows", base, "/from/root", expected)); + + expected = DocumentName.builder(WINDOWS).setName("dir\\up\\and\\down").setBaseName("C:\\\\").build(); + lst.add(Arguments.of("windows", base, "../up/and/down", expected)); + + expected = DocumentName.builder(WINDOWS).setName("\\from\\root").setBaseName("C:\\\\").build(); + lst.add(Arguments.of("windows", base, "\\from\\root", expected)); + + expected = DocumentName.builder(WINDOWS).setName("dir\\up\\and\\down").setBaseName("C:\\\\").build(); + lst.add(Arguments.of("windows", base, "..\\up\\and\\down", expected)); + + // OSX + base = DocumentName.builder(OSX).setName("/dir/osx").setBaseName("/").build(); + + expected = DocumentName.builder(OSX).setName("/dir/osx/relative").setBaseName("/").build(); + lst.add(Arguments.of("osx", base, "relative", expected)); + + expected = DocumentName.builder(OSX).setName("/from/root").setBaseName("/").build(); + lst.add(Arguments.of("osx", base, "/from/root", expected)); + + expected = DocumentName.builder(OSX).setName("dir/up/and/down").setBaseName("/").build(); + lst.add(Arguments.of("osx", base, "../up/and/down", expected)); + + expected = DocumentName.builder(OSX).setName("/from/root").setBaseName("/").build(); + lst.add(Arguments.of("osx", base, "\\from\\root", expected)); + + expected = DocumentName.builder(OSX).setName("dir/up/and/down").setBaseName("/").build(); + lst.add(Arguments.of("osx", base, "..\\up\\and\\down", expected)); + + return lst.stream(); + + } + @Test - public void localizeTest() { - DocumentName documentName = DocumentName.builder().setName("/a/b/c") - .setBaseName("/a").setDirSeparator("/").setCaseSensitive(false).build(); + void localizeTest() { + DocumentName documentName = DocumentName.builder(UNIX).setName("/a/b/c") + .setBaseName("/a").build(); + assertThat(documentName.localized()).isEqualTo("/b/c"); + assertThat(documentName.localized("-")).isEqualTo("-b-c"); + + documentName = DocumentName.builder(WINDOWS).setName("\\a\\b\\c") + .setBaseName("\\a").build(); + assertThat(documentName.localized()).isEqualTo("\\b\\c"); + assertThat(documentName.localized("-")).isEqualTo("-b-c"); + + documentName = DocumentName.builder(OSX).setName("/a/b/c") + .setBaseName("/a").build(); assertThat(documentName.localized()).isEqualTo("/b/c"); assertThat(documentName.localized("-")).isEqualTo("-b-c"); + } - @ParameterizedTest(name ="{index} {0}") + @ParameterizedTest(name = "{index} {0}") @MethodSource("validBuilderData") void validBuilderTest(String testName, DocumentName.Builder builder, String root, String name, String baseName, String dirSeparator) { DocumentName underTest = builder.build(); assertThat(underTest.getRoot()).as(testName).isEqualTo(root); assertThat(underTest.getDirectorySeparator()).as(testName).isEqualTo(dirSeparator); - assertThat(underTest.getName()).as(testName).isEqualTo(root+dirSeparator+name); - assertThat(underTest.getBaseName()).as(testName).isEqualTo(root+dirSeparator+baseName); + assertThat(underTest.getName()).as(testName).isEqualTo(root + dirSeparator + name); + assertThat(underTest.getBaseName()).as(testName).isEqualTo(root + dirSeparator + baseName); } - private static Stream validBuilderData() { + private static Stream validBuilderData() throws IOException { List lst = new ArrayList<>(); File f = Files.newTemporaryFile(); @@ -94,98 +180,88 @@ private static Stream validBuilderData() { lst.add(Arguments.of("setName(root)", DocumentName.builder().setName(r), root, "", "", File.separator)); lst.add(Arguments.of("Builder(root)", DocumentName.builder(r), root, "", "", File.separator)); - lst.add(Arguments.of("foo/bar foo", DocumentName.builder().setDirSeparator("/") + + lst.add(Arguments.of("foo/bar foo", DocumentName.builder(UNIX) + .setName("/foo/bar").setBaseName("foo"), "", "foo/bar", "foo", "/")); + + DocumentName.Builder builder = DocumentName.builder(WINDOWS).setName("\\foo\\bar").setBaseName("C:\\\\foo") + .setRoot("C:\\"); + lst.add(Arguments.of("\\foo\\bar foo", builder, "C:\\", "foo\\bar", "foo", "\\")); + + lst.add(Arguments.of("foo/bar foo", DocumentName.builder(OSX) .setName("/foo/bar").setBaseName("foo"), "", "foo/bar", "foo", "/")); - DocumentName.Builder builder = DocumentName.builder().setDirSeparator("\\").setName("\\foo\\bar").setBaseName("foo") - .setRoot("C:"); - lst.add(Arguments.of("C:\\foo\\bar foo", builder, "C:", "foo\\bar", "foo", "\\")); return lst.stream(); } @Test - public void splitRootsTest() { - Set preserve = new HashSet<>(DocumentName.ROOTS); - try { - DocumentName.ROOTS.clear(); - DocumentName.ROOTS.add("C:\\"); - Pair result = DocumentName.Builder.splitRoot("C:\\My\\path\\to\\a\\file.txt", "\\"); - assertThat(result.getLeft()).isEqualTo("C:"); - assertThat(result.getRight()).isEqualTo("My\\path\\to\\a\\file.txt"); - - - DocumentName.ROOTS.clear(); - DocumentName.ROOTS.add("/"); - result = DocumentName.Builder.splitRoot("/My/path/to/a/file.txt", "/"); - assertThat(result.getLeft()).isEqualTo(""); - assertThat(result.getRight()).isEqualTo("My/path/to/a/file.txt"); - - } finally { - DocumentName.ROOTS.clear(); - DocumentName.ROOTS.addAll(preserve); - } + void splitRootsTest() throws IOException { + Pair result = DocumentName.builder(WINDOWS).splitRoot("C:\\My\\path\\to\\a\\file.txt"); + assertThat(result.getLeft()).isEqualTo("C:"); + assertThat(result.getRight()).isEqualTo("My\\path\\to\\a\\file.txt"); + + result = DocumentName.builder(UNIX).splitRoot("/My/path/to/a/file.txt"); + assertThat(result.getLeft()).isEqualTo(""); + assertThat(result.getRight()).isEqualTo("My/path/to/a/file.txt"); + + result = DocumentName.builder(OSX).splitRoot("/My/path/to/a/file.txt"); + assertThat(result.getLeft()).isEqualTo(""); + assertThat(result.getRight()).isEqualTo("My/path/to/a/file.txt"); + } @Test - public void archiveEntryNameTest() { - Set preserve = new HashSet<>(DocumentName.ROOTS); - try { - DocumentName.ROOTS.clear(); - DocumentName.ROOTS.add("C:\\"); - - DocumentName archiveName = DocumentName.builder().setDirSeparator("\\") - .setName("C:\\archives\\anArchive.zip").setBaseName("archives").build(); - assertThat(archiveName.getRoot()).isEqualTo("C:"); - assertThat(archiveName.getDirectorySeparator()).isEqualTo("\\"); - assertThat(archiveName.getBaseName()).isEqualTo("C:\\archives"); - assertThat(archiveName.getName()).isEqualTo("C:\\archives\\anArchive.zip"); - assertThat(archiveName.localized()).isEqualTo("\\anArchive.zip"); - - String entryName = "./anArchiveEntry.txt"; - DocumentName innerName = DocumentName.builder() - .setDirSeparator("/").setName(entryName) - .setBaseName(".").setCaseSensitive(true).build(); - assertThat(innerName.getRoot()).isEqualTo(""); - assertThat(innerName.getDirectorySeparator()).isEqualTo("/"); - assertThat(innerName.getBaseName()).isEqualTo("/."); - assertThat(innerName.getName()).isEqualTo("/" + entryName); - assertThat(innerName.localized()).isEqualTo("/anArchiveEntry.txt"); - - String outerNameStr = format("%s#%s", archiveName.getName(), entryName); - DocumentName outerName = DocumentName.builder(archiveName).setName(outerNameStr) - .setCaseSensitive(innerName.isCaseSensitive()).build(); - - assertThat(outerName.getRoot()).isEqualTo("C:"); - assertThat(outerName.getDirectorySeparator()).isEqualTo("\\"); - assertThat(outerName.getBaseName()).isEqualTo("C:\\archives"); - assertThat(outerName.getName()).isEqualTo("C:\\archives\\anArchive.zip#./anArchiveEntry.txt"); - assertThat(outerName.localized()).isEqualTo("\\anArchive.zip#./anArchiveEntry.txt"); - assertThat(outerName.localized("/")).isEqualTo("/anArchive.zip#./anArchiveEntry.txt"); - - // test with directory - entryName = "./someDir/anArchiveEntry.txt"; - innerName = DocumentName.builder() - .setDirSeparator("/").setName(entryName) - .setBaseName(".").setCaseSensitive(true).build(); - assertThat(innerName.getRoot()).isEqualTo(""); - assertThat(innerName.getDirectorySeparator()).isEqualTo("/"); - assertThat(innerName.getBaseName()).isEqualTo("/."); - assertThat(innerName.getName()).isEqualTo("/" + entryName); - assertThat(innerName.localized()).isEqualTo("/someDir/anArchiveEntry.txt"); - - outerNameStr = format("%s#%s", archiveName.getName(), entryName); - outerName = DocumentName.builder(archiveName).setName(outerNameStr) - .setCaseSensitive(innerName.isCaseSensitive()).build(); - - assertThat(outerName.getRoot()).isEqualTo("C:"); - assertThat(outerName.getDirectorySeparator()).isEqualTo("\\"); - assertThat(outerName.getBaseName()).isEqualTo("C:\\archives"); - assertThat(outerName.getName()).isEqualTo("C:\\archives\\anArchive.zip#./someDir/anArchiveEntry.txt"); - assertThat(outerName.localized()).isEqualTo("\\anArchive.zip#./someDir/anArchiveEntry.txt"); - assertThat(outerName.localized("/")).isEqualTo("/anArchive.zip#./someDir/anArchiveEntry.txt"); - } finally { - DocumentName.ROOTS.clear(); - DocumentName.ROOTS.addAll(preserve); - } + void archiveEntryNameTest() throws IOException { + String entryName = "./anArchiveEntry.txt"; + + + DocumentName archiveName = DocumentName.builder(WINDOWS) + .setName("C:\\archives\\anArchive.zip").setBaseName("C:\\archives").build(); + assertThat(archiveName.getRoot()).isEqualTo("C:"); + assertThat(archiveName.getDirectorySeparator()).isEqualTo("\\"); + assertThat(archiveName.getBaseName()).isEqualTo("C:\\archives"); + assertThat(archiveName.getName()).isEqualTo("C:\\archives\\anArchive.zip"); + assertThat(archiveName.localized()).isEqualTo("\\anArchive.zip"); + + DocumentName innerName = DocumentName.builder(UNIX) + .setName(entryName) + .setBaseName(".").build(); + assertThat(innerName.getRoot()).isEqualTo(""); + assertThat(innerName.getDirectorySeparator()).isEqualTo("/"); + assertThat(innerName.getBaseName()).isEqualTo("/."); + assertThat(innerName.getName()).isEqualTo("/" + entryName); + assertThat(innerName.localized()).isEqualTo("/anArchiveEntry.txt"); + + String outerNameStr = format("%s#%s", archiveName.getName(), entryName); + DocumentName outerName = DocumentName.builder(archiveName).setName(outerNameStr) + .build(); + + assertThat(outerName.getRoot()).isEqualTo("C:"); + assertThat(outerName.getDirectorySeparator()).isEqualTo("\\"); + assertThat(outerName.getBaseName()).isEqualTo("C:\\archives"); + assertThat(outerName.getName()).isEqualTo("C:\\archives\\anArchive.zip#./anArchiveEntry.txt"); + assertThat(outerName.localized()).isEqualTo("\\anArchive.zip#./anArchiveEntry.txt"); + assertThat(outerName.localized("/")).isEqualTo("/anArchive.zip#./anArchiveEntry.txt"); + + // test with directory + entryName = "./someDir/anArchiveEntry.txt"; + innerName = DocumentName.builder(UNIX) + .setName(entryName) + .setBaseName(".").build(); + assertThat(innerName.getRoot()).isEqualTo(""); + assertThat(innerName.getDirectorySeparator()).isEqualTo("/"); + assertThat(innerName.getBaseName()).isEqualTo("/."); + assertThat(innerName.getName()).isEqualTo("/" + entryName); + assertThat(innerName.localized()).isEqualTo("/someDir/anArchiveEntry.txt"); + + outerNameStr = format("%s#%s", archiveName.getName(), entryName); + outerName = DocumentName.builder(archiveName).setName(outerNameStr).build(); + + assertThat(outerName.getRoot()).isEqualTo("C:"); + assertThat(outerName.getDirectorySeparator()).isEqualTo("\\"); + assertThat(outerName.getBaseName()).isEqualTo("C:\\archives"); + assertThat(outerName.getName()).isEqualTo("C:\\archives\\anArchive.zip#./someDir/anArchiveEntry.txt"); + assertThat(outerName.localized()).isEqualTo("\\anArchive.zip#./someDir/anArchiveEntry.txt"); + assertThat(outerName.localized("/")).isEqualTo("/anArchive.zip#./someDir/anArchiveEntry.txt"); } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/FSInfoTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/FSInfoTest.java new file mode 100644 index 000000000..4c0e4ac8e --- /dev/null +++ b/apache-rat-core/src/test/java/org/apache/rat/document/FSInfoTest.java @@ -0,0 +1,60 @@ +/* + * 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 com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import java.io.File; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; +import org.apache.commons.lang3.tuple.Pair; +import org.assertj.core.util.Files; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThat; + +public class FSInfoTest { + public static final DocumentName.FSInfo DEFAULT; + public static final DocumentName.FSInfo OSX; + public static final DocumentName.FSInfo UNIX; + public static final DocumentName.FSInfo WINDOWS; + + static { + try (FileSystem osx = Jimfs.newFileSystem(Configuration.osX()); + FileSystem unix = Jimfs.newFileSystem(Configuration.unix()); + FileSystem windows = Jimfs.newFileSystem(Configuration.windows())) { + OSX = new DocumentName.FSInfo(osx); + UNIX = new DocumentName.FSInfo(unix); + WINDOWS = new DocumentName.FSInfo(windows); + DEFAULT = new DocumentName.FSInfo(FileSystems.getDefault()); + } catch (IOException e) { + throw new RuntimeException("Unable to creat FSInfo objects: " + e.getMessage(), e); + } + } +} diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java index 2abf19340..633cc3776 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java @@ -18,6 +18,10 @@ */ package org.apache.rat.document.guesser; +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import java.io.IOException; +import java.nio.file.FileSystem; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; @@ -28,6 +32,9 @@ import org.junit.jupiter.params.provider.MethodSource; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.apache.rat.document.FSInfoTest.OSX; +import static org.apache.rat.document.FSInfoTest.UNIX; +import static org.apache.rat.document.FSInfoTest.WINDOWS; public class NoteGuesserTest { @@ -38,13 +45,12 @@ public void testMatches(DocumentName testingName, boolean expected) { assertEquals(expected, actual, testingName::getName); } - private static Stream nameData() { + private static Stream nameData() throws IOException { List lst = new ArrayList<>(); - final DocumentName linuxBaseName = DocumentName.builder().setName("/").setBaseName("/").setDirSeparator("/") - .setCaseSensitive(true).build(); - final DocumentName windowsBaseName = DocumentName.builder().setName("\\").setBaseName("\\") - .setDirSeparator("\\").setCaseSensitive(false).build(); + final DocumentName osxBaseName = DocumentName.builder(OSX).setName("/").setBaseName("/").build(); + final DocumentName linuxBaseName = DocumentName.builder(UNIX).setName("/").setBaseName("/").build(); + final DocumentName windowsBaseName = DocumentName.builder(WINDOWS).setName("\\").setBaseName("\\").build(); lst.add(Arguments.of(linuxBaseName.resolve("DEPENDENCIES"), true)); lst.add(Arguments.of(linuxBaseName.resolve("LICENSE"), true)); @@ -78,6 +84,22 @@ private static Stream nameData() { lst.add(Arguments.of(windowsBaseName.resolve("src\\test\\README.txt"), true)); lst.add(Arguments.of(windowsBaseName.resolve("src\\test\\README.shouldFail"), false)); + lst.add(Arguments.of(osxBaseName.resolve("DEPENDENCIES"), true)); + lst.add(Arguments.of(osxBaseName.resolve("LICENSE"), true)); + lst.add(Arguments.of(osxBaseName.resolve("LICENSE.txt"), true)); + lst.add(Arguments.of(osxBaseName.resolve("NOTICE"), true)); + lst.add(Arguments.of(osxBaseName.resolve("NOTICE.txt"), true)); + lst.add(Arguments.of(osxBaseName.resolve("README"), true)); + lst.add(Arguments.of(osxBaseName.resolve("README.txt"), true)); + lst.add(Arguments.of(osxBaseName.resolve("src/test/DEPENDENCIES"), true)); + lst.add(Arguments.of(osxBaseName.resolve("src/test/LICENSE"), true)); + lst.add(Arguments.of(osxBaseName.resolve("src/test/LICENSE.txt"), true)); + lst.add(Arguments.of(osxBaseName.resolve("src/test/NOTICE"), true)); + lst.add(Arguments.of(osxBaseName.resolve("src/test/NOTICE.txt"), true)); + lst.add(Arguments.of(osxBaseName.resolve("src/test/README"), true)); + lst.add(Arguments.of(osxBaseName.resolve("src/test/README.txt"), true)); + lst.add(Arguments.of(osxBaseName.resolve("src/test/README.shouldFail"), false)); + return lst.stream(); } } 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 c1e756687..532182b8e 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 @@ -50,13 +50,13 @@ public TestingDocument(DocumentName documentName) { } public TestingDocument(String name, DocumentNameMatcher matcher) { - super(DocumentName.builder().setName(name).setBaseName("").setDirSeparator("/").setCaseSensitive(true).build(), matcher); + super(DocumentName.builder().setName(name).setBaseName("").build(), matcher); this.reader = null; this.input = null; } public TestingDocument(Reader reader, String name) { - super(DocumentName.builder().setName(name).setBaseName("").setDirSeparator("/").setCaseSensitive(true).build(), DocumentNameMatcher.MATCHES_ALL); + super(DocumentName.builder().setName(name).setBaseName("").build(), DocumentNameMatcher.MATCHES_ALL); this.reader = reader; this.input = null; } diff --git a/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java b/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java index 14ac1478b..1c115f674 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java @@ -33,8 +33,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class FileListWalkerTest { @@ -84,7 +83,7 @@ public static void setUp() throws Exception { source = new File(working, "source.txt"); - DocumentName sourceName = DocumentName.builder(source).setBaseName(working.getAbsolutePath()).build(); + DocumentName sourceName = DocumentName.builder(source).build(); File regular = new File(working, "regular"); regular.mkdir(); fileWriter(regular, "regularFile", "regular file"); @@ -112,7 +111,7 @@ public static void setUp() throws Exception { System.out.flush(); } - hiddenName = DocumentName.builder(hiddenFile).setBaseName(rootName.getBaseName()).build(); + //hiddenName = DocumentName.builder(hiddenFile).setBaseName(rootName.getBaseName()).build(); } @Test @@ -122,10 +121,7 @@ public void readFilesTest() throws RatException { walker.run(new TestRatReport(scanned)); String[] expected = {regularName.localized("/"), hiddenName.localized("/"), anotherName.localized("/")}; - assertEquals(3, scanned.size()); - for (String ex : expected) { - assertTrue(scanned.contains(ex), ()-> String.format("Missing %s from %s", ex, String.join(", ", scanned))); - } + assertThat(scanned).containsExactly(expected); } static class TestRatReport implements RatReport { diff --git a/pom.xml b/pom.xml index b181a2056..6ee80685e 100644 --- a/pom.xml +++ b/pom.xml @@ -217,6 +217,12 @@ agnostic home for software distribution comprehension and audit tools. 2.4.21 test + + com.google.jimfs + jimfs + 1.3.0 + test + From 136ddb658015b1f2eeddc7ecf00d720af817a915 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Thu, 2 Jan 2025 21:51:39 +0000 Subject: [PATCH 023/123] clean up of remaingin core tests --- .../apache/rat/commandline/Converters.java | 5 ++-- .../rat/config/exclusion/ExclusionUtils.java | 15 +++++----- .../AbstractFileProcessorBuilder.java | 5 ++-- .../org/apache/rat/document/DocumentName.java | 21 +++++++++---- .../rat/analysis/AnalyserFactoryTest.java | 2 +- .../org/apache/rat/commandline/ArgTests.java | 1 - .../apache/rat/document/FileDocumentTest.java | 30 ++++++++++++------- 7 files changed, 49 insertions(+), 30 deletions(-) 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 61f27cdbe..ce5291de0 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 @@ -21,6 +21,7 @@ import java.io.File; import java.io.IOException; +import java.nio.file.FileSystems; import org.apache.commons.cli.Converter; import org.apache.commons.lang3.tuple.Pair; import org.apache.rat.ConfigurationException; @@ -92,9 +93,7 @@ public File apply(final String fileName) throws NullPointerException { // is this a relative file? if (!fileName.startsWith(File.separator)) { // check for a root provided (e.g. C:\\)" - DocumentName.Builder builder = DocumentName.builder(file); - final DocumentName name = builder.build(); - if (name.getRoot().isEmpty()) { + if (!DocumentName.DEFAULT_FSINFO.rootFor(file.getAbsolutePath()).isPresent()) { // no root, resolve against workingDirectory file = new File(workingDirectory.resolve(fileName).getName()).getAbsoluteFile(); } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java index 772526d67..936a9b147 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java @@ -226,16 +226,17 @@ public static String localizePattern(final DocumentName documentName, final Stri String workingPattern = prefix ? pattern.substring(1) : pattern; String normalizedPattern = SelectorUtils.extractPattern(workingPattern, documentName.getDirectorySeparator()); - String result = SelectorUtils.isRegexPrefixedPattern(workingPattern) ? - new StringBuilder(prefix ? NEGATION_PREFIX : "") - .append(SelectorUtils.REGEX_HANDLER_PREFIX) + StringBuilder sb = new StringBuilder(prefix ? NEGATION_PREFIX : ""); + if (SelectorUtils.isRegexPrefixedPattern(workingPattern)) { + sb.append(SelectorUtils.REGEX_HANDLER_PREFIX) .append("\\Q").append(documentName.getBaseName()) .append(documentName.getDirectorySeparator()) .append("\\E").append(normalizedPattern) - .append(SelectorUtils.PATTERN_HANDLER_SUFFIX) - .toString() - : documentName.getBaseDocumentName().resolve(normalizedPattern).getName(); - return (prefix ? NEGATION_PREFIX : "") + result; + .append(SelectorUtils.PATTERN_HANDLER_SUFFIX); + } else { + sb.append(documentName.getBaseDocumentName().resolve(normalizedPattern).getName()); + } + return sb.toString(); } /** diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java index c5f7470e9..f6788f223 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java @@ -157,8 +157,9 @@ protected MatcherSet process(final Consumer matcherSetConsumer, fina Set included = new HashSet<>(); Set excluded = new HashSet<>(); MatcherSet.Builder.segregateList(excluded, included, iterable); - matcherSetBuilder.addExcluded(root, excluded); - matcherSetBuilder.addIncluded(root, included); + DocumentName displayName = DocumentName.builder(root).setName(documentName.getName()).build(); + matcherSetBuilder.addExcluded(displayName, excluded); + matcherSetBuilder.addIncluded(displayName, included); return matcherSetBuilder.build(); } diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java index 1c7d50625..c3dc9c128 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java @@ -31,6 +31,7 @@ import java.util.Objects; import java.util.Optional; +import java.util.function.Predicate; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.CompareToBuilder; @@ -66,8 +67,8 @@ public class DocumentName implements Comparable { private final FSInfo fsInfo; /** The root for the DocumentName. May be empty but not null. */ private final String root; - - private static final FSInfo DEFAULT_FSINFO = new FSInfo(FileSystems.getDefault()); + /** The File System info for the default file system */ + public static final FSInfo DEFAULT_FSINFO = new FSInfo(FileSystems.getDefault()); private static boolean isCaseSensitive(FileSystem fs) { boolean isCaseSensitive = false; @@ -266,10 +267,14 @@ public String localized(final String dirSeparator) { if (tokens.length == 1) { return dirSeparator + tokens[0]; } + Predicate check = s -> s.startsWith(dirSeparator); String modifiedRoot = dirSeparator.equals("/") ? root.replace('\\', '/') : root.replace('/', '\\'); + if (StringUtils.isNotEmpty(modifiedRoot)) { + check = check.or(s -> s.startsWith(modifiedRoot)); + } String result = String.join(dirSeparator, tokens); - return result.startsWith(dirSeparator) || result.startsWith(modifiedRoot) ? result : dirSeparator + result; + return check.test(result) ? result : dirSeparator + result; } @@ -451,9 +456,9 @@ private void verify() { } if (!sameNameFlag) { Objects.requireNonNull(baseName, "Basename cannot be null"); - if (!name.startsWith(baseName.name)) { - throw new IllegalArgumentException(String.format("name '%s' must start with baseName '%s'", name, baseName.name)); - } +// if (!name.startsWith(baseName.name)) { +// throw new IllegalArgumentException(String.format("name '%s' must start with baseName '%s'", name, baseName.name)); +// } } } @@ -542,6 +547,10 @@ public Builder setName(final File file) { File p = file.getParentFile(); if (p != null) { setBaseName(p); + } else { + Builder baseBuilder = new Builder(this.fsInfo).setName(this.directorySeparator()); + baseBuilder.sameNameFlag = true; + setBaseName(baseBuilder.build()); } } return this; 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 4e2461ce6..1d60457f0 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 @@ -71,7 +71,7 @@ public void setUp() { @Test public void standardTypeAnalyser() throws Exception { - final Document document = new FileDocument(basedir, + final Document document = new FileDocument( Resources.getExampleResource("exampleData/Text.txt"), DocumentNameMatcher.MATCHES_ALL); analyser.analyse(document); assertThat(document.getMetaData().getDocumentType()).isEqualTo(Document.Type.STANDARD); diff --git a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java index c40941028..484f8a632 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java +++ b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java @@ -29,7 +29,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; - import java.io.File; import static org.assertj.core.api.Assertions.assertThat; diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/FileDocumentTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/FileDocumentTest.java index f1ebb38cf..d63dfe503 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/FileDocumentTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/FileDocumentTest.java @@ -18,6 +18,8 @@ */ package org.apache.rat.document; +import java.nio.file.Path; +import org.apache.commons.io.FileUtils; import org.apache.rat.api.Document; import org.apache.rat.test.utils.Resources; import org.assertj.core.util.Files; @@ -27,32 +29,40 @@ import java.io.BufferedReader; import java.io.File; import java.io.Reader; +import org.junit.jupiter.api.io.TempDir; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; public class FileDocumentTest { private Document document; private File file; - + + @TempDir + private static Path tempDir; + @BeforeEach public void setUp() throws Exception { - File basedir = new File(Files.currentFolder(), Resources.SRC_TEST_RESOURCES); - file = Resources.getExampleResource("exampleData/Source.java"); - document = new FileDocument(DocumentName.builder(basedir).build(), file, DocumentNameMatcher.MATCHES_ALL); + + File basedir = new File(tempDir.toFile(), Resources.SRC_TEST_RESOURCES); + basedir.mkdirs(); + File sourceData = Resources.getExampleResource("exampleData/Source.java"); + file = new File(basedir, "Source.java"); + FileUtils.copyFile(sourceData, file); + + DocumentName docName = DocumentName.builder(basedir).build(); + document = new FileDocument(docName, file, DocumentNameMatcher.MATCHES_ALL); } @Test public void reader() throws Exception { Reader reader = document.reader(); - assertNotNull(reader, "Reader should be returned"); - assertEquals("package elements;", - new BufferedReader(reader).readLine(), "First file line expected"); + assertThat(reader).isNotNull(); + assertThat(new BufferedReader(reader).readLine()).isEqualTo("package elements;"); } @Test public void getName() { final DocumentName name = document.getName(); - assertNotNull(name, "Name is set"); + assertThat(name).isNotNull(); } } From 047358b8e1388879dd8f801cb4cac1d7209bdf02 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 13:26:09 +0000 Subject: [PATCH 024/123] fixed archive processing and naming issues --- .../it/java/org/apache/rat/ReportTest.java | 2 +- .../apache/rat/analysis/TikaProcessor.java | 27 ++++- .../java/org/apache/rat/commandline/Arg.java | 8 +- .../apache/rat/commandline/Converters.java | 2 +- .../rat/document/ArchiveEntryDocument.java | 6 +- .../apache/rat/document/ArchiveEntryName.java | 107 +++++++++++++++++ .../org/apache/rat/document/DocumentName.java | 108 ++++++++++-------- .../org/apache/rat/walker/ArchiveWalker.java | 7 +- .../org/apache/rat/OptionCollectionTest.java | 8 +- .../rat/analysis/AnalyserFactoryTest.java | 4 +- .../apache/rat/document/DocumentNameTest.java | 57 +++------ .../org/apache/rat/mp/RatCheckMojoTest.java | 8 +- 12 files changed, 231 insertions(+), 113 deletions(-) create mode 100644 apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryName.java 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 b58c6732b..76e3f09c9 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 @@ -163,7 +163,7 @@ public static Stream args() throws RatException { @Override public void report(Document document) { if (!document.isIgnored()) { - String[] tokens = document.getName().tokenize(document.getName().localized()); + String[] tokens = DocumentName.DEFAULT_FSINFO.tokenize(document.getName().localized()); results.add(Arguments.of(tokens[1], document)); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/analysis/TikaProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/analysis/TikaProcessor.java index 5f128668d..065efcb6d 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/analysis/TikaProcessor.java +++ b/apache-rat-core/src/main/java/org/apache/rat/analysis/TikaProcessor.java @@ -122,6 +122,28 @@ public static InputStream markSupportedInputStream(final InputStream stream) { return stream.markSupported() ? stream : new BufferedInputStream(stream); } + /** + * Extracts the media type properly from zero length files. + * @param stream the InputStream from the file. + * @param documentName the name of the document + * @return the mime type for the document + * @throws IOException on error. + */ + private static String detectMediaType(InputStream stream, DocumentName documentName) throws IOException { + stream.mark(1); + int ch = stream.read(); + stream.reset(); + Metadata metadata = new Metadata(); + String name = documentName.localized(); + if (ch == -1) { + name = name.substring(name.lastIndexOf("/") + 1); + metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, name); + return TIKA.detect(null, metadata); + } + metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, name); + return TIKA.detect(stream, metadata); + } + /** * Process the input document. * @param document the Document to process. @@ -129,10 +151,8 @@ public static InputStream markSupportedInputStream(final InputStream stream) { * @throws RatDocumentAnalysisException on error. */ public static String process(final Document document) throws RatDocumentAnalysisException { - Metadata metadata = new Metadata(); try (InputStream stream = markSupportedInputStream(document.inputStream())) { - metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, document.getName().getName()); - String result = TIKA.detect(stream, metadata); + String result = detectMediaType(stream, document.getName()); String[] parts = result.split("/"); MediaType mediaType = new MediaType(parts[0], parts[1]); document.getMetaData().setMediaType(mediaType); @@ -146,7 +166,6 @@ public static String process(final Document document) throws RatDocumentAnalysis document.getMetaData().setDocumentType(Document.Type.NOTICE); } } - return result; } catch (IOException e) { throw new RatDocumentAnalysisException(e); 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 f916e3843..293b93bcd 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 @@ -849,12 +849,12 @@ private static void processOutputArgs(final ArgumentContext context) { if (OUTPUT_FILE.isSelected()) { try { - File f = context.getCommandLine().getParsedOptionValue(OUTPUT_FILE.getSelected()); - File parent = f.getParentFile(); + File file = context.getCommandLine().getParsedOptionValue(OUTPUT_FILE.getSelected()); + File parent = file.getParentFile(); if (!parent.mkdirs() && !parent.isDirectory()) { - DefaultLog.getInstance().error("Could not create report parent directory " + f); + DefaultLog.getInstance().error("Could not create report parent directory " + file); } - context.getConfiguration().setOut(f); + context.getConfiguration().setOut(file); } catch (ParseException e) { context.logParseException(e, OUTPUT_FILE.getSelected(), "System.out"); context.getConfiguration().setOut((IOSupplier) null); 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 ce5291de0..9e1cf88c2 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 @@ -93,7 +93,7 @@ public File apply(final String fileName) throws NullPointerException { // is this a relative file? if (!fileName.startsWith(File.separator)) { // check for a root provided (e.g. C:\\)" - if (!DocumentName.DEFAULT_FSINFO.rootFor(file.getAbsolutePath()).isPresent()) { + if (!DocumentName.DEFAULT_FSINFO.rootFor(fileName).isPresent()) { // no root, resolve against workingDirectory file = new File(workingDirectory.resolve(fileName).getName()).getAbsoluteFile(); } 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 index 0553e4339..dabc848bc 100644 --- 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 @@ -36,12 +36,12 @@ public class ArchiveEntryDocument extends Document { /** * Creates an Archive entry. - * @param outerName the name of this entry from outside the archive. + * @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 DocumentName outerName, final byte[] contents, final DocumentNameMatcher nameMatcher) { - super(outerName, nameMatcher); + public ArchiveEntryDocument(final ArchiveEntryName entryName, final byte[] contents, final DocumentNameMatcher nameMatcher) { + super(entryName, nameMatcher); this.contents = contents; } diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryName.java b/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryName.java new file mode 100644 index 000000000..ad03c3684 --- /dev/null +++ b/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryName.java @@ -0,0 +1,107 @@ +package org.apache.rat.document; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; + +public class ArchiveEntryName extends DocumentName { + + private final DocumentName archiveFileName; + + private static DocumentName.Builder prepareBuilder(DocumentName archiveFileName, String archiveEntryName) { + String root = archiveFileName.getName() + "#"; + FSInfo fsInfo = new FSInfo("/", true, Collections.singletonList(root)); + return DocumentName.builder(fsInfo) + .setRoot(root) + .setBaseName(root + "/") + .setName(archiveEntryName); + } + public ArchiveEntryName(final DocumentName archiveFileName, final String archiveEntryName) { + super(prepareBuilder(archiveFileName, archiveEntryName)); + this.archiveFileName = archiveFileName; + } + + @Override + public File asFile() { + return archiveFileName.asFile(); + } + + @Override + public Path asPath() { + return Paths.get( archiveFileName.asPath().toString(), "#", super.asPath().toString()); + } + + @Override + public DocumentName resolve(String child) { + return new ArchiveEntryName(this.archiveFileName, super.resolve(child).localized()); + } + +// @Override +// public String getName() { +// return archiveFileName.getName(), localized()); +// } + + @Override + public String getBaseName() { + return archiveFileName.getName()+"#"; + } + +// @Override +// public DocumentName getBaseDocumentName() { +// return super.getBaseDocumentName(); +// } +// +// @Override +// public String getDirectorySeparator() { +// return super.getDirectorySeparator(); +// } + + @Override + boolean startsWithRootOrSeparator(String candidate, String root, String separator) { + return super.startsWithRootOrSeparator(candidate, root, separator); + } + + @Override + public String localized() { + return /*archiveFileName.localized() + "#" +*/ super.localized(); + } + + @Override + public String localized(String dirSeparator) { + String superLocal = super.localized(dirSeparator); + superLocal = superLocal.substring(superLocal.lastIndexOf("#")+1); + return archiveFileName.localized(dirSeparator) + "#" + superLocal; + } + + @Override + public String getShortName() { + return super.getShortName(); + } + + @Override + public boolean isCaseSensitive() { + return super.isCaseSensitive(); + } + + @Override + public String toString() { + return super.toString(); + } + + @Override + public int compareTo(DocumentName other) { + return super.compareTo(other); + } + + @Override + public boolean equals(Object other) { + return super.equals(other); + } + + @Override + public int hashCode() { + return super.hashCode(); + } +} diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java index c3dc9c128..8171d98c2 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java @@ -31,7 +31,6 @@ import java.util.Objects; import java.util.Optional; -import java.util.function.Predicate; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.CompareToBuilder; @@ -142,7 +141,7 @@ public static Builder builder(final DocumentName documentName) { * Builds the DocumentName from the builder. * @param builder the builder to provide the values. */ - private DocumentName(final Builder builder) { + DocumentName(final Builder builder) { this.name = builder.name; this.fsInfo = builder.fsInfo; this.root = builder.root; @@ -168,7 +167,7 @@ public DocumentName resolve(final String child) { if (StringUtils.isBlank(child)) { return this; } - String separator = getDirectorySeparator(); + String separator = fsInfo.dirSeparator(); String pattern = separator.equals("/") ? child.replace('\\', '/') : child.replace('/', '\\'); @@ -176,24 +175,7 @@ public DocumentName resolve(final String child) { pattern = name + separator + pattern; } - return new Builder(this).setName(normalize(pattern)).build(); - } - - private String normalize(String pattern) { - List parts = new ArrayList<>(Arrays.asList(tokenize(pattern))); - for (int i=0; i check = s -> s.startsWith(dirSeparator); + String modifiedRoot = dirSeparator.equals("/") ? root.replace('\\', '/') : root.replace('/', '\\'); - if (StringUtils.isNotEmpty(modifiedRoot)) { - check = check.or(s -> s.startsWith(modifiedRoot)); - } String result = String.join(dirSeparator, tokens); - return check.test(result) ? result : dirSeparator + result; - } - - - - /** - * Tokenizes the string based on the directory separator of this DocumentName. - * @param source the source to tokenize - * @return the array of tokenized strings. - */ - public String[] tokenize(final String source) { - return source.split("\\Q" + fsInfo.dirSeparator() + "\\E"); + return startsWithRootOrSeparator(result, modifiedRoot, dirSeparator) ? result : dirSeparator + result; } /** @@ -341,6 +320,12 @@ public FSInfo(FileSystem fileSystem) { fileSystem.getRootDirectories().forEach(r -> roots.add(r.toString())); } + FSInfo(String separator, boolean isCaseSensitive, List roots) { + this.separator = separator; + this.isCaseSensitive = isCaseSensitive; + this.roots = new ArrayList<>(roots); + } + public String dirSeparator() { return separator; } @@ -358,6 +343,40 @@ public Optional rootFor(String workingName) { return Optional.empty(); } + /** + * Tokenizes the string based on the directory separator of this DocumentName. + * @param source the source to tokenize + * @return the array of tokenized strings. + */ + public String[] tokenize(final String source) { + return source.split("\\Q" + dirSeparator() + "\\E"); + } + + /** + * Removes "." and ".." from filenames names. + * @param pattern the file name pattern + * @return the normalized file name. + */ + public String normalize(String pattern) { + if (StringUtils.isBlank(pattern)) { + return ""; + } + List parts = new ArrayList<>(Arrays.asList(tokenize(pattern))); + for (int i=0; i pair = splitRoot(StringUtils.defaultIfEmpty(name, "")); + Pair pair = splitRoot(StringUtils.defaultIfBlank(name, "")); if (this.root.isEmpty()) { this.root = pair.getLeft(); } - this.name = pair.getRight(); + this.name = fsInfo.normalize(pair.getRight()); if (this.baseName != null && !baseName.name.isEmpty()) { if (!this.name.startsWith(baseName.name)) { this.name = this.name.isEmpty() ? baseName.name : @@ -540,7 +556,7 @@ private void setEmptyRoot(final String root) { public Builder setName(final File file) { Pair pair = splitRoot(file.getAbsolutePath()); setEmptyRoot(pair.getLeft()); - this.name = pair.getRight(); + this.name = fsInfo.normalize(pair.getRight()); if (file.isDirectory()) { sameNameFlag = true; } else { 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 7ad4ca23c..342a99994 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 @@ -36,6 +36,7 @@ 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.report.RatReport; import org.apache.rat.utils.DefaultLog; @@ -93,10 +94,8 @@ public Collection getDocuments() throws RatException { if (this.getDocument().getNameExcluder().matches(innerName)) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); IOUtils.copy(input, baos); - DocumentName archiveName = getDocument().getName(); - String outerNameStr = format("%s#%s", archiveName.getName(), entry.getName()); - DocumentName outerName = DocumentName.builder(archiveName).setName(outerNameStr).build(); - result.add(new ArchiveEntryDocument(outerName, baos.toByteArray(), getDocument().getNameExcluder())); + ArchiveEntryName entryName = new ArchiveEntryName(getDocument().getName(), entry.getName()); + result.add(new ArchiveEntryDocument(entryName, baos.toByteArray(), getDocument().getNameExcluder())); } } } 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 bd31ea1f9..40ab11a2c 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 @@ -25,6 +25,7 @@ import org.apache.commons.cli.ParseException; import org.apache.commons.lang3.tuple.Pair; import org.apache.rat.commandline.ArgumentContext; +import org.apache.rat.document.DocumentName; import org.apache.rat.license.LicenseSetFactory; import org.apache.rat.report.IReportable; import org.apache.rat.test.AbstractOptionsProvider; @@ -141,11 +142,12 @@ public void testDefaultConfiguration() throws ParseException { @ParameterizedTest @ValueSource(strings = { ".", "./", "target", "./target" }) public void getReportableTest(String fName) throws IOException { - File expected = new File(fName); + File base = new File(fName); + String expected = DocumentName.DEFAULT_FSINFO.normalize(base.getAbsolutePath()); ReportConfiguration config = OptionCollection.parseCommands(testPath.toFile(), new String[]{fName}, o -> fail("Help called"), false); - IReportable reportable = OptionCollection.getReportable(expected, config); + IReportable reportable = OptionCollection.getReportable(base, config); assertThat(reportable).as(() -> format("'%s' returned null", fName)).isNotNull(); - assertThat(reportable.getName().getName()).isEqualTo(expected.getAbsolutePath()); + assertThat(reportable.getName().getName()).isEqualTo(expected); } /** 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 1d60457f0..067dc5f15 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 @@ -114,8 +114,8 @@ public void archiveTypeAnalyserTest() throws Exception { private static Stream archiveProcessingTestData() { List lst = new ArrayList<>(); lst.add(Arguments.of(ReportConfiguration.Processing.NOTIFICATION, 0)); - lst.add(Arguments.of(ReportConfiguration.Processing.PRESENCE, 2)); - lst.add(Arguments.of(ReportConfiguration.Processing.ABSENCE, 3)); + lst.add(Arguments.of(ReportConfiguration.Processing.PRESENCE, 1)); + lst.add(Arguments.of(ReportConfiguration.Processing.ABSENCE, 2)); return lst.stream(); } diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java index 457362f29..599a4d9c7 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java @@ -213,55 +213,34 @@ void splitRootsTest() throws IOException { @Test void archiveEntryNameTest() throws IOException { String entryName = "./anArchiveEntry.txt"; - - DocumentName archiveName = DocumentName.builder(WINDOWS) .setName("C:\\archives\\anArchive.zip").setBaseName("C:\\archives").build(); + assertThat(archiveName.getRoot()).isEqualTo("C:"); assertThat(archiveName.getDirectorySeparator()).isEqualTo("\\"); assertThat(archiveName.getBaseName()).isEqualTo("C:\\archives"); assertThat(archiveName.getName()).isEqualTo("C:\\archives\\anArchive.zip"); assertThat(archiveName.localized()).isEqualTo("\\anArchive.zip"); - DocumentName innerName = DocumentName.builder(UNIX) - .setName(entryName) - .setBaseName(".").build(); - assertThat(innerName.getRoot()).isEqualTo(""); - assertThat(innerName.getDirectorySeparator()).isEqualTo("/"); - assertThat(innerName.getBaseName()).isEqualTo("/."); - assertThat(innerName.getName()).isEqualTo("/" + entryName); - assertThat(innerName.localized()).isEqualTo("/anArchiveEntry.txt"); - - String outerNameStr = format("%s#%s", archiveName.getName(), entryName); - DocumentName outerName = DocumentName.builder(archiveName).setName(outerNameStr) - .build(); - - assertThat(outerName.getRoot()).isEqualTo("C:"); - assertThat(outerName.getDirectorySeparator()).isEqualTo("\\"); - assertThat(outerName.getBaseName()).isEqualTo("C:\\archives"); - assertThat(outerName.getName()).isEqualTo("C:\\archives\\anArchive.zip#./anArchiveEntry.txt"); - assertThat(outerName.localized()).isEqualTo("\\anArchive.zip#./anArchiveEntry.txt"); - assertThat(outerName.localized("/")).isEqualTo("/anArchive.zip#./anArchiveEntry.txt"); + + ArchiveEntryName archiveEntryName = new ArchiveEntryName(archiveName, entryName); + + assertThat(archiveEntryName.getRoot()).isEqualTo(archiveName.getName()+"#"); + assertThat(archiveEntryName.getDirectorySeparator()).isEqualTo("/"); + assertThat(archiveEntryName.getBaseName()).isEqualTo("C:\\archives\\anArchive.zip#"); + assertThat(archiveEntryName.getName()).isEqualTo("C:\\archives\\anArchive.zip#/anArchiveEntry.txt"); + assertThat(archiveEntryName.localized()).isEqualTo("/anArchiveEntry.txt"); + assertThat(archiveEntryName.localized("/")).isEqualTo("/anArchive.zip#/anArchiveEntry.txt"); // test with directory entryName = "./someDir/anArchiveEntry.txt"; - innerName = DocumentName.builder(UNIX) - .setName(entryName) - .setBaseName(".").build(); - assertThat(innerName.getRoot()).isEqualTo(""); - assertThat(innerName.getDirectorySeparator()).isEqualTo("/"); - assertThat(innerName.getBaseName()).isEqualTo("/."); - assertThat(innerName.getName()).isEqualTo("/" + entryName); - assertThat(innerName.localized()).isEqualTo("/someDir/anArchiveEntry.txt"); - - outerNameStr = format("%s#%s", archiveName.getName(), entryName); - outerName = DocumentName.builder(archiveName).setName(outerNameStr).build(); - - assertThat(outerName.getRoot()).isEqualTo("C:"); - assertThat(outerName.getDirectorySeparator()).isEqualTo("\\"); - assertThat(outerName.getBaseName()).isEqualTo("C:\\archives"); - assertThat(outerName.getName()).isEqualTo("C:\\archives\\anArchive.zip#./someDir/anArchiveEntry.txt"); - assertThat(outerName.localized()).isEqualTo("\\anArchive.zip#./someDir/anArchiveEntry.txt"); - assertThat(outerName.localized("/")).isEqualTo("/anArchive.zip#./someDir/anArchiveEntry.txt"); + archiveEntryName = new ArchiveEntryName(archiveName, entryName); + + assertThat(archiveEntryName.getRoot()).isEqualTo(archiveName.getName()+"#"); + assertThat(archiveEntryName.getDirectorySeparator()).isEqualTo("/"); + assertThat(archiveEntryName.getBaseName()).isEqualTo("C:\\archives\\anArchive.zip#"); + assertThat(archiveEntryName.getName()).isEqualTo("C:\\archives\\anArchive.zip#/someDir/anArchiveEntry.txt"); + assertThat(archiveEntryName.localized()).isEqualTo("/someDir/anArchiveEntry.txt"); + assertThat(archiveEntryName.localized("/")).isEqualTo("/anArchive.zip#/someDir/anArchiveEntry.txt"); } } diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java index c10b10bb6..a260bca3e 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java @@ -258,12 +258,8 @@ void it5() throws Exception { ReportConfigurationTest.validateDefaultLicenses(config, "CC-BY-NC-ND", "YAL"); assertThat(LicenseSetFactory.search("YAL", "YAL", config.getLicenses(LicenseFilter.ALL))).isPresent(); - //try { - mojo.execute(); - // fail("Should have thrown exception"); -// } catch (RatCheckException e) { -// assertThat(e.getMessage()).contains("LICENSE_CATEGORIES, LICENSE_NAMES, STANDARDS exceeded"); -// } + + mojo.execute(); Map data = new HashMap<>(); data.put(ClaimStatistic.Counter.APPROVED, "1"); From 9748adf485da05bc611ed2cce25586718cf319f9 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 14:03:03 +0000 Subject: [PATCH 025/123] fixed checkstyle issues --- .../apache/rat/analysis/TikaProcessor.java | 26 +---- .../apache/rat/commandline/Converters.java | 1 - .../config/exclusion/ExclusionProcessor.java | 9 +- .../config/exclusion/StandardCollection.java | 4 +- .../apache/rat/document/ArchiveEntryName.java | 85 +++++---------- .../org/apache/rat/document/DocumentName.java | 103 ++++++++++++++---- .../org/apache/rat/walker/ArchiveWalker.java | 1 - 7 files changed, 119 insertions(+), 110 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/analysis/TikaProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/analysis/TikaProcessor.java index 065efcb6d..6991f4924 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/analysis/TikaProcessor.java +++ b/apache-rat-core/src/main/java/org/apache/rat/analysis/TikaProcessor.java @@ -122,28 +122,6 @@ public static InputStream markSupportedInputStream(final InputStream stream) { return stream.markSupported() ? stream : new BufferedInputStream(stream); } - /** - * Extracts the media type properly from zero length files. - * @param stream the InputStream from the file. - * @param documentName the name of the document - * @return the mime type for the document - * @throws IOException on error. - */ - private static String detectMediaType(InputStream stream, DocumentName documentName) throws IOException { - stream.mark(1); - int ch = stream.read(); - stream.reset(); - Metadata metadata = new Metadata(); - String name = documentName.localized(); - if (ch == -1) { - name = name.substring(name.lastIndexOf("/") + 1); - metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, name); - return TIKA.detect(null, metadata); - } - metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, name); - return TIKA.detect(stream, metadata); - } - /** * Process the input document. * @param document the Document to process. @@ -152,7 +130,9 @@ private static String detectMediaType(InputStream stream, DocumentName documentN */ public static String process(final Document document) throws RatDocumentAnalysisException { try (InputStream stream = markSupportedInputStream(document.inputStream())) { - String result = detectMediaType(stream, document.getName()); + Metadata metadata = new Metadata(); + metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, document.getName().getShortName()); + String result = TIKA.detect(stream, metadata); String[] parts = result.split("/"); MediaType mediaType = new MediaType(parts[0], parts[1]); document.getMetaData().setMediaType(mediaType); 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 9e1cf88c2..7375d44b5 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 @@ -21,7 +21,6 @@ import java.io.File; import java.io.IOException; -import java.nio.file.FileSystems; import org.apache.commons.cli.Converter; import org.apache.commons.lang3.tuple.Pair; import org.apache.rat.ConfigurationException; 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 48d5eddc3..45001ba29 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 @@ -219,7 +219,14 @@ private List extractFileProcessors(final DocumentName basedir) { return fileProcessorList; } - private String preparePattern(DocumentName documentName, String pattern) { + /** + * Converts the pattern to use the directory separator specified by the document name and localises it for + * exclusion processing. + * @param documentName The document name to adjust the pattern against. + * @param pattern the pattern. + * @return the prepared pattern. + */ + private String preparePattern(final DocumentName documentName, final String pattern) { return ExclusionUtils.localizePattern(documentName, ExclusionUtils.convertSeparator(pattern, "/", documentName.getDirectorySeparator())); } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java index 5921ecaa7..03f364112 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java @@ -103,7 +103,7 @@ null, new CVSIgnoreBuilder()), null, new DocumentNameMatcher("HIDDEN_DIR", new Predicate() { @Override - public boolean test(DocumentName documentName) { + public boolean test(final DocumentName documentName) { File file = documentName.asFile(); return file.isDirectory() && ExclusionUtils.isHidden(documentName.getShortName()); } @@ -120,7 +120,7 @@ public String toString() { null, new DocumentNameMatcher("HIDDEN_FILE", new Predicate() { @Override - public boolean test(DocumentName documentName) { + public boolean test(final DocumentName documentName) { File file = documentName.asFile(); return file.isFile() && ExclusionUtils.isHidden(documentName.getShortName()); } diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryName.java b/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryName.java index ad03c3684..f9818fedb 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryName.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryName.java @@ -1,16 +1,33 @@ +/* + * 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.File; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Arrays; import java.util.Collections; public class ArchiveEntryName extends DocumentName { - + /** Then name of the document that contains this entry */ private final DocumentName archiveFileName; - private static DocumentName.Builder prepareBuilder(DocumentName archiveFileName, String archiveEntryName) { + private static DocumentName.Builder prepareBuilder(final DocumentName archiveFileName, final String archiveEntryName) { String root = archiveFileName.getName() + "#"; FSInfo fsInfo = new FSInfo("/", true, Collections.singletonList(root)); return DocumentName.builder(fsInfo) @@ -30,78 +47,28 @@ public File asFile() { @Override public Path asPath() { - return Paths.get( archiveFileName.asPath().toString(), "#", super.asPath().toString()); + return Paths.get(archiveFileName.asPath().toString(), "#", super.asPath().toString()); } @Override - public DocumentName resolve(String child) { + public DocumentName resolve(final String child) { return new ArchiveEntryName(this.archiveFileName, super.resolve(child).localized()); } -// @Override -// public String getName() { -// return archiveFileName.getName(), localized()); -// } - @Override public String getBaseName() { - return archiveFileName.getName()+"#"; + return archiveFileName.getName() + "#"; } -// @Override -// public DocumentName getBaseDocumentName() { -// return super.getBaseDocumentName(); -// } -// -// @Override -// public String getDirectorySeparator() { -// return super.getDirectorySeparator(); -// } - @Override - boolean startsWithRootOrSeparator(String candidate, String root, String separator) { + boolean startsWithRootOrSeparator(final String candidate, final String root, final String separator) { return super.startsWithRootOrSeparator(candidate, root, separator); } @Override - public String localized() { - return /*archiveFileName.localized() + "#" +*/ super.localized(); - } - - @Override - public String localized(String dirSeparator) { + public String localized(final String dirSeparator) { String superLocal = super.localized(dirSeparator); - superLocal = superLocal.substring(superLocal.lastIndexOf("#")+1); + superLocal = superLocal.substring(superLocal.lastIndexOf("#") + 1); return archiveFileName.localized(dirSeparator) + "#" + superLocal; } - - @Override - public String getShortName() { - return super.getShortName(); - } - - @Override - public boolean isCaseSensitive() { - return super.isCaseSensitive(); - } - - @Override - public String toString() { - return super.toString(); - } - - @Override - public int compareTo(DocumentName other) { - return super.compareTo(other); - } - - @Override - public boolean equals(Object other) { - return super.equals(other); - } - - @Override - public int hashCode() { - return super.hashCode(); - } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java index 8171d98c2..419b27c6b 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java @@ -30,8 +30,8 @@ import java.util.List; import java.util.Objects; import java.util.Optional; - import java.util.stream.Collectors; + import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.CompareToBuilder; import org.apache.commons.lang3.builder.EqualsBuilder; @@ -69,14 +69,19 @@ public class DocumentName implements Comparable { /** The File System info for the default file system */ public static final FSInfo DEFAULT_FSINFO = new FSInfo(FileSystems.getDefault()); - private static boolean isCaseSensitive(FileSystem fs) { + /** + * Determines if the file system is case-sensitive. + * @param fileSystem the file system to check + * @return {@code true} if the file system is case-sensitive. + */ + private static boolean isCaseSensitive(final FileSystem fileSystem) { boolean isCaseSensitive = false; Path nameSet = null; Path filea = null; Path fileA = null; try { try { - Path root = fs.getPath(""); + Path root = fileSystem.getPath(""); nameSet = Files.createTempDirectory(root, "NameSet"); filea = nameSet.resolve("a"); fileA = nameSet.resolve("A"); @@ -103,18 +108,29 @@ private static boolean isCaseSensitive(FileSystem fs) { } /** - * Creates a Builder with directory separator and case sensitivity based on the local file system. + * Creates a Builder with the default File system info. * @return the Builder. + * @see FSInfo */ public static Builder builder() { return new Builder(DEFAULT_FSINFO); } - public static Builder builder(FSInfo fsInfo) { + /** + * Creates a builder with the specified FSInfo instance. + * @param fsInfo the FSInfo to use for the builder. + * @return a new builder. + */ + public static Builder builder(final FSInfo fsInfo) { return new Builder(fsInfo); } - public static Builder builder(FileSystem fileSystem) { + /** + * Creates a builder for the specified file system. + * @param fileSystem the file system to create ethe builder on. + * @return a new builder. + */ + public static Builder builder(final FileSystem fileSystem) { return new Builder(fileSystem); } @@ -148,10 +164,18 @@ public static Builder builder(final DocumentName documentName) { this.baseName = builder.sameNameFlag ? this : builder.baseName; } + /** + * Creates a file from the document name. + * @return a new File object. + */ public File asFile() { return new File(getName()); } + /** + * Creates a path from the document name. + * @return an new Path object. + */ public Path asPath() { return Paths.get(name); } @@ -218,7 +242,14 @@ public String getDirectorySeparator() { return fsInfo.dirSeparator(); } - boolean startsWithRootOrSeparator(String candidate, String root, String separator) { + /** + * Determines if the candidate starts with the root or separator strings. + * @param candidate the candidate ot check. If blank method will return false. + * @param root the root to check. If blank the root check is skipped. + * @param separator the separator to check. If blank the check is skipped. + * @return true if either the root or separator check returned true. + */ + boolean startsWithRootOrSeparator(final String candidate, final String root, final String separator) { if (StringUtils.isBlank(candidate)) { return false; } @@ -308,35 +339,64 @@ public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); } - public static class FSInfo implements Comparable{ + /** + * The File system information needed to process document names. + */ + public static class FSInfo implements Comparable { + /** The separator between directory names */ private final String separator; + /** The case-sensitivity flag. */ private final boolean isCaseSensitive; + /** The list of roots for the file system */ private final List roots; - public FSInfo(FileSystem fileSystem) { + /** + * Constructor. Extracts the necessary data from the file system. + * @param fileSystem the file system to extract data from. + */ + public FSInfo(final FileSystem fileSystem) { this.separator = fileSystem.getSeparator(); this.isCaseSensitive = DocumentName.isCaseSensitive(fileSystem); roots = new ArrayList<>(); fileSystem.getRootDirectories().forEach(r -> roots.add(r.toString())); } - FSInfo(String separator, boolean isCaseSensitive, List roots) { + /** + * Constructor for virtual/abstract file systems for example the entry names within an an archive. + * @param separator the separator string to use. + * @param isCaseSensitive the case-sensitivity flag. + * @param roots the roots for the file system. + */ + FSInfo(final String separator, final boolean isCaseSensitive, final List roots) { this.separator = separator; this.isCaseSensitive = isCaseSensitive; this.roots = new ArrayList<>(roots); } + /** + * Gets the directory separator. + * @return The directory separator. + */ public String dirSeparator() { return separator; } + /** + * Gets the case-sensitivity flag. + * @return the case-sensitivity flag. + */ public boolean isCaseSensitive() { return isCaseSensitive; } - public Optional rootFor(String workingName) { + /** + * Retrieves the root extracted from the name. + * @param name the name to extract the root from + * @return an optional containing the root or empty. + */ + public Optional rootFor(final String name) { for (String sysRoot : roots) { - if (workingName.startsWith(sysRoot)) { + if (name.startsWith(sysRoot)) { return Optional.of(sysRoot); } } @@ -357,12 +417,12 @@ public String[] tokenize(final String source) { * @param pattern the file name pattern * @return the normalized file name. */ - public String normalize(String pattern) { + public String normalize(final String pattern) { if (StringUtils.isBlank(pattern)) { return ""; } List parts = new ArrayList<>(Arrays.asList(tokenize(pattern))); - for (int i=0; i Date: Sat, 4 Jan 2025 15:55:54 +0000 Subject: [PATCH 026/123] added debug to test --- .../src/test/java/org/apache/rat/OptionCollectionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 40ab11a2c..5fc082705 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 @@ -155,7 +155,7 @@ public void getReportableTest(String fName) throws IOException { * @param name The name of the test. * @param test the option test to execute. */ - @ParameterizedTest + @ParameterizedTest( name = "{index} {0}") @ArgumentsSource(CliOptionsProvider.class) public void testOptionsUpdateConfig(String name, OptionTest test) { DefaultLog.getInstance().log(Log.Level.INFO, "Running test for: " + name); From 1ce3724a814a3296f133e29c4b3f8fca759851a8 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 16:20:09 +0000 Subject: [PATCH 027/123] added debug to test --- .../java/org/apache/rat/document/DocumentNameMatcher.java | 6 +++--- .../java/org/apache/rat/test/AbstractOptionsProvider.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 4a8925594..cc714fdd4 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -375,7 +375,7 @@ public boolean test(final DocumentName documentName) { @Override public String toString() { - return fileFilter.toString(); + return "Predicate: " + fileFilter.toString(); } } @@ -403,7 +403,7 @@ public Iterable getMatchers() { } public String toString() { - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(this.getClass().getName()).append(": ").append(System.lineSeparator()); for (DocumentNameMatcher matcher : matchers) { builder.append(matcher.predicate.toString()).append(System.lineSeparator()); } @@ -500,7 +500,7 @@ public String toString() { return fill + matcher.toString() + " : " + result + System.lineSeparator() + - fill + " " + + fill + " predicate: " + matcher.predicate.toString(); } } 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 4d8ff6de2..25365c09e 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 @@ -258,7 +258,7 @@ private String dump(DocumentNameMatcher nameMatcher, DocumentName name) { } private String dump(Option option, String fname, DocumentNameMatcher matcher, DocumentName name) { - return String.format("%s%n%s", displayArgAndName(option, fname), dump(matcher, name)); + return String.format("Argument and Name: %s%nMatcher decomposition:%n%s", displayArgAndName(option, fname), dump(matcher, name)); } // exclude tests From 754e6980bffe9ec9d28e04b1195891553896cb3c Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 16:28:22 +0000 Subject: [PATCH 028/123] added debug to test --- .../org/apache/rat/document/DocumentNameMatcher.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index cc714fdd4..37eab14b3 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -160,12 +160,12 @@ public List decompose(final DocumentName candidate) { private void decompose(final int level, final DocumentNameMatcher matcher, final DocumentName candidate, final List result) { final Predicate pred = matcher.getPredicate(); result.add(new DecomposeData(level, matcher, pred.test(candidate))); -// if (pred instanceof DocumentNameMatcher.CollectionPredicate) { -// final DocumentNameMatcher.CollectionPredicate collection = (DocumentNameMatcher.CollectionPredicate) pred; -// for (DocumentNameMatcher subMatcher : collection.getMatchers()) { -// decompose(level + 1, subMatcher, candidate, result); -// } -// } + if (pred instanceof DocumentNameMatcher.CollectionPredicate) { + final DocumentNameMatcher.CollectionPredicate collection = (DocumentNameMatcher.CollectionPredicate) pred; + for (DocumentNameMatcher subMatcher : collection.getMatchers()) { + decompose(level + 1, subMatcher, candidate, result); + } + } } /** From 99a550aec0bed128a4fc8563a2d6fe5a6d87af8f Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 17:55:47 +0000 Subject: [PATCH 029/123] Added detail to decomposition --- .../exclusion/plexus/MatchPatterns.java | 5 ++ .../rat/document/DocumentNameMatcher.java | 48 ++++++++++++++----- .../rat/document/DocumentNameMatcherTest.java | 21 +++++++- 3 files changed, 59 insertions(+), 15 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java index 88f4aa77c..828999775 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java @@ -22,6 +22,7 @@ import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.function.Predicate; @@ -52,6 +53,10 @@ public String source() { return "[" + String.join(", ", sources) + "]"; } + public Iterable patterns() { + return Arrays.asList(patterns); + } + /** *

    Checks these MatchPatterns against a specified string.

    * diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 37eab14b3..2abcfc859 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -66,7 +66,7 @@ public final class DocumentNameMatcher { public DocumentNameMatcher(final String name, final Predicate predicate) { this.name = name; this.predicate = predicate; - this.isCollection = predicate instanceof CollectionPredicate; + this.isCollection = predicate instanceof CollectionPredicateImpl; } /** @@ -109,7 +109,20 @@ private static char[][] tokenize(final String name, final String dirSeparator) { * @param matchers fully specified matchers. */ public DocumentNameMatcher(final String name, final MatchPatterns matchers) { - this(name, (Predicate) documentName -> matchers.matches(documentName.getName(), documentName.isCaseSensitive())); + this(name, new CollectionPredicate() { + @Override + public Iterable getMatchers() { + final List result = new ArrayList<>(); + matchers.patterns().forEach(p -> result.add(new DocumentNameMatcher(p.source(), + (Predicate) x -> MatchPatterns.from("/", p.source()).matches(x.getName(), x.isCaseSensitive())))); + return result; + } + + @Override + public boolean test(final DocumentName documentName) { + return matchers.matches(documentName.getName(), documentName.isCaseSensitive()); + } + }); } /** @@ -159,9 +172,9 @@ public List decompose(final DocumentName candidate) { private void decompose(final int level, final DocumentNameMatcher matcher, final DocumentName candidate, final List result) { final Predicate pred = matcher.getPredicate(); - result.add(new DecomposeData(level, matcher, pred.test(candidate))); - if (pred instanceof DocumentNameMatcher.CollectionPredicate) { - final DocumentNameMatcher.CollectionPredicate collection = (DocumentNameMatcher.CollectionPredicate) pred; + result.add(new DecomposeData(level, matcher, candidate, pred.test(candidate))); + if (pred instanceof CollectionPredicate) { + final CollectionPredicate collection = (CollectionPredicate) pred; for (DocumentNameMatcher subMatcher : collection.getMatchers()) { decompose(level + 1, subMatcher, candidate, result); } @@ -308,6 +321,8 @@ public static DocumentNameMatcher and(final DocumentNameMatcher... matchers) { return and(Arrays.asList(matchers)); } + + /** * A DocumentName predicate that uses MatchPatterns. */ @@ -379,10 +394,13 @@ public String toString() { } } + interface CollectionPredicate extends Predicate { + Iterable getMatchers(); + } /** * A marker interface to indicate this predicate contains a collection of matchers. */ - abstract static class CollectionPredicate implements Predicate { + abstract static class CollectionPredicateImpl implements CollectionPredicate { /** The collection for matchers that make up this predicate */ private final Iterable matchers; @@ -390,7 +408,7 @@ abstract static class CollectionPredicate implements Predicate { * Constructs a collecton predicate from the collection of matchers * @param matchers the colleciton of matchers to use. */ - protected CollectionPredicate(final Iterable matchers) { + protected CollectionPredicateImpl(final Iterable matchers) { this.matchers = matchers; } @@ -415,7 +433,7 @@ public String toString() { * An implementation of "and" logic across a collection of DocumentNameMatchers. */ // package private for testing access - static class And extends CollectionPredicate { + static class And extends CollectionPredicateImpl { And(final Iterable matchers) { super(matchers); } @@ -435,7 +453,7 @@ public boolean test(final DocumentName documentName) { * An implementation of "or" logic across a collection of DocumentNameMatchers. */ // package private for testing access - static class Or extends CollectionPredicate { + static class Or extends CollectionPredicateImpl { Or(final Iterable matchers) { super(matchers); } @@ -455,7 +473,7 @@ public boolean test(final DocumentName documentName) { * An implementation of "or" logic across a collection of DocumentNameMatchers. */ // package private for testing access - static class MatcherPredicate extends CollectionPredicate { + static class MatcherPredicate extends CollectionPredicateImpl { MatcherPredicate(final Iterable matchers) { super(matchers); } @@ -485,11 +503,14 @@ public static final class DecomposeData { private final DocumentNameMatcher matcher; /** The result of the check. */ private final boolean result; + /** The candidate */ + private final DocumentName candidate; - private DecomposeData(final int level, final DocumentNameMatcher matcher, final boolean result) { + private DecomposeData(final int level, final DocumentNameMatcher matcher, final DocumentName candidate, final boolean result) { this.level = level; this.matcher = matcher; this.result = result; + this.candidate = candidate; } @Override @@ -498,9 +519,10 @@ public String toString() { Arrays.fill(chars, ' '); final String fill = new String(chars); return fill + - matcher.toString() + " : " + result + + matcher.toString() + " : >>" + result + "<< " + + (level == 0 ? candidate.getName() : "") + System.lineSeparator() + - fill + " predicate: " + + fill + " " + matcher.predicate.toString(); } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java index 6b7c3e374..df3de205a 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java @@ -18,10 +18,9 @@ */ package org.apache.rat.document; -import java.io.File; -import java.io.FileFilter; import java.util.function.Predicate; import org.apache.commons.io.filefilter.NameFileFilter; +import org.apache.rat.config.exclusion.plexus.MatchPatterns; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -70,4 +69,22 @@ public void matcherSetTest() { assertThat(DocumentNameMatcher.matcherSet(SOME, MATCHES_NONE)).as("X,None").isEqualTo(MATCHES_ALL); assertThat(DocumentNameMatcher.matcherSet(SOME, SOME).toString()).as("X,X").isEqualTo("matcherSet(X, X)"); } + + @Test + void testDecompose() { + DocumentNameMatcher matcher = new DocumentNameMatcher("FileFilterTest", new NameFileFilter("File.name")); + final StringBuilder sb = new StringBuilder(); + matcher.decompose(testName).forEach(s -> sb.append(s).append("\n")); + String result = sb.toString(); + assertThat(result).contains("FileFilterTest : >>false<<").contains("Predicate: NameFileFilter(File.name)"); + + matcher = new DocumentNameMatcher("MatchPatternsTest", MatchPatterns.from("/", "**/test*", "**/*Name")); + + sb.setLength(0); + matcher.decompose(testName).forEach(s -> sb.append(s).append("\n")); + result = sb.toString(); + + System.out.println(sb.toString()); + + } } From e03c483ea3e575714ea81277f3e31f49d8e0aa92 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 19:29:18 +0000 Subject: [PATCH 030/123] used decomposition in more tests --- .../rat/document/DocumentNameMatcher.java | 11 ++++---- .../AbstractIgnoreBuilderTest.java | 5 ++-- .../rat/document/DocumentNameBuilderTest.java | 26 ------------------- .../rat/document/DocumentNameMatcherTest.java | 17 ++++++------ .../rat/test/AbstractOptionsProvider.java | 10 +++---- 5 files changed, 19 insertions(+), 50 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 2abcfc859..004a3b890 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -518,12 +518,11 @@ public String toString() { final char[] chars = new char[level * 2]; Arrays.fill(chars, ' '); final String fill = new String(chars); - return fill + - matcher.toString() + " : >>" + result + "<< " + - (level == 0 ? candidate.getName() : "") + - System.lineSeparator() + - fill + " " + - matcher.predicate.toString(); + return format( "%s%s: >>%s<< %s%n%s predicate: %s", + fill, matcher.toString(), result, + (level == 0 ? candidate.getName() : ""), + fill, + matcher.predicate.toString()); } } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java index 4c4f03e8d..0cc39e8e7 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java @@ -24,6 +24,7 @@ import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; +import org.apache.rat.document.DocumentNameMatcherTest; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.condition.EnabledOnOs; @@ -98,11 +99,11 @@ protected void assertCorrect(List matcherSets, DocumentName baseDir, DocumentNameMatcher excluder = MatcherSet.merge(matcherSets).createMatcher(); for (String name : matching) { DocumentName docName = baseDir.resolve(SelectorUtils.extractPattern(name, File.separator)); - assertThat(excluder.matches(docName)).as(docName.getName()).isFalse(); + assertThat(excluder.matches(docName)).as(() -> DocumentNameMatcherTest.processDecompose(excluder, docName)).isFalse(); } for (String name : notMatching) { DocumentName docName = baseDir.resolve(SelectorUtils.extractPattern(name, File.separator)); - assertThat(excluder.matches(docName)).as(docName.getName()).isTrue(); + assertThat(excluder.matches(docName)).as(() -> DocumentNameMatcherTest.processDecompose(excluder, docName)).isTrue(); } } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java index 0531897da..47741fef0 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java @@ -18,44 +18,18 @@ */ package org.apache.rat.document; -import com.google.common.jimfs.Configuration; -import com.google.common.jimfs.Jimfs; import java.io.File; import java.io.IOException; -import java.net.URI; -import java.net.URL; -import java.nio.file.FileAlreadyExistsException; -import java.nio.file.FileStore; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang3.builder.CompareToBuilder; -import org.apache.commons.lang3.builder.EqualsBuilder; -import org.apache.commons.lang3.builder.HashCodeBuilder; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.rat.utils.DefaultLog; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import static java.lang.String.format; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.apache.rat.document.FSInfoTest.OSX; -import static org.apache.rat.document.FSInfoTest.UNIX; import static org.apache.rat.document.FSInfoTest.WINDOWS; diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java index df3de205a..88d741a28 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java @@ -34,6 +34,12 @@ public class DocumentNameMatcherTest { private final static DocumentNameMatcher SOME = new DocumentNameMatcher("X", (Predicate)name -> false); private final static DocumentName testName = DocumentName.builder().setName("testName").setBaseName("/").build(); + public static String processDecompose(DocumentNameMatcher matcher, DocumentName candidate) { + StringBuilder sb = new StringBuilder(); + matcher.decompose(candidate).forEach(s -> sb.append(s).append("\n")); + return sb.toString(); + } + @Test public void orTest() { assertThat(DocumentNameMatcher.or(TRUE, FALSE).matches(testName)).as("T,F").isTrue(); @@ -73,18 +79,11 @@ public void matcherSetTest() { @Test void testDecompose() { DocumentNameMatcher matcher = new DocumentNameMatcher("FileFilterTest", new NameFileFilter("File.name")); - final StringBuilder sb = new StringBuilder(); - matcher.decompose(testName).forEach(s -> sb.append(s).append("\n")); - String result = sb.toString(); + String result = processDecompose(matcher, testName); assertThat(result).contains("FileFilterTest : >>false<<").contains("Predicate: NameFileFilter(File.name)"); matcher = new DocumentNameMatcher("MatchPatternsTest", MatchPatterns.from("/", "**/test*", "**/*Name")); - - sb.setLength(0); - matcher.decompose(testName).forEach(s -> sb.append(s).append("\n")); - result = sb.toString(); - - System.out.println(sb.toString()); + System.out.println(processDecompose(matcher, testName)); } } 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 25365c09e..863f32bd0 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 @@ -33,6 +33,7 @@ import org.apache.rat.config.exclusion.StandardCollection; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcherTest; import org.apache.rat.license.ILicense; import org.apache.rat.license.ILicenseFamily; import org.apache.rat.license.LicenseSetFactory; @@ -251,14 +252,9 @@ private String displayArgAndName(Option option, String fname) { return String.format("%s %s", option.getLongOpt(), fname); } - private String dump(DocumentNameMatcher nameMatcher, DocumentName name) { - StringBuilder sb = new StringBuilder(); - nameMatcher.decompose(name).forEach(s -> sb.append(s).append("\n")); - return sb.toString(); - } - private String dump(Option option, String fname, DocumentNameMatcher matcher, DocumentName name) { - return String.format("Argument and Name: %s%nMatcher decomposition:%n%s", displayArgAndName(option, fname), dump(matcher, name)); + return String.format("Argument and Name: %s%nMatcher decomposition:%n%s", displayArgAndName(option, fname), + DocumentNameMatcherTest.processDecompose(matcher, name)); } // exclude tests From 0b79d611d5b87ba94e93224041061010918677c9 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 19:33:03 +0000 Subject: [PATCH 031/123] used decomposition in more tests --- .../java/org/apache/rat/document/DocumentNameMatcher.java | 4 ++-- .../java/org/apache/rat/document/DocumentNameMatcherTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 004a3b890..7cda81818 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -518,9 +518,9 @@ public String toString() { final char[] chars = new char[level * 2]; Arrays.fill(chars, ' '); final String fill = new String(chars); - return format( "%s%s: >>%s<< %s%n%s predicate: %s", + return format("%s%s: >>%s<< %s%n%s predicate: %s", fill, matcher.toString(), result, - (level == 0 ? candidate.getName() : ""), + level == 0 ? candidate.getName() : "", fill, matcher.predicate.toString()); } diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java index 88d741a28..1477b909c 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java @@ -80,7 +80,7 @@ public void matcherSetTest() { void testDecompose() { DocumentNameMatcher matcher = new DocumentNameMatcher("FileFilterTest", new NameFileFilter("File.name")); String result = processDecompose(matcher, testName); - assertThat(result).contains("FileFilterTest : >>false<<").contains("Predicate: NameFileFilter(File.name)"); + assertThat(result).contains("FileFilterTest: >>false<<").contains("Predicate: NameFileFilter(File.name)"); matcher = new DocumentNameMatcher("MatchPatternsTest", MatchPatterns.from("/", "**/test*", "**/*Name")); System.out.println(processDecompose(matcher, testName)); From 143def265bb0dbd8133913d9ac2cfd2187f117e9 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 20:22:41 +0000 Subject: [PATCH 032/123] cleaned up decomposition reports --- .../rat/document/DocumentNameMatcher.java | 36 ++++++++++++------- .../rat/document/DocumentNameMatcherTest.java | 15 +++++--- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 7cda81818..16555b392 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -173,12 +173,6 @@ public List decompose(final DocumentName candidate) { private void decompose(final int level, final DocumentNameMatcher matcher, final DocumentName candidate, final List result) { final Predicate pred = matcher.getPredicate(); result.add(new DecomposeData(level, matcher, candidate, pred.test(candidate))); - if (pred instanceof CollectionPredicate) { - final CollectionPredicate collection = (CollectionPredicate) pred; - for (DocumentNameMatcher subMatcher : collection.getMatchers()) { - decompose(level + 1, subMatcher, candidate, result); - } - } } /** @@ -390,7 +384,7 @@ public boolean test(final DocumentName documentName) { @Override public String toString() { - return "Predicate: " + fileFilter.toString(); + return fileFilter.toString(); } } @@ -515,14 +509,30 @@ private DecomposeData(final int level, final DocumentNameMatcher matcher, final @Override public String toString() { - final char[] chars = new char[level * 2]; - Arrays.fill(chars, ' '); - final String fill = new String(chars); - return format("%s%s: >>%s<< %s%n%s predicate: %s", + final String fill = createFill(level); + return format("%s%s: >>%s<< %s%n%s", fill, matcher.toString(), result, level == 0 ? candidate.getName() : "", - fill, - matcher.predicate.toString()); + matcher.predicate instanceof CollectionPredicate ? + decompose(level + 1, (CollectionPredicate)matcher.predicate, candidate) : + String.format("%s%s >>%s<<", createFill(level + 1), matcher.predicate.toString(), matcher.predicate.test(candidate))); + } + + private String createFill(final int level) { + final char[] chars = new char[level * 2]; + Arrays.fill(chars, ' '); + return new String(chars); + } + + private String decompose(final int level, final CollectionPredicate predicate, final DocumentName candidate) { + List result = new ArrayList<>(); + + for (DocumentNameMatcher nameMatcher : predicate.getMatchers()) { + nameMatcher.decompose(level, nameMatcher, candidate, result); + } + StringBuilder sb = new StringBuilder(); + result.forEach(x -> sb.append(x).append(System.lineSeparator())); + return sb.toString(); } } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java index 1477b909c..7526ca05d 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java @@ -78,12 +78,17 @@ public void matcherSetTest() { @Test void testDecompose() { - DocumentNameMatcher matcher = new DocumentNameMatcher("FileFilterTest", new NameFileFilter("File.name")); - String result = processDecompose(matcher, testName); - assertThat(result).contains("FileFilterTest: >>false<<").contains("Predicate: NameFileFilter(File.name)"); + DocumentNameMatcher matcher1 = new DocumentNameMatcher("FileFilterTest", new NameFileFilter("File.name")); + String result = processDecompose(matcher1, testName); + assertThat(result).contains("FileFilterTest: >>false<<").contains(" NameFileFilter(File.name)"); - matcher = new DocumentNameMatcher("MatchPatternsTest", MatchPatterns.from("/", "**/test*", "**/*Name")); - System.out.println(processDecompose(matcher, testName)); + DocumentNameMatcher matcher2 = new DocumentNameMatcher("MatchPatternsTest", MatchPatterns.from("/", "**/test1*", "**/*Name")); + result = processDecompose(matcher2, testName); + assertThat(result).contains("MatchPatternsTest: >>true<<").contains(" **/test1*: >>false<<").contains(" **/*Name: >>true<<"); + + DocumentNameMatcher matcher3 = DocumentNameMatcher.matcherSet(matcher1, matcher2); + result = processDecompose(matcher3, testName); + assertThat(result).contains("MatchPatternsTest: >>true<<").contains(" **/test1*: >>false<<").contains(" **/*Name: >>true<<"); } } From 460b85b9d86fc6db4cc31bc70b7d3260863debc8 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 20:25:04 +0000 Subject: [PATCH 033/123] cleaned up decomposition reports --- .../main/java/org/apache/rat/document/DocumentNameMatcher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 16555b392..0e66b19f7 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -514,7 +514,7 @@ public String toString() { fill, matcher.toString(), result, level == 0 ? candidate.getName() : "", matcher.predicate instanceof CollectionPredicate ? - decompose(level + 1, (CollectionPredicate)matcher.predicate, candidate) : + decompose(level + 1, (CollectionPredicate) matcher.predicate, candidate) : String.format("%s%s >>%s<<", createFill(level + 1), matcher.predicate.toString(), matcher.predicate.test(candidate))); } From aeb058f199fb77091008315ac41315f2ad08b5d0 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 21:21:10 +0000 Subject: [PATCH 034/123] Added wild logging to find Windows problem --- .../exclusion/plexus/MatchPatterns.java | 17 +- .../exclusion/plexus/SelectorUtils.java | 4 +- .../rat/document/DocumentNameBuilderTest.java | 176 +++--------------- .../apache/rat/document/DocumentNameTest.java | 18 +- 4 files changed, 40 insertions(+), 175 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java index 828999775..23437bfc4 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java @@ -24,7 +24,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.function.Predicate; + +import org.apache.rat.utils.DefaultLog; @SuppressWarnings({"checkstyle:RegexpSingleLine", "checkstyle:JavadocVariable"}) /** @@ -80,6 +81,7 @@ public boolean matches(final String name, final String[] tokenizedName, final bo } public boolean matches(final String name, final char[][] tokenizedNameChar, final boolean isCaseSensitive) { + DefaultLog.getInstance().warn(String.format("Matching %s against %s case-sensitivity: %s", name, tokenizedNameChar, isCaseSensitive)); for (MatchPattern pattern : patterns) { if (pattern.matchPath(name, tokenizedNameChar, isCaseSensitive)) { return true; @@ -88,19 +90,6 @@ public boolean matches(final String name, final char[][] tokenizedNameChar, fina return false; } - public Predicate asPredicate(final boolean isCaseSensitive) { - return name -> matches(name, isCaseSensitive); - } - - public boolean matchesPatternStart(final String name, final boolean isCaseSensitive) { - for (MatchPattern includesPattern : patterns) { - if (includesPattern.matchPatternStart(name, isCaseSensitive)) { - return true; - } - } - return false; - } - public static MatchPatterns from(final String separator, final String... sources) { final int length = sources.length; MatchPattern[] result = new MatchPattern[length]; diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java index 92c53528d..cd79f6322 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java @@ -54,12 +54,13 @@ * . * */ - import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; +import org.apache.rat.utils.DefaultLog; + @SuppressWarnings({"checkstyle:RegexpSingleLine", "checkstyle:JavadocVariable"}) /** *

    This is a utility class used by selectors and DirectoryScanner. The functionality more properly belongs just to @@ -397,6 +398,7 @@ static boolean matchAntPathPattern(final String[] patDirs, final String[] strDir } static boolean matchAntPathPattern(final char[][] patDirs, final char[][] strDirs, final boolean isCaseSensitive) { + DefaultLog.getInstance().warn(String.format("... Comparing against %s", (Object) patDirs)); int patIdxStart = 0; int patIdxEnd = patDirs.length - 1; int strIdxStart = 0; diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java index 47741fef0..a9e2ae385 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java @@ -60,237 +60,111 @@ static Stream buildTestData() throws IOException { // String testName = "windows\\foo direct"; - DocumentName documentName = DocumentName.builder(WINDOWS).setName("C:\\\\windows\\foo").setBaseName("C:\\\\windows").build(); - lst.add(Arguments.of( testName, documentName, "C:\\\\windows\\foo", "foo", "C:\\\\windows", "C:\\", "\\", false, + DocumentName documentName = DocumentName.builder(WINDOWS).setName("C:\\windows\\foo").setBaseName("C:\\windows").build(); + lst.add(Arguments.of( testName, documentName, "C:\\windows\\foo", "foo", "C:\\windows", "C:", "\\", false, "\\foo", "/foo")); DocumentName baseName = documentName; // testName = "builder(docName)"; documentName = DocumentName.builder(baseName).build(); - lst.add(Arguments.of( testName, documentName, "C:\\\\windows\\foo", "foo", "C:\\\\windows", "C:\\", "\\", false, + lst.add(Arguments.of( testName, documentName, "C:\\windows\\foo", "foo", "C:\\windows", "C:", "\\", false, "\\foo", "/foo")); // testName = "windows\\foo\\bar by resolve"; documentName = baseName.resolve("bar"); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows\\foo\\bar", "bar", "C:\\windows", "C:", "\\", false, "\\foo\\bar", "/foo/bar")); // testName = "windows\\foo\\direct by basename"; documentName = DocumentName.builder(baseName).setName("windows\\foo\\direct").build(); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\direct", "direct", "C:\\\\windows", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows\\foo\\direct", "direct", "C:\\windows", "C:", "\\", false, "\\foo\\direct", "/foo/direct")); // testName = "windows\\foo\\bar by file"; File file = mock(File.class); File parent = mock(File.class); - when(file.getAbsolutePath()).thenReturn("C:\\\\windows\\foo\\bar"); + when(file.getAbsolutePath()).thenReturn("C:\\windows\\foo\\bar"); when(file.getParentFile()).thenReturn(parent); when(file.isDirectory()).thenReturn(false); - when(parent.getAbsolutePath()).thenReturn("C:\\\\windows\\foo"); + when(parent.getAbsolutePath()).thenReturn("C:\\windows\\foo"); when(parent.isDirectory()).thenReturn(true); documentName = new DocumentName.Builder(WINDOWS, file).build(); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows\\foo", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows\\foo\\bar", "bar", "C:\\windows\\foo", "C:", "\\", false, "\\bar", "/bar")); // testName = "windows\\foo\\bar by directory"; file = mock(File.class); parent = mock(File.class); - when(file.getAbsolutePath()).thenReturn("C:\\\\windows\\foo\\bar"); + when(file.getAbsolutePath()).thenReturn("C:\\windows\\foo\\bar"); when(file.getParentFile()).thenReturn(parent); when(file.isDirectory()).thenReturn(true); - when(parent.getAbsolutePath()).thenReturn("C:\\\\windows\\foo"); + when(parent.getAbsolutePath()).thenReturn("C:\\windows\\foo"); when(parent.isDirectory()).thenReturn(true); documentName = new DocumentName.Builder(WINDOWS, file).build(); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows\\foo\\bar", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows\\foo\\bar", "bar", "C:\\windows\\foo\\bar", "C:", "\\", false, "\\", "/")); // testName = "windows setRoot"; - documentName = DocumentName.builder(baseName).setRoot("D:\\").build(); - lst.add(Arguments.of(testName, documentName, "D:\\\\windows\\foo", "foo", "C:\\\\windows", "D:\\", "\\", false, - "D:\\\\windows\\foo", "D://windows/foo")); + documentName = DocumentName.builder(baseName).setRoot("D:").build(); + lst.add(Arguments.of(testName, documentName, "D:\\windows\\foo", "foo", "C:\\windows", "D:", "\\", false, + "D:\\windows\\foo", "D:/windows/foo")); testName = "windows setRoot(null)"; documentName = DocumentName.builder(baseName).setRoot(null).build(); - lst.add(Arguments.of(testName, documentName, "\\windows\\foo", "foo", "C:\\\\windows", "", "\\", false, + lst.add(Arguments.of(testName, documentName, "\\windows\\foo", "foo", "C:\\windows", "", "\\", false, "\\windows\\foo", "/windows/foo")); testName = "windows setRoot('')"; documentName = DocumentName.builder(baseName).setRoot("").build(); - lst.add(Arguments.of(testName, documentName, "\\windows\\foo", "foo", "C:\\\\windows", "", "\\", false, + lst.add(Arguments.of(testName, documentName, "\\windows\\foo", "foo", "C:\\windows", "", "\\", false, "\\windows\\foo", "/windows/foo")); // testName = "windows setName('baz')"; documentName = DocumentName.builder(baseName).setName("baz").build(); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\baz", "baz", "C:\\\\windows", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows\\baz", "baz", "C:\\windows", "C:", "\\", false, "\\baz", "/baz")); testName = "windows setName((String)null)"; documentName = DocumentName.builder(baseName).setName((String)null).build(); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows", "windows", "C:\\\\windows", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows", "windows", "C:\\windows", "C:", "\\", false, "\\", "/")); testName = "windows setName('')"; documentName = DocumentName.builder(baseName).setName("").build(); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows", "windows", "C:\\\\windows", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows", "windows", "C:\\windows", "C:", "\\", false, "\\", "/")); file = mock(File.class); parent = mock(File.class); - when(file.getAbsolutePath()).thenReturn("C:\\\\windows\\foo\\bar"); + when(file.getAbsolutePath()).thenReturn("C:\\windows\\foo\\bar"); when(file.getParentFile()).thenReturn(parent); when(file.isDirectory()).thenReturn(false); - when(parent.getAbsolutePath()).thenReturn("C:\\\\windows\\foo"); + when(parent.getAbsolutePath()).thenReturn("C:\\windows\\foo"); when(parent.isDirectory()).thenReturn(true); testName = "windows setName(file)"; documentName = DocumentName.builder(baseName).setName(file).build(); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows\\foo", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows\\foo\\bar", "bar", "C:\\windows\\foo", "C:", "\\", false, "\\bar", "/bar")); file = mock(File.class); parent = mock(File.class); - when(file.getAbsolutePath()).thenReturn("C:\\\\windows\\foo\\bar"); + when(file.getAbsolutePath()).thenReturn("C:\\windows\\foo\\bar"); when(file.getParentFile()).thenReturn(parent); when(file.isDirectory()).thenReturn(true); - when(parent.getAbsolutePath()).thenReturn("C:\\\\windows\\foo"); + when(parent.getAbsolutePath()).thenReturn("C:\\windows\\foo"); when(parent.isDirectory()).thenReturn(true); testName = "windows setName(directory)"; documentName = DocumentName.builder(baseName).setName(file).build(); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows\\foo\\bar", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows\\foo\\bar", "bar", "C:\\windows\\foo\\bar", "C:", "\\", false, "\\", "/")); return lst.stream(); - - -// -// /** -// * Sets the baseName. -// * Will set the root if it is not set. -// *

    -// * To correctly parse the string it must use the directory separator specified by this builder. -// *

    -// * @param baseName the basename to use. -// * @return this. -// */ -// public DocumentName.Builder setBaseName(final String baseName) { -// DocumentName.Builder builder = DocumentName.builder(fsInfo).setName(baseName); -// builder.sameNameFlag = true; -// setBaseName(builder); -// return this; -// } -// -// /** -// * Sets the basename from the {@link #name} of the specified DocumentName. -// * Will set the root the baseName has the root set. -// * @param baseName the DocumentName to set the basename from. -// * @return this. -// */ -// public DocumentName.Builder setBaseName(final DocumentName baseName) { -// this.baseName = baseName; -// if (!baseName.getRoot().isEmpty()) { -// this.root = baseName.getRoot(); -// } -// return this; -// } -// -// /** -// * Executes the builder, sets the base name and clears the sameName flag. -// * @param builder the builder for the base name. -// */ -// private void setBaseName(DocumentName.Builder builder) { -// this.baseName = builder.build(); -// this.sameNameFlag = false; -// } -// -// /** -// * Sets the basename from a File. Sets {@link #root} and the {@link #baseName} -// * Will set the root. -// * @param file the file to set the base name from. -// * @return this. -// */ -// public DocumentName.Builder setBaseName(final File file) { -// DocumentName.Builder builder = DocumentName.builder(fsInfo).setName(file); -// builder.sameNameFlag = true; -// setBaseName(builder); -// return this; -// } -// -// /** -// * Build a DocumentName from this builder. -// * @return A new DocumentName. -// */ -// public DocumentName build() { -// verify(); -// return new DocumentName(this); -// } - -// -// assertThat(documentName.getName()).isEqualTo("C:\\\\windows\\foo") -// -// -// assertThat(documentName.getRoot()).isEqualTo("C:\\"); -// assertThat(documentName.isCaseSensitive()).isFalse(); -// assertThat(documentName.getShortName()).isEqualTo("foo"); -// assertThat(documentName.localized("/")).isEqualTo("/windows/foo"); -// assertThat(documentName.getBaseName()).isEqualTo("C:\\\\windows"); -// documentName.getBaseDocumentName(); -// documentName.getDirectorySeparator(); -// -// -// public String getName() -// -// -// public String getBaseName() -// -// -// public String getRoot() -// -// -// public DocumentName getBaseDocumentName -// -// public String getDirectorySeparator( -// -// -// public String localized() -// -// public String localized(final String dirSeparator) -// -// -// public String[] tokenize(final String source) { -// // return source.split("\\Q" + fsInfo.dirSeparator() + "\\E"); -// -// -// -// public String getShortName() -// -// public boolean isCaseSensitive() - - -/* - @Override - public int compareTo(final DocumentName other) { - return CompareToBuilder.reflectionCompare(this, other); - } - - @Override - public boolean equals(final Object other) { - return EqualsBuilder.reflectionEquals(this, other); - } - - @Override - public int hashCode() { - return HashCodeBuilder.reflectionHashCode(this); - } - -*/ - } - - } diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java index 599a4d9c7..fe5101ca2 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java @@ -72,21 +72,21 @@ private static Stream resolveTestData() { lst.add(Arguments.of("unix", base, "..\\up\\and\\down", expected)); // WINDOWS - base = DocumentName.builder(WINDOWS).setName("\\dir\\windows").setBaseName("C:\\\\").build(); + base = DocumentName.builder(WINDOWS).setName("\\dir\\windows").setBaseName("C:\\").build(); - expected = DocumentName.builder(WINDOWS).setName("\\dir\\windows\\relative").setBaseName("C:\\\\").build(); + expected = DocumentName.builder(WINDOWS).setName("\\dir\\windows\\relative").setBaseName("C:\\").build(); lst.add(Arguments.of("windows", base, "relative", expected)); - expected = DocumentName.builder(WINDOWS).setName("\\from\\root").setBaseName("C:\\\\").build(); + expected = DocumentName.builder(WINDOWS).setName("\\from\\root").setBaseName("C:\\").build(); lst.add(Arguments.of("windows", base, "/from/root", expected)); - expected = DocumentName.builder(WINDOWS).setName("dir\\up\\and\\down").setBaseName("C:\\\\").build(); + expected = DocumentName.builder(WINDOWS).setName("dir\\up\\and\\down").setBaseName("C:\\").build(); lst.add(Arguments.of("windows", base, "../up/and/down", expected)); - expected = DocumentName.builder(WINDOWS).setName("\\from\\root").setBaseName("C:\\\\").build(); + expected = DocumentName.builder(WINDOWS).setName("\\from\\root").setBaseName("C:\\").build(); lst.add(Arguments.of("windows", base, "\\from\\root", expected)); - expected = DocumentName.builder(WINDOWS).setName("dir\\up\\and\\down").setBaseName("C:\\\\").build(); + expected = DocumentName.builder(WINDOWS).setName("dir\\up\\and\\down").setBaseName("C:\\").build(); lst.add(Arguments.of("windows", base, "..\\up\\and\\down", expected)); // OSX @@ -184,9 +184,9 @@ private static Stream validBuilderData() throws IOException { lst.add(Arguments.of("foo/bar foo", DocumentName.builder(UNIX) .setName("/foo/bar").setBaseName("foo"), "", "foo/bar", "foo", "/")); - DocumentName.Builder builder = DocumentName.builder(WINDOWS).setName("\\foo\\bar").setBaseName("C:\\\\foo") - .setRoot("C:\\"); - lst.add(Arguments.of("\\foo\\bar foo", builder, "C:\\", "foo\\bar", "foo", "\\")); + DocumentName.Builder builder = DocumentName.builder(WINDOWS).setName("\\foo\\bar").setBaseName("C:\\foo") + .setRoot("C:"); + lst.add(Arguments.of("\\foo\\bar foo", builder, "C:", "foo\\bar", "foo", "\\")); lst.add(Arguments.of("foo/bar foo", DocumentName.builder(OSX) .setName("/foo/bar").setBaseName("foo"), "", "foo/bar", "foo", "/")); From 0023c54d4786ccda71555d6bb5c88bd0561e26f4 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 21:22:37 +0000 Subject: [PATCH 035/123] removed excess builds --- .github/workflows/maven.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 593c3afa0..2a2609d46 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -31,12 +31,14 @@ jobs: strategy: matrix: - os: [ubuntu-latest, windows-latest] + #os: [ubuntu-latest, windows-latest] + os: [windows-latest] # RAT-296: disable JDK10 due to # Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target # # Java 17 disabled, because we are running into https://bugs.openjdk.java.net/browse/JDK-8270866 - java: [8, 11, 21] + #java: [8, 11, 21] + java: [8] fail-fast: false runs-on: ${{ matrix.os }} From b6f09a58c61bd22210bb0e65e0c7bad2ad30bfe7 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 21:32:16 +0000 Subject: [PATCH 036/123] Added wild logging to find Windows problem --- .../org/apache/rat/config/exclusion/plexus/MatchPatterns.java | 4 +++- .../org/apache/rat/config/exclusion/plexus/SelectorUtils.java | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java index 23437bfc4..46f182497 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import org.apache.rat.utils.DefaultLog; @@ -81,7 +82,8 @@ public boolean matches(final String name, final String[] tokenizedName, final bo } public boolean matches(final String name, final char[][] tokenizedNameChar, final boolean isCaseSensitive) { - DefaultLog.getInstance().warn(String.format("Matching %s against %s case-sensitivity: %s", name, tokenizedNameChar, isCaseSensitive)); + DefaultLog.getInstance().warn(String.format("Matching %s against %s case-sensitivity: %s", name, + Arrays.asList(tokenizedNameChar).stream().map(String::new).collect(Collectors.toList()), isCaseSensitive)); for (MatchPattern pattern : patterns) { if (pattern.matchPath(name, tokenizedNameChar, isCaseSensitive)) { return true; diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java index cd79f6322..cddf6a403 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java @@ -56,8 +56,10 @@ */ import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.StringTokenizer; +import java.util.stream.Collectors; import org.apache.rat.utils.DefaultLog; @@ -398,7 +400,7 @@ static boolean matchAntPathPattern(final String[] patDirs, final String[] strDir } static boolean matchAntPathPattern(final char[][] patDirs, final char[][] strDirs, final boolean isCaseSensitive) { - DefaultLog.getInstance().warn(String.format("... Comparing against %s", (Object) patDirs)); + DefaultLog.getInstance().warn(String.format("... Comparing against %s", Arrays.asList(patDirs).stream().map(String::new).collect(Collectors.toList()))); int patIdxStart = 0; int patIdxEnd = patDirs.length - 1; int strIdxStart = 0; From 295093f9e87162a7da38834d5d4099824c7b2f87 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 14:30:56 +0000 Subject: [PATCH 037/123] debugging for tests --- .../it/java/org/apache/rat/ReportTest.java | 2 +- .../apache/rat/commandline/Converters.java | 2 +- .../config/exclusion/ExclusionProcessor.java | 2 +- .../rat/config/exclusion/ExclusionUtils.java | 2 +- .../rat/config/exclusion/MatcherSet.java | 31 ++++--- .../AbstractFileProcessorBuilder.java | 6 +- .../fileProcessors/CVSIgnoreBuilder.java | 2 +- .../fileProcessors/GitIgnoreBuilder.java | 2 +- .../exclusion/plexus/MatchPatterns.java | 2 +- .../apache/rat/document/ArchiveEntryName.java | 2 +- .../org/apache/rat/document/DocumentName.java | 41 +++++++-- .../org/apache/rat/OptionCollectionTest.java | 2 +- .../config/exclusion/FileProcessorTest.java | 5 +- .../AbstractIgnoreBuilderTest.java | 27 ++++-- .../fileProcessors/GitIgnoreBuilderTest.java | 70 +++++++------- .../apache/rat/document/DocumentNameTest.java | 92 ++++++++++++++++++- .../org/apache/rat/document/FSInfoTest.java | 30 +++--- 17 files changed, 228 insertions(+), 92 deletions(-) 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 76e3f09c9..16bc908bc 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 @@ -163,7 +163,7 @@ public static Stream args() throws RatException { @Override public void report(Document document) { if (!document.isIgnored()) { - String[] tokens = DocumentName.DEFAULT_FSINFO.tokenize(document.getName().localized()); + String[] tokens = DocumentName.FSInfo.getDefault().tokenize(document.getName().localized()); results.add(Arguments.of(tokens[1], 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 7375d44b5..8f5fc1c66 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 @@ -92,7 +92,7 @@ public File apply(final String fileName) throws NullPointerException { // is this a relative file? if (!fileName.startsWith(File.separator)) { // check for a root provided (e.g. C:\\)" - if (!DocumentName.DEFAULT_FSINFO.rootFor(fileName).isPresent()) { + if (!DocumentName.FSInfo.getDefault().rootFor(fileName).isPresent()) { // no root, resolve against workingDirectory file = new File(workingDirectory.resolve(fileName).getName()).getAbsoluteFile(); } 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 45001ba29..e92ebafd3 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 @@ -227,7 +227,7 @@ private List extractFileProcessors(final DocumentName basedir) { * @return the prepared pattern. */ private String preparePattern(final DocumentName documentName, final String pattern) { - return ExclusionUtils.localizePattern(documentName, + return ExclusionUtils.qualifyPattern(documentName, ExclusionUtils.convertSeparator(pattern, "/", documentName.getDirectorySeparator())); } /** diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java index 936a9b147..731517fca 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java @@ -221,7 +221,7 @@ private static void verifyFile(final File file) { * @param pattern the pattern to format. * @return the completely formatted pattern */ - public static String localizePattern(final DocumentName documentName, final String pattern) { + public static String qualifyPattern(final DocumentName documentName, final String pattern) { boolean prefix = pattern.startsWith(NEGATION_PREFIX); String workingPattern = prefix ? pattern.substring(1) : pattern; String normalizedPattern = SelectorUtils.extractPattern(workingPattern, documentName.getDirectorySeparator()); diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java index da6ed194e..f03d641f4 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.function.Consumer; import org.apache.rat.config.exclusion.plexus.MatchPattern; import org.apache.rat.config.exclusion.plexus.MatchPatterns; @@ -92,18 +93,29 @@ public static void segregateList(final Set matching, final Set n public Builder() { } + /** + * Converts a collection names into DocumentNameMatchers that use the {@code fromDocument} directory separator. + * @param dest the consumer to accept the DocumentNameMatcher. + * @param nameFmt the format for the matcher names. Requires '%s' for the {@code fromDocument} localized name. + * @param fromDocument the document that the patterns are associated with. + * @param names the list of patterns. If empty no action is taken. + */ + private void processNames(final Consumer dest, final String nameFmt, final DocumentName fromDocument, final Set names) { + if (!names.isEmpty()) { + String name = String.format(nameFmt, fromDocument.localized("/").substring(1)); + //Stream iter = names.stream().map(s ->ExclusionUtils.convertSeparator(s, "/", fromDocument.getDirectorySeparator())); + dest.accept(new DocumentNameMatcher(name, MatchPatterns.from(fromDocument.getDirectorySeparator(), names), fromDocument.getBaseDocumentName())); + } + } /** * Adds included file names from the specified document. File names are resolved relative to the directory * of the {@code fromDocument}. * @param fromDocument the document the names were read from. - * @param names the names that were read from the document. + * @param names the names that were read from the document. Must be use the separator specified by {@code fromDocument}. * @return this */ public Builder addIncluded(final DocumentName fromDocument, final Set names) { - if (!names.isEmpty()) { - String name = String.format("'included %s'", fromDocument.localized("/").substring(1)); - addIncluded(new DocumentNameMatcher(name, MatchPatterns.from("/", names), fromDocument.getBaseDocumentName())); - } + processNames(this::addIncluded, "'included %s'", fromDocument, names); return this; } @@ -111,14 +123,11 @@ public Builder addIncluded(final DocumentName fromDocument, final Set na * Adds excluded file names from the specified document. File names are resolved relative to the directory * of the {@code fromDocument}. * @param fromDocument the document the names were read from. - * @param names the names that were read from the document. + * @param names the names that were read from the document. Must be use the separator specified by {@code fromDocument}. * @return this */ public Builder addExcluded(final DocumentName fromDocument, final Set names) { - if (!names.isEmpty()) { - String name = String.format("'excluded %s'", fromDocument.localized("/").substring(1)); - addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(fromDocument.getDirectorySeparator(), names), fromDocument.getBaseDocumentName())); - } + processNames(this::addExcluded, "'excluded %s'", fromDocument, names); return this; } @@ -144,7 +153,7 @@ public Builder addExcluded(final DocumentNameMatcher matcher) { } /** - * Builds a MatcherSet. When {@link #build()} is called the builder is reset to the initial state. + * Builds a MatcherSet. When {@code build()} is called the builder is reset to the initial state. * @return the MatcherSet based upon the included and excluded matchers. */ public MatcherSet build() { diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java index f6788f223..4fc22e6aa 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java @@ -121,7 +121,7 @@ private List createMatcherSetList() { public final List build(final DocumentName root) { if (includeProcessorFile) { String name = String.format("**/%s", fileName); - String pattern = ExclusionUtils.localizePattern(root, name); + String pattern = ExclusionUtils.qualifyPattern(root, name); MatcherSet matcherSet = new MatcherSet.Builder() .addExcluded(new DocumentNameMatcher(name, MatchPatterns.from("/", Collections.singletonList(pattern)), root)) .build(); @@ -148,10 +148,10 @@ public final List build(final DocumentName root) { protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName root, final DocumentName documentName) { final MatcherSet.Builder matcherSetBuilder = new MatcherSet.Builder(); final List iterable = new ArrayList<>(); - ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) + ExclusionUtils.asIterator(documentName.asFile(), commentFilter) .map(entry -> modifyEntry(matcherSetConsumer, documentName, entry).orElse(null)) .filter(Objects::nonNull) - .map(entry -> ExclusionUtils.localizePattern(documentName, entry)) + .map(entry -> ExclusionUtils.qualifyPattern(documentName, entry)) .forEachRemaining(iterable::add); Set included = new HashSet<>(); diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java index 0f6a7b26d..16bf5f974 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java @@ -54,7 +54,7 @@ protected MatcherSet process(final Consumer matcherSetConsumer, fina String[] parts = line.split("\\s+"); for (String part : parts) { if (!part.isEmpty()) { - result.add(ExclusionUtils.localizePattern(documentName, part)); + result.add(ExclusionUtils.qualifyPattern(documentName, part)); } } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java index 6c70fb736..7b67ab53f 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java @@ -89,7 +89,7 @@ protected Optional modifyEntry(final Consumer matcherSetCons DocumentName matcherPattern = DocumentName.builder(documentName).setName(name.replace(SLASH, documentName.getDirectorySeparator())) .build(); DocumentNameMatcher matcher = DocumentNameMatcher.and(new DocumentNameMatcher("isDirectory", File::isDirectory), - new DocumentNameMatcher(name, MatchPatterns.from(matcherPattern.localized(SLASH)))); + new DocumentNameMatcher(name, MatchPatterns.from(matcherPattern.localized(documentName.getDirectorySeparator())))); MatcherSet.Builder builder = new MatcherSet.Builder(); if (prefix) { diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java index 46f182497..717bca0b6 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java @@ -82,7 +82,7 @@ public boolean matches(final String name, final String[] tokenizedName, final bo } public boolean matches(final String name, final char[][] tokenizedNameChar, final boolean isCaseSensitive) { - DefaultLog.getInstance().warn(String.format("Matching %s against %s case-sensitivity: %s", name, + DefaultLog.getInstance().warn(String.format("Matching %s as %s case-sensitivity: %s", name, Arrays.asList(tokenizedNameChar).stream().map(String::new).collect(Collectors.toList()), isCaseSensitive)); for (MatchPattern pattern : patterns) { if (pattern.matchPath(name, tokenizedNameChar, isCaseSensitive)) { diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryName.java b/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryName.java index f9818fedb..889a7b165 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryName.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryName.java @@ -29,7 +29,7 @@ public class ArchiveEntryName extends DocumentName { private static DocumentName.Builder prepareBuilder(final DocumentName archiveFileName, final String archiveEntryName) { String root = archiveFileName.getName() + "#"; - FSInfo fsInfo = new FSInfo("/", true, Collections.singletonList(root)); + FSInfo fsInfo = new FSInfo("archiveEntry", "/", true, Collections.singletonList(root)); return DocumentName.builder(fsInfo) .setRoot(root) .setBaseName(root + "/") diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java index 419b27c6b..9b0c6a0d9 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java @@ -66,8 +66,6 @@ public class DocumentName implements Comparable { private final FSInfo fsInfo; /** The root for the DocumentName. May be empty but not null. */ private final String root; - /** The File System info for the default file system */ - public static final FSInfo DEFAULT_FSINFO = new FSInfo(FileSystems.getDefault()); /** * Determines if the file system is case-sensitive. @@ -113,7 +111,7 @@ private static boolean isCaseSensitive(final FileSystem fileSystem) { * @see FSInfo */ public static Builder builder() { - return new Builder(DEFAULT_FSINFO); + return new Builder(FSInfo.getDefault()); } /** @@ -253,9 +251,9 @@ boolean startsWithRootOrSeparator(final String candidate, final String root, fin if (StringUtils.isBlank(candidate)) { return false; } - boolean result = StringUtils.isBlank(root) ? false : candidate.startsWith(root); + boolean result = !StringUtils.isBlank(root) && candidate.startsWith(root); if (!result) { - result = StringUtils.isBlank(separator) ? false : candidate.startsWith(separator); + result = !StringUtils.isBlank(separator) && candidate.startsWith(separator); } return result; } @@ -343,6 +341,8 @@ public int hashCode() { * The File system information needed to process document names. */ public static class FSInfo implements Comparable { + /** The common name for the file system this Info represents */ + private final String name; /** The separator between directory names */ private final String separator; /** The case-sensitivity flag. */ @@ -350,24 +350,48 @@ public static class FSInfo implements Comparable { /** The list of roots for the file system */ private final List roots; + public static FSInfo getDefault() { + FSInfo result = (FSInfo) System.getProperties().get("FSInfo"); + return result == null ? + new FSInfo("default", FileSystems.getDefault()) + : result; + } /** * Constructor. Extracts the necessary data from the file system. * @param fileSystem the file system to extract data from. */ public FSInfo(final FileSystem fileSystem) { + this("anon", fileSystem); + } + + /** + * Constructor. Extracts the necessary data from the file system. + * @param fileSystem the file system to extract data from. + */ + public FSInfo(final String name, final FileSystem fileSystem) { + this.name = name; this.separator = fileSystem.getSeparator(); this.isCaseSensitive = DocumentName.isCaseSensitive(fileSystem); roots = new ArrayList<>(); fileSystem.getRootDirectories().forEach(r -> roots.add(r.toString())); } + /** + * Gets the common name for the underlying file system. + * @return the common file system name. + */ + @Override + public String toString() { + return name; + } /** * Constructor for virtual/abstract file systems for example the entry names within an an archive. * @param separator the separator string to use. * @param isCaseSensitive the case-sensitivity flag. * @param roots the roots for the file system. */ - FSInfo(final String separator, final boolean isCaseSensitive, final List roots) { + FSInfo(final String name, final String separator, final boolean isCaseSensitive, final List roots) { + this.name = name; this.separator = separator; this.isCaseSensitive = isCaseSensitive; this.roots = new ArrayList<>(roots); @@ -480,8 +504,7 @@ private Builder(final FSInfo fsInfo) { * Create with default settings. */ private Builder(final FileSystem fileSystem) { - fsInfo = fileSystem.equals(FileSystems.getDefault()) ? DEFAULT_FSINFO : new FSInfo(fileSystem); - root = ""; + this(new FSInfo(fileSystem)); } /** @@ -489,7 +512,7 @@ private Builder(final FileSystem fileSystem) { * @param file the file to base the builder on. */ private Builder(final File file) { - this(DEFAULT_FSINFO); + this(FSInfo.getDefault()); setName(file); } 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 5fc082705..08cf817fa 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 @@ -143,7 +143,7 @@ public void testDefaultConfiguration() throws ParseException { @ValueSource(strings = { ".", "./", "target", "./target" }) public void getReportableTest(String fName) throws IOException { File base = new File(fName); - String expected = DocumentName.DEFAULT_FSINFO.normalize(base.getAbsolutePath()); + String expected = DocumentName.FSInfo.getDefault().normalize(base.getAbsolutePath()); ReportConfiguration config = OptionCollection.parseCommands(testPath.toFile(), new String[]{fName}, o -> fail("Help called"), false); IReportable reportable = OptionCollection.getReportable(base, config); assertThat(reportable).as(() -> format("'%s' returned null", fName)).isNotNull(); diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java index 2deba2c9b..fc1e2ccaf 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java @@ -18,10 +18,7 @@ */ package org.apache.rat.config.exclusion; -import com.google.common.jimfs.Configuration; -import com.google.common.jimfs.Jimfs; import java.io.IOException; -import java.nio.file.FileSystem; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -46,7 +43,7 @@ public class FileProcessorTest { @ParameterizedTest(name="{index} {1}") @MethodSource("localizePatternData") void localizePatternTest(DocumentName baseName, String pattern, String expectedStr) { - assertThat(ExclusionUtils.localizePattern(baseName, pattern)).isEqualTo(expectedStr); + assertThat(ExclusionUtils.qualifyPattern(baseName, pattern)).isEqualTo(expectedStr); } public static Stream localizePatternData() throws IOException { diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java index 0cc39e8e7..68460e78d 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java @@ -18,13 +18,15 @@ */ package org.apache.rat.config.exclusion.fileProcessors; +import java.nio.file.Path; import java.util.List; -import org.apache.rat.config.exclusion.ExclusionUtils; +import java.util.stream.Stream; import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.document.DocumentNameMatcherTest; +import org.apache.rat.document.FSInfoTest; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.condition.EnabledOnOs; @@ -35,6 +37,7 @@ import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; +import org.junit.jupiter.params.provider.Arguments; import static org.assertj.core.api.Assertions.assertThat; @@ -45,12 +48,22 @@ public class AbstractIgnoreBuilderTest { @TempDir - protected File baseDir; + protected Path tmpPath; protected DocumentName baseName; @BeforeEach - public void setup() { - baseName = DocumentName.builder(baseDir).build(); + protected void setup() throws IOException { + baseName = DocumentName.builder(tmpPath.toFile()).build(); + } + + protected static Stream fsInfoArgs() { + return FSInfoTest.fsInfoArgs(); + } + + @AfterEach + @EnabledOnOs(OS.WINDOWS) + void reset() { + baseName = null; } /** @@ -71,7 +84,7 @@ void cleanUp() { * @throws IOException if file cannot be created. */ protected File writeFile(String name, Iterable lines) throws IOException { - File file = new File(baseDir, name); + File file = new File(tmpPath.toFile(), name); try (PrintWriter writer = new PrintWriter(new FileWriter(file))) { lines.forEach(writer::println); } @@ -98,11 +111,11 @@ protected void assertCorrect(AbstractFileProcessorBuilder builder, Iterable matcherSets, DocumentName baseDir, Iterable matching, Iterable notMatching) { DocumentNameMatcher excluder = MatcherSet.merge(matcherSets).createMatcher(); for (String name : matching) { - DocumentName docName = baseDir.resolve(SelectorUtils.extractPattern(name, File.separator)); + DocumentName docName = baseDir.resolve(SelectorUtils.extractPattern(name, baseDir.getDirectorySeparator())); assertThat(excluder.matches(docName)).as(() -> DocumentNameMatcherTest.processDecompose(excluder, docName)).isFalse(); } for (String name : notMatching) { - DocumentName docName = baseDir.resolve(SelectorUtils.extractPattern(name, File.separator)); + DocumentName docName = baseDir.resolve(SelectorUtils.extractPattern(name, baseDir.getDirectorySeparator())); assertThat(excluder.matches(docName)).as(() -> DocumentNameMatcherTest.processDecompose(excluder, docName)).isTrue(); } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java index b98c446e7..f3c7fc43e 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java @@ -25,15 +25,18 @@ import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; +import org.apache.rat.document.FSInfoTest; import org.junit.jupiter.api.Test; import java.io.IOException; import java.net.URL; import java.util.Arrays; import java.util.List; +import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; import static org.assertj.core.api.Assertions.assertThat; @@ -41,29 +44,32 @@ public class GitIgnoreBuilderTest extends AbstractIgnoreBuilderTest { @Test public void processExampleFileTest() throws IOException { - String[] lines = { - "# somethings", - "!thingone", "thing*", System.lineSeparator(), - "# some fish", - "**/fish", "*_fish", - "# some colorful directories", - "red/", "blue/*/"}; - - List matches = Arrays.asList("some/things", "some/fish", "another/red_fish"); - - List notMatches = Arrays.asList("some/thingone", "thingone"); - - writeFile(".gitignore", Arrays.asList(lines)); - - assertCorrect(new GitIgnoreBuilder(), matches, notMatches); + try { + String[] lines = { + "# somethings", + "!thingone", "thing*", System.lineSeparator(), + "# some fish", + "**/fish", "*_fish", + "# some colorful directories", + "red/", "blue/*/"}; + List matches = Arrays.asList("some/things", "some/fish", "another/red_fish"); + + List notMatches = Arrays.asList("some/thingone", "thingone"); + + writeFile(".gitignore", Arrays.asList(lines)); + + assertCorrect(new GitIgnoreBuilder(), matches, notMatches); + } finally { + System.getProperties().remove("FSInfo"); + } } // see https://git-scm.com/docs/gitignore @ParameterizedTest @MethodSource("modifyEntryData") - public void modifyEntryTest(String source, String expected) { + public void modifyEntryTest(DocumentName.FSInfo fsInfo, String source, String expected) { GitIgnoreBuilder underTest = new GitIgnoreBuilder(); - DocumentName testName = DocumentName.builder().setName("GitIgnoreBuilderTest").setBaseName("testDir").build(); + DocumentName testName = DocumentName.builder(fsInfo).setName("GitIgnoreBuilderTest").setBaseName("testDir").build(); List matcherSets = new ArrayList<>(); Optional entry = underTest.modifyEntry(matcherSets::add, testName, source); @@ -79,21 +85,21 @@ public void modifyEntryTest(String source, String expected) { private static Stream modifyEntryData() { List lst = new ArrayList<>(); - - lst.add(Arguments.of("\\#filename", "**/#filename")); - - lst.add(Arguments.of("!#filename", "!**/#filename")); - lst.add(Arguments.of("\\#filename", "**/#filename")); - lst.add(Arguments.of("!#filename", "!**/#filename")); - lst.add(Arguments.of("/filename", "filename")); - lst.add(Arguments.of("file/name", "file/name")); - lst.add(Arguments.of("/file/name", "file/name")); - lst.add(Arguments.of("filename", "**/filename")); - lst.add(Arguments.of("filename/", "not(and(isDirectory, **/filename))")); - lst.add(Arguments.of("/filename/", "not(and(isDirectory, filename))")); - // inclusion by itself becomes nothing. - lst.add(Arguments.of("!filename/", "TRUE")); - + for (DocumentName.FSInfo fsInfo : FSInfoTest.TEST_SUITE) { + lst.add(Arguments.of(fsInfo, "\\#filename", "**/#filename")); + + lst.add(Arguments.of(fsInfo, "!#filename", "!**/#filename")); + lst.add(Arguments.of(fsInfo, "\\#filename", "**/#filename")); + lst.add(Arguments.of(fsInfo, "!#filename", "!**/#filename")); + lst.add(Arguments.of(fsInfo, "/filename", "filename")); + lst.add(Arguments.of(fsInfo, "file/name", "file/name")); + lst.add(Arguments.of(fsInfo, "/file/name", "file/name")); + lst.add(Arguments.of(fsInfo, "filename", "**/filename")); + lst.add(Arguments.of(fsInfo, "filename/", "not(and(isDirectory, **/filename))")); + lst.add(Arguments.of(fsInfo, "/filename/", "not(and(isDirectory, filename))")); + // inclusion by itself becomes nothing. + lst.add(Arguments.of(fsInfo, "!filename/", "TRUE")); + } return lst.stream(); } diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java index fe5101ca2..31693e030 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java @@ -21,28 +21,117 @@ import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; import java.io.File; +import java.io.FileFilter; +import java.io.FilenameFilter; import java.io.IOException; import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Stream; + +import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.tuple.Pair; +import org.apache.rat.config.exclusion.ExclusionUtils; +import org.apache.rat.document.DocumentName.FSInfo; + import org.assertj.core.util.Files; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mockito; -import static java.lang.String.format; import static org.assertj.core.api.Assertions.assertThat; import static org.apache.rat.document.FSInfoTest.OSX; import static org.apache.rat.document.FSInfoTest.UNIX; import static org.apache.rat.document.FSInfoTest.WINDOWS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.any; public class DocumentNameTest { + public static DocumentName mkName(Path tempDir, FSInfo fsInfo) throws IOException { + File docFile = mkFile(tempDir.toFile(), fsInfo); + DocumentName result = DocumentName.builder(fsInfo).setName(docFile).build(); + DocumentName mocked = Mockito.spy(result); + + String fn = result.localized(FileSystems.getDefault().getSeparator()); + File file = tempDir.resolve(fn.substring(1)).toFile(); + File mockedFile = mkFile(file, fsInfo); + when(mocked.asFile()).thenReturn(mockedFile); + + assertThat(mocked.asFile()).isEqualTo(mockedFile); + return mocked; + } + + private static File[] listFiles(File file, FSInfo fsInfo) { + File[] fileList = file.listFiles(); + if (fileList == null) { + return fileList; + } + return Arrays.stream(fileList).map(f -> mkFile(f, fsInfo)).toArray(File[]::new); + } + + private static File[] listFiles(File file, FSInfo fsInfo, FileFilter filter) { + File[] fileList = file.listFiles(); + if (fileList == null) { + return fileList; + } + return Arrays.stream(fileList).map(f -> mkFile(f, fsInfo)).filter(filter::accept).toArray(File[]::new); + } + + private static File[] listFiles(File file, FSInfo fsInfo, FilenameFilter filter) { + File[] fileList = file.listFiles(); + if (fileList == null) { + return fileList; + } + return Arrays.stream(fileList).map(f -> mkFile(f, fsInfo)).filter(x -> filter.accept(x, x.getName())).toArray(File[]::new); + } + + public static File mkFile(final File file, final FSInfo fsInfo) { + File mockedFile = mock(File.class); + when(mockedFile.listFiles()).thenAnswer( env -> listFiles(file, fsInfo)); + when(mockedFile.listFiles(any(FilenameFilter.class))).thenAnswer( env -> listFiles(file, fsInfo, env.getArgument(0, FilenameFilter.class))); + when(mockedFile.listFiles(any(FileFilter.class))).thenAnswer(env -> listFiles(file, fsInfo, env.getArgument(0, FileFilter.class))); + when(mockedFile.getName()).thenReturn(ExclusionUtils.convertSeparator(file.getName(), FSInfoTest.DEFAULT.dirSeparator(), fsInfo.dirSeparator())); + when(mockedFile.getAbsolutePath()).thenReturn(ExclusionUtils.convertSeparator(file.getAbsolutePath(), FSInfoTest.DEFAULT.dirSeparator(), fsInfo.dirSeparator())); + when(mockedFile.isFile()).thenAnswer(env -> file.isFile()); + when(mockedFile.exists()).thenAnswer(emv -> file.exists()); + when(mockedFile.isDirectory()).thenAnswer(env -> file.isDirectory()); + + return mockedFile; + } + + public static DocumentName mkName(Path tempDir, DocumentName baseDir, String pth) throws IOException { + DocumentName result = baseDir.resolve(ExclusionUtils.convertSeparator(pth, "/", baseDir.getDirectorySeparator())); + DocumentName mocked = Mockito.spy(result); + + String fn = result.localized(FileSystems.getDefault().getSeparator()); + File file = tempDir.resolve(fn.substring(1)).toFile(); + File parent = file.getParentFile(); + if (parent.exists() && !parent.isDirectory()) { + parent.delete(); + } + parent.mkdirs(); + if (file.exists()) { + if (file.isDirectory()) { + FileUtils.deleteDirectory(file); + } else { + FileUtils.delete(file); + } + } + file.createNewFile(); + when(mocked.asFile()).thenReturn(file); + return mocked; + } + + @ParameterizedTest(name = "{index} {0} {2}") @MethodSource("resolveTestData") void resolveTest(String testName, DocumentName base, String toResolve, DocumentName expected) { @@ -50,7 +139,6 @@ void resolveTest(String testName, DocumentName base, String toResolve, DocumentN assertThat(actual).isEqualTo(expected); } - private static Stream resolveTestData() { List lst = new ArrayList<>(); diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/FSInfoTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/FSInfoTest.java index 4c0e4ac8e..db2f91ea2 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/FSInfoTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/FSInfoTest.java @@ -20,24 +20,14 @@ import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; -import java.io.File; import java.io.IOException; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.util.ArrayList; -import java.util.HashSet; +import java.util.Arrays; import java.util.List; -import java.util.Set; import java.util.stream.Stream; -import org.apache.commons.lang3.tuple.Pair; -import org.assertj.core.util.Files; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import static java.lang.String.format; -import static org.assertj.core.api.Assertions.assertThat; public class FSInfoTest { public static final DocumentName.FSInfo DEFAULT; @@ -49,12 +39,22 @@ public class FSInfoTest { try (FileSystem osx = Jimfs.newFileSystem(Configuration.osX()); FileSystem unix = Jimfs.newFileSystem(Configuration.unix()); FileSystem windows = Jimfs.newFileSystem(Configuration.windows())) { - OSX = new DocumentName.FSInfo(osx); - UNIX = new DocumentName.FSInfo(unix); - WINDOWS = new DocumentName.FSInfo(windows); - DEFAULT = new DocumentName.FSInfo(FileSystems.getDefault()); + OSX = new DocumentName.FSInfo("osx", osx); + UNIX = new DocumentName.FSInfo("unix", unix); + WINDOWS = new DocumentName.FSInfo("windows", windows); + DEFAULT = new DocumentName.FSInfo("default", FileSystems.getDefault()); } catch (IOException e) { throw new RuntimeException("Unable to creat FSInfo objects: " + e.getMessage(), e); } } + + public static final DocumentName.FSInfo[] TEST_SUITE = {UNIX, WINDOWS, OSX}; + + /** + * Provided arguments for parameterized tests that only require the fsInfo. + * @return a stream of TEST_SUITE based Arguments. + */ + public static Stream fsInfoArgs() { + return Arrays.stream(TEST_SUITE).map(Arguments::of); + } } From db8d117929e296b85af495cfe4b489d4c98a7314 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 14:43:57 +0000 Subject: [PATCH 038/123] debugging for tests --- .../org/apache/rat/config/exclusion/plexus/MatchPattern.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java index 9715b99ec..08732de7e 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java @@ -19,6 +19,7 @@ import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.StringTokenizer; @@ -116,7 +117,7 @@ public boolean startsWith(final String string) { @Override public String toString() { - return source; + return Arrays.asList(tokenized).toString(); } public String source() { From af28b37842a87adf5a00094a3aedc173ffd5cba1 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 14:51:01 +0000 Subject: [PATCH 039/123] debugging for tests --- .../apache/rat/config/exclusion/plexus/MatchPatterns.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java index 717bca0b6..e6d80d888 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java @@ -44,15 +44,11 @@ private MatchPatterns(final MatchPattern[] patterns) { @Override public String toString() { - return source(); + return Arrays.stream(patterns).map(MatchPattern::toString).collect(Collectors.toList()).toString(); } public String source() { - List sources = new ArrayList<>(); - for (MatchPattern pattern : patterns) { - sources.add(pattern.source()); - } - return "[" + String.join(", ", sources) + "]"; + return Arrays.stream(patterns).map(MatchPattern::source).collect(Collectors.toList()).toString(); } public Iterable patterns() { From 76da4a75bb549d93033f424731fbcec21ac2ce95 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 15:06:12 +0000 Subject: [PATCH 040/123] debugging for tests --- .../org/apache/rat/config/exclusion/plexus/MatchPattern.java | 1 + 1 file changed, 1 insertion(+) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java index 08732de7e..ea170e1bb 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java @@ -67,6 +67,7 @@ public MatchPattern(final String source, final String separator) { for (int i = 0; i < tokenized.length; i++) { tokenizedChar[i] = tokenized[i].toCharArray(); } + DefaultLog.getInstance().warn("MatchPattern( " + source + ", " + separator + ") ... " + this.toString()); } public boolean matchPath(final String str, final boolean isCaseSensitive) { From 82e0d375b3ef608171f8b948e6c0cb0adec01fcd Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 15:32:02 +0000 Subject: [PATCH 041/123] debugging for tests --- .../main/java/org/apache/rat/config/exclusion/MatcherSet.java | 1 - .../org/apache/rat/config/exclusion/plexus/MatchPatterns.java | 2 -- .../org/apache/rat/config/exclusion/plexus/SelectorUtils.java | 1 - 3 files changed, 4 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java index f03d641f4..c1c5b6dac 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -103,7 +103,6 @@ public Builder() { private void processNames(final Consumer dest, final String nameFmt, final DocumentName fromDocument, final Set names) { if (!names.isEmpty()) { String name = String.format(nameFmt, fromDocument.localized("/").substring(1)); - //Stream iter = names.stream().map(s ->ExclusionUtils.convertSeparator(s, "/", fromDocument.getDirectorySeparator())); dest.accept(new DocumentNameMatcher(name, MatchPatterns.from(fromDocument.getDirectorySeparator(), names), fromDocument.getBaseDocumentName())); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java index e6d80d888..98f421f2c 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java @@ -78,8 +78,6 @@ public boolean matches(final String name, final String[] tokenizedName, final bo } public boolean matches(final String name, final char[][] tokenizedNameChar, final boolean isCaseSensitive) { - DefaultLog.getInstance().warn(String.format("Matching %s as %s case-sensitivity: %s", name, - Arrays.asList(tokenizedNameChar).stream().map(String::new).collect(Collectors.toList()), isCaseSensitive)); for (MatchPattern pattern : patterns) { if (pattern.matchPath(name, tokenizedNameChar, isCaseSensitive)) { return true; diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java index cddf6a403..b53be7cf1 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java @@ -400,7 +400,6 @@ static boolean matchAntPathPattern(final String[] patDirs, final String[] strDir } static boolean matchAntPathPattern(final char[][] patDirs, final char[][] strDirs, final boolean isCaseSensitive) { - DefaultLog.getInstance().warn(String.format("... Comparing against %s", Arrays.asList(patDirs).stream().map(String::new).collect(Collectors.toList()))); int patIdxStart = 0; int patIdxEnd = patDirs.length - 1; int strIdxStart = 0; From fc7bd52ccea84b9ded3aeb88f3b833f59a51b552 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 15:36:28 +0000 Subject: [PATCH 042/123] removed unused imports --- .../org/apache/rat/config/exclusion/plexus/MatchPatterns.java | 2 -- .../org/apache/rat/config/exclusion/plexus/SelectorUtils.java | 4 ---- 2 files changed, 6 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java index 98f421f2c..9a6d443e4 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java @@ -26,8 +26,6 @@ import java.util.List; import java.util.stream.Collectors; -import org.apache.rat.utils.DefaultLog; - @SuppressWarnings({"checkstyle:RegexpSingleLine", "checkstyle:JavadocVariable"}) /** * A list of patterns to be matched diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java index b53be7cf1..923950f24 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java @@ -56,12 +56,8 @@ */ import java.io.File; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.StringTokenizer; -import java.util.stream.Collectors; - -import org.apache.rat.utils.DefaultLog; @SuppressWarnings({"checkstyle:RegexpSingleLine", "checkstyle:JavadocVariable"}) /** From 86ce6ca1bdb3cd830c082dc9405444d1d5ae3202 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 15:48:04 +0000 Subject: [PATCH 043/123] possible fix --- .../exclusion/fileProcessors/AbstractFileProcessorBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java index 4fc22e6aa..9e6b1a8ac 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java @@ -123,7 +123,7 @@ public final List build(final DocumentName root) { String name = String.format("**/%s", fileName); String pattern = ExclusionUtils.qualifyPattern(root, name); MatcherSet matcherSet = new MatcherSet.Builder() - .addExcluded(new DocumentNameMatcher(name, MatchPatterns.from("/", Collections.singletonList(pattern)), root)) + .addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(root.getDirectorySeparator(), Collections.singletonList(pattern)), root)) .build(); LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(0, k -> new LevelBuilder()); levelBuilder.add(matcherSet); From 59b05f5121abaa097bf303c24ca105e3e73d5f99 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 16:08:16 +0000 Subject: [PATCH 044/123] debugging for tests --- .../org/apache/rat/config/exclusion/plexus/MatchPattern.java | 1 - .../src/test/java/org/apache/rat/commandline/ArgTests.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java index ea170e1bb..08732de7e 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java @@ -67,7 +67,6 @@ public MatchPattern(final String source, final String separator) { for (int i = 0; i < tokenized.length; i++) { tokenizedChar[i] = tokenized[i].toCharArray(); } - DefaultLog.getInstance().warn("MatchPattern( " + source + ", " + separator + ") ... " + this.toString()); } public boolean matchPath(final String str, final boolean isCaseSensitive) { diff --git a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java index 484f8a632..77148c18b 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java +++ b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java @@ -41,7 +41,7 @@ private CommandLine createCommandLine(String[] args) throws ParseException { .setAllowPartialMatching(true).build().parse(opts, args); } - @ParameterizedTest + @ParameterizedTest(name = "{0}") @ValueSource(strings = { "rat.txt", "./rat.txt", "/rat.txt", "target/rat.test" }) public void outputFleNameNoDirectoryTest(String name) throws ParseException, IOException { class OutputFileConfig extends ReportConfiguration { From f5847c9b4919e1136910987a8dceba351b9de431 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 21:46:04 +0000 Subject: [PATCH 045/123] debugging for tests --- .../src/test/java/org/apache/rat/commandline/ArgTests.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java index 77148c18b..7f27cb8d1 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java +++ b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java @@ -26,6 +26,7 @@ import org.apache.rat.DeprecationReporter; import org.apache.rat.OptionCollection; import org.apache.rat.ReportConfiguration; +import org.apache.rat.document.DocumentName; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -51,10 +52,10 @@ public void setOut(File file) { actual = file; } } + String fileName = name.replace("/", DocumentName.FSInfo.getDefault().dirSeparator()); + File expected = new File(fileName); - File expected = new File(name); - - CommandLine commandLine = createCommandLine(new String[] {"--output-file", name}); + CommandLine commandLine = createCommandLine(new String[] {"--output-file", fileName}); OutputFileConfig configuration = new OutputFileConfig(); ArgumentContext ctxt = new ArgumentContext(new File("."), configuration, commandLine); Arg.processArgs(ctxt); From d7b60065b6e53be36e51db3dc6c8f94428761b09 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 21:51:47 +0000 Subject: [PATCH 046/123] put full testing back --- .github/workflows/maven.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 2a2609d46..593c3afa0 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -31,14 +31,12 @@ jobs: strategy: matrix: - #os: [ubuntu-latest, windows-latest] - os: [windows-latest] + os: [ubuntu-latest, windows-latest] # RAT-296: disable JDK10 due to # Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target # # Java 17 disabled, because we are running into https://bugs.openjdk.java.net/browse/JDK-8270866 - #java: [8, 11, 21] - java: [8] + java: [8, 11, 21] fail-fast: false runs-on: ${{ matrix.os }} From 8a80dbe4863837fc58c362deb27a8ba06b387f15 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Tue, 7 Jan 2025 15:17:52 +0000 Subject: [PATCH 047/123] Fix for windows bug --- .../test/java/org/apache/rat/mp/RatCheckMojoTest.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java index a260bca3e..533cdaff8 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java @@ -51,6 +51,8 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.io.TempDir; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NodeList; @@ -58,7 +60,7 @@ /** * Test case for the {@link RatCheckMojo} and {@link RatReportMojo}. */ -public class RatCheckMojoTest { //extends BetterAbstractMojoTestCase { +public class RatCheckMojoTest { @TempDir static Path tempDir; @@ -70,6 +72,11 @@ static void preserveData() { AbstractOptionsProvider.preserveData(tempDir.toFile(), "unit"); } + @AfterAll + @EnabledOnOs(OS.WINDOWS) + static void cleanup() { + System.gc(); // hacky workaround for windows bug. + } private RatCheckMojo getMojo(File pomFile) throws IOException { try { From 9c14a1e71b78e5545d1a9ab6d9c0170a358a02da Mon Sep 17 00:00:00 2001 From: "P. Ottlinger" Date: Mon, 6 Jan 2025 17:37:03 +0100 Subject: [PATCH 048/123] RAT-98: Fix typos --- .../java/org/apache/rat/commandline/ArgumentContext.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java b/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java index dfa7be71e..09f3bc5f4 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java +++ b/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java @@ -54,7 +54,7 @@ public ArgumentContext(final File workingDirectory, final ReportConfiguration co } /** - * Creates a context with an emtpy configuration. + * Creates a context with an empty configuration. * @param workingDirectory The directory from which to resolve relative file names. * @param commandLine The command line. */ @@ -86,7 +86,7 @@ public CommandLine getCommandLine() { } /** - * Gets the directory name from which releative file names will be resolved. + * Gets the directory name from which relative file names will be resolved. * @return The directory name from which releative file names will be resolved. */ public DocumentName getWorkingDirectory() { @@ -94,7 +94,7 @@ public DocumentName getWorkingDirectory() { } // /** -// * Resolves the file name to the working directory if necessayr. +// * Resolves the file name to the working directory if necessary. // * @param fileName the file name to resolve. // * @return the file name string. // */ From fb1dd27b20c81eaa3bb4ec737c0f76912acdc670 Mon Sep 17 00:00:00 2001 From: "P. Ottlinger" Date: Mon, 6 Jan 2025 17:44:40 +0100 Subject: [PATCH 049/123] Minor cleanup --- .../config/exclusion/ExclusionProcessor.java | 4 +--- .../apache/rat/config/exclusion/MatcherSet.java | 17 ++++++++--------- 2 files changed, 9 insertions(+), 12 deletions(-) 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 e92ebafd3..8fec1d903 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 @@ -232,7 +232,7 @@ private String preparePattern(final DocumentName documentName, final String patt } /** * Extracts {@link #includedPatterns} and {@link #excludedPatterns} into the specified matcherBuilder. - * @param nameBuilder The name builder for the pattern. File names are resolved against the generated name. + * @param nameBuilder The name builder for the pattern. File names are resolved against the generated name. * @param matcherBuilder the MatcherSet.Builder to add the patterns to. */ private void extractPatterns(final DocumentName.Builder nameBuilder, final MatcherSet.Builder matcherBuilder) { @@ -292,7 +292,6 @@ private void extractCollectionMatchers(final MatcherSet.Builder matcherBuilder) .map(StandardCollection::staticDocumentNameMatcher) .filter(Objects::nonNull) .forEachRemaining(matcherBuilder::addExcluded); - } /** @@ -314,5 +313,4 @@ private void extractPaths(final MatcherSet.Builder matcherBuilder) { } } - } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java index c1c5b6dac..181b05569 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -46,7 +46,7 @@ default String getDescription() { return String.format("MatcherSet: include [%s] exclude [%s]", includes().orElse(MATCHES_NONE), excludes().orElse(MATCHES_NONE)); } /** - * Creates a DocumentNameMatcher from an iterable of MatcherSets. + * Creates a DocumentNameMatcher from an iterable of matcher sets. * @return A DocumentNameMatcher that processes the matcher sets. */ default DocumentNameMatcher createMatcher() { @@ -64,7 +64,7 @@ static MatcherSet merge(List matcherSets) { /** * A MatcherSet that assumes the files contain the already formatted strings and just need to be - * localized for the fileName. When {@link #build()} is called the builder is reset to the initial state. + * localized for the fileName. When {@link #build()} is called the builder is reset to the initial state. */ class Builder { @@ -98,7 +98,7 @@ public Builder() { * @param dest the consumer to accept the DocumentNameMatcher. * @param nameFmt the format for the matcher names. Requires '%s' for the {@code fromDocument} localized name. * @param fromDocument the document that the patterns are associated with. - * @param names the list of patterns. If empty no action is taken. + * @param names the list of patterns. If empty no action is taken. */ private void processNames(final Consumer dest, final String nameFmt, final DocumentName fromDocument, final Set names) { if (!names.isEmpty()) { @@ -107,10 +107,10 @@ private void processNames(final Consumer dest, final String } } /** - * Adds included file names from the specified document. File names are resolved relative to the directory + * Adds included file names from the specified document. File names are resolved relative to the directory * of the {@code fromDocument}. * @param fromDocument the document the names were read from. - * @param names the names that were read from the document. Must be use the separator specified by {@code fromDocument}. + * @param names the names that were read from the document. Must be use the separator specified by {@code fromDocument}. * @return this */ public Builder addIncluded(final DocumentName fromDocument, final Set names) { @@ -119,10 +119,10 @@ public Builder addIncluded(final DocumentName fromDocument, final Set na } /** - * Adds excluded file names from the specified document. File names are resolved relative to the directory + * Adds excluded file names from the specified document. File names are resolved relative to the directory * of the {@code fromDocument}. * @param fromDocument the document the names were read from. - * @param names the names that were read from the document. Must be use the separator specified by {@code fromDocument}. + * @param names the names that were read from the document. Must be use the separator specified by {@code fromDocument}. * @return this */ public Builder addExcluded(final DocumentName fromDocument, final Set names) { @@ -130,7 +130,6 @@ public Builder addExcluded(final DocumentName fromDocument, final Set na return this; } - /** * Adds specified DocumentNameMatcher to the included matchers. * @param matcher A document name matcher to add to the included set. @@ -152,7 +151,7 @@ public Builder addExcluded(final DocumentNameMatcher matcher) { } /** - * Builds a MatcherSet. When {@code build()} is called the builder is reset to the initial state. + * Builds a MatcherSet. When {@code build()} is called the builder is reset to the initial state. * @return the MatcherSet based upon the included and excluded matchers. */ public MatcherSet build() { From e989016ca9d7c83351a17c7342c4ac7134c0bb4f Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Tue, 7 Jan 2025 15:52:28 +0000 Subject: [PATCH 050/123] removed dead lines / updated javadoc --- .../ReportTest/RAT_335/verify.groovy | 65 ------------------- .../rat/commandline/ArgumentContext.java | 13 ---- .../config/exclusion/StandardCollection.java | 2 +- .../apache/rat/walker/FileListWalkerTest.java | 2 - 4 files changed, 1 insertion(+), 81 deletions(-) diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy index d660f59fd..e3917feeb 100644 --- a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy @@ -36,74 +36,9 @@ private static Map mapOf(String... parts) { output = new File(args[0]) content = output.text -//Map data = new HashMap<>() -//data.put(ClaimStatistic.Counter.APPROVED, "2") -//data.put(ClaimStatistic.Counter.ARCHIVES, "0") -//data.put(ClaimStatistic.Counter.BINARIES, "0") -//data.put(ClaimStatistic.Counter.DOCUMENT_TYPES, "3") -//data.put(ClaimStatistic.Counter.IGNORED, "6") -//data.put(ClaimStatistic.Counter.LICENSE_CATEGORIES, "2") -//data.put(ClaimStatistic.Counter.LICENSE_NAMES, "2") -//data.put(ClaimStatistic.Counter.NOTICES, "1") -//data.put(ClaimStatistic.Counter.STANDARDS, "6") -//data.put(ClaimStatistic.Counter.UNAPPROVED, "4") -//data.put(ClaimStatistic.Counter.UNKNOWN, "4") - Document document = XmlUtils.toDom(new FileInputStream(args[0])) XPath xPath = XPathFactory.newInstance().newXPath() -//for (ClaimStatistic.Counter counter : ClaimStatistic.Counter.values()) { -// String xpath = String.format("/rat-report/statistics/statistic[@name='%s']", counter.displayName()) -// Map map = mapOf("approval", -// counter == ClaimStatistic.Counter.UNAPPROVED ? "false" : "true", -// "count", data.get(counter), -// "description", counter.getDescription()) -// XmlUtils.assertAttributes(document, xPath, xpath, map) -//} - -//// license categories -//XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseCategory[@name='?????']", -// mapOf("count", "4" )) -// -//XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseCategory[@name='AL ']", -// mapOf("count", "2" )) -// -//// license names -//XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseName[@name='Apache License Version 2.0']", -// mapOf("count", "2" )) -// -//XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseName[@name='Unknown license']", -// mapOf("count", "4" )) - - - -//Note the output when running in the real commandline version of git -// -//# Files that must be ignored (dropping the gitignore matches outside of this test tree) -//$ git check-ignore --no-index --verbose $(find . -type f|sort) -// -// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore:2:!dir1.md ./dir1/dir1.md -// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore:1:*.txt ./dir1/dir1.txt -// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore:3:file1.log ./dir1/file1.log -// .gitignore:20:**/.gitignore ./dir1/.gitignore -// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore:1:*.md ./dir2/dir2.md -// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore:4:*.log ./dir3/dir3.log -// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore:7:!file*.log ./dir3/file3.log -// .gitignore:20:**/.gitignore ./.gitignore -// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore:1:*.md ./root.md - -/* list of excluded files: - -./dir1/dir1.txt -./dir1/file1.log -./dir1/.gitignore -./dir2/dir2.md -./dir3/dir3.log -./.gitignore -./root.md - - */ - List ignoredFiles = new ArrayList<>(Arrays.asList( "/dir1/dir1.txt", "/dir1/.gitignore", diff --git a/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java b/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java index 09f3bc5f4..b69c5b7f8 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java +++ b/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java @@ -93,19 +93,6 @@ public DocumentName getWorkingDirectory() { return workingDirectory; } -// /** -// * Resolves the file name to the working directory if necessary. -// * @param fileName the file name to resolve. -// * @return the file name string. -// */ -// public File resolve(final String fileName) { -// if (!fileName.startsWith("/")) { -// DocumentName fn = DocumentName.builder().setName(fileName).setBaseName("/").build(); -// return new File(workingDirectory.resolve(fn.localized()).getName()); -// } -// return new File(fileName); -// } - /** * Logs a ParseException as a warning. * @param exception the parse exception to log diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java index 03f364112..08bc3ec6d 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java @@ -214,7 +214,7 @@ public String toString() { private final Collection patterns; /** A document name matcher supplier to create a document name matcher. May be null */ private final DocumentNameMatcher staticDocumentNameMatcher; - /** The MatcherSet to process the exclude file associated with this exclusion. May be null. */ + /** The AbstractFileProcessorBuilder to process the exclude file associated with this exclusion. May be null. */ private final AbstractFileProcessorBuilder fileProcessorBuilder; /** The description of this collection */ private final String desc; diff --git a/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java b/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java index 1c115f674..ec739f643 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java @@ -110,8 +110,6 @@ public static void setUp() throws Exception { writer.flush(); System.out.flush(); } - - //hiddenName = DocumentName.builder(hiddenFile).setBaseName(rootName.getBaseName()).build(); } @Test From 3b1ac562157bb72046b863655a45ba89bcd3a8b9 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Mon, 13 Jan 2025 23:24:31 +0000 Subject: [PATCH 051/123] fixed rebase errors --- .../apache/rat/ReportConfigurationTest.java | 8 ++++---- .../rat/test/AbstractOptionsProvider.java | 20 +++++++++---------- .../rat/testhelpers/TestingDocument.java | 3 ++- 3 files changed, 16 insertions(+), 15 deletions(-) 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 581d474b5..3de2faa5a 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 @@ -88,13 +88,13 @@ public void cleanup() { public void testAddIncludedFilter() { DocumentName dirName = DocumentName.builder(tempDir).build(); underTest.addExcludedFilter(DirectoryFileFilter.INSTANCE); - DocumentNameMatcher matcher = underTest.getDocumentExcluder(dirName); + DocumentNameMatcher excluder = underTest.getDocumentExcluder(dirName); - assertThat(matcher.toString()).isEqualTo("not(DirectoryFileFilter)"); - assertThat(matcher.matches(DocumentName.builder(tempDir).build())).isFalse(); + assertThat(excluder.toString()).isEqualTo("not(DirectoryFileFilter)"); + assertThat(excluder.matches(DocumentName.builder(tempDir).build())).isFalse(); File f = new File(tempDir, "foo.txt"); - assertThat(exlcuder.matches(DocumentName.builder(f).build())).isTrue(); + assertThat(excluder.matches(DocumentName.builder(f).build())).isTrue(); } @Test 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 863f32bd0..d508e39f8 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 @@ -266,11 +266,11 @@ private void execExcludeTest(Option option, String[] args) { DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : notExcluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isTrue(); } for (String fname : excluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isFalse(); } } catch (IOException e) { fail(e.getMessage()); @@ -308,11 +308,11 @@ protected void inputExcludeStdTest() { DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isFalse(); } for (String fname : notExcluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -372,11 +372,11 @@ private void inputExcludeSizeTest() { DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isFalse(); } for (String fname : notExcluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -394,11 +394,11 @@ private void execIncludeTest(Option option, String[] args) { DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isFalse(); } for (String fname : notExcluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); @@ -438,11 +438,11 @@ protected void inputIncludeStdTest() { DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); for (String fname : excluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isFalse(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isFalse(); } for (String fname : notExcluded) { DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)).as(() -> dump(option, fname, matcher, docName)).isTrue(); + assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isTrue(); } } catch (IOException e) { fail(e.getMessage()); 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 532182b8e..1bd66377b 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 @@ -29,6 +29,7 @@ import org.apache.rat.api.Document; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.document.DocumentName; +import org.apache.rat.document.FSInfoTest; public class TestingDocument extends Document { @@ -62,7 +63,7 @@ public TestingDocument(Reader reader, String name) { } public TestingDocument(IOSupplier inputStream, String name) { - super(DocumentName.builder().setName(name).setBaseName("").setDirSeparator("/").setCaseSensitive(true).build(), DocumentNameMatcher.MATCHES_ALL); + super(DocumentName.builder(FSInfoTest.UNIX).setName(name).setBaseName("").build(), DocumentNameMatcher.MATCHES_ALL); this.input = inputStream; this.reader = null; } From 9f82d3d5db8fd1640cbbf991c32077c3f396c9a6 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 12 Jan 2025 16:01:43 +0000 Subject: [PATCH 052/123] Added FSInfo to handle file system differences --- apache-rat-core/pom.xml | 5 + .../it/java/org/apache/rat/ReportTest.java | 2 +- .../rat/config/exclusion/ExclusionUtils.java | 14 + .../apache/rat/document/ArchiveEntryName.java | 74 +++ .../org/apache/rat/document/DocumentName.java | 553 ++++++++++++------ .../org/apache/rat/walker/ArchiveWalker.java | 15 +- .../org/apache/rat/OptionCollectionTest.java | 12 +- .../rat/analysis/AnalyserFactoryTest.java | 4 +- .../config/exclusion/FileProcessorTest.java | 3 +- .../apache/rat/document/DocumentNameTest.java | 325 +++++++--- .../org/apache/rat/document/FSInfoTest.java | 60 ++ .../rat/document/guesser/NoteGuesserTest.java | 7 +- .../rat/testhelpers/TestingDocument.java | 4 +- pom.xml | 10 +- 14 files changed, 798 insertions(+), 290 deletions(-) create mode 100644 apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryName.java create mode 100644 apache-rat-core/src/test/java/org/apache/rat/document/FSInfoTest.java diff --git a/apache-rat-core/pom.xml b/apache-rat-core/pom.xml index 8ac00d1e3..844a7efc5 100644 --- a/apache-rat-core/pom.xml +++ b/apache-rat-core/pom.xml @@ -281,5 +281,10 @@ groovy-all test + + com.google.jimfs + jimfs + test + 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 b58c6732b..16bc908bc 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 @@ -163,7 +163,7 @@ public static Stream args() throws RatException { @Override public void report(Document document) { if (!document.isIgnored()) { - String[] tokens = document.getName().tokenize(document.getName().localized()); + String[] tokens = DocumentName.FSInfo.getDefault().tokenize(document.getName().localized()); results.add(Arguments.of(tokens[1], document)); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java index 339ce0978..3f082336a 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java @@ -185,4 +185,18 @@ private static void verifyFile(final File file) { throw new ConfigurationException(format("%s is not a valid file.", file)); } } + + /** + * Tokenizes the string based on the directory separator. + * @param source the source to tokenize + * @param from the directory separator for the source. + * @param to the directory separator for the result. + * @return the source string with the separators converted. + */ + public static String convertSeparator(final String source, final String from, final String to) { + if (StringUtils.isEmpty(source) || from.equals(to)) { + return source; + } + return String.join(to, source.split("\\Q" + from + "\\E")); + } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryName.java b/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryName.java new file mode 100644 index 000000000..889a7b165 --- /dev/null +++ b/apache-rat-core/src/main/java/org/apache/rat/document/ArchiveEntryName.java @@ -0,0 +1,74 @@ +/* + * 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.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; + +public class ArchiveEntryName extends DocumentName { + /** Then name of the document that contains this entry */ + private final DocumentName archiveFileName; + + private static DocumentName.Builder prepareBuilder(final DocumentName archiveFileName, final String archiveEntryName) { + String root = archiveFileName.getName() + "#"; + FSInfo fsInfo = new FSInfo("archiveEntry", "/", true, Collections.singletonList(root)); + return DocumentName.builder(fsInfo) + .setRoot(root) + .setBaseName(root + "/") + .setName(archiveEntryName); + } + public ArchiveEntryName(final DocumentName archiveFileName, final String archiveEntryName) { + super(prepareBuilder(archiveFileName, archiveEntryName)); + this.archiveFileName = archiveFileName; + } + + @Override + public File asFile() { + return archiveFileName.asFile(); + } + + @Override + public Path asPath() { + return Paths.get(archiveFileName.asPath().toString(), "#", super.asPath().toString()); + } + + @Override + public DocumentName resolve(final String child) { + return new ArchiveEntryName(this.archiveFileName, super.resolve(child).localized()); + } + + @Override + public String getBaseName() { + return archiveFileName.getName() + "#"; + } + + @Override + boolean startsWithRootOrSeparator(final String candidate, final String root, final String separator) { + return super.startsWithRootOrSeparator(candidate, root, separator); + } + + @Override + public String localized(final String dirSeparator) { + String superLocal = super.localized(dirSeparator); + superLocal = superLocal.substring(superLocal.lastIndexOf("#") + 1); + return archiveFileName.localized(dirSeparator) + "#" + superLocal; + } +} diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java index e71bed85b..9b0c6a0d9 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java @@ -20,19 +20,24 @@ import java.io.File; import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.Objects; -import java.util.Set; +import java.util.Optional; +import java.util.stream.Collectors; -import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.builder.CompareToBuilder; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; -import org.apache.rat.utils.DefaultLog; /** * The name for a document. The {@code DocumentName} is an immutable structure that handles all the intricacies of file @@ -51,66 +56,85 @@ * within an archive. When representing a file in an archive the baseName is the name of the enclosing archive document. *

    */ -public final class DocumentName implements Comparable { - /** The list of all roots on the file system. */ - static final Set ROOTS = new HashSet<>(); - /** {@code True} if the file system on which we are operating is case-sensitive. */ - public static final boolean FS_IS_CASE_SENSITIVE; +public class DocumentName implements Comparable { /** The full name for the document. */ private final String name; /** The name of the base directory for the document. */ - private final String baseName; - /** The directory separator for this document. */ - private final String dirSeparator; - /** The case-sensitive flag */ - private final boolean isCaseSensitive; + //private final String baseName; + private final DocumentName baseName; + /** The file system info for this document. */ + private final FSInfo fsInfo; /** The root for the DocumentName. May be empty but not null. */ private final String root; - // determine the case sensitivity of the file system we are operating on. - static { - boolean fsSensitive = true; - File f = null; + /** + * Determines if the file system is case-sensitive. + * @param fileSystem the file system to check + * @return {@code true} if the file system is case-sensitive. + */ + private static boolean isCaseSensitive(final FileSystem fileSystem) { + boolean isCaseSensitive = false; + Path nameSet = null; + Path filea = null; + Path fileA = null; try { - Path p = Files.createTempDirectory("NameSet"); - f = p.toFile(); - fsSensitive = !new File(f, "a").equals(new File(f, "A")); - } catch (IOException e) { - fsSensitive = true; - } finally { - if (f != null) { - try { - FileUtils.deleteDirectory(f); - } catch (IOException e) { - DefaultLog.getInstance().warn("Unable to delete temporary directory: " + f, e); + try { + Path root = fileSystem.getPath(""); + nameSet = Files.createTempDirectory(root, "NameSet"); + filea = nameSet.resolve("a"); + fileA = nameSet.resolve("A"); + Files.createFile(filea); + Files.createFile(fileA); + isCaseSensitive = true; + } catch (IOException e) { + // do nothing + } finally { + if (filea != null) { + Files.deleteIfExists(filea); + } + if (fileA != null) { + Files.deleteIfExists(fileA); + } + if (nameSet != null) { + Files.deleteIfExists(nameSet); } } + } catch (IOException e) { + // do nothing. } - FS_IS_CASE_SENSITIVE = fsSensitive; - - // determine all the roots on the file system(s). - File[] roots = File.listRoots(); - if (roots != null) { - for (File root : roots) { - String name = root.getPath(); - ROOTS.add(name); - } - } - + return isCaseSensitive; } /** - * Creates a Builder with directory separator and case sensitivity based on the local file system. + * Creates a Builder with the default File system info. * @return the Builder. + * @see FSInfo */ public static Builder builder() { - return new Builder(); + return new Builder(FSInfo.getDefault()); + } + + /** + * Creates a builder with the specified FSInfo instance. + * @param fsInfo the FSInfo to use for the builder. + * @return a new builder. + */ + public static Builder builder(final FSInfo fsInfo) { + return new Builder(fsInfo); + } + + /** + * Creates a builder for the specified file system. + * @param fileSystem the file system to create ethe builder on. + * @return a new builder. + */ + public static Builder builder(final FileSystem fileSystem) { + return new Builder(fileSystem); } /** * Creates a builder from a File. The {@link #baseName} is set to the file name if it is a directory otherwise - * it is set to the directory containing the file. The {@link #dirSeparator} is set from the file and - * case sensitivity based on the local file system. + * it is set to the directory containing the file. * @param file The file to set defaults from. * @return the Builder. */ @@ -131,26 +155,49 @@ public static Builder builder(final DocumentName documentName) { * Builds the DocumentName from the builder. * @param builder the builder to provide the values. */ - private DocumentName(final Builder builder) { + DocumentName(final Builder builder) { this.name = builder.name; - this.baseName = builder.baseName; - this.dirSeparator = builder.dirSeparator; - this.isCaseSensitive = builder.isCaseSensitive; + this.fsInfo = builder.fsInfo; this.root = builder.root; + this.baseName = builder.sameNameFlag ? this : builder.baseName; + } + + /** + * Creates a file from the document name. + * @return a new File object. + */ + public File asFile() { + return new File(getName()); + } + + /** + * Creates a path from the document name. + * @return an new Path object. + */ + public Path asPath() { + return Paths.get(name); } /** - * Creates a new DocumentName by adding the child to the current name. + * Creates a new DocumentName by adding the child to the current name. Resulting documentName will + * have the same base name. * @param child the child to add (must use directory separator from this document name). - * @return the new document name with the same {@link #baseName}, {@link #dirSeparator} and case sensitivity as + * @return the new document name with the same {@link #baseName}, directory sensitivity and case sensitivity as * this one. */ public DocumentName resolve(final String child) { - List parts = new ArrayList<>(); - parts.addAll(Arrays.asList(tokenize(name))); - parts.addAll(Arrays.asList(tokenize(child))); - String newName = String.join(dirSeparator, parts); - return new Builder(this).setName(newName).build(); + if (StringUtils.isBlank(child)) { + return this; + } + String separator = fsInfo.dirSeparator(); + String pattern = separator.equals("/") ? child.replace('\\', '/') : + child.replace('/', '\\'); + + if (!pattern.startsWith(separator)) { + pattern = name + separator + pattern; + } + + return new Builder(this).setName(pattern).build(); } /** @@ -158,7 +205,7 @@ public DocumentName resolve(final String child) { * @return the fully qualified name of the document. */ public String getName() { - return root + dirSeparator + name; + return root + fsInfo.dirSeparator() + name; } /** @@ -166,7 +213,7 @@ public String getName() { * @return the fully qualified basename of the document. */ public String getBaseName() { - return root + dirSeparator + baseName; + return baseName.getName(); } /** @@ -182,7 +229,7 @@ public String getRoot() { * @return the DocumentName for the basename of this document name. */ public DocumentName getBaseDocumentName() { - return name.equals(baseName) ? this : builder(this).setName(baseName).build(); + return baseName; } /** @@ -190,7 +237,25 @@ public DocumentName getBaseDocumentName() { * @return the directory separator. */ public String getDirectorySeparator() { - return dirSeparator; + return fsInfo.dirSeparator(); + } + + /** + * Determines if the candidate starts with the root or separator strings. + * @param candidate the candidate ot check. If blank method will return false. + * @param root the root to check. If blank the root check is skipped. + * @param separator the separator to check. If blank the check is skipped. + * @return true if either the root or separator check returned true. + */ + boolean startsWithRootOrSeparator(final String candidate, final String root, final String separator) { + if (StringUtils.isBlank(candidate)) { + return false; + } + boolean result = !StringUtils.isBlank(root) && candidate.startsWith(root); + if (!result) { + result = !StringUtils.isBlank(separator) && candidate.startsWith(separator); + } + return result; } /** @@ -199,12 +264,13 @@ public String getDirectorySeparator() { * @return the portion of the name that is not part of the base name. */ public String localized() { - String result = name; - if (result.startsWith(baseName)) { - result = result.substring(baseName.length()); + String result = getName(); + String baseNameStr = baseName.getName(); + if (result.startsWith(baseNameStr)) { + result = result.substring(baseNameStr.length()); } - if (!result.startsWith(dirSeparator)) { - result = dirSeparator + result; + if (!startsWithRootOrSeparator(result, getRoot(), fsInfo.dirSeparator())) { + result = fsInfo.dirSeparator() + result; } return result; } @@ -216,24 +282,26 @@ public String localized() { * @return the portion of the name that is not part of the base name. */ public String localized(final String dirSeparator) { - return String.join(dirSeparator, tokenize(localized())); - } + String[] tokens = fsInfo.tokenize(localized()); + if (tokens.length == 0) { + return dirSeparator; + } + if (tokens.length == 1) { + return dirSeparator + tokens[0]; + } - /** - * Tokenizes the string based on the {@link #dirSeparator} of this DocumentName. - * @param source the source to tokenize - * @return the array of tokenized strings. - */ - public String[] tokenize(final String source) { - return source.split("\\Q" + dirSeparator + "\\E"); + String modifiedRoot = dirSeparator.equals("/") ? root.replace('\\', '/') : + root.replace('/', '\\'); + String result = String.join(dirSeparator, tokens); + return startsWithRootOrSeparator(result, modifiedRoot, dirSeparator) ? result : dirSeparator + result; } /** - * Gets the last segment of the name. This is the part after the last {@link #dirSeparator}.. + * Gets the last segment of the name. This is the part after the last directory separator. * @return the last segment of the name. */ public String getShortName() { - int pos = name.lastIndexOf(dirSeparator); + int pos = name.lastIndexOf(fsInfo.dirSeparator()); return pos == -1 ? name : name.substring(pos + 1); } @@ -242,7 +310,7 @@ public String getShortName() { * @return {@code true} if the name is case-sensitive. */ public boolean isCaseSensitive() { - return isCaseSensitive; + return fsInfo.isCaseSensitive(); } /** @@ -255,28 +323,158 @@ public String toString() { } @Override - public int compareTo(final DocumentName o) { - return FS_IS_CASE_SENSITIVE ? name.compareTo(o.name) : name.compareToIgnoreCase(o.name); + public int compareTo(final DocumentName other) { + return CompareToBuilder.reflectionCompare(this, other); } @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - DocumentName that = (DocumentName) o; - if (isCaseSensitive() == that.isCaseSensitive() && Objects.equals(dirSeparator, that.dirSeparator)) { - return isCaseSensitive ? name.equalsIgnoreCase(that.name) : name.equals(that.name); - } - return false; + public boolean equals(final Object other) { + return EqualsBuilder.reflectionEquals(this, other); } @Override public int hashCode() { - return Objects.hash(name, dirSeparator, isCaseSensitive()); + return HashCodeBuilder.reflectionHashCode(this); + } + + /** + * The File system information needed to process document names. + */ + public static class FSInfo implements Comparable { + /** The common name for the file system this Info represents */ + private final String name; + /** The separator between directory names */ + private final String separator; + /** The case-sensitivity flag. */ + private final boolean isCaseSensitive; + /** The list of roots for the file system */ + private final List roots; + + public static FSInfo getDefault() { + FSInfo result = (FSInfo) System.getProperties().get("FSInfo"); + return result == null ? + new FSInfo("default", FileSystems.getDefault()) + : result; + } + /** + * Constructor. Extracts the necessary data from the file system. + * @param fileSystem the file system to extract data from. + */ + public FSInfo(final FileSystem fileSystem) { + this("anon", fileSystem); + } + + /** + * Constructor. Extracts the necessary data from the file system. + * @param fileSystem the file system to extract data from. + */ + public FSInfo(final String name, final FileSystem fileSystem) { + this.name = name; + this.separator = fileSystem.getSeparator(); + this.isCaseSensitive = DocumentName.isCaseSensitive(fileSystem); + roots = new ArrayList<>(); + fileSystem.getRootDirectories().forEach(r -> roots.add(r.toString())); + } + + /** + * Gets the common name for the underlying file system. + * @return the common file system name. + */ + @Override + public String toString() { + return name; + } + /** + * Constructor for virtual/abstract file systems for example the entry names within an an archive. + * @param separator the separator string to use. + * @param isCaseSensitive the case-sensitivity flag. + * @param roots the roots for the file system. + */ + FSInfo(final String name, final String separator, final boolean isCaseSensitive, final List roots) { + this.name = name; + this.separator = separator; + this.isCaseSensitive = isCaseSensitive; + this.roots = new ArrayList<>(roots); + } + + /** + * Gets the directory separator. + * @return The directory separator. + */ + public String dirSeparator() { + return separator; + } + + /** + * Gets the case-sensitivity flag. + * @return the case-sensitivity flag. + */ + public boolean isCaseSensitive() { + return isCaseSensitive; + } + + /** + * Retrieves the root extracted from the name. + * @param name the name to extract the root from + * @return an optional containing the root or empty. + */ + public Optional rootFor(final String name) { + for (String sysRoot : roots) { + if (name.startsWith(sysRoot)) { + return Optional.of(sysRoot); + } + } + return Optional.empty(); + } + + /** + * Tokenizes the string based on the directory separator of this DocumentName. + * @param source the source to tokenize + * @return the array of tokenized strings. + */ + public String[] tokenize(final String source) { + return source.split("\\Q" + dirSeparator() + "\\E"); + } + + /** + * Removes "." and ".." from filenames names. + * @param pattern the file name pattern + * @return the normalized file name. + */ + public String normalize(final String pattern) { + if (StringUtils.isBlank(pattern)) { + return ""; + } + List parts = new ArrayList<>(Arrays.asList(tokenize(pattern))); + for (int i = 0; i < parts.size(); i++) { + String part = parts.get(i); + if (part.equals("..")) { + if (i == 0) { + throw new IllegalStateException("can not creat path before root"); + } + parts.set(i - 1, null); + parts.set(i, null); + } else if (part.equals(".")) { + parts.set(i, null); + } + } + return parts.stream().filter(Objects::nonNull).collect(Collectors.joining(dirSeparator())); + } + + @Override + public int compareTo(final FSInfo other) { + return CompareToBuilder.reflectionCompare(this, other); + } + + @Override + public boolean equals(final Object other) { + return EqualsBuilder.reflectionEquals(this, other); + } + + @Override + public int hashCode() { + return HashCodeBuilder.reflectionHashCode(this); + } } /** @@ -286,44 +484,65 @@ public static final class Builder { /** The name for the document */ private String name; /** The base name for the document */ - private String baseName; - /** The directory separator */ - private String dirSeparator; - /** The case sensitivity flag */ - private boolean isCaseSensitive; + private DocumentName baseName; + /** The file system info */ + private final FSInfo fsInfo; /** The file system root */ private String root; + /** A flag for baseName same as this */ + private boolean sameNameFlag; /** * Create with default settings. */ - private Builder() { - isCaseSensitive = FS_IS_CASE_SENSITIVE; - dirSeparator = File.separator; + private Builder(final FSInfo fsInfo) { + this.fsInfo = fsInfo; root = ""; } + /** + * Create with default settings. + */ + private Builder(final FileSystem fileSystem) { + this(new FSInfo(fileSystem)); + } + /** * Create based on the file provided. * @param file the file to base the builder on. */ private Builder(final File file) { - this(); + this(FSInfo.getDefault()); + setName(file); + } + + /** + * Used in testing + * @param fsInfo the FSInfo for the file. + * @param file the file to process + */ + Builder(final FSInfo fsInfo, final File file) { + this(fsInfo); setName(file); - isCaseSensitive = FS_IS_CASE_SENSITIVE; - dirSeparator = File.separator; } /** * Create a Builder that clones the specified DocumentName. * @param documentName the DocumentName to clone. */ - private Builder(final DocumentName documentName) { + Builder(final DocumentName documentName) { this.root = documentName.root; this.name = documentName.name; this.baseName = documentName.baseName; - this.isCaseSensitive = documentName.isCaseSensitive; - this.dirSeparator = documentName.dirSeparator; + this.fsInfo = documentName.fsInfo; + } + + /** + * Get the directory separator for this builder. + * @return the directory separator fo this builder. + */ + public String directorySeparator() { + return fsInfo.dirSeparator(); } /** @@ -331,12 +550,11 @@ private Builder(final DocumentName documentName) { */ private void verify() { Objects.requireNonNull(name, "Name cannot be null"); - Objects.requireNonNull(baseName, "Basename cannot be null"); - if (name.startsWith(dirSeparator)) { - name = name.substring(dirSeparator.length()); + if (name.startsWith(fsInfo.dirSeparator())) { + name = name.substring(fsInfo.dirSeparator().length()); } - if (baseName.startsWith(dirSeparator)) { - baseName = baseName.substring(dirSeparator.length()); + if (!sameNameFlag) { + Objects.requireNonNull(baseName, "Basename cannot be null"); } } @@ -346,58 +564,54 @@ private void verify() { * @return this. */ public Builder setRoot(final String root) { - this.root = root; + this.root = StringUtils.defaultIfBlank(root, ""); return this; } /** - * Sets the name for this DocumentName. Will reset the root to the empty string. + * Sets the name for this DocumentName relative to the baseName. If the {@code name} is null + * an empty string is used. *

    - * To correctly parse the string it must either be the directory separator specified by - * {@link File#separator} or must have been explicitly set by calling {@link #setDirSeparator(String)} - * before making this call. + * To correctly parse the string it must use the directory separator specified by + * this Document. *

    - * @param name the name for this Document name. + * @param name the name for this Document name. Will be made relative to the baseName * @return this */ public Builder setName(final String name) { - Pair pair = splitRoot(name, dirSeparator); + Pair pair = splitRoot(StringUtils.defaultIfBlank(name, "")); if (this.root.isEmpty()) { this.root = pair.getLeft(); } - this.name = pair.getRight(); + this.name = fsInfo.normalize(pair.getRight()); + if (this.baseName != null && !baseName.name.isEmpty()) { + if (!this.name.startsWith(baseName.name)) { + this.name = this.name.isEmpty() ? baseName.name : + baseName.name + fsInfo.dirSeparator() + this.name; + } + } return this; } - /** - * Extracts the root/name pair from a file. - * @param file the file to extract the root/name pair from. - * @return the root/name pair. - */ - static Pair splitRoot(final File file) { - return splitRoot(file.getAbsolutePath(), File.separator); - } - /** * Extracts the root/name pair from a name string. *

    * Package private for testing. *

    * @param name the name to extract the root/name pair from. - * @param dirSeparator the directory separator. * @return the root/name pair. */ - static Pair splitRoot(final String name, final String dirSeparator) { + Pair splitRoot(final String name) { String workingName = name; - String root = ""; - for (String sysRoot : ROOTS) { - if (workingName.startsWith(sysRoot)) { - workingName = workingName.substring(sysRoot.length()); - if (!workingName.startsWith(dirSeparator)) { - if (sysRoot.endsWith(dirSeparator)) { - root = sysRoot.substring(0, sysRoot.length() - dirSeparator.length()); + Optional maybeRoot = fsInfo.rootFor(name); + String root = maybeRoot.orElse(""); + if (!root.isEmpty()) { + if (workingName.startsWith(root)) { + workingName = workingName.substring(root.length()); + if (!workingName.startsWith(fsInfo.dirSeparator())) { + if (root.endsWith(fsInfo.dirSeparator())) { + root = root.substring(0, root.length() - fsInfo.dirSeparator().length()); } - return ImmutablePair.of(root, workingName); } } } @@ -415,21 +629,24 @@ private void setEmptyRoot(final String root) { } /** - * Sets the properties from the file. This method sets the {@link #root} if it is empty, and resets {@link #name}, - * {@link #dirSeparator} and {@link #baseName}. + * Sets the properties from the file. Will reset the baseName appropraitly. * @param file the file to set the properties from. * @return this. */ public Builder setName(final File file) { - Pair pair = splitRoot(file); + Pair pair = splitRoot(file.getAbsolutePath()); setEmptyRoot(pair.getLeft()); - this.name = pair.getRight(); - this.dirSeparator = File.separator; - this.baseName = name; - if (!file.isDirectory()) { + this.name = fsInfo.normalize(pair.getRight()); + if (file.isDirectory()) { + sameNameFlag = true; + } else { File p = file.getParentFile(); if (p != null) { setBaseName(p); + } else { + Builder baseBuilder = new Builder(this.fsInfo).setName(this.directorySeparator()); + baseBuilder.sameNameFlag = true; + setBaseName(baseBuilder.build()); } } return this; @@ -439,17 +656,15 @@ public Builder setName(final File file) { * Sets the baseName. * Will set the root if it is not set. *

    - * To correctly parse the string it must either be the directory separator specified by - * {@link File#separator} or must have been explicitly set by calling {@link #setDirSeparator(String)} - * before making this call. + * To correctly parse the string it must use the directory separator specified by this builder. *

    * @param baseName the basename to use. * @return this. */ public Builder setBaseName(final String baseName) { - Pair pair = splitRoot(baseName, dirSeparator); - setEmptyRoot(pair.getLeft()); - this.baseName = pair.getRight(); + DocumentName.Builder builder = DocumentName.builder(fsInfo).setName(baseName); + builder.sameNameFlag = true; + setBaseName(builder); return this; } @@ -460,7 +675,7 @@ public Builder setBaseName(final String baseName) { * @return this. */ public Builder setBaseName(final DocumentName baseName) { - this.baseName = baseName.getName(); + this.baseName = baseName; if (!baseName.getRoot().isEmpty()) { this.root = baseName.getRoot(); } @@ -468,36 +683,24 @@ public Builder setBaseName(final DocumentName baseName) { } /** - * Sets the basename from a File. Sets {@link #root} and the {@link #baseName} - * Will set the root. - * @param file the file to set the base name from. - * @return this. + * Executes the builder, sets the base name and clears the sameName flag. + * @param builder the builder for the base name. */ - public Builder setBaseName(final File file) { - Pair pair = splitRoot(file); - this.root = pair.getLeft(); - this.baseName = pair.getRight(); - return this; + private void setBaseName(final DocumentName.Builder builder) { + this.baseName = builder.build(); + this.sameNameFlag = false; } /** - * Sets the directory separator. - * @param dirSeparator the directory separator to use. - * @return this. - */ - public Builder setDirSeparator(final String dirSeparator) { - Objects.requireNonNull(dirSeparator, "Directory separator cannot be null"); - this.dirSeparator = dirSeparator; - return this; - } - - /** - * Sets the {@link #isCaseSensitive} flag. - * @param isCaseSensitive the expected state of the flag. + * Sets the basename from a File. Sets {@link #root} and the {@link #baseName} + * Will set the root. + * @param file the file to set the base name from. * @return this. */ - public Builder setCaseSensitive(final boolean isCaseSensitive) { - this.isCaseSensitive = isCaseSensitive; + public Builder setBaseName(final File file) { + DocumentName.Builder builder = DocumentName.builder(fsInfo).setName(file); + builder.sameNameFlag = true; + setBaseName(builder); return this; } 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 d9148701e..e2cc470e6 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 @@ -35,6 +35,7 @@ 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.report.RatReport; import org.apache.rat.utils.DefaultLog; @@ -82,20 +83,18 @@ private InputStream createInputStream() throws IOException { */ public Collection getDocuments() throws RatException { List result = new ArrayList<>(); + //DocumentName.FSInfo archiveInfo = new DocumentName.FSInfo(true, Arrays.asList("/"), "/"); try (ArchiveInputStream input = new ArchiveStreamFactory().createArchiveInputStream(createInputStream())) { - ArchiveEntry entry = null; + ArchiveEntry entry; while ((entry = input.getNextEntry()) != null) { if (!entry.isDirectory() && input.canReadEntryData(entry)) { - DocumentName innerName = DocumentName.builder().setDirSeparator("/").setName(entry.getName()) - .setBaseName(".").setCaseSensitive(true).build(); + DocumentName innerName = DocumentName.builder().setName(entry.getName()) + .setBaseName(".").build(); if (this.getDocument().getNameExcluder().matches(innerName)) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); IOUtils.copy(input, baos); - DocumentName archiveName = getDocument().getName(); - String outerNameStr = format("%s#%s", archiveName.getName(), entry.getName()); - DocumentName outerName = DocumentName.builder(archiveName).setName(outerNameStr) - .setCaseSensitive(true).build(); - result.add(new ArchiveEntryDocument(outerName, baos.toByteArray(), getDocument().getNameExcluder())); + ArchiveEntryName entryName = new ArchiveEntryName(getDocument().getName(), entry.getName()); + result.add(new ArchiveEntryDocument(entryName, baos.toByteArray(), getDocument().getNameExcluder())); } } } 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 ab1ce763a..38712c9bf 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 @@ -18,11 +18,13 @@ */ package org.apache.rat; +import java.nio.file.Path; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.Option; import org.apache.commons.cli.ParseException; import org.apache.commons.lang3.tuple.Pair; +import org.apache.rat.document.DocumentName; import org.apache.rat.license.LicenseSetFactory; import org.apache.rat.report.IReportable; import org.apache.rat.test.AbstractOptionsProvider; @@ -46,6 +48,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import static java.lang.String.format; + import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -148,11 +151,12 @@ public void testDefaultConfiguration() throws ParseException { @ParameterizedTest @ValueSource(strings = { ".", "./", "target", "./target" }) public void getReportableTest(String fName) throws IOException { - File expected = new File(fName); + File base = new File(fName); + String expected = DocumentName.FSInfo.getDefault().normalize(base.getAbsolutePath()); ReportConfiguration config = OptionCollection.parseCommands(new String[]{fName}, o -> fail("Help called"), false); - IReportable reportable = OptionCollection.getReportable(expected, config); - assertNotNull(reportable, () -> format("'%s' returned null", fName)); - assertThat(reportable.getName().getName()).isEqualTo(expected.getAbsolutePath()); + IReportable reportable = OptionCollection.getReportable(base, config); + assertThat(reportable).as(() -> format("'%s' returned null", fName)).isNotNull(); + assertThat(reportable.getName().getName()).isEqualTo(expected); } /** 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 4e2461ce6..72ebff4be 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 @@ -114,8 +114,8 @@ public void archiveTypeAnalyserTest() throws Exception { private static Stream archiveProcessingTestData() { List lst = new ArrayList<>(); lst.add(Arguments.of(ReportConfiguration.Processing.NOTIFICATION, 0)); - lst.add(Arguments.of(ReportConfiguration.Processing.PRESENCE, 2)); - lst.add(Arguments.of(ReportConfiguration.Processing.ABSENCE, 3)); + lst.add(Arguments.of(ReportConfiguration.Processing.PRESENCE, 1)); + lst.add(Arguments.of(ReportConfiguration.Processing.ABSENCE, 2)); return lst.stream(); } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java index 0519cee82..922912674 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.stream.Stream; import org.apache.rat.document.DocumentName; +import org.apache.rat.document.FSInfoTest; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -40,7 +41,7 @@ void localizePatternTest(DocumentName baseName, String pattern, String expectedS public static Stream localizePatternData() { List lst = new ArrayList<>(); - DocumentName baseName = DocumentName.builder().setName("fileBeingRead").setBaseName("baseDir").setDirSeparator("/").build(); + DocumentName baseName = DocumentName.builder(FSInfoTest.UNIX).setName("fileBeingRead").setBaseName("baseDir").build(); lst.add(Arguments.of(baseName, "file", "/baseDir/file")); lst.add(Arguments.of(baseName, "!file", "!/baseDir/file")); diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java index def6ec447..31693e030 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java @@ -18,43 +18,217 @@ */ package org.apache.rat.document; +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; import java.io.File; +import java.io.FileFilter; +import java.io.FilenameFilter; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Stream; + +import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.tuple.Pair; +import org.apache.rat.config.exclusion.ExclusionUtils; +import org.apache.rat.document.DocumentName.FSInfo; + import org.assertj.core.util.Files; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mockito; -import static java.lang.String.format; import static org.assertj.core.api.Assertions.assertThat; +import static org.apache.rat.document.FSInfoTest.OSX; +import static org.apache.rat.document.FSInfoTest.UNIX; +import static org.apache.rat.document.FSInfoTest.WINDOWS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.any; public class DocumentNameTest { + public static DocumentName mkName(Path tempDir, FSInfo fsInfo) throws IOException { + File docFile = mkFile(tempDir.toFile(), fsInfo); + DocumentName result = DocumentName.builder(fsInfo).setName(docFile).build(); + DocumentName mocked = Mockito.spy(result); + + String fn = result.localized(FileSystems.getDefault().getSeparator()); + File file = tempDir.resolve(fn.substring(1)).toFile(); + File mockedFile = mkFile(file, fsInfo); + when(mocked.asFile()).thenReturn(mockedFile); + + assertThat(mocked.asFile()).isEqualTo(mockedFile); + return mocked; + } + + private static File[] listFiles(File file, FSInfo fsInfo) { + File[] fileList = file.listFiles(); + if (fileList == null) { + return fileList; + } + return Arrays.stream(fileList).map(f -> mkFile(f, fsInfo)).toArray(File[]::new); + } + + private static File[] listFiles(File file, FSInfo fsInfo, FileFilter filter) { + File[] fileList = file.listFiles(); + if (fileList == null) { + return fileList; + } + return Arrays.stream(fileList).map(f -> mkFile(f, fsInfo)).filter(filter::accept).toArray(File[]::new); + } + + private static File[] listFiles(File file, FSInfo fsInfo, FilenameFilter filter) { + File[] fileList = file.listFiles(); + if (fileList == null) { + return fileList; + } + return Arrays.stream(fileList).map(f -> mkFile(f, fsInfo)).filter(x -> filter.accept(x, x.getName())).toArray(File[]::new); + } + + public static File mkFile(final File file, final FSInfo fsInfo) { + File mockedFile = mock(File.class); + when(mockedFile.listFiles()).thenAnswer( env -> listFiles(file, fsInfo)); + when(mockedFile.listFiles(any(FilenameFilter.class))).thenAnswer( env -> listFiles(file, fsInfo, env.getArgument(0, FilenameFilter.class))); + when(mockedFile.listFiles(any(FileFilter.class))).thenAnswer(env -> listFiles(file, fsInfo, env.getArgument(0, FileFilter.class))); + when(mockedFile.getName()).thenReturn(ExclusionUtils.convertSeparator(file.getName(), FSInfoTest.DEFAULT.dirSeparator(), fsInfo.dirSeparator())); + when(mockedFile.getAbsolutePath()).thenReturn(ExclusionUtils.convertSeparator(file.getAbsolutePath(), FSInfoTest.DEFAULT.dirSeparator(), fsInfo.dirSeparator())); + when(mockedFile.isFile()).thenAnswer(env -> file.isFile()); + when(mockedFile.exists()).thenAnswer(emv -> file.exists()); + when(mockedFile.isDirectory()).thenAnswer(env -> file.isDirectory()); + + return mockedFile; + } + + public static DocumentName mkName(Path tempDir, DocumentName baseDir, String pth) throws IOException { + DocumentName result = baseDir.resolve(ExclusionUtils.convertSeparator(pth, "/", baseDir.getDirectorySeparator())); + DocumentName mocked = Mockito.spy(result); + + String fn = result.localized(FileSystems.getDefault().getSeparator()); + File file = tempDir.resolve(fn.substring(1)).toFile(); + File parent = file.getParentFile(); + if (parent.exists() && !parent.isDirectory()) { + parent.delete(); + } + parent.mkdirs(); + if (file.exists()) { + if (file.isDirectory()) { + FileUtils.deleteDirectory(file); + } else { + FileUtils.delete(file); + } + } + file.createNewFile(); + when(mocked.asFile()).thenReturn(file); + return mocked; + } + + + @ParameterizedTest(name = "{index} {0} {2}") + @MethodSource("resolveTestData") + void resolveTest(String testName, DocumentName base, String toResolve, DocumentName expected) { + DocumentName actual = base.resolve(toResolve); + assertThat(actual).isEqualTo(expected); + } + + private static Stream resolveTestData() { + List lst = new ArrayList<>(); + + DocumentName base = DocumentName.builder(UNIX).setName("/dir/unix").setBaseName("/").build(); + + DocumentName expected = DocumentName.builder(UNIX).setName("/dir/unix/relative").setBaseName("/").build(); + lst.add(Arguments.of("unix", base, "relative", expected)); + + expected = DocumentName.builder(UNIX).setName("/from/root").setBaseName("/").build(); + lst.add(Arguments.of("unix", base, "/from/root", expected)); + + expected = DocumentName.builder(UNIX).setName("dir/up/and/down").setBaseName("/").build(); + lst.add(Arguments.of("unix", base, "../up/and/down", expected)); + + expected = DocumentName.builder(UNIX).setName("/from/root").setBaseName("/").build(); + lst.add(Arguments.of("unix", base, "\\from\\root", expected)); + + expected = DocumentName.builder(UNIX).setName("dir/up/and/down").setBaseName("/").build(); + lst.add(Arguments.of("unix", base, "..\\up\\and\\down", expected)); + + // WINDOWS + base = DocumentName.builder(WINDOWS).setName("\\dir\\windows").setBaseName("C:\\").build(); + + expected = DocumentName.builder(WINDOWS).setName("\\dir\\windows\\relative").setBaseName("C:\\").build(); + lst.add(Arguments.of("windows", base, "relative", expected)); + + expected = DocumentName.builder(WINDOWS).setName("\\from\\root").setBaseName("C:\\").build(); + lst.add(Arguments.of("windows", base, "/from/root", expected)); + + expected = DocumentName.builder(WINDOWS).setName("dir\\up\\and\\down").setBaseName("C:\\").build(); + lst.add(Arguments.of("windows", base, "../up/and/down", expected)); + + expected = DocumentName.builder(WINDOWS).setName("\\from\\root").setBaseName("C:\\").build(); + lst.add(Arguments.of("windows", base, "\\from\\root", expected)); + + expected = DocumentName.builder(WINDOWS).setName("dir\\up\\and\\down").setBaseName("C:\\").build(); + lst.add(Arguments.of("windows", base, "..\\up\\and\\down", expected)); + + // OSX + base = DocumentName.builder(OSX).setName("/dir/osx").setBaseName("/").build(); + + expected = DocumentName.builder(OSX).setName("/dir/osx/relative").setBaseName("/").build(); + lst.add(Arguments.of("osx", base, "relative", expected)); + + expected = DocumentName.builder(OSX).setName("/from/root").setBaseName("/").build(); + lst.add(Arguments.of("osx", base, "/from/root", expected)); + + expected = DocumentName.builder(OSX).setName("dir/up/and/down").setBaseName("/").build(); + lst.add(Arguments.of("osx", base, "../up/and/down", expected)); + + expected = DocumentName.builder(OSX).setName("/from/root").setBaseName("/").build(); + lst.add(Arguments.of("osx", base, "\\from\\root", expected)); + + expected = DocumentName.builder(OSX).setName("dir/up/and/down").setBaseName("/").build(); + lst.add(Arguments.of("osx", base, "..\\up\\and\\down", expected)); + + return lst.stream(); + + } + @Test - public void localizeTest() { - DocumentName documentName = DocumentName.builder().setName("/a/b/c") - .setBaseName("/a").setDirSeparator("/").setCaseSensitive(false).build(); + void localizeTest() { + DocumentName documentName = DocumentName.builder(UNIX).setName("/a/b/c") + .setBaseName("/a").build(); + assertThat(documentName.localized()).isEqualTo("/b/c"); + assertThat(documentName.localized("-")).isEqualTo("-b-c"); + + documentName = DocumentName.builder(WINDOWS).setName("\\a\\b\\c") + .setBaseName("\\a").build(); + assertThat(documentName.localized()).isEqualTo("\\b\\c"); + assertThat(documentName.localized("-")).isEqualTo("-b-c"); + + documentName = DocumentName.builder(OSX).setName("/a/b/c") + .setBaseName("/a").build(); assertThat(documentName.localized()).isEqualTo("/b/c"); assertThat(documentName.localized("-")).isEqualTo("-b-c"); + } - @ParameterizedTest(name ="{index} {0}") + @ParameterizedTest(name = "{index} {0}") @MethodSource("validBuilderData") void validBuilderTest(String testName, DocumentName.Builder builder, String root, String name, String baseName, String dirSeparator) { DocumentName underTest = builder.build(); assertThat(underTest.getRoot()).as(testName).isEqualTo(root); assertThat(underTest.getDirectorySeparator()).as(testName).isEqualTo(dirSeparator); - assertThat(underTest.getName()).as(testName).isEqualTo(root+dirSeparator+name); - assertThat(underTest.getBaseName()).as(testName).isEqualTo(root+dirSeparator+baseName); + assertThat(underTest.getName()).as(testName).isEqualTo(root + dirSeparator + name); + assertThat(underTest.getBaseName()).as(testName).isEqualTo(root + dirSeparator + baseName); } - private static Stream validBuilderData() { + private static Stream validBuilderData() throws IOException { List lst = new ArrayList<>(); File f = Files.newTemporaryFile(); @@ -94,98 +268,67 @@ private static Stream validBuilderData() { lst.add(Arguments.of("setName(root)", DocumentName.builder().setName(r), root, "", "", File.separator)); lst.add(Arguments.of("Builder(root)", DocumentName.builder(r), root, "", "", File.separator)); - lst.add(Arguments.of("foo/bar foo", DocumentName.builder().setDirSeparator("/") + + lst.add(Arguments.of("foo/bar foo", DocumentName.builder(UNIX) .setName("/foo/bar").setBaseName("foo"), "", "foo/bar", "foo", "/")); - DocumentName.Builder builder = DocumentName.builder().setDirSeparator("\\").setName("\\foo\\bar").setBaseName("foo") + + DocumentName.Builder builder = DocumentName.builder(WINDOWS).setName("\\foo\\bar").setBaseName("C:\\foo") .setRoot("C:"); - lst.add(Arguments.of("C:\\foo\\bar foo", builder, "C:", "foo\\bar", "foo", "\\")); + lst.add(Arguments.of("\\foo\\bar foo", builder, "C:", "foo\\bar", "foo", "\\")); + + lst.add(Arguments.of("foo/bar foo", DocumentName.builder(OSX) + .setName("/foo/bar").setBaseName("foo"), "", "foo/bar", "foo", "/")); return lst.stream(); } @Test - public void splitRootsTest() { - Set preserve = new HashSet<>(DocumentName.ROOTS); - try { - DocumentName.ROOTS.clear(); - DocumentName.ROOTS.add("C:\\"); - Pair result = DocumentName.Builder.splitRoot("C:\\My\\path\\to\\a\\file.txt", "\\"); - assertThat(result.getLeft()).isEqualTo("C:"); - assertThat(result.getRight()).isEqualTo("My\\path\\to\\a\\file.txt"); - - - DocumentName.ROOTS.clear(); - DocumentName.ROOTS.add("/"); - result = DocumentName.Builder.splitRoot("/My/path/to/a/file.txt", "/"); - assertThat(result.getLeft()).isEqualTo(""); - assertThat(result.getRight()).isEqualTo("My/path/to/a/file.txt"); - - } finally { - DocumentName.ROOTS.clear(); - DocumentName.ROOTS.addAll(preserve); - } + void splitRootsTest() throws IOException { + Pair result = DocumentName.builder(WINDOWS).splitRoot("C:\\My\\path\\to\\a\\file.txt"); + assertThat(result.getLeft()).isEqualTo("C:"); + assertThat(result.getRight()).isEqualTo("My\\path\\to\\a\\file.txt"); + + result = DocumentName.builder(UNIX).splitRoot("/My/path/to/a/file.txt"); + assertThat(result.getLeft()).isEqualTo(""); + assertThat(result.getRight()).isEqualTo("My/path/to/a/file.txt"); + + result = DocumentName.builder(OSX).splitRoot("/My/path/to/a/file.txt"); + assertThat(result.getLeft()).isEqualTo(""); + assertThat(result.getRight()).isEqualTo("My/path/to/a/file.txt"); + } @Test - public void archiveEntryNameTest() { - Set preserve = new HashSet<>(DocumentName.ROOTS); - try { - DocumentName.ROOTS.clear(); - DocumentName.ROOTS.add("C:\\"); - - DocumentName archiveName = DocumentName.builder().setDirSeparator("\\") - .setName("C:\\archives\\anArchive.zip").setBaseName("archives").build(); - assertThat(archiveName.getRoot()).isEqualTo("C:"); - assertThat(archiveName.getDirectorySeparator()).isEqualTo("\\"); - assertThat(archiveName.getBaseName()).isEqualTo("C:\\archives"); - assertThat(archiveName.getName()).isEqualTo("C:\\archives\\anArchive.zip"); - assertThat(archiveName.localized()).isEqualTo("\\anArchive.zip"); - - String entryName = "./anArchiveEntry.txt"; - DocumentName innerName = DocumentName.builder() - .setDirSeparator("/").setName(entryName) - .setBaseName(".").setCaseSensitive(true).build(); - assertThat(innerName.getRoot()).isEqualTo(""); - assertThat(innerName.getDirectorySeparator()).isEqualTo("/"); - assertThat(innerName.getBaseName()).isEqualTo("/."); - assertThat(innerName.getName()).isEqualTo("/" + entryName); - assertThat(innerName.localized()).isEqualTo("/anArchiveEntry.txt"); - - String outerNameStr = format("%s#%s", archiveName.getName(), entryName); - DocumentName outerName = DocumentName.builder(archiveName).setName(outerNameStr) - .setCaseSensitive(innerName.isCaseSensitive()).build(); - - assertThat(outerName.getRoot()).isEqualTo("C:"); - assertThat(outerName.getDirectorySeparator()).isEqualTo("\\"); - assertThat(outerName.getBaseName()).isEqualTo("C:\\archives"); - assertThat(outerName.getName()).isEqualTo("C:\\archives\\anArchive.zip#./anArchiveEntry.txt"); - assertThat(outerName.localized()).isEqualTo("\\anArchive.zip#./anArchiveEntry.txt"); - assertThat(outerName.localized("/")).isEqualTo("/anArchive.zip#./anArchiveEntry.txt"); - - // test with directory - entryName = "./someDir/anArchiveEntry.txt"; - innerName = DocumentName.builder() - .setDirSeparator("/").setName(entryName) - .setBaseName(".").setCaseSensitive(true).build(); - assertThat(innerName.getRoot()).isEqualTo(""); - assertThat(innerName.getDirectorySeparator()).isEqualTo("/"); - assertThat(innerName.getBaseName()).isEqualTo("/."); - assertThat(innerName.getName()).isEqualTo("/" + entryName); - assertThat(innerName.localized()).isEqualTo("/someDir/anArchiveEntry.txt"); - - outerNameStr = format("%s#%s", archiveName.getName(), entryName); - outerName = DocumentName.builder(archiveName).setName(outerNameStr) - .setCaseSensitive(innerName.isCaseSensitive()).build(); - - assertThat(outerName.getRoot()).isEqualTo("C:"); - assertThat(outerName.getDirectorySeparator()).isEqualTo("\\"); - assertThat(outerName.getBaseName()).isEqualTo("C:\\archives"); - assertThat(outerName.getName()).isEqualTo("C:\\archives\\anArchive.zip#./someDir/anArchiveEntry.txt"); - assertThat(outerName.localized()).isEqualTo("\\anArchive.zip#./someDir/anArchiveEntry.txt"); - assertThat(outerName.localized("/")).isEqualTo("/anArchive.zip#./someDir/anArchiveEntry.txt"); - } finally { - DocumentName.ROOTS.clear(); - DocumentName.ROOTS.addAll(preserve); - } + void archiveEntryNameTest() throws IOException { + String entryName = "./anArchiveEntry.txt"; + DocumentName archiveName = DocumentName.builder(WINDOWS) + .setName("C:\\archives\\anArchive.zip").setBaseName("C:\\archives").build(); + + assertThat(archiveName.getRoot()).isEqualTo("C:"); + assertThat(archiveName.getDirectorySeparator()).isEqualTo("\\"); + assertThat(archiveName.getBaseName()).isEqualTo("C:\\archives"); + assertThat(archiveName.getName()).isEqualTo("C:\\archives\\anArchive.zip"); + assertThat(archiveName.localized()).isEqualTo("\\anArchive.zip"); + + + ArchiveEntryName archiveEntryName = new ArchiveEntryName(archiveName, entryName); + + assertThat(archiveEntryName.getRoot()).isEqualTo(archiveName.getName()+"#"); + assertThat(archiveEntryName.getDirectorySeparator()).isEqualTo("/"); + assertThat(archiveEntryName.getBaseName()).isEqualTo("C:\\archives\\anArchive.zip#"); + assertThat(archiveEntryName.getName()).isEqualTo("C:\\archives\\anArchive.zip#/anArchiveEntry.txt"); + assertThat(archiveEntryName.localized()).isEqualTo("/anArchiveEntry.txt"); + assertThat(archiveEntryName.localized("/")).isEqualTo("/anArchive.zip#/anArchiveEntry.txt"); + + // test with directory + entryName = "./someDir/anArchiveEntry.txt"; + archiveEntryName = new ArchiveEntryName(archiveName, entryName); + + assertThat(archiveEntryName.getRoot()).isEqualTo(archiveName.getName()+"#"); + assertThat(archiveEntryName.getDirectorySeparator()).isEqualTo("/"); + assertThat(archiveEntryName.getBaseName()).isEqualTo("C:\\archives\\anArchive.zip#"); + assertThat(archiveEntryName.getName()).isEqualTo("C:\\archives\\anArchive.zip#/someDir/anArchiveEntry.txt"); + assertThat(archiveEntryName.localized()).isEqualTo("/someDir/anArchiveEntry.txt"); + assertThat(archiveEntryName.localized("/")).isEqualTo("/anArchive.zip#/someDir/anArchiveEntry.txt"); } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/FSInfoTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/FSInfoTest.java new file mode 100644 index 000000000..db2f91ea2 --- /dev/null +++ b/apache-rat-core/src/test/java/org/apache/rat/document/FSInfoTest.java @@ -0,0 +1,60 @@ +/* + * 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 com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.params.provider.Arguments; + +public class FSInfoTest { + public static final DocumentName.FSInfo DEFAULT; + public static final DocumentName.FSInfo OSX; + public static final DocumentName.FSInfo UNIX; + public static final DocumentName.FSInfo WINDOWS; + + static { + try (FileSystem osx = Jimfs.newFileSystem(Configuration.osX()); + FileSystem unix = Jimfs.newFileSystem(Configuration.unix()); + FileSystem windows = Jimfs.newFileSystem(Configuration.windows())) { + OSX = new DocumentName.FSInfo("osx", osx); + UNIX = new DocumentName.FSInfo("unix", unix); + WINDOWS = new DocumentName.FSInfo("windows", windows); + DEFAULT = new DocumentName.FSInfo("default", FileSystems.getDefault()); + } catch (IOException e) { + throw new RuntimeException("Unable to creat FSInfo objects: " + e.getMessage(), e); + } + } + + public static final DocumentName.FSInfo[] TEST_SUITE = {UNIX, WINDOWS, OSX}; + + /** + * Provided arguments for parameterized tests that only require the fsInfo. + * @return a stream of TEST_SUITE based Arguments. + */ + public static Stream fsInfoArgs() { + return Arrays.stream(TEST_SUITE).map(Arguments::of); + } +} diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java index 2abf19340..87d157a0e 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.stream.Stream; import org.apache.rat.document.DocumentName; +import org.apache.rat.document.FSInfoTest; import org.apache.rat.testhelpers.TestingDocument; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -41,10 +42,8 @@ public void testMatches(DocumentName testingName, boolean expected) { private static Stream nameData() { List lst = new ArrayList<>(); - final DocumentName linuxBaseName = DocumentName.builder().setName("/").setBaseName("/").setDirSeparator("/") - .setCaseSensitive(true).build(); - final DocumentName windowsBaseName = DocumentName.builder().setName("\\").setBaseName("\\") - .setDirSeparator("\\").setCaseSensitive(false).build(); + final DocumentName linuxBaseName = DocumentName.builder(FSInfoTest.UNIX).setName("/").setBaseName("/").build(); + final DocumentName windowsBaseName = DocumentName.builder(FSInfoTest.WINDOWS).setName("\\").setBaseName("\\").build(); lst.add(Arguments.of(linuxBaseName.resolve("DEPENDENCIES"), true)); lst.add(Arguments.of(linuxBaseName.resolve("LICENSE"), true)); 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 c1e756687..532182b8e 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 @@ -50,13 +50,13 @@ public TestingDocument(DocumentName documentName) { } public TestingDocument(String name, DocumentNameMatcher matcher) { - super(DocumentName.builder().setName(name).setBaseName("").setDirSeparator("/").setCaseSensitive(true).build(), matcher); + super(DocumentName.builder().setName(name).setBaseName("").build(), matcher); this.reader = null; this.input = null; } public TestingDocument(Reader reader, String name) { - super(DocumentName.builder().setName(name).setBaseName("").setDirSeparator("/").setCaseSensitive(true).build(), DocumentNameMatcher.MATCHES_ALL); + super(DocumentName.builder().setName(name).setBaseName("").build(), DocumentNameMatcher.MATCHES_ALL); this.reader = reader; this.input = null; } diff --git a/pom.xml b/pom.xml index b181a2056..531a403e2 100644 --- a/pom.xml +++ b/pom.xml @@ -198,7 +198,7 @@ agnostic home for software distribution comprehension and audit tools. org.assertj assertj-core - 3.27.2 + 3.27.1 test @@ -217,6 +217,12 @@ agnostic home for software distribution comprehension and audit tools. 2.4.21 test + + com.google.jimfs + jimfs + 1.3.0 + test + @@ -489,7 +495,7 @@ agnostic home for software distribution comprehension and audit tools. org.apache.maven.plugins maven-remote-resources-plugin - 3.3.0 + 3.2.0 org.apache.maven.plugins From f9a46f61127c8cdfab0bdf5c46cb7500976ae2b2 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 12 Jan 2025 16:18:06 +0000 Subject: [PATCH 053/123] updated spotbugs --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 531a403e2..890ec493a 100644 --- a/pom.xml +++ b/pom.xml @@ -386,7 +386,7 @@ agnostic home for software distribution comprehension and audit tools. 4.8.6.6 - 94 + 98 true org.apache.rat.- From cefaff7e2329caee6e00029dda7bc98c10ba977f Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 12 Jan 2025 17:34:34 +0000 Subject: [PATCH 054/123] attempt to fix windows error --- .../org/apache/rat/walker/FileListWalkerTest.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java b/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java index 14ac1478b..9bc554029 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java @@ -33,8 +33,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; public class FileListWalkerTest { @@ -117,15 +116,13 @@ public static void setUp() throws Exception { @Test public void readFilesTest() throws RatException { - FileListWalker walker = new FileListWalker(new FileDocument(source, DocumentNameMatcher.MATCHES_ALL)); + FileDocument fileDocument = new FileDocument(source, DocumentNameMatcher.MATCHES_ALL); + FileListWalker walker = new FileListWalker(fileDocument); List scanned = new ArrayList<>(); walker.run(new TestRatReport(scanned)); String[] expected = {regularName.localized("/"), hiddenName.localized("/"), anotherName.localized("/")}; - assertEquals(3, scanned.size()); - for (String ex : expected) { - assertTrue(scanned.contains(ex), ()-> String.format("Missing %s from %s", ex, String.join(", ", scanned))); - } + assertThat(scanned).containsExactly(expected); } static class TestRatReport implements RatReport { From a46a244676557e0a65a5dd9e4c00808c39b85233 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 12 Jan 2025 18:00:11 +0000 Subject: [PATCH 055/123] fixed merge error --- .../test/java/org/apache/rat/testhelpers/TestingDocument.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 532182b8e..1bd66377b 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 @@ -29,6 +29,7 @@ import org.apache.rat.api.Document; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.document.DocumentName; +import org.apache.rat.document.FSInfoTest; public class TestingDocument extends Document { @@ -62,7 +63,7 @@ public TestingDocument(Reader reader, String name) { } public TestingDocument(IOSupplier inputStream, String name) { - super(DocumentName.builder().setName(name).setBaseName("").setDirSeparator("/").setCaseSensitive(true).build(), DocumentNameMatcher.MATCHES_ALL); + super(DocumentName.builder(FSInfoTest.UNIX).setName(name).setBaseName("").build(), DocumentNameMatcher.MATCHES_ALL); this.input = inputStream; this.reader = null; } From 103d9dbbf48c26c3c22a665da6c9fd38a239e58d Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Mon, 13 Jan 2025 23:43:39 +0000 Subject: [PATCH 056/123] fixed pattern match --- .../config/exclusion/ExclusionProcessor.java | 4 +- .../config/exclusion/plexus/MatchPattern.java | 2 +- .../exclusion/plexus/MatchPatterns.java | 40 +- .../rat/document/DocumentNameMatcher.java | 390 ++++++++++++++++-- 4 files changed, 370 insertions(+), 66 deletions(-) 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 e21432e03..105312930 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 @@ -255,10 +255,10 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { .addTo(new ArrayList<>()); if (!incl.isEmpty()) { - inclMatchers.add(new DocumentNameMatcher("included patterns", MatchPatterns.from(incl), basedir)); + inclMatchers.add(new DocumentNameMatcher("included patterns", MatchPatterns.from("/", incl), basedir)); } if (!excl.isEmpty()) { - exclMatchers.add(new DocumentNameMatcher("excluded patterns", MatchPatterns.from(excl), basedir)); + exclMatchers.add(new DocumentNameMatcher("excluded patterns", MatchPatterns.from("/", excl), basedir)); } if (!includedPaths.isEmpty()) { diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java index c43836ecd..c2c3ae7c9 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java @@ -49,7 +49,7 @@ public final class MatchPattern { private final char[][] tokenizedChar; - private MatchPattern(final String source, final String separator) { + MatchPattern(final String source, final String separator) { regexPattern = SelectorUtils.isRegexPrefixedPattern(source) ? source.substring( SelectorUtils.REGEX_HANDLER_PREFIX.length(), diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java index 454ba304e..9a6d443e4 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java @@ -22,8 +22,9 @@ import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import java.util.function.Predicate; +import java.util.stream.Collectors; @SuppressWarnings({"checkstyle:RegexpSingleLine", "checkstyle:JavadocVariable"}) /** @@ -41,15 +42,15 @@ private MatchPatterns(final MatchPattern[] patterns) { @Override public String toString() { - return source(); + return Arrays.stream(patterns).map(MatchPattern::toString).collect(Collectors.toList()).toString(); } public String source() { - List sources = new ArrayList<>(); - for (MatchPattern pattern : patterns) { - sources.add(pattern.source()); - } - return "[" + String.join(", ", sources) + "]"; + return Arrays.stream(patterns).map(MatchPattern::source).collect(Collectors.toList()).toString(); + } + + public Iterable patterns() { + return Arrays.asList(patterns); } /** @@ -83,36 +84,23 @@ public boolean matches(final String name, final char[][] tokenizedNameChar, fina return false; } - public Predicate asPredicate(final boolean isCaseSensitive) { - return name -> matches(name, isCaseSensitive); - } - - public boolean matchesPatternStart(final String name, final boolean isCaseSensitive) { - for (MatchPattern includesPattern : patterns) { - if (includesPattern.matchPatternStart(name, isCaseSensitive)) { - return true; - } - } - return false; - } - - public static MatchPatterns from(final String... sources) { + public static MatchPatterns from(final String separator, final String... sources) { final int length = sources.length; MatchPattern[] result = new MatchPattern[length]; for (int i = 0; i < length; i++) { - result[i] = MatchPattern.fromString(sources[i]); + result[i] = new MatchPattern(sources[i], separator); } return new MatchPatterns(result); } - public static MatchPatterns from(final Iterable strings) { - return new MatchPatterns(getMatchPatterns(strings)); + public static MatchPatterns from(final String separator, final Iterable strings) { + return new MatchPatterns(getMatchPatterns(separator, strings)); } - private static MatchPattern[] getMatchPatterns(final Iterable items) { + private static MatchPattern[] getMatchPatterns(final String separator, final Iterable items) { List result = new ArrayList<>(); for (String string : items) { - result.add(MatchPattern.fromString(string)); + result.add(new MatchPattern(string, separator)); } return result.toArray(new MatchPattern[0]); } diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 30bbbbede..0e66b19f7 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -23,9 +23,14 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Optional; +import java.util.Set; import java.util.function.Predicate; +import org.apache.rat.ConfigurationException; import org.apache.rat.config.exclusion.plexus.MatchPattern; import org.apache.rat.config.exclusion.plexus.MatchPatterns; @@ -40,6 +45,8 @@ public final class DocumentNameMatcher { private final Predicate predicate; /** The name of this matcher. */ private final String name; + /** {@code true} this this matcher is a collection of matchers */ + private final boolean isCollection; /** * A matcher that matches all documents. @@ -59,6 +66,7 @@ public final class DocumentNameMatcher { public DocumentNameMatcher(final String name, final Predicate predicate) { this.name = name; this.predicate = predicate; + this.isCollection = predicate instanceof CollectionPredicateImpl; } /** @@ -77,9 +85,22 @@ public DocumentNameMatcher(final String name, final DocumentNameMatcher delegate * @param basedir the base directory for the scanning. */ public DocumentNameMatcher(final String name, final MatchPatterns patterns, final DocumentName basedir) { - this(name, (Predicate) documentName -> patterns.matches(documentName.getName(), - MatchPattern.tokenizePathToString(documentName.getName(), basedir.getDirectorySeparator()), - basedir.isCaseSensitive())); + this(name, new MatchPatternsPredicate(basedir, patterns)); + } + + /** + * Tokenizes name for faster Matcher processing. + * @param name the name to tokenize + * @param dirSeparator the directory separator + * @return the tokenized name. + */ + private static char[][] tokenize(final String name, final String dirSeparator) { + String[] tokenizedName = MatchPattern.tokenizePathToString(name, dirSeparator); + char[][] tokenizedNameChar = new char[tokenizedName.length][]; + for (int i = 0; i < tokenizedName.length; i++) { + tokenizedNameChar[i] = tokenizedName[i].toCharArray(); + } + return tokenizedNameChar; } /** @@ -88,7 +109,20 @@ public DocumentNameMatcher(final String name, final MatchPatterns patterns, fina * @param matchers fully specified matchers. */ public DocumentNameMatcher(final String name, final MatchPatterns matchers) { - this(name, (Predicate) documentName -> matchers.matches(documentName.getName(), documentName.isCaseSensitive())); + this(name, new CollectionPredicate() { + @Override + public Iterable getMatchers() { + final List result = new ArrayList<>(); + matchers.patterns().forEach(p -> result.add(new DocumentNameMatcher(p.source(), + (Predicate) x -> MatchPatterns.from("/", p.source()).matches(x.getName(), x.isCaseSensitive())))); + return result; + } + + @Override + public boolean test(final DocumentName documentName) { + return matchers.matches(documentName.getName(), documentName.isCaseSensitive()); + } + }); } /** @@ -97,7 +131,7 @@ public DocumentNameMatcher(final String name, final MatchPatterns matchers) { * @param fileFilter the file filter to execute. */ public DocumentNameMatcher(final String name, final FileFilter fileFilter) { - this(name, (Predicate) documentName -> fileFilter.accept(new File(documentName.getName()))); + this(name, new FileFilterPredicate(fileFilter)); } /** @@ -108,11 +142,39 @@ public DocumentNameMatcher(final FileFilter fileFilter) { this(fileFilter.toString(), fileFilter); } + public boolean isCollection() { + return isCollection; + } + + /** + * Returns the predicate that this DocumentNameMatcher is using. + * @return The predicate that this DocumentNameMatcher is using. + */ + public Predicate getPredicate() { + return predicate; + } + @Override public String toString() { return name; } + /** + * Decomposes the matcher execution against the candidate. + * @param candidate the candiate to check. + * @return a list of {@link DecomposeData} for each evaluation in the matcher. + */ + public List decompose(final DocumentName candidate) { + final List result = new ArrayList<>(); + decompose(0, this, candidate, result); + return result; + } + + private void decompose(final int level, final DocumentNameMatcher matcher, final DocumentName candidate, final List result) { + final Predicate pred = matcher.getPredicate(); + result.add(new DecomposeData(level, matcher, candidate, pred.test(candidate))); + } + /** * Performs the match against the DocumentName. * @param documentName the document name to check. @@ -135,8 +197,7 @@ public static DocumentNameMatcher not(final DocumentNameMatcher nameMatcher) { return MATCHES_ALL; } - return new DocumentNameMatcher(format("not(%s)", nameMatcher), - (Predicate) documentName -> !nameMatcher.matches(documentName)); + return new DocumentNameMatcher(format("not(%s)", nameMatcher), new NotPredicate(nameMatcher)); } /** @@ -150,30 +211,43 @@ private static String join(final Collection matchers) { return String.join(", ", children); } + private static Optional standardCollectionCheck(final Collection matchers, + final DocumentNameMatcher override) { + if (matchers.isEmpty()) { + throw new ConfigurationException("Empty matcher collection"); + } + if (matchers.size() == 1) { + return Optional.of(matchers.iterator().next()); + } + if (matchers.contains(override)) { + return Optional.of(override); + } + return Optional.empty(); + } + /** * Performs a logical {@code OR} across the collection of matchers. * @param matchers the matchers to check. * @return a matcher that returns {@code true} if any of the enclosed matchers returns {@code true}. */ public static DocumentNameMatcher or(final Collection matchers) { - if (matchers.isEmpty()) { - return MATCHES_NONE; - } - if (matchers.size() == 1) { - return matchers.iterator().next(); - } - if (matchers.contains(MATCHES_ALL)) { - return MATCHES_ALL; + Optional opt = standardCollectionCheck(matchers, MATCHES_ALL); + if (opt.isPresent()) { + return opt.get(); } - return new DocumentNameMatcher(format("or(%s)", join(matchers)), (Predicate) documentName -> { - for (DocumentNameMatcher matcher : matchers) { - if (matcher.matches(documentName)) { - return true; - } - } - return false; - }); + // preserve order + Set workingSet = new LinkedHashSet<>(); + for (DocumentNameMatcher matcher : matchers) { + // check for nested or + if (matcher.predicate instanceof Or) { + ((Or) matcher.predicate).getMatchers().forEach(workingSet::add); + } else { + workingSet.add(matcher); + } + } + return standardCollectionCheck(matchers, MATCHES_ALL) + .orElseGet(() -> new DocumentNameMatcher(format("or(%s)", join(workingSet)), new Or(workingSet))); } /** @@ -191,24 +265,45 @@ public static DocumentNameMatcher or(final DocumentNameMatcher... matchers) { * @return a matcher that returns {@code true} if all the enclosed matchers return {@code true}. */ public static DocumentNameMatcher and(final Collection matchers) { - if (matchers.isEmpty()) { - return MATCHES_NONE; - } - if (matchers.size() == 1) { - return matchers.iterator().next(); + Optional opt = standardCollectionCheck(matchers, MATCHES_NONE); + if (opt.isPresent()) { + return opt.get(); } - if (matchers.contains(MATCHES_NONE)) { - return MATCHES_NONE; + + // preserve order + Set workingSet = new LinkedHashSet<>(); + for (DocumentNameMatcher matcher : matchers) { + // check for nexted And + if (matcher.predicate instanceof And) { + ((And) matcher.predicate).getMatchers().forEach(workingSet::add); + } else { + workingSet.add(matcher); + } } + opt = standardCollectionCheck(matchers, MATCHES_NONE); + return opt.orElseGet(() -> new DocumentNameMatcher(format("and(%s)", join(workingSet)), new And(workingSet))); + } - return new DocumentNameMatcher(format("and(%s)", join(matchers)), (Predicate) documentName -> { - for (DocumentNameMatcher matcher : matchers) { - if (!matcher.matches(documentName)) { - return false; - } + /** + * A particular matcher that will not match any excluded unless they are listed in the includes. + * @param includes the DocumentNameMatcher to match the includes. + * @param excludes the DocumentNameMatcher to match the excludes. + * @return a DocumentNameMatcher with the specified logic. + */ + public static DocumentNameMatcher matcherSet(final DocumentNameMatcher includes, + final DocumentNameMatcher excludes) { + if (excludes == MATCHES_NONE) { + return MATCHES_ALL; + } else { + if (includes == MATCHES_NONE) { + return not(excludes); } - return true; - }); + } + if (includes == MATCHES_ALL) { + return MATCHES_ALL; + } + List workingSet = Arrays.asList(includes, excludes); + return new DocumentNameMatcher(format("matcherSet(%s)", join(workingSet)), new MatcherPredicate(workingSet)); } /** @@ -219,4 +314,225 @@ public static DocumentNameMatcher and(final Collection matc public static DocumentNameMatcher and(final DocumentNameMatcher... matchers) { return and(Arrays.asList(matchers)); } + + + + /** + * A DocumentName predicate that uses MatchPatterns. + */ + public static final class MatchPatternsPredicate implements Predicate { + /** The base diirectory for the pattern matches */ + private final DocumentName basedir; + /** The patter matchers */ + private final MatchPatterns patterns; + + private MatchPatternsPredicate(final DocumentName basedir, final MatchPatterns patterns) { + this.basedir = basedir; + this.patterns = patterns; + } + + @Override + public boolean test(final DocumentName documentName) { + return patterns.matches(documentName.getName(), + tokenize(documentName.getName(), basedir.getDirectorySeparator()), + basedir.isCaseSensitive()); + } + + @Override + public String toString() { + return patterns.toString(); + } + } + + /** + * A DocumentName predicate reverses another DocumentNameMatcher + */ + public static final class NotPredicate implements Predicate { + /** The document name matcher to reverse */ + private final DocumentNameMatcher nameMatcher; + + private NotPredicate(final DocumentNameMatcher nameMatcher) { + this.nameMatcher = nameMatcher; + } + + @Override + public boolean test(final DocumentName documentName) { + return !nameMatcher.matches(documentName); + } + + @Override + public String toString() { + return nameMatcher.predicate.toString(); + } + } + + /** + * A DocumentName predicate that uses FileFilter. + */ + public static final class FileFilterPredicate implements Predicate { + /** The file filter */ + private final FileFilter fileFilter; + + private FileFilterPredicate(final FileFilter fileFilter) { + this.fileFilter = fileFilter; + } + + @Override + public boolean test(final DocumentName documentName) { + return fileFilter.accept(new File(documentName.getName())); + } + + @Override + public String toString() { + return fileFilter.toString(); + } + } + + interface CollectionPredicate extends Predicate { + Iterable getMatchers(); + } + /** + * A marker interface to indicate this predicate contains a collection of matchers. + */ + abstract static class CollectionPredicateImpl implements CollectionPredicate { + /** The collection for matchers that make up this predicate */ + private final Iterable matchers; + + /** + * Constructs a collecton predicate from the collection of matchers + * @param matchers the colleciton of matchers to use. + */ + protected CollectionPredicateImpl(final Iterable matchers) { + this.matchers = matchers; + } + + /** + * Gets the internal matchers. + * @return an iterable over the internal matchers. + */ + public Iterable getMatchers() { + return matchers; + } + + public String toString() { + StringBuilder builder = new StringBuilder(this.getClass().getName()).append(": ").append(System.lineSeparator()); + for (DocumentNameMatcher matcher : matchers) { + builder.append(matcher.predicate.toString()).append(System.lineSeparator()); + } + return builder.toString(); + } + } + + /** + * An implementation of "and" logic across a collection of DocumentNameMatchers. + */ + // package private for testing access + static class And extends CollectionPredicateImpl { + And(final Iterable matchers) { + super(matchers); + } + + @Override + public boolean test(final DocumentName documentName) { + for (DocumentNameMatcher matcher : getMatchers()) { + if (!matcher.matches(documentName)) { + return false; + } + } + return true; + } + } + + /** + * An implementation of "or" logic across a collection of DocumentNameMatchers. + */ + // package private for testing access + static class Or extends CollectionPredicateImpl { + Or(final Iterable matchers) { + super(matchers); + } + + @Override + public boolean test(final DocumentName documentName) { + for (DocumentNameMatcher matcher : getMatchers()) { + if (matcher.matches(documentName)) { + return true; + } + } + return false; + } + } + + /** + * An implementation of "or" logic across a collection of DocumentNameMatchers. + */ + // package private for testing access + static class MatcherPredicate extends CollectionPredicateImpl { + MatcherPredicate(final Iterable matchers) { + super(matchers); + } + + @Override + public boolean test(final DocumentName documentName) { + Iterator iter = getMatchers().iterator(); + // included + if (iter.next().matches(documentName)) { + return true; + } + // excluded + if (iter.next().matches(documentName)) { + return false; + } + return true; + } + } + + /** + * Data from a {@link DocumentNameMatcher#decompose(DocumentName)} call. + */ + public static final class DecomposeData { + /** the level this data was generated at */ + private final int level; + /** The name of the DocumentNameMatcher that created this result */ + private final DocumentNameMatcher matcher; + /** The result of the check. */ + private final boolean result; + /** The candidate */ + private final DocumentName candidate; + + private DecomposeData(final int level, final DocumentNameMatcher matcher, final DocumentName candidate, final boolean result) { + this.level = level; + this.matcher = matcher; + this.result = result; + this.candidate = candidate; + } + + @Override + public String toString() { + final String fill = createFill(level); + return format("%s%s: >>%s<< %s%n%s", + fill, matcher.toString(), result, + level == 0 ? candidate.getName() : "", + matcher.predicate instanceof CollectionPredicate ? + decompose(level + 1, (CollectionPredicate) matcher.predicate, candidate) : + String.format("%s%s >>%s<<", createFill(level + 1), matcher.predicate.toString(), matcher.predicate.test(candidate))); + } + + private String createFill(final int level) { + final char[] chars = new char[level * 2]; + Arrays.fill(chars, ' '); + return new String(chars); + } + + private String decompose(final int level, final CollectionPredicate predicate, final DocumentName candidate) { + List result = new ArrayList<>(); + + for (DocumentNameMatcher nameMatcher : predicate.getMatchers()) { + nameMatcher.decompose(level, nameMatcher, candidate, result); + } + StringBuilder sb = new StringBuilder(); + result.forEach(x -> sb.append(x).append(System.lineSeparator())); + return sb.toString(); + } + } } From 507600946bfae60e399010011034ce7269f478a0 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Tue, 14 Jan 2025 17:50:37 +0000 Subject: [PATCH 057/123] fix for file delete on windows --- .../test/java/org/apache/rat/mp/OptionMojoTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java index 67b71126d..58c0aea9f 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java @@ -31,8 +31,11 @@ import org.apache.rat.plugin.BaseRatMojo; import org.codehaus.plexus.component.configurator.ComponentConfigurationException; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsProvider; @@ -68,6 +71,16 @@ static void preserveData() { AbstractOptionsProvider.preserveData(testPath.toFile(), "optionTest"); } + /** + * This method is a known workaround for + * {@link junit 5 issue #2811 }. + */ + @AfterEach + @EnabledOnOs(OS.WINDOWS) + void cleanUp() { + System.gc(); + } + @ParameterizedTest @ArgumentsSource(MojoOptionsProvider.class) void testOptionsUpdateConfig(String name, OptionCollectionTest.OptionTest test) { From 818618f21d572fab83bb03cbc53acacc0a8798f5 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Tue, 14 Jan 2025 18:12:26 +0000 Subject: [PATCH 058/123] added more descriptive failure messages --- .../rat/config/exclusion/ExclusionProcessorTest.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/ExclusionProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/ExclusionProcessorTest.java index 580d10849..f8535a90b 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/ExclusionProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/ExclusionProcessorTest.java @@ -51,7 +51,13 @@ public void setup() { } private void testParseExclusion(DocumentNameMatcher nameMatcher, DocumentName name, boolean expected) { - assertThat(nameMatcher.matches(name)).as(() -> format("Failed on [%s %s]", basedir, name)).isEqualTo(expected); + assertThat(nameMatcher.matches(name)).as(() -> format("Failed on [%s %s]%n%s", basedir, name, dump(nameMatcher, name))).isEqualTo(expected); + } + + private String dump(DocumentNameMatcher nameMatcher, DocumentName name) { + StringBuilder sb = new StringBuilder(); + nameMatcher.decompose(name).forEach(s -> sb.append(s).append("\n")); + return sb.toString(); } private DocumentName mkName(String pth) { From a0bd888a73838cbc341f5ac71df6ffe689e592ff Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Tue, 14 Jan 2025 18:34:22 +0000 Subject: [PATCH 059/123] added file converter + test --- .../java/org/apache/rat/commandline/Arg.java | 36 +++++++------ .../apache/rat/commandline/Converters.java | 51 ++++++++++++++++++- .../org/apache/rat/commandline/ArgTests.java | 17 ++++--- 3 files changed, 80 insertions(+), 24 deletions(-) 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 3ba85b95a..293b93bcd 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 @@ -119,10 +119,14 @@ public enum Arg { CONFIGURATION(new OptionGroup() .addOption(Option.builder().longOpt("config").hasArgs().argName("File") .desc("File names for system configuration.") + .converter(Converters.FILE_CONVERTER) + .type(File.class) .build()) .addOption(Option.builder().longOpt("licenses").hasArgs().argName("File") .desc("File names for system configuration.") .deprecated(DeprecatedAttributes.builder().setSince("0.17").setForRemoval(true).setDescription(StdMsgs.useMsg("--config")).get()) + .converter(Converters.FILE_CONVERTER) + .type(File.class) .build())), /** @@ -186,7 +190,6 @@ public enum Arg { .hasArg().argName("File").type(File.class) .converter(Converters.FILE_CONVERTER) .desc("Name of file containing the denied license IDs.") - .converter(Converters.FILE_CONVERTER) .build())), /** @@ -234,6 +237,7 @@ public enum Arg { "File names must use linux directory separator ('/') or none at all. " + "File names that do not start with '/' are relative to the directory where the " + "argument is located.") + .converter(Converters.FILE_CONVERTER) .type(File.class) .build())), @@ -585,8 +589,9 @@ private static void processConfigurationArgs(final ArgumentContext context) thro try { Defaults.Builder defaultBuilder = Defaults.builder(); if (CONFIGURATION.isSelected()) { - for (String fn : context.getCommandLine().getOptionValues(CONFIGURATION.getSelected())) { - defaultBuilder.add(fn); + File[] files = CONFIGURATION.getParsedOptionValues(context.getCommandLine()); + for (File file : files) { + defaultBuilder.add(file); } } if (CONFIGURATION_NO_DEFAULTS.isSelected()) { @@ -607,7 +612,7 @@ private static void processConfigurationArgs(final ArgumentContext context) thro try (InputStream in = Files.newInputStream(f.toPath())) { context.getConfiguration().addApprovedLicenseCategories(IOUtils.readLines(in, StandardCharsets.UTF_8)); } - } catch (IOException | ParseException e) { + } catch (IOException e) { throw new ConfigurationException(e); } } @@ -622,7 +627,7 @@ private static void processConfigurationArgs(final ArgumentContext context) thro try (InputStream in = Files.newInputStream(f.toPath())) { context.getConfiguration().removeApprovedLicenseCategories(IOUtils.readLines(in, StandardCharsets.UTF_8)); } - } catch (IOException | ParseException e) { + } catch (IOException e) { throw new ConfigurationException(e); } } @@ -634,11 +639,11 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (LICENSES_APPROVED_FILE.isSelected()) { try { - File f = context.getCommandLine().getParsedOptionValue(LICENSES_APPROVED_FILE.getSelected()); - try (InputStream in = Files.newInputStream(f.toPath())) { + File file = context.getCommandLine().getParsedOptionValue(LICENSES_APPROVED_FILE.getSelected()); + try (InputStream in = Files.newInputStream(file.toPath())) { context.getConfiguration().addApprovedLicenseIds(IOUtils.readLines(in, StandardCharsets.UTF_8)); } - } catch (IOException | ParseException e) { + } catch (IOException e) { throw new ConfigurationException(e); } } @@ -649,11 +654,11 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (LICENSES_DENIED_FILE.isSelected()) { try { - File f = context.getCommandLine().getParsedOptionValue(LICENSES_DENIED_FILE.getSelected()); - try (InputStream in = Files.newInputStream(f.toPath())) { + File file = context.getCommandLine().getParsedOptionValue(LICENSES_DENIED_FILE.getSelected()); + try (InputStream in = Files.newInputStream(file.toPath())) { context.getConfiguration().removeApprovedLicenseIds(IOUtils.readLines(in, StandardCharsets.UTF_8)); } - } catch (IOException | ParseException e) { + } catch (IOException e) { throw new ConfigurationException(e); } } @@ -795,6 +800,7 @@ public static void processLogLevel(final CommandLine commandLine) { * @throws ConfigurationException on error */ public static void processArgs(final ArgumentContext context) throws ConfigurationException { + Converters.FILE_CONVERTER.setWorkingDirectory(context.getWorkingDirectory()); processOutputArgs(context); processEditArgs(context); processInputArgs(context); @@ -843,12 +849,12 @@ private static void processOutputArgs(final ArgumentContext context) { if (OUTPUT_FILE.isSelected()) { try { - File f = context.getCommandLine().getParsedOptionValue(OUTPUT_FILE.getSelected()); - File parent = f.getParentFile(); + File file = context.getCommandLine().getParsedOptionValue(OUTPUT_FILE.getSelected()); + File parent = file.getParentFile(); if (!parent.mkdirs() && !parent.isDirectory()) { - DefaultLog.getInstance().error("Could not create report parent directory " + f); + DefaultLog.getInstance().error("Could not create report parent directory " + file); } - context.getConfiguration().setOut(f); + context.getConfiguration().setOut(file); } catch (ParseException e) { context.logParseException(e, OUTPUT_FILE.getSelected(), "System.out"); context.getConfiguration().setOut((IOSupplier) null); 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 197703f93..8f5fc1c66 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 @@ -19,10 +19,12 @@ package org.apache.rat.commandline; import java.io.File; +import java.io.IOException; import org.apache.commons.cli.Converter; import org.apache.commons.lang3.tuple.Pair; import org.apache.rat.ConfigurationException; +import org.apache.rat.document.DocumentName; import org.apache.rat.report.claim.ClaimStatistic; import static java.lang.String.format; @@ -39,7 +41,8 @@ private Converters() { /** * Creates a File with fully qualified name */ - public static final Converter FILE_CONVERTER = s -> new File(s).getAbsoluteFile(); + public static final FileConverter FILE_CONVERTER = new FileConverter(); + /** * converts the Converter pattern into a Converter, count pair. */ @@ -55,4 +58,50 @@ private Converters() { throw new ConfigurationException(format("'%s' is not a valid Counter", parts[0]), e); } }; + + /** + * A converter that can handle relative or absolute files. + */ + public static final class FileConverter implements Converter { + /** The working directory to resolve relative files agains */ + private DocumentName workingDirectory; + + /** + * The constructor. + */ + private FileConverter() { + // private construction only. + } + + /** + * Sets the working directory for the conversion. + * @param workingDirectory + */ + public void setWorkingDirectory(final DocumentName workingDirectory) { + this.workingDirectory = workingDirectory; + } + + /** + * Applies the conversion function to the specified file name. + * @param fileName the file name to create a file from. + * @return a File. + * @throws NullPointerException if {@code fileName} is null. + */ + public File apply(final String fileName) throws NullPointerException { + File file = new File(fileName); + // is this a relative file? + if (!fileName.startsWith(File.separator)) { + // check for a root provided (e.g. C:\\)" + if (!DocumentName.FSInfo.getDefault().rootFor(fileName).isPresent()) { + // no root, resolve against workingDirectory + file = new File(workingDirectory.resolve(fileName).getName()).getAbsoluteFile(); + } + } + try { + return file.getCanonicalFile(); + } catch (IOException e) { + return file.getAbsoluteFile(); + } + } + } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java index fc4c980f9..7f27cb8d1 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java +++ b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java @@ -18,6 +18,7 @@ */ package org.apache.rat.commandline; +import java.io.IOException; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.Options; @@ -25,13 +26,13 @@ import org.apache.rat.DeprecationReporter; import org.apache.rat.OptionCollection; import org.apache.rat.ReportConfiguration; +import org.apache.rat.document.DocumentName; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; - import java.io.File; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; public class ArgTests { @@ -41,9 +42,9 @@ private CommandLine createCommandLine(String[] args) throws ParseException { .setAllowPartialMatching(true).build().parse(opts, args); } - @ParameterizedTest + @ParameterizedTest(name = "{0}") @ValueSource(strings = { "rat.txt", "./rat.txt", "/rat.txt", "target/rat.test" }) - public void outputFleNameNoDirectoryTest(String name) throws ParseException { + public void outputFleNameNoDirectoryTest(String name) throws ParseException, IOException { class OutputFileConfig extends ReportConfiguration { private File actual = null; @Override @@ -51,13 +52,13 @@ public void setOut(File file) { actual = file; } } + String fileName = name.replace("/", DocumentName.FSInfo.getDefault().dirSeparator()); + File expected = new File(fileName); - File expected = new File(name); - - CommandLine commandLine = createCommandLine(new String[] {"--output-file", name}); + CommandLine commandLine = createCommandLine(new String[] {"--output-file", fileName}); OutputFileConfig configuration = new OutputFileConfig(); ArgumentContext ctxt = new ArgumentContext(new File("."), configuration, commandLine); Arg.processArgs(ctxt); - assertEquals(expected.getAbsolutePath(), configuration.actual.getAbsolutePath()); + assertThat(configuration.actual.getAbsolutePath()).isEqualTo(expected.getCanonicalPath()); } } From 12d4f1c32758d7ae3010389e6efcd9c14772e74d Mon Sep 17 00:00:00 2001 From: "P. Ottlinger" Date: Tue, 14 Jan 2025 22:57:55 +0100 Subject: [PATCH 060/123] Minor cleanups --- .../apache/rat/commandline/ArgumentContext.java | 2 +- .../apache/rat/document/DocumentNameMatcher.java | 15 +++++++-------- .../apache/rat/test/AbstractOptionsProvider.java | 2 +- .../java/org/apache/rat/test/utils/Resources.java | 15 +++++++-------- .../java/org/apache/rat/testhelpers/XmlUtils.java | 8 ++++---- 5 files changed, 20 insertions(+), 22 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java b/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java index b69c5b7f8..ea672bc8d 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java +++ b/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java @@ -87,7 +87,7 @@ public CommandLine getCommandLine() { /** * Gets the directory name from which relative file names will be resolved. - * @return The directory name from which releative file names will be resolved. + * @return The directory name from which relative file names will be resolved. */ public DocumentName getWorkingDirectory() { return workingDirectory; diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 0e66b19f7..b61b4c178 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -45,7 +45,7 @@ public final class DocumentNameMatcher { private final Predicate predicate; /** The name of this matcher. */ private final String name; - /** {@code true} this this matcher is a collection of matchers */ + /** {@code true} if this matcher is a collection of matchers. */ private final boolean isCollection; /** @@ -315,15 +315,13 @@ public static DocumentNameMatcher and(final DocumentNameMatcher... matchers) { return and(Arrays.asList(matchers)); } - - /** * A DocumentName predicate that uses MatchPatterns. */ public static final class MatchPatternsPredicate implements Predicate { - /** The base diirectory for the pattern matches */ + /** The base directory for the pattern matches */ private final DocumentName basedir; - /** The patter matchers */ + /** The pattern matchers */ private final MatchPatterns patterns; private MatchPatternsPredicate(final DocumentName basedir, final MatchPatterns patterns) { @@ -345,7 +343,7 @@ public String toString() { } /** - * A DocumentName predicate reverses another DocumentNameMatcher + * A DocumentName predicate that reverses another DocumentNameMatcher. */ public static final class NotPredicate implements Predicate { /** The document name matcher to reverse */ @@ -399,7 +397,7 @@ abstract static class CollectionPredicateImpl implements CollectionPredicate { private final Iterable matchers; /** - * Constructs a collecton predicate from the collection of matchers + * Constructs a collection predicate from the collection of matchers. * @param matchers the colleciton of matchers to use. */ protected CollectionPredicateImpl(final Iterable matchers) { @@ -414,6 +412,7 @@ public Iterable getMatchers() { return matchers; } + @Override public String toString() { StringBuilder builder = new StringBuilder(this.getClass().getName()).append(": ").append(System.lineSeparator()); for (DocumentNameMatcher matcher : matchers) { @@ -491,7 +490,7 @@ public boolean test(final DocumentName documentName) { * Data from a {@link DocumentNameMatcher#decompose(DocumentName)} call. */ public static final class DecomposeData { - /** the level this data was generated at */ + /** The level this data was generated at */ private final int level; /** The name of the DocumentNameMatcher that created this result */ private final DocumentNameMatcher matcher; 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 d508e39f8..57c5a0518 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 @@ -247,7 +247,7 @@ protected DocumentName mkDocName(String name) { /* tests to be implemented */ protected abstract void helpTest(); - /** Displayd the option and value under test */ + /* Display the option and value under test */ private String displayArgAndName(Option option, String fname) { return String.format("%s %s", option.getLongOpt(), fname); } diff --git a/apache-rat-core/src/test/java/org/apache/rat/test/utils/Resources.java b/apache-rat-core/src/test/java/org/apache/rat/test/utils/Resources.java index 67a96afd9..8f52f2879 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/test/utils/Resources.java +++ b/apache-rat-core/src/test/java/org/apache/rat/test/utils/Resources.java @@ -47,7 +47,7 @@ private Resources() { private static final File RESOURCE_BASE_PATH = new File(SRC_MAIN_RESOURCES); /** - * Locates a test resource file in the class path. + * Locates a test resource file in the classpath. */ public static File getResourceFile(String pResource) throws IOException { File f = getResourceFromBase(TEST_RESOURCE_BASE_PATH, pResource); @@ -58,17 +58,16 @@ public static File getResourceFile(String pResource) throws IOException { } /** - * Locates a test resource directory in the class path. + * Locates a test resource directory in the classpath. */ public static File getResourceDirectory(String pResource) throws IOException { File f = getResourceFromBase(TEST_RESOURCE_BASE_PATH, pResource); if (!f.isDirectory()) { - throw new FileNotFoundException("Unable to locate resource file: " + pResource); + throw new FileNotFoundException("Unable to locate resource directory: " + pResource); } return f; } - /** * Locates a file in the unpacked example data archive. * @param pResource the name of the resource to find. @@ -81,7 +80,7 @@ public static File getExampleResource(String pResource) { } /** - * Try to load the given file from baseDir, in case of errors try to add + * Try to load the given file from baseDir. In case of errors try to add * module names to fix behaviour from within IntelliJ. */ private static File getResourceFromBase(File baseDir, String pResource) throws IOException { @@ -103,21 +102,21 @@ public static File[] getResourceFiles(String pResource) throws IOException { } /** - * Locates a resource file in the class path and returns an {@link InputStream}. + * Locates a resource file in the classpath and returns an {@link InputStream}. */ public static InputStream getResourceStream(String pResource) throws IOException { return Files.newInputStream(getResourceFile(pResource).toPath()); } /** - * Locates a resource file in the class path and returns a {@link Reader}. + * Locates a resource file in the classpath and returns a {@link Reader}. */ public static Reader getResourceReader(String pResource) throws IOException { return new InputStreamReader(getResourceStream(pResource), StandardCharsets.UTF_8); } /** - * Locates a resource file in the class path and returns a + * Locates a resource file in the classpath and returns a * {@link BufferedReader}. */ public static BufferedReader getBufferedReader(File file) throws IOException { 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 69b2b00b0..e2a1bbe3f 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 @@ -175,13 +175,13 @@ public static String getAttribute(Object source, XPath xPath, String xpath, Stri Node node = XmlUtils.getNode(source, xPath, xpath); NamedNodeMap attr = node.getAttributes(); node = attr.getNamedItem(attribute); - assertThat(node).as(attribute+" was not found").isNotNull(); + assertThat(node).as(attribute + " was not found").isNotNull(); return node.getNodeValue(); } public static Map mapOf(String... parts) { Map map = new HashMap<>(); - for (int i=0; i Date: Tue, 14 Jan 2025 23:36:38 +0100 Subject: [PATCH 061/123] Minor fixes --- .../rat/config/exclusion/plexus/MatchPatterns.java | 2 +- .../org/apache/rat/document/DocumentNameMatcher.java | 9 +++------ .../test/java/org/apache/rat/OptionCollectionTest.java | 3 --- .../src/test/java/org/apache/rat/ReporterTest.java | 2 -- .../test/java/org/apache/rat/commandline/ArgTests.java | 1 - .../org/apache/rat/document/DocumentNameMatcherTest.java | 1 - .../src/test/java/org/apache/rat/mp/OptionMojoTest.java | 2 ++ .../java/org/apache/rat/anttasks/ReportOptionTest.java | 3 ++- 8 files changed, 8 insertions(+), 15 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java index 9a6d443e4..06c4672d6 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java @@ -59,7 +59,7 @@ public Iterable patterns() { *

    Uses far less string tokenization than any of the alternatives.

    * * @param name The name to look for - * @param isCaseSensitive If the comparison is case sensitive + * @param isCaseSensitive If the comparison is case-sensitive * @return true if any of the supplied patterns match */ public boolean matches(final String name, final boolean isCaseSensitive) { diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index b61b4c178..80fe275e4 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -161,7 +161,7 @@ public String toString() { /** * Decomposes the matcher execution against the candidate. - * @param candidate the candiate to check. + * @param candidate the candidate to check. * @return a list of {@link DecomposeData} for each evaluation in the matcher. */ public List decompose(final DocumentName candidate) { @@ -398,7 +398,7 @@ abstract static class CollectionPredicateImpl implements CollectionPredicate { /** * Constructs a collection predicate from the collection of matchers. - * @param matchers the colleciton of matchers to use. + * @param matchers the collection of matchers to use. */ protected CollectionPredicateImpl(final Iterable matchers) { this.matchers = matchers; @@ -479,10 +479,7 @@ public boolean test(final DocumentName documentName) { return true; } // excluded - if (iter.next().matches(documentName)) { - return false; - } - return true; + return !iter.next().matches(documentName); } } 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 e761afe32..f723e5fd1 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 @@ -51,10 +51,7 @@ import static java.lang.String.format; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; public class OptionCollectionTest { 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 5e64a6b62..4d6b5ab3b 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 @@ -18,11 +18,9 @@ */ package org.apache.rat; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Fail.fail; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; diff --git a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java index fc4c980f9..7472a0a9e 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java +++ b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java @@ -28,7 +28,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; - import java.io.File; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java index 7526ca05d..c53fb23db 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameMatcherTest.java @@ -89,6 +89,5 @@ void testDecompose() { DocumentNameMatcher matcher3 = DocumentNameMatcher.matcherSet(matcher1, matcher2); result = processDecompose(matcher3, testName); assertThat(result).contains("MatchPatternsTest: >>true<<").contains(" **/test1*: >>false<<").contains(" **/*Name: >>true<<"); - } } diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java index 58c0aea9f..5f5eceb67 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java @@ -29,6 +29,7 @@ import org.apache.rat.OptionCollectionTest; import org.apache.rat.ReportConfiguration; import org.apache.rat.plugin.BaseRatMojo; +import org.apache.rat.utils.DefaultLog; import org.codehaus.plexus.component.configurator.ComponentConfigurationException; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; @@ -84,6 +85,7 @@ void cleanUp() { @ParameterizedTest @ArgumentsSource(MojoOptionsProvider.class) void testOptionsUpdateConfig(String name, OptionCollectionTest.OptionTest test) { + DefaultLog.getInstance().info("Running " + name); test.test(); } diff --git a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java index db7440a90..cc465da37 100644 --- a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java +++ b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java @@ -59,6 +59,7 @@ static void preserveData() { @ParameterizedTest @ArgumentsSource(AntOptionsProvider.class) public void testOptionsUpdateConfig(String name, OptionCollectionTest.OptionTest test) { + DefaultLog.getInstance().info("Running " + name); test.test(); } @@ -80,7 +81,7 @@ public AntOptionsProvider() { super(BaseAntTask.unsupportedArgs(), testPath.toFile()); } - protected final ReportConfiguration generateConfig(List> args) { + protected ReportConfiguration generateConfig(List> args) { BuildTask task = args.get(0).getKey() == null ? new BuildTask() : new BuildTask(args.get(0).getKey()); task.setUp(args); task.buildRule.executeTarget(task.name); From b66ff14e2327134e7c8723075f3b9de05842abc9 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Thu, 16 Jan 2025 14:30:01 +0000 Subject: [PATCH 062/123] fixes file list walker --- .../org/apache/rat/walker/FileListWalker.java | 20 +++++++++---------- .../apache/rat/walker/FileListWalkerTest.java | 7 ++----- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/walker/FileListWalker.java b/apache-rat-core/src/main/java/org/apache/rat/walker/FileListWalker.java index 6e6c50e5a..5aa48852d 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/walker/FileListWalker.java +++ b/apache-rat-core/src/main/java/org/apache/rat/walker/FileListWalker.java @@ -25,6 +25,7 @@ import org.apache.commons.io.IOUtils; import org.apache.rat.api.RatException; import org.apache.rat.commandline.Arg; +import org.apache.rat.config.exclusion.ExclusionUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.document.FileDocument; @@ -40,9 +41,9 @@ public class FileListWalker implements IReportable { /** The source document name */ private final FileDocument source; /** The root document name */ - private final FileDocument rootDoc; + private final DocumentName rootDoc; /** the base directory for the source document */ - private final FileDocument baseDoc; + private final DocumentName baseDoc; /** * Constructor. @@ -51,22 +52,21 @@ public class FileListWalker implements IReportable { public FileListWalker(final FileDocument source) { this.source = source; File baseDir = source.getFile().getParentFile().getAbsoluteFile(); - this.baseDoc = new FileDocument(baseDir, DocumentNameMatcher.MATCHES_ALL); + this.baseDoc = DocumentName.builder(baseDir).build(); File p = baseDir; while (p.getParentFile() != null) { p = p.getParentFile(); } - File rootDir = p; - rootDoc = new FileDocument(rootDir, DocumentNameMatcher.MATCHES_ALL); + this.rootDoc = DocumentName.builder(p).build(); } private FileDocument createDocument(final String unixFileName) { DocumentName sourceName = source.getName(); - String finalName = "/".equals(sourceName.getDirectorySeparator()) ? unixFileName : - unixFileName.replace("/", sourceName.getDirectorySeparator()); - FileDocument documentBase = unixFileName.startsWith("/") ? rootDoc : baseDoc; - File documentFile = new File(documentBase.getFile(), finalName); - return new FileDocument(rootDoc.getName(), documentFile, DocumentNameMatcher.MATCHES_ALL); + String finalName = ExclusionUtils.convertSeparator(unixFileName, "/", sourceName.getDirectorySeparator()); + DocumentName documentBase = unixFileName.startsWith("/") ? rootDoc : baseDoc; + DocumentName documentName = documentBase.resolve(finalName); + File documentFile = documentName.asFile(); + return new FileDocument(documentBase, documentFile, DocumentNameMatcher.MATCHES_ALL); } @Override diff --git a/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java b/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java index 9bc554029..ec739f643 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java @@ -83,7 +83,7 @@ public static void setUp() throws Exception { source = new File(working, "source.txt"); - DocumentName sourceName = DocumentName.builder(source).setBaseName(working.getAbsolutePath()).build(); + DocumentName sourceName = DocumentName.builder(source).build(); File regular = new File(working, "regular"); regular.mkdir(); fileWriter(regular, "regularFile", "regular file"); @@ -110,14 +110,11 @@ public static void setUp() throws Exception { writer.flush(); System.out.flush(); } - - hiddenName = DocumentName.builder(hiddenFile).setBaseName(rootName.getBaseName()).build(); } @Test public void readFilesTest() throws RatException { - FileDocument fileDocument = new FileDocument(source, DocumentNameMatcher.MATCHES_ALL); - FileListWalker walker = new FileListWalker(fileDocument); + FileListWalker walker = new FileListWalker(new FileDocument(source, DocumentNameMatcher.MATCHES_ALL)); List scanned = new ArrayList<>(); walker.run(new TestRatReport(scanned)); String[] expected = {regularName.localized("/"), hiddenName.localized("/"), From 81a97f6df1d7a87eccd5c8b36ee165b9310d23c2 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Fri, 17 Jan 2025 22:59:58 +0000 Subject: [PATCH 063/123] fixed deprecated messages --- .../java/org/apache/rat/mp/AbstractRatMojo.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apache-rat-plugin/src/main/java/org/apache/rat/mp/AbstractRatMojo.java b/apache-rat-plugin/src/main/java/org/apache/rat/mp/AbstractRatMojo.java index 1f69e3c12..d5e70ed74 100644 --- a/apache-rat-plugin/src/main/java/org/apache/rat/mp/AbstractRatMojo.java +++ b/apache-rat-plugin/src/main/java/org/apache/rat/mp/AbstractRatMojo.java @@ -78,7 +78,7 @@ public abstract class AbstractRatMojo extends BaseRatMojo { * Specifies the licenses to accept. By default, these are added to the default * licenses, unless you set <addDefaultLicenseMatchers> to false. Arguments should be * file name of <Configs> file structure. - * @deprecated Use <config>. + * @deprecated Use specific configuration under <configuration>. * @since 0.8 */ @Parameter @@ -87,7 +87,7 @@ public abstract class AbstractRatMojo extends BaseRatMojo { /** * Specifies the additional licenses file. - * @deprecated Use <config>. + * @deprecated Use specific configuration under <configuration>. */ @Parameter @Deprecated @@ -105,21 +105,21 @@ public void setAddDefaultLicenses(final boolean addDefaultLicenses) { /** * Whether to add the default list of license matchers. - * @deprecated Use <config>. + * @deprecated @deprecated Use specific configuration under <configuration>. */ @Deprecated @Parameter(property = "rat.addDefaultLicenseMatchers") private boolean addDefaultLicenseMatchers; /** The list of approved licenses - * @deprecated Use <config>. + * @deprecated @deprecated Use specific configuration under <configuration>. */ @Deprecated @Parameter(required = false) private String[] approvedLicenses; /** The file of approved licenses - * @deprecated Use <config>. + * @deprecated @deprecated Use specific configuration under <configuration>. */ @Deprecated @Parameter(property = "rat.approvedFile") @@ -136,14 +136,14 @@ public void setAddDefaultLicenses(final boolean addDefaultLicenses) { private SimpleLicenseFamily[] licenseFamilies; /** The list of license definitions. - * @deprecated Deprecated for removal since 0.17: Use <Config> instead. See configuration file documentation. + * @deprecated Deprecated for removal since 0.17: Use specific configuration under <configuration>. See configuration file documentation. */ @Deprecated @Parameter private Object[] licenses; /** The list of family definitions. - * @deprecated Use <Configs>. + * @deprecated Use specific configuration under <configuration>. */ @Deprecated @Parameter From 53a3f8eaa69502c47b572624854a2ea89a7dcdbf Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Mon, 27 Jan 2025 17:18:56 +0000 Subject: [PATCH 064/123] removed MatcherPredicate and inlined the code to make it easier to read --- .../rat/document/DocumentNameMatcher.java | 49 +++++++------------ 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 0e66b19f7..c5c533f45 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -23,7 +23,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; @@ -161,7 +160,7 @@ public String toString() { /** * Decomposes the matcher execution against the candidate. - * @param candidate the candiate to check. + * @param candidate the candidate to check. * @return a list of {@link DecomposeData} for each evaluation in the matcher. */ public List decompose(final DocumentName candidate) { @@ -181,7 +180,7 @@ private void decompose(final int level, final DocumentNameMatcher matcher, final * @return true if the documentName matchers this DocumentNameMatcher. */ public boolean matches(final DocumentName documentName) { - return predicate.test(documentName); + return predicate.test(documentName); } /** @@ -303,7 +302,19 @@ public static DocumentNameMatcher matcherSet(final DocumentNameMatcher includes, return MATCHES_ALL; } List workingSet = Arrays.asList(includes, excludes); - return new DocumentNameMatcher(format("matcherSet(%s)", join(workingSet)), new MatcherPredicate(workingSet)); + return new DocumentNameMatcher(format("matcherSet(%s)", join(workingSet)), + new CollectionPredicateImpl(Arrays.asList(includes, excludes)) { + @Override + public boolean test(final DocumentName documentName) { + if (includes.matches(documentName)) { + return true; + } + if (excludes.matches(documentName)) { + return false; + } + return true; + } + }); } /** @@ -321,7 +332,7 @@ public static DocumentNameMatcher and(final DocumentNameMatcher... matchers) { * A DocumentName predicate that uses MatchPatterns. */ public static final class MatchPatternsPredicate implements Predicate { - /** The base diirectory for the pattern matches */ + /** The base directory for the pattern matches */ private final DocumentName basedir; /** The patter matchers */ private final MatchPatterns patterns; @@ -399,8 +410,8 @@ abstract static class CollectionPredicateImpl implements CollectionPredicate { private final Iterable matchers; /** - * Constructs a collecton predicate from the collection of matchers - * @param matchers the colleciton of matchers to use. + * Constructs a collection predicate from the collection of matchers + * @param matchers the collection of matchers to use. */ protected CollectionPredicateImpl(final Iterable matchers) { this.matchers = matchers; @@ -463,30 +474,6 @@ public boolean test(final DocumentName documentName) { } } - /** - * An implementation of "or" logic across a collection of DocumentNameMatchers. - */ - // package private for testing access - static class MatcherPredicate extends CollectionPredicateImpl { - MatcherPredicate(final Iterable matchers) { - super(matchers); - } - - @Override - public boolean test(final DocumentName documentName) { - Iterator iter = getMatchers().iterator(); - // included - if (iter.next().matches(documentName)) { - return true; - } - // excluded - if (iter.next().matches(documentName)) { - return false; - } - return true; - } - } - /** * Data from a {@link DocumentNameMatcher#decompose(DocumentName)} call. */ From 89192f88d04c0121df22310c64a2d2a34d63ef01 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Thu, 23 Jan 2025 15:59:11 +0000 Subject: [PATCH 065/123] implemented matcher set in ExclusionProcessor --- .../config/exclusion/ExclusionProcessor.java | 218 ++++++++++-------- .../rat/config/exclusion/ExclusionUtils.java | 67 +++++- .../rat/config/exclusion/MatcherSet.java | 177 ++++++++++++++ .../config/exclusion/StandardCollection.java | 30 ++- 4 files changed, 384 insertions(+), 108 deletions(-) create mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java 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 c1de611ff..0b1014af9 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 @@ -24,8 +24,8 @@ import java.util.Objects; import java.util.Set; import java.util.TreeSet; +import java.util.stream.Collectors; -import org.apache.rat.config.exclusion.plexus.MatchPatterns; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.utils.DefaultLog; @@ -85,10 +85,8 @@ private void resetLastMatcher() { * @return this */ public ExclusionProcessor addIncludedPatterns(final Iterable patterns) { - List lst = new ArrayList<>(); - patterns.forEach(lst::add); - DefaultLog.getInstance().info(format("Including patterns: %s", String.join(", ", lst))); - includedPatterns.addAll(lst); + DefaultLog.getInstance().info(format("Including patterns: %s", String.join(", ", patterns))); + patterns.forEach(includedPatterns::add); resetLastMatcher(); return this; } @@ -140,10 +138,8 @@ public ExclusionProcessor addIncludedCollection(final StandardCollection collect * @return this */ public ExclusionProcessor addExcludedPatterns(final Iterable patterns) { - List lst = new ArrayList<>(); - patterns.forEach(lst::add); - DefaultLog.getInstance().info(format("Excluding patterns: %s", String.join(", ", lst))); - excludedPatterns.addAll(lst); + DefaultLog.getInstance().info(format("Excluding patterns: %s", String.join(", ", patterns))); + patterns.forEach(excludedPatterns::add); resetLastMatcher(); return this; } @@ -175,22 +171,6 @@ public ExclusionProcessor addExcludedCollection(final StandardCollection collect return this; } - /** - * Adds to lists of qualified file patterns. Non-matching patterns start with a {@code !}. - * @param matching the list to put matching file patterns into. - * @param notMatching the list to put non-matching files patterns into. - * @param patterns the patterns to match. - */ - private void segregateList(final Set matching, final Set notMatching, - final Iterable patterns) { - if (patterns.iterator().hasNext()) { - ExtendedIterator.create(patterns.iterator()).filter(ExclusionUtils.MATCH_FILTER).forEachRemaining(matching::add); - ExtendedIterator.create(patterns.iterator()).filter(ExclusionUtils.NOT_MATCH_FILTER) - .map(s -> s.substring(1)) - .forEachRemaining(notMatching::add); - } - } - /** * Creates a Document name matcher that will return {@code false} on any * document that is excluded. @@ -204,84 +184,136 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { if (lastMatcher == null || !basedir.equals(lastMatcherBaseDir)) { lastMatcherBaseDir = basedir; - final Set incl = new TreeSet<>(); - final Set excl = new TreeSet<>(); - final List inclMatchers = new ArrayList<>(); - // add the file processors - for (StandardCollection sc : fileProcessors) { - ExtendedIterator iter = sc.fileProcessor(); - if (iter.hasNext()) { - iter.forEachRemaining(fp -> { - segregateList(excl, incl, fp.apply(basedir)); - fp.customDocumentNameMatchers().forEach(inclMatchers::add); - }); - } else { - DefaultLog.getInstance().info(String.format("%s does not have a fileProcessor.", sc)); - } - } - - // add the standard patterns - segregateList(incl, excl, new FileProcessor(includedPatterns).apply(basedir)); - segregateList(excl, incl, new FileProcessor(excludedPatterns).apply(basedir)); + final List matchers = extractFileProcessors(basedir); + final MatcherSet.Builder fromCommandLine = new MatcherSet.Builder(); + DocumentName.Builder nameBuilder = DocumentName.builder(basedir).setBaseName(basedir); + extractPatterns(nameBuilder, fromCommandLine); + extractCollectionPatterns(nameBuilder, fromCommandLine); + extractCollectionMatchers(fromCommandLine); + extractPaths(fromCommandLine); + matchers.add(fromCommandLine.build()); - // add the collection patterns - for (StandardCollection sc : includedCollections) { - Set patterns = sc.patterns(); - if (patterns.isEmpty()) { - DefaultLog.getInstance().info(String.format("%s does not have a defined collection for inclusion.", sc)); - } else { - segregateList(incl, excl, new FileProcessor(sc.patterns()).apply(basedir)); - } - } - for (StandardCollection sc : excludedCollections) { - Set patterns = sc.patterns(); - if (patterns.isEmpty()) { - DefaultLog.getInstance().info(String.format("%s does not have a defined collection for exclusion.", sc)); - } else { - segregateList(excl, incl, new FileProcessor(sc.patterns()).apply(basedir)); - } - } + lastMatcher = MatcherSet.merge(matchers).createMatcher(); + DefaultLog.getInstance().debug(format("Created matcher set for %s%n%s", basedir.getName(), + lastMatcher)); + } + return lastMatcher; + } - // add the matchers - ExtendedIterator.create(includedCollections.iterator()) - .map(StandardCollection::staticDocumentNameMatcher) - .filter(Objects::nonNull) - .forEachRemaining(inclMatchers::add); + /** + * Extracts the file processors from {@link #fileProcessors}. + * @param basedir The directory to base the file processors on. + * @return a list of MatcherSets that are created for each {@link #fileProcessors} entry. + */ + private List extractFileProcessors(final DocumentName basedir) { + final List fileProcessorList = new ArrayList<>(); + for (StandardCollection sc : fileProcessors) { + final Set names = new HashSet<>(); + sc.fileProcessor().map(fp -> fp.apply(basedir)).forEachRemaining(n -> n.forEach(names::add)); + MatcherSet.Builder builder = new MatcherSet.Builder(); + Set matching = new HashSet<>(); + Set notMatching = new HashSet<>(); + MatcherSet.Builder.segregateList(matching, notMatching, names); + builder.addIncluded(basedir.resolve(sc.name()), notMatching); + builder.addExcluded(basedir.resolve(sc.name()), matching); + fileProcessorList.add(builder.build()); + } + return fileProcessorList; + } - List exclMatchers = ExtendedIterator.create(excludedCollections.iterator()) - .map(StandardCollection::staticDocumentNameMatcher) - .filter(Objects::nonNull) - .addTo(new ArrayList<>()); + /** + * Converts the pattern to use the directory separator specified by the document name and localises it for + * exclusion processing. + * @param documentName The document name to adjust the pattern against. + * @param pattern the pattern. + * @return the prepared pattern. + */ + private String preparePattern(final DocumentName documentName, final String pattern) { + return ExclusionUtils.qualifyPattern(documentName, + ExclusionUtils.convertSeparator(pattern, "/", documentName.getDirectorySeparator())); + } + /** + * Extracts {@link #includedPatterns} and {@link #excludedPatterns} into the specified matcherBuilder. + * @param nameBuilder The name builder for the pattern. File names are resolved against the generated name. + * @param matcherBuilder the MatcherSet.Builder to add the patterns to. + */ + private void extractPatterns(final DocumentName.Builder nameBuilder, final MatcherSet.Builder matcherBuilder) { + DocumentName name = nameBuilder.setName("Patterns").build(); + if (!excludedPatterns.isEmpty()) { + matcherBuilder.addExcluded(name, excludedPatterns.stream() + .map(s -> preparePattern(name, s)) + .collect(Collectors.toSet())); + } + if (!includedPatterns.isEmpty()) { + matcherBuilder.addIncluded(name, includedPatterns.stream() + .map(s -> preparePattern(name, s)).collect(Collectors.toSet())); + } + } - if (!incl.isEmpty()) { - inclMatchers.add(new DocumentNameMatcher("included patterns", MatchPatterns.from(basedir.getDirectorySeparator(), incl), basedir)); + /** + * Extracts {@link #includedCollections} and {@link #excludedCollections} patterns into the specified matcherBuilder. + * @param nameBuilder the name builder for the pattern names. + * @param matcherBuilder the MatcherSet.Builder to add the collections to. + */ + private void extractCollectionPatterns(final DocumentName.Builder nameBuilder, final MatcherSet.Builder matcherBuilder) { + final Set incl = new TreeSet<>(); + final Set excl = new TreeSet<>(); + for (StandardCollection sc : includedCollections) { + Set patterns = sc.patterns(); + if (patterns.isEmpty()) { + DefaultLog.getInstance().debug(String.format("%s does not have a defined collection for inclusion.", sc)); + } else { + MatcherSet.Builder.segregateList(incl, excl, sc.patterns()); } - if (!excl.isEmpty()) { - exclMatchers.add(new DocumentNameMatcher("excluded patterns", MatchPatterns.from(basedir.getDirectorySeparator(), excl), basedir)); + } + for (StandardCollection sc : excludedCollections) { + Set patterns = sc.patterns(); + if (patterns.isEmpty()) { + DefaultLog.getInstance().debug(String.format("%s does not have a defined collection for exclusion.", sc)); + } else { + MatcherSet.Builder.segregateList(excl, incl, sc.patterns()); } + } + DocumentName name = nameBuilder.setName("Collections").build(); + matcherBuilder + .addExcluded(name, excl.stream().map(s -> preparePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())) + .addIncluded(name, incl.stream().map(s -> preparePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); + } - if (!includedPaths.isEmpty()) { - for (DocumentNameMatcher matcher : includedPaths) { - DefaultLog.getInstance().info(format("Including path matcher %s", matcher)); - inclMatchers.add(matcher); - } - } - if (!excludedPaths.isEmpty()) { - for (DocumentNameMatcher matcher : excludedPaths) { - DefaultLog.getInstance().info(format("Excluding path matcher %s", matcher)); - exclMatchers.add(matcher); - } - } + /** + * Extracts {@link #includedCollections} and {@link #excludedCollections} matchers into the specified matcherBuilder. + * @param matcherBuilder the MatcherSet.Builder to add the collections to. + */ + private void extractCollectionMatchers(final MatcherSet.Builder matcherBuilder) { + ExtendedIterator.create(includedCollections.iterator()) + .map(StandardCollection::staticDocumentNameMatcher) + .filter(Objects::nonNull) + .forEachRemaining(matcherBuilder::addIncluded); - lastMatcher = DocumentNameMatcher.MATCHES_ALL; - if (!exclMatchers.isEmpty()) { - lastMatcher = DocumentNameMatcher.not(DocumentNameMatcher.or(exclMatchers)); - if (!inclMatchers.isEmpty()) { - lastMatcher = DocumentNameMatcher.or(DocumentNameMatcher.or(inclMatchers), lastMatcher); - } + ExtendedIterator.create(excludedCollections.iterator()) + .map(StandardCollection::staticDocumentNameMatcher) + .filter(Objects::nonNull) + .forEachRemaining(matcherBuilder::addExcluded); + } + + /** + * Extracts {@link #includedPaths} and {@link #excludedPaths} patterns into the specified matcherBuilder. + * @param matcherBuilder the MatcherSet.Builder to add the collections to. + */ + private void extractPaths(final MatcherSet.Builder matcherBuilder) { + if (!includedPaths.isEmpty()) { + for (DocumentNameMatcher matcher : includedPaths) { + DefaultLog.getInstance().info(format("Including path matcher %s", matcher)); + matcherBuilder.addIncluded(matcher); + } + } + if (!excludedPaths.isEmpty()) { + for (DocumentNameMatcher matcher : excludedPaths) { + DefaultLog.getInstance().info(format("Excluding path matcher %s", matcher)); + matcherBuilder.addExcluded(matcher); } } - return lastMatcher; } + } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java index 7932db4f6..74305bfad 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java @@ -34,9 +34,13 @@ import org.apache.commons.io.LineIterator; import org.apache.commons.lang3.StringUtils; import org.apache.rat.ConfigurationException; +import org.apache.rat.config.exclusion.plexus.MatchPattern; +import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; +import org.apache.rat.utils.DefaultLog; import org.apache.rat.utils.ExtendedIterator; +import org.apache.rat.utils.Log; import static java.lang.String.format; @@ -48,11 +52,14 @@ public final class ExclusionUtils { /** The list of comment prefixes that are used to filter comment lines. */ public static final List COMMENT_PREFIXES = Arrays.asList("#", "##", "//", "/**", "/*"); + /** Prefix used to negate the given pattern. */ + public static final String NEGATION_PREFIX = "!"; + /** A predicate that filters out lines that do NOT start with "!" */ - public static final Predicate NOT_MATCH_FILTER = s -> s.startsWith("!"); + public static final Predicate NOT_MATCH_FILTER = s -> s.startsWith(NEGATION_PREFIX); /** A predicate that filters out lines that start with "!" */ - public static final Predicate MATCH_FILTER = s -> !s.startsWith("!"); + public static final Predicate MATCH_FILTER = NOT_MATCH_FILTER.negate(); private ExclusionUtils() { // do not instantiate @@ -112,7 +119,20 @@ public static Predicate commentFilter(final String commentPrefix) { * @return a FileFilter. */ public static FileFilter asFileFilter(final DocumentName parent, final DocumentNameMatcher nameMatcher) { - return file -> nameMatcher.matches(DocumentName.builder(file).setBaseName(parent.getBaseName()).build()); + return file -> { + DocumentName candidate = DocumentName.builder(file).setBaseName(parent.getBaseName()).build(); + boolean result = nameMatcher.matches(candidate); + Log log = DefaultLog.getInstance(); + if (log.isEnabled(Log.Level.DEBUG)) { + log.debug(format("FILTER TEST for %s -> %s", file, result)); + if (!result) { + List< DocumentNameMatcher.DecomposeData> data = nameMatcher.decompose(candidate); + log.debug("Decomposition for " + candidate); + data.forEach(log::debug); + } + } + return result; + }; } /** @@ -172,12 +192,20 @@ protected boolean isValidLine(final String line) { /** * Returns {@code true} if the file name represents a hidden file. - * @param f the file to check. + * @param file the file to check. * @return {@code true} if it is the name of a hidden file. */ - public static boolean isHidden(final File f) { - String s = f.getName(); - return s.startsWith(".") && !(s.equals(".") || s.equals("..")); + public static boolean isHidden(final File file) { + return isHidden(file.getName()); + } + + /** + * Returns {@code true} if the filename represents a hidden file + * @param fileName the file to check. + * @return true if it is the name of a hidden file. + */ + public static boolean isHidden(final String fileName) { + return fileName.startsWith(".") && !(fileName.equals(".") || fileName.equals("..")); } private static void verifyFile(final File file) { @@ -186,6 +214,31 @@ private static void verifyFile(final File file) { } } + /** + * Modifies the {@link MatchPattern} formatted {@code pattern} argument by expanding the pattern and + * by adjusting the pattern to include the basename from the {@code documentName} argument. + * @param documentName the name of the file being read. + * @param pattern the pattern to format. + * @return the completely formatted pattern + */ + public static String qualifyPattern(final DocumentName documentName, final String pattern) { + boolean prefix = pattern.startsWith(NEGATION_PREFIX); + String workingPattern = prefix ? pattern.substring(1) : pattern; + String normalizedPattern = SelectorUtils.extractPattern(workingPattern, documentName.getDirectorySeparator()); + + StringBuilder sb = new StringBuilder(prefix ? NEGATION_PREFIX : ""); + if (SelectorUtils.isRegexPrefixedPattern(workingPattern)) { + sb.append(SelectorUtils.REGEX_HANDLER_PREFIX) + .append("\\Q").append(documentName.getBaseName()) + .append(documentName.getDirectorySeparator()) + .append("\\E").append(normalizedPattern) + .append(SelectorUtils.PATTERN_HANDLER_SUFFIX); + } else { + sb.append(documentName.getBaseDocumentName().resolve(normalizedPattern).getName()); + } + return sb.toString(); + } + /** * Tokenizes the string based on the directory separator. * @param source the source to tokenize. diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java new file mode 100644 index 000000000..181b05569 --- /dev/null +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -0,0 +1,177 @@ +/* + * 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.config.exclusion; + +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.function.Consumer; + +import org.apache.rat.config.exclusion.plexus.MatchPattern; +import org.apache.rat.config.exclusion.plexus.MatchPatterns; +import org.apache.rat.config.exclusion.plexus.SelectorUtils; +import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; + +import static org.apache.rat.document.DocumentNameMatcher.MATCHES_NONE; + +/** + * The file processor reads the file specified in the DocumentName. + * It must return a list of fully qualified strings for the {@link MatchPattern} to process. + * It may return either Ant or Regex style strings, or a mixture of both. + * See {@link SelectorUtils} for a description of the formats. + * It may also generate custom DocumentNameMatchers which are added to the customMatchers instance variable. + */ +public interface MatcherSet { + Optional includes(); + Optional excludes(); + + default String getDescription() { + return String.format("MatcherSet: include [%s] exclude [%s]", includes().orElse(MATCHES_NONE), excludes().orElse(MATCHES_NONE)); + } + /** + * Creates a DocumentNameMatcher from an iterable of matcher sets. + * @return A DocumentNameMatcher that processes the matcher sets. + */ + default DocumentNameMatcher createMatcher() { + return DocumentNameMatcher.matcherSet(includes().orElse(MATCHES_NONE), excludes().orElse(MATCHES_NONE)); + } + + static MatcherSet merge(List matcherSets) { + Builder builder = new Builder(); + for (MatcherSet matcherSet : matcherSets) { + matcherSet.includes().ifPresent(builder::addIncluded); + matcherSet.excludes().ifPresent(builder::addExcluded); + } + return builder.build(); + } + + /** + * A MatcherSet that assumes the files contain the already formatted strings and just need to be + * localized for the fileName. When {@link #build()} is called the builder is reset to the initial state. + */ + class Builder { + + /** + * Adds to lists of qualified file patterns. Non-matching patterns start with a {@code !}. + * @param matching the list to put matching file patterns into. + * @param notMatching the list to put non-matching files patterns into. + * @param patterns the patterns to match. + */ + public static void segregateList(final Set matching, final Set notMatching, + final Iterable patterns) { + patterns.forEach(s -> { + if (ExclusionUtils.MATCH_FILTER.test(s)) { + matching.add(s); + } else { + notMatching.add(s.substring(1)); + } + }); + } + + /** the DocumentNameMatcher that specifies included files */ + protected DocumentNameMatcher included; + /** The DocumentNameMatcher that specifies excluded files */ + protected DocumentNameMatcher excluded; + + public Builder() { + } + + /** + * Converts a collection names into DocumentNameMatchers that use the {@code fromDocument} directory separator. + * @param dest the consumer to accept the DocumentNameMatcher. + * @param nameFmt the format for the matcher names. Requires '%s' for the {@code fromDocument} localized name. + * @param fromDocument the document that the patterns are associated with. + * @param names the list of patterns. If empty no action is taken. + */ + private void processNames(final Consumer dest, final String nameFmt, final DocumentName fromDocument, final Set names) { + if (!names.isEmpty()) { + String name = String.format(nameFmt, fromDocument.localized("/").substring(1)); + dest.accept(new DocumentNameMatcher(name, MatchPatterns.from(fromDocument.getDirectorySeparator(), names), fromDocument.getBaseDocumentName())); + } + } + /** + * Adds included file names from the specified document. File names are resolved relative to the directory + * of the {@code fromDocument}. + * @param fromDocument the document the names were read from. + * @param names the names that were read from the document. Must be use the separator specified by {@code fromDocument}. + * @return this + */ + public Builder addIncluded(final DocumentName fromDocument, final Set names) { + processNames(this::addIncluded, "'included %s'", fromDocument, names); + return this; + } + + /** + * Adds excluded file names from the specified document. File names are resolved relative to the directory + * of the {@code fromDocument}. + * @param fromDocument the document the names were read from. + * @param names the names that were read from the document. Must be use the separator specified by {@code fromDocument}. + * @return this + */ + public Builder addExcluded(final DocumentName fromDocument, final Set names) { + processNames(this::addExcluded, "'excluded %s'", fromDocument, names); + return this; + } + + /** + * Adds specified DocumentNameMatcher to the included matchers. + * @param matcher A document name matcher to add to the included set. + * @return this + */ + public Builder addIncluded(final DocumentNameMatcher matcher) { + this.included = this.included == null ? matcher : DocumentNameMatcher.or(this.included, matcher); + return this; + } + + /** + * Adds specified DocumentNameMatcher to the excluded matchers. + * @param matcher A document name matcher to add to the excluded set. + * @return this + */ + public Builder addExcluded(final DocumentNameMatcher matcher) { + this.excluded = this.excluded == null ? matcher : DocumentNameMatcher.or(this.excluded, matcher); + return this; + } + + /** + * Builds a MatcherSet. When {@code build()} is called the builder is reset to the initial state. + * @return the MatcherSet based upon the included and excluded matchers. + */ + public MatcherSet build() { + MatcherSet result = new MatcherSet() { + private final DocumentNameMatcher myIncluded = included; + private final DocumentNameMatcher myExcluded = excluded; + + @Override + public Optional includes() { + return Optional.ofNullable(myIncluded); + } + + @Override + public Optional excludes() { + return Optional.ofNullable(myExcluded); + } + }; + included = null; + excluded = null; + return result; + } + } +} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java index 1bd805f41..c028f1128 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java @@ -100,20 +100,34 @@ null, new CVSFileProcessor()), */ HIDDEN_DIR("The hidden directories. Directories with names that start with '.'", null, - new DocumentNameMatcher("HIDDEN_DIR", (Predicate) documentName -> { - File f = new File(documentName.getName()); - return f.isDirectory() && ExclusionUtils.isHidden(f); - }), null + new DocumentNameMatcher("HIDDEN_DIR", new Predicate() { + @Override + public boolean test(final DocumentName documentName) { + File file = documentName.asFile(); + return file.isDirectory() && ExclusionUtils.isHidden(documentName.getShortName()); + } + @Override + public String toString() { + return "HIDDEN_DIR"; + } + }), null ), /** * The hidden files. Directories with names that start with '.' */ HIDDEN_FILE("The hidden files. Directories with names that start with '.'", null, - new DocumentNameMatcher("HIDDEN_FILE", (Predicate) documentName -> { - File f = new File(documentName.getName()); - return f.isFile() && ExclusionUtils.isHidden(f); - }), null + new DocumentNameMatcher("HIDDEN_FILE", new Predicate() { + @Override + public boolean test(final DocumentName documentName) { + File file = documentName.asFile(); + return file.isFile() && ExclusionUtils.isHidden(documentName.getShortName()); + } + @Override + public String toString() { + return "HIDDEN_FILE"; + } + }), null ), /** * The files and directories created by an IDEA IDE based tool. From b928be2a43721092822fb730446daa862597a693 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Tue, 28 Jan 2025 08:34:50 +0000 Subject: [PATCH 066/123] fixed NoteGuesserTest --- .../org/apache/rat/document/guesser/NoteGuesserTest.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java index 5d0798e65..bcb6229b3 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java @@ -18,10 +18,8 @@ */ package org.apache.rat.document.guesser; -import com.google.common.jimfs.Configuration; -import com.google.common.jimfs.Jimfs; + import java.io.IOException; -import java.nio.file.FileSystem; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; @@ -33,9 +31,6 @@ import org.junit.jupiter.params.provider.MethodSource; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.apache.rat.document.FSInfoTest.OSX; -import static org.apache.rat.document.FSInfoTest.UNIX; -import static org.apache.rat.document.FSInfoTest.WINDOWS; public class NoteGuesserTest { @@ -51,7 +46,7 @@ private static Stream nameData() throws IOException { final DocumentName linuxBaseName = DocumentName.builder(FSInfoTest.UNIX).setName("/").setBaseName("/").build(); final DocumentName windowsBaseName = DocumentName.builder(FSInfoTest.WINDOWS).setName("\\").setBaseName("\\").build(); - final DocumentName osxBaseName = DocumentName.builder(OSX).setName("/").setBaseName("/").build(); + final DocumentName osxBaseName = DocumentName.builder(FSInfoTest.OSX).setName("/").setBaseName("/").build(); lst.add(Arguments.of(linuxBaseName.resolve("DEPENDENCIES"), true)); lst.add(Arguments.of(linuxBaseName.resolve("LICENSE"), true)); From 7d9e739726ac9cf6b4e551aa314b8fde288bd81a Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Mon, 3 Feb 2025 09:34:09 +0000 Subject: [PATCH 067/123] fixed DocumentNameMatcher idiom misuse --- .../rat/document/DocumentNameMatcher.java | 33 ++++++------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 6b3c31bd0..51f5117a4 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -23,7 +23,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; @@ -303,7 +302,16 @@ public static DocumentNameMatcher matcherSet(final DocumentNameMatcher includes, return MATCHES_ALL; } List workingSet = Arrays.asList(includes, excludes); - return new DocumentNameMatcher(format("matcherSet(%s)", join(workingSet)), new MatcherPredicate(workingSet)); + return new DocumentNameMatcher(format("matcherSet(%s)", join(workingSet)), + new CollectionPredicateImpl(workingSet) { + @Override + public boolean test(DocumentName documentName) { + if (includes.matches(documentName)) { + return true; + } + return !excludes.matches(documentName); + } + }); } /** @@ -466,27 +474,6 @@ public boolean test(final DocumentName documentName) { } } - /** - * An implementation of "or" logic across a collection of DocumentNameMatchers. - */ - // package private for testing access - static class MatcherPredicate extends CollectionPredicateImpl { - MatcherPredicate(final Iterable matchers) { - super(matchers); - } - - @Override - public boolean test(final DocumentName documentName) { - Iterator iter = getMatchers().iterator(); - // included - if (iter.next().matches(documentName)) { - return true; - } - // excluded - return !iter.next().matches(documentName); - } - } - /** * Data from a {@link DocumentNameMatcher#decompose(DocumentName)} call. */ From e140777c5e0bcf2484615b6634a56ef06c1460b1 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Mon, 3 Feb 2025 10:18:55 +0000 Subject: [PATCH 068/123] fixed javadoc --- .../rat/config/exclusion/ExclusionProcessor.java | 15 ++++++--------- .../org/apache/rat/document/DocumentName.java | 2 +- .../apache/rat/test/AbstractOptionsProvider.java | 2 +- 3 files changed, 8 insertions(+), 11 deletions(-) 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 0b1014af9..8fec1d903 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 @@ -209,15 +209,12 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { private List extractFileProcessors(final DocumentName basedir) { final List fileProcessorList = new ArrayList<>(); for (StandardCollection sc : fileProcessors) { - final Set names = new HashSet<>(); - sc.fileProcessor().map(fp -> fp.apply(basedir)).forEachRemaining(n -> n.forEach(names::add)); - MatcherSet.Builder builder = new MatcherSet.Builder(); - Set matching = new HashSet<>(); - Set notMatching = new HashSet<>(); - MatcherSet.Builder.segregateList(matching, notMatching, names); - builder.addIncluded(basedir.resolve(sc.name()), notMatching); - builder.addExcluded(basedir.resolve(sc.name()), matching); - fileProcessorList.add(builder.build()); + ExtendedIterator> iter = sc.fileProcessorBuilder().map(builder -> builder.build(basedir)); + if (iter.hasNext()) { + iter.forEachRemaining(fileProcessorList::addAll); + } else { + DefaultLog.getInstance().debug(String.format("%s does not have a fileProcessor.", sc)); + } } return fileProcessorList; } diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java index d5cc1126c..4d52a2244 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java @@ -241,7 +241,7 @@ public String getDirectorySeparator() { /** * Determines if the candidate starts with the root or separator strings. - * @param candidate the candidate ot check. If blank method will return {@code false}. + * @param candidate the candidate to check. If blank method will return {@code false}. * @param root the root to check. If blank the root check is skipped. * @param separator the separator to check. If blank the check is skipped. * @return true if either the root or separator check returned {@code true}. 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 8a34245e9..bec9ceb99 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 @@ -247,7 +247,7 @@ protected DocumentName mkDocName(String name) { /* Tests to be implemented */ protected abstract void helpTest(); - /* Display the option and value under test */ + /** Display the option and value under test */ private String displayArgAndName(Option option, String fname) { return String.format("%s %s", option.getLongOpt(), fname); } From f7679b561c47fdab8a5f67872374092225eea8f7 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Mon, 3 Feb 2025 10:27:02 +0000 Subject: [PATCH 069/123] fixed checkstyle --- .../main/java/org/apache/rat/document/DocumentNameMatcher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index ca390d0d0..b8ec78458 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -305,7 +305,7 @@ public static DocumentNameMatcher matcherSet(final DocumentNameMatcher includes, return new DocumentNameMatcher(format("matcherSet(%s)", join(workingSet)), new CollectionPredicateImpl(workingSet) { @Override - public boolean test(DocumentName documentName) { + public boolean test(final DocumentName documentName) { if (includes.matches(documentName)) { return true; } From 04a9da18b33401c0688d855ba4435ec60d9ba7f7 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 14 Dec 2024 08:40:52 +0000 Subject: [PATCH 070/123] initial design comments --- .../config/exclusion/fileProcessors/GitFileProcessor.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessor.java index 8cf2d0960..37af81b61 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessor.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessor.java @@ -29,6 +29,11 @@ * @see .gitignore documentation */ public class GitFileProcessor extends DescendingFileProcessor { + // create a list of levels that a list of processors at that level. + // will return a custom matcher that from an overridden FileProcessor.customDocumentNameMatchers method + // build LevelMatcher as a system that returns Include, Exclude or no status for each check. + // put the level matcher in an array with other level matchers at the specific level below the root + // When searching start at the lowest level and work up the tree. /** * Constructs a file processor that processes a .gitignore file and ignores any lines starting with "#". From 6180a137b5dfa8962109f9eba2fa160ab5cc2159 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 21 Dec 2024 08:55:25 +0000 Subject: [PATCH 071/123] fixes for tests --- .../config/exclusion/ExclusionProcessor.java | 177 ++++++++----- .../rat/config/exclusion/ExclusionUtils.java | 7 +- .../rat/config/exclusion/FileProcessor.java | 115 --------- .../rat/config/exclusion/MatcherSet.java | 244 ++++++++++++++++++ .../config/exclusion/StandardCollection.java | 32 +-- ...rocessor.java => BazaarIgnoreBuilder.java} | 5 +- ...leProcessor.java => CVSIgnoreBuilder.java} | 17 +- .../DescendingFileProcessor.java | 121 --------- .../fileProcessors/GitFileProcessor.java | 75 ------ .../fileProcessors/GitIgnoreBuilder.java | 180 +++++++++++++ ...oreProcessor.java => HgIgnoreBuilder.java} | 10 +- .../main/java/org/apache/rat/help/Help.java | 2 +- .../development/write_file_processor.md | 2 +- .../apache/rat/ReportConfigurationTest.java | 3 +- .../config/exclusion/FileProcessorTest.java | 2 +- .../exclusion/StandardCollectionTest.java | 2 +- ...st.java => AbstractIgnoreBuilderTest.java} | 2 +- .../BazaarIgnoreBuilderTest.java | 59 +++++ ...sorTest.java => CVSIgnoreBuilderTest.java} | 24 +- .../DescendingFileProcessorTest.java | 70 ----- .../fileProcessors/GitFileProcessorTest.java | 118 --------- .../fileProcessors/GitIgnoreBuilderTest.java | 147 +++++++++++ .../fileProcessors/HgIgnoreBuilderTest.java | 82 ++++++ .../fileProcessors/HgIgnoreProcessorTest.java | 66 ----- 24 files changed, 887 insertions(+), 675 deletions(-) delete mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/FileProcessor.java create mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java rename apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/{BazaarIgnoreProcessor.java => BazaarIgnoreBuilder.java} (90%) rename apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/{CVSFileProcessor.java => CVSIgnoreBuilder.java} (78%) delete mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/DescendingFileProcessor.java delete mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessor.java create mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java rename apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/{HgIgnoreProcessor.java => HgIgnoreBuilder.java} (90%) rename apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/{AbstractIgnoreProcessorTest.java => AbstractIgnoreBuilderTest.java} (97%) create mode 100644 apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java rename apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/{CVSFileProcessorTest.java => CVSIgnoreBuilderTest.java} (59%) delete mode 100644 apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/DescendingFileProcessorTest.java delete mode 100644 apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessorTest.java create mode 100644 apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java create mode 100644 apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java delete mode 100644 apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreProcessorTest.java 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 c1de611ff..918b2e163 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 @@ -32,6 +32,8 @@ import org.apache.rat.utils.ExtendedIterator; import static java.lang.String.format; +import static org.apache.rat.document.DocumentNameMatcher.MATCHES_ALL; +import static org.apache.rat.document.DocumentNameMatcher.MATCHES_NONE; /** * Processes the include and exclude patterns and applies the result against a base directory @@ -204,84 +206,133 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { if (lastMatcher == null || !basedir.equals(lastMatcherBaseDir)) { lastMatcherBaseDir = basedir; - final Set incl = new TreeSet<>(); - final Set excl = new TreeSet<>(); - final List inclMatchers = new ArrayList<>(); - // add the file processors - for (StandardCollection sc : fileProcessors) { - ExtendedIterator iter = sc.fileProcessor(); - if (iter.hasNext()) { - iter.forEachRemaining(fp -> { - segregateList(excl, incl, fp.apply(basedir)); - fp.customDocumentNameMatchers().forEach(inclMatchers::add); - }); - } else { - DefaultLog.getInstance().info(String.format("%s does not have a fileProcessor.", sc)); - } + final List fileProcessors = extractFileProcessors(basedir, new ArrayList<>()); + + DocumentName.Builder nameBuilder = DocumentName.builder().setBaseName(basedir); + MatcherSet.Builder fromCommandLine = new MatcherSet.Builder() + .addExcluded(nameBuilder.setName("excludedPatterns").build(), excludedPatterns) + .addIncluded(nameBuilder.setName("includedPatterns").build(), includedPatterns); + extractCollectionPatterns(nameBuilder, fromCommandLine); + extractCollectionMatchers(fromCommandLine); + extractPaths(fromCommandLine); + + fileProcessors.add(fromCommandLine.build(basedir)); + + lastMatcher = createMatcher(fileProcessors); + } + return lastMatcher; + } + + private List extractFileProcessors(final DocumentName basedir, final List fileProcessorList) { + for (StandardCollection sc : fileProcessors) { + ExtendedIterator iter = sc.fileProcessorBuilder().map(builder -> builder.build(basedir)); + if (iter.hasNext()) { + iter.forEachRemaining(fileProcessorList::add); + } else { + DefaultLog.getInstance().debug(String.format("%s does not have a fileProcessor.", sc)); } + } + return fileProcessorList; + } - // add the standard patterns - segregateList(incl, excl, new FileProcessor(includedPatterns).apply(basedir)); - segregateList(excl, incl, new FileProcessor(excludedPatterns).apply(basedir)); - - // add the collection patterns - for (StandardCollection sc : includedCollections) { - Set patterns = sc.patterns(); - if (patterns.isEmpty()) { - DefaultLog.getInstance().info(String.format("%s does not have a defined collection for inclusion.", sc)); - } else { - segregateList(incl, excl, new FileProcessor(sc.patterns()).apply(basedir)); - } + private void extractPatterns(final DocumentName commandLine, final MatcherSet.Builder fromCommandLine) { + fromCommandLine + .addExcluded(commandLine, excludedPatterns) + .addIncluded(commandLine, includedPatterns); + } + + private void extractCollectionPatterns(final DocumentName.Builder nameBuilder, final MatcherSet.Builder fileProcessorBuilder) { + // add the collection patterns + final Set incl = new TreeSet<>(); + final Set excl = new TreeSet<>(); + for (StandardCollection sc : includedCollections) { + Set patterns = sc.patterns(); + if (patterns.isEmpty()) { + DefaultLog.getInstance().debug(String.format("%s does not have a defined collection for inclusion.", sc)); + } else { + MatcherSet.Builder.segregateList(incl, excl, sc.patterns()); } - for (StandardCollection sc : excludedCollections) { - Set patterns = sc.patterns(); - if (patterns.isEmpty()) { - DefaultLog.getInstance().info(String.format("%s does not have a defined collection for exclusion.", sc)); - } else { - segregateList(excl, incl, new FileProcessor(sc.patterns()).apply(basedir)); - } + } + for (StandardCollection sc : excludedCollections) { + Set patterns = sc.patterns(); + if (patterns.isEmpty()) { + DefaultLog.getInstance().info(String.format("%s does not have a defined collection for exclusion.", sc)); + } else { + MatcherSet.Builder.segregateList(excl, incl, sc.patterns()); } + } + nameBuilder.setName("collections"); + fileProcessorBuilder + .addExcluded(nameBuilder.setName("excludedCollections").build(), excl) + .addIncluded(nameBuilder.setName("includedCollections").build(), incl); - // add the matchers - ExtendedIterator.create(includedCollections.iterator()) - .map(StandardCollection::staticDocumentNameMatcher) - .filter(Objects::nonNull) - .forEachRemaining(inclMatchers::add); + } - List exclMatchers = ExtendedIterator.create(excludedCollections.iterator()) - .map(StandardCollection::staticDocumentNameMatcher) - .filter(Objects::nonNull) - .addTo(new ArrayList<>()); + private void extractCollectionMatchers(final MatcherSet.Builder fromCommandLine) { + // add the matchers + ExtendedIterator.create(includedCollections.iterator()) + .map(StandardCollection::staticDocumentNameMatcher) + .filter(Objects::nonNull) + .forEachRemaining(fromCommandLine::addIncluded); - if (!incl.isEmpty()) { - inclMatchers.add(new DocumentNameMatcher("included patterns", MatchPatterns.from(basedir.getDirectorySeparator(), incl), basedir)); + ExtendedIterator.create(excludedCollections.iterator()) + .map(StandardCollection::staticDocumentNameMatcher) + .filter(Objects::nonNull) + .forEachRemaining(fromCommandLine::addExcluded); + + } + + private void extractPaths(final MatcherSet.Builder fromCommandLine) { + if (!includedPaths.isEmpty()) { + for (DocumentNameMatcher matcher : includedPaths) { + DefaultLog.getInstance().info(format("Including path matcher %s", matcher)); + fromCommandLine.addIncluded(matcher); } - if (!excl.isEmpty()) { - exclMatchers.add(new DocumentNameMatcher("excluded patterns", MatchPatterns.from(basedir.getDirectorySeparator(), excl), basedir)); + } + if (!excludedPaths.isEmpty()) { + for (DocumentNameMatcher matcher : excludedPaths) { + DefaultLog.getInstance().info(format("Excluding path matcher %s", matcher)); + fromCommandLine.addExcluded(matcher); } + } - if (!includedPaths.isEmpty()) { - for (DocumentNameMatcher matcher : includedPaths) { - DefaultLog.getInstance().info(format("Including path matcher %s", matcher)); - inclMatchers.add(matcher); - } + } + + private DocumentNameMatcher createMatcher(List fileProcessors) { + + List includedList = new ArrayList<>(); + List excludedList = new ArrayList<>(); + + for (MatcherSet processor : fileProcessors) { + if (processor.includes().isPresent()) { + includedList.add(processor.includes().get()); } - if (!excludedPaths.isEmpty()) { - for (DocumentNameMatcher matcher : excludedPaths) { - DefaultLog.getInstance().info(format("Excluding path matcher %s", matcher)); - exclMatchers.add(matcher); - } + if (processor.excludes().isPresent()) { + excludedList.add(processor.excludes().get()); } + } - lastMatcher = DocumentNameMatcher.MATCHES_ALL; - if (!exclMatchers.isEmpty()) { - lastMatcher = DocumentNameMatcher.not(DocumentNameMatcher.or(exclMatchers)); - if (!inclMatchers.isEmpty()) { - lastMatcher = DocumentNameMatcher.or(DocumentNameMatcher.or(inclMatchers), lastMatcher); - } + final DocumentNameMatcher included = includedList.isEmpty() ? MATCHES_NONE : DocumentNameMatcher.or(includedList); + final DocumentNameMatcher excluded = excludedList.isEmpty() ? MATCHES_NONE : DocumentNameMatcher.or(excludedList); + + if (excluded == MATCHES_NONE) { + return (included == MATCHES_NONE) ? MATCHES_ALL : included; + } else { + if (included == MATCHES_NONE) { + return DocumentNameMatcher.not(excluded); } + Predicate pred = documentName -> { + if (included.matches(documentName)) { + return true; + } + if (excluded.matches(documentName)) { + return false; + } + return true; + }; + final String name = format("or(%s, not(%s)", included, excluded); + return new DocumentNameMatcher(name, pred); } - return lastMatcher; } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java index 7932db4f6..98e005285 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java @@ -48,11 +48,14 @@ public final class ExclusionUtils { /** The list of comment prefixes that are used to filter comment lines. */ public static final List COMMENT_PREFIXES = Arrays.asList("#", "##", "//", "/**", "/*"); + /** Prefix used to negate the given pattern. */ + public static final String NEGATION_PREFIX = "!"; + /** A predicate that filters out lines that do NOT start with "!" */ - public static final Predicate NOT_MATCH_FILTER = s -> s.startsWith("!"); + public static final Predicate NOT_MATCH_FILTER = s -> s.startsWith(NEGATION_PREFIX); /** A predicate that filters out lines that start with "!" */ - public static final Predicate MATCH_FILTER = s -> !s.startsWith("!"); + public static final Predicate MATCH_FILTER = NOT_MATCH_FILTER.negate(); private ExclusionUtils() { // do not instantiate diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/FileProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/FileProcessor.java deleted file mode 100644 index 9d7886596..000000000 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/FileProcessor.java +++ /dev/null @@ -1,115 +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.config.exclusion; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Function; -import java.util.stream.Collectors; - -import org.apache.rat.config.exclusion.plexus.MatchPattern; -import org.apache.rat.config.exclusion.plexus.SelectorUtils; -import org.apache.rat.document.DocumentName; -import org.apache.rat.document.DocumentNameMatcher; - -/** - * The file processor reads the file specified in the DocumentName. - * It must return a list of fully qualified strings for the {@link MatchPattern} to process. - * It may return either Ant or Regex style strings, or a mixture of both. - * See {@link SelectorUtils} for a description of the formats. - * It may also generate custom DocumentNameMatchers which are added to the customMatchers instance variable. - */ -public class FileProcessor implements Function> { - /** A String format pattern to print a regex string */ - public static final String REGEX_FMT = "%%regex[%s]"; - /** An empty file processor returning no entries.*/ - public static final FileProcessor EMPTY = new FileProcessor(); - /** Prefix used to negate the given pattern. */ - public static final String NEGATION_PREFIX = "!"; - /** The list of patterns that will be converted into DocumentNameMatchers */ - private final List patterns = new ArrayList<>(); - /** The collection of custom DocumentNameMatchers generated by this processor */ - protected final List customMatchers = new ArrayList<>(); - - /** - * Protected constructor. - */ - protected FileProcessor() { - } - - /** - * Create a file processor out of a list of file patterns. - * @param patterns the patterns to simulate the file from. - */ - public FileProcessor(final Iterable patterns) { - patterns.forEach(this.patterns::add); - } - - @Override - public Iterable apply(final DocumentName documentName) { - return patterns.stream().map(entry -> localizePattern(documentName, entry)).collect(Collectors.toList()); - } - - /** - * If this FileProcessor builds custom matchers to handles special cases this method returns them - * to the processing stream. - * @return A collection of DocumentNameMatchers. Default returns an empty list. - */ - public final Iterable customDocumentNameMatchers() { - return customMatchers; - } - - /** - * Allows modification of the file entry to match the {@link MatchPattern} format. - * Default implementation returns the @{code entry} argument. - * @param documentName the name of the document that the file was read from. - * @param entry the entry from that document. - * @return the modified string or null to skip the string. - */ - protected String modifyEntry(final DocumentName documentName, final String entry) { - return entry; - } - - /** - * Modifies the {@link MatchPattern} formatted {@code pattern} argument by expanding the pattern and - * by adjusting the pattern to include the basename from the {@code documentName} argument. - * @param documentName the name of the file being read. - * @param pattern the pattern to format. - * @return the completely formatted pattern - */ - protected final String localizePattern(final DocumentName documentName, final String pattern) { - boolean prefix = pattern.startsWith(NEGATION_PREFIX); - String workingPattern = prefix ? pattern.substring(1) : pattern; - String normalizedPattern = SelectorUtils.extractPattern(workingPattern, documentName.getDirectorySeparator()); - StringBuilder sb = new StringBuilder(); - if (SelectorUtils.isRegexPrefixedPattern(workingPattern)) { - sb.append(prefix ? NEGATION_PREFIX : "") - .append(SelectorUtils.REGEX_HANDLER_PREFIX) - .append("\\Q").append(documentName.getBaseName()) - .append(documentName.getDirectorySeparator()) - .append("\\E").append(normalizedPattern) - .append(SelectorUtils.PATTERN_HANDLER_SUFFIX); - return sb.toString(); - } else { - sb.append(documentName.getBaseName()) - .append(documentName.getDirectorySeparator()).append(normalizedPattern); - return (prefix ? NEGATION_PREFIX : "") + DocumentName.builder(documentName).setName(sb.toString()).build().getName(); - } - } -} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java new file mode 100644 index 000000000..c13b1cee9 --- /dev/null +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -0,0 +1,244 @@ +/* + * 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.config.exclusion; + +import java.io.File; +import java.io.FileFilter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import java.util.Set; +import java.util.function.Predicate; +import org.apache.commons.io.filefilter.DirectoryFileFilter; +import org.apache.commons.io.filefilter.NameFileFilter; +import org.apache.commons.lang3.StringUtils; +import org.apache.rat.config.exclusion.plexus.MatchPattern; +import org.apache.rat.config.exclusion.plexus.MatchPatterns; +import org.apache.rat.config.exclusion.plexus.SelectorUtils; +import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; +import org.apache.rat.utils.ExtendedIterator; + +/** + * The file processor reads the file specified in the DocumentName. + * It must return a list of fully qualified strings for the {@link MatchPattern} to process. + * It may return either Ant or Regex style strings, or a mixture of both. + * See {@link SelectorUtils} for a description of the formats. + * It may also generate custom DocumentNameMatchers which are added to the customMatchers instance variable. + */ +public interface MatcherSet { + Optional includes(); + Optional excludes(); + + /** + * A MatcherSet that assumes the files contain the already formatted strings and just need to be + * localized for the fileName. + */ + class Builder { + + /** A String format pattern to print a regex string */ + public static final String REGEX_FMT = "%%regex[%s]"; + + /** + * Modifies the {@link MatchPattern} formatted {@code pattern} argument by expanding the pattern and + * by adjusting the pattern to include the basename from the {@code documentName} argument. + * @param documentName the name of the file being read. + * @param pattern the pattern to format. + * @return the completely formatted pattern + */ + public static String localizePattern(final DocumentName documentName, final String pattern) { + boolean prefix = pattern.startsWith(ExclusionUtils.NEGATION_PREFIX); + String workingPattern = prefix ? pattern.substring(1) : pattern; + String normalizedPattern = SelectorUtils.extractPattern(workingPattern, documentName.getDirectorySeparator()); + StringBuilder sb = new StringBuilder(); + if (SelectorUtils.isRegexPrefixedPattern(workingPattern)) { + sb.append(prefix ? ExclusionUtils.NEGATION_PREFIX : "") + .append(SelectorUtils.REGEX_HANDLER_PREFIX) + .append("\\Q").append(documentName.getBaseName()) + .append(documentName.getDirectorySeparator()) + .append("\\E").append(normalizedPattern) + .append(SelectorUtils.PATTERN_HANDLER_SUFFIX); + return sb.toString(); + } else { + sb.append(documentName.getBaseName()) + .append(documentName.getDirectorySeparator()).append(normalizedPattern); + return (prefix ? ExclusionUtils.NEGATION_PREFIX : "") + DocumentName.builder(documentName).setName(sb.toString()).build().getName(); + } + } + + /** + * Adds to lists of qualified file patterns. Non-matching patterns start with a {@code !}. + * @param matching the list to put matching file patterns into. + * @param notMatching the list to put non-matching files patterns into. + * @param patterns the patterns to match. + */ + public static void segregateList(final Set matching, final Set notMatching, + final Iterable patterns) { + patterns.forEach(s -> { + if (ExclusionUtils.MATCH_FILTER.test(s)) { + matching.add(s); + } else { + notMatching.add(s.substring(1)); + } + }); + } + + /** The name of the file being processed */ + protected final String fileName; + + /** The predicate that will return {@code false} for any comment line in the file. */ + protected final Predicate commentFilter; + + protected DocumentNameMatcher included; + + protected DocumentNameMatcher excluded; + + Builder() { + fileName = StringUtils.EMPTY; + commentFilter = StringUtils::isNotBlank; + } + + /** + * Constructor. + * @param fileName The name of the file to process. + * @param commentPrefix the comment prefix + */ + protected Builder(final String fileName, final String commentPrefix) { + this(fileName, commentPrefix == null ? null : Collections.singletonList(commentPrefix)); + } + + /** + * Constructor. + * @param fileName name of the file to process + * @param commentPrefixes a collection of comment prefixes. + */ + protected Builder(final String fileName, final Iterable commentPrefixes) { + super(); + this.fileName = fileName; + // null prefixes = check prefix may not be blank. + this.commentFilter = commentPrefixes == null ? StringUtils::isNotBlank : ExclusionUtils.commentFilter(commentPrefixes); + } + + /** + * Allows modification of the file entry to match the {@link MatchPattern} format. + * Default implementation returns the @{code entry} argument. + * @param documentName the name of the document that the file was read from. + * @param entry the entry from that document. + * @return the modified string or null to skip the string. + */ + protected String modifyEntry(final DocumentName documentName, final String entry) { + return entry; + } + + public Builder addIncluded(DocumentName fromDocument, Set names) { + if (!names.isEmpty()) { + addIncluded(new DocumentNameMatcher(fromDocument.localized("/"), MatchPatterns.from(names), fromDocument.getBaseDocumentName())); + } + return this; + } + + public Builder addExcluded(DocumentName fromDocument, Set names) { + if (!names.isEmpty()) { + addExcluded(new DocumentNameMatcher(fromDocument.localized("/"), MatchPatterns.from(names), fromDocument.getBaseDocumentName())); + } + return this; + } + + public Builder addIncluded(DocumentNameMatcher matcher) { + this.included = this.included == null ? matcher : DocumentNameMatcher.or(this.included, matcher); + return this; + } + + public Builder addExcluded(DocumentNameMatcher matcher) { + this.excluded = this.excluded == null ? matcher : DocumentNameMatcher.or(this.excluded, matcher); + return this; + } + + /** + * Process by reading the file setting the {@link #included} and {@link #excluded} DocumentMatchers. + * @param documentName the file to read. + */ + protected void process(final DocumentName documentName) { + Set included = new HashSet<>(); + Set excluded = new HashSet<>(); + List iterable = new ArrayList<>(); + ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) + .map(entry -> modifyEntry(documentName, entry)) + .filter(Objects::nonNull) + .map(entry -> localizePattern(documentName, entry)) + .forEachRemaining(iterable::add); + segregateList(included, excluded, iterable); + addExcluded(documentName, excluded); + addIncluded(documentName, included); + } + + /** + * Create a list of files by applying the filter to the specified directory. + * @param dir the directory. + * @param filter the filter. + * @return an array of files. May be empty but will not be null. + */ + protected File[] listFiles(final File dir, final FileFilter filter) { + File[] result = dir.listFiles(filter); + return result == null ? new File[0] : result; + } + + /** + * Process the directory tree looking for files that match the filter. Call {@link #process} on any matching file. + * @param directory The name of the directory to process. + * @param fileFilter the filter to detect processable files with. + */ + protected void checkDirectory(final DocumentName directory, final FileFilter fileFilter) { + File dirFile = new File(directory.getName()); + for (File f : listFiles(dirFile, fileFilter)) { + process(DocumentName.builder(f).setBaseName(directory.getBaseName()).build()); + } + for (File dir : listFiles(dirFile, DirectoryFileFilter.DIRECTORY)) { + checkDirectory(DocumentName.builder(dir).build(), fileFilter); + } + } + + public MatcherSet build(final DocumentName dir) { + checkDirectory(dir, new NameFileFilter(fileName)); + + MatcherSet result = new MatcherSet() { + final DocumentNameMatcher myIncluded = included; + final DocumentNameMatcher myExcluded = excluded; + + @Override + public Optional includes() { + return Optional.ofNullable(myIncluded); + } + + @Override + public Optional excludes() { + return Optional.ofNullable(myExcluded); + } + }; + included = null; + excluded = null; + return result; + } + + } +} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java index 1bd805f41..9d6874c40 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java @@ -28,10 +28,10 @@ import java.util.Set; import java.util.function.Predicate; -import org.apache.rat.config.exclusion.fileProcessors.BazaarIgnoreProcessor; -import org.apache.rat.config.exclusion.fileProcessors.CVSFileProcessor; -import org.apache.rat.config.exclusion.fileProcessors.GitFileProcessor; -import org.apache.rat.config.exclusion.fileProcessors.HgIgnoreProcessor; +import org.apache.rat.config.exclusion.fileProcessors.BazaarIgnoreBuilder; +import org.apache.rat.config.exclusion.fileProcessors.CVSIgnoreBuilder; +import org.apache.rat.config.exclusion.fileProcessors.GitIgnoreBuilder; +import org.apache.rat.config.exclusion.fileProcessors.HgIgnoreBuilder; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.utils.ExtendedIterator; @@ -55,7 +55,7 @@ public enum StandardCollection { * The files and directories created by a Bazaar source code control based tool. */ BAZAAR("The files and directories created by a Bazaar source code control based tool.", - Arrays.asList("**/.bzr/**", "**/.bzrignore"), null, new BazaarIgnoreProcessor()), + Arrays.asList("**/.bzr/**", "**/.bzrignore"), null, new BazaarIgnoreBuilder()), /** * The files and directories created by a Bitkeeper source code control based tool. */ @@ -74,7 +74,7 @@ public enum StandardCollection { "**/*.orig", "**/*.rej", "**/.del-*", "**/*.a", "**/*.old", "**/*.o", "**/*.obj", "**/*.so", "**/*.exe", "**/*.Z", "**/*.elc", "**/*.ln", "**/core"), - null, new CVSFileProcessor()), + null, new CVSIgnoreBuilder()), /** * The files and directories created by a DARCS source code control based tool. */ @@ -93,7 +93,7 @@ null, new CVSFileProcessor()), GIT("The files and directories created by GIT source code control to support GIT, also processes files listed in '.gitignore'.", Arrays.asList("**/.git/**", "**/.gitignore"), null, - new GitFileProcessor() + new GitIgnoreBuilder() ), /** * The hidden directories. Directories with names that start with '.' @@ -142,7 +142,7 @@ null, new CVSFileProcessor()), * The files and directories created by a Mercurial source code control based tool. */ MERCURIAL("The files and directories created by a Mercurial source code control based tool.", - Arrays.asList("**/.hg/**", "**/.hgignore"), null, new HgIgnoreProcessor()), + Arrays.asList("**/.hg/**", "**/.hgignore"), null, new HgIgnoreBuilder()), /** * The set of miscellaneous files generally left by editors and the like. */ @@ -199,17 +199,17 @@ null, new CVSFileProcessor()), private final Collection patterns; /** A document name matcher supplier to create a document name matcher. May be null */ private final DocumentNameMatcher staticDocumentNameMatcher; - /** The FileProcessor to process the exclude file associated with this exclusion. May be null. */ - private final FileProcessor fileProcessor; + /** The MatcherSet to process the exclude file associated with this exclusion. May be null. */ + private final MatcherSet.Builder fileProcessorBuilder; /** The description of this collection */ private final String desc; StandardCollection(final String desc, final Collection patterns, final DocumentNameMatcher documentNameMatcher, - final FileProcessor fileProcessor) { + final MatcherSet.Builder fileProcessorBuilder) { this.desc = desc; this.patterns = patterns == null ? Collections.emptyList() : new HashSet<>(patterns); this.staticDocumentNameMatcher = documentNameMatcher; - this.fileProcessor = fileProcessor; + this.fileProcessorBuilder = fileProcessorBuilder; } /** @@ -263,11 +263,11 @@ public Set patterns() { * * @return the fileProcessor if it exists, {@code null} otherwise. */ - public ExtendedIterator fileProcessor() { - List lst = new ArrayList<>(); + public ExtendedIterator fileProcessorBuilder() { + List lst = new ArrayList<>(); for (StandardCollection sc : getCollections()) { - if (sc.fileProcessor != null) { - lst.add(sc.fileProcessor); + if (sc.fileProcessorBuilder != null) { + lst.add(sc.fileProcessorBuilder); } } return ExtendedIterator.create(lst.iterator()); diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java similarity index 90% rename from apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreProcessor.java rename to apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java index 65217c37f..315ec99dc 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreProcessor.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java @@ -18,6 +18,7 @@ */ package org.apache.rat.config.exclusion.fileProcessors; +import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; import static java.lang.String.format; @@ -25,11 +26,11 @@ /** * A processor for {@code .bzrignore} files. */ -public final class BazaarIgnoreProcessor extends DescendingFileProcessor { +public final class BazaarIgnoreBuilder extends MatcherSet.Builder { /** * Constructor. */ - public BazaarIgnoreProcessor() { + public BazaarIgnoreBuilder() { super(".bzrignore", "#"); } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSFileProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java similarity index 78% rename from apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSFileProcessor.java rename to apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java index a1f6582c2..cd308e923 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSFileProcessor.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java @@ -19,39 +19,40 @@ package org.apache.rat.config.exclusion.fileProcessors; import java.io.File; -import java.util.ArrayList; +import java.util.HashSet; import java.util.Iterator; -import java.util.List; +import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.apache.rat.config.exclusion.ExclusionUtils; +import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; /** * A file processor for the {@code .csvignore} file. */ -public class CVSFileProcessor extends DescendingFileProcessor { +public class CVSIgnoreBuilder extends MatcherSet.Builder { /** * The constructor. */ - public CVSFileProcessor() { + public CVSIgnoreBuilder() { super(".cvsignore", (String) null); } @Override - protected List process(final DocumentName documentName) { + protected void process(final DocumentName documentName) { final File dir = new File(documentName.getName()); - List result = new ArrayList<>(); + Set result = new HashSet<>(); Iterator iter = ExclusionUtils.asIterator(dir, StringUtils::isNotBlank); while (iter.hasNext()) { String line = iter.next(); String[] parts = line.split("\\s+"); for (String part : parts) { if (!part.isEmpty()) { - result.add(this.localizePattern(documentName, part)); + result.add(localizePattern(documentName, part)); } } } - return result; + addIncluded(documentName.getBaseDocumentName(), result); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/DescendingFileProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/DescendingFileProcessor.java deleted file mode 100644 index 438f00752..000000000 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/DescendingFileProcessor.java +++ /dev/null @@ -1,121 +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.config.exclusion.fileProcessors; - -import java.io.File; -import java.io.FileFilter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.function.Predicate; - -import org.apache.commons.io.filefilter.DirectoryFileFilter; -import org.apache.commons.io.filefilter.NameFileFilter; -import org.apache.commons.lang3.StringUtils; -import org.apache.rat.config.exclusion.ExclusionUtils; -import org.apache.rat.config.exclusion.FileProcessor; -import org.apache.rat.document.DocumentName; - -/** - * A FileProcessor that assumes the files contain the already formatted strings and just need to be - * localized for the fileName. - */ -public class DescendingFileProcessor extends FileProcessor { - /** The name of the file being processed */ - private final String fileName; - /** The predicate that will return {@code false} for any comment line in the file. */ - protected final Predicate commentFilter; - - /** - * Constructor. - * @param fileName The name of the file to process. - * @param commentPrefix the comment prefix - */ - public DescendingFileProcessor(final String fileName, final String commentPrefix) { - this(fileName, commentPrefix == null ? null : Collections.singletonList(commentPrefix)); - } - - /** - * Constructor. - * @param fileName name of the file to process - * @param commentPrefixes a collection of comment prefixes. - */ - public DescendingFileProcessor(final String fileName, final Iterable commentPrefixes) { - super(); - this.fileName = fileName; - // null prefixes = check prefix may not be blank. - this.commentFilter = commentPrefixes == null ? StringUtils::isNotBlank : ExclusionUtils.commentFilter(commentPrefixes); - } - - /** - * Process by reading the file and return a list of properly formatted patterns. - * The default implementation does the following: - *
      - *
    • reads lines from the file specified by documentName
    • - *
    • modifies those entries by calling {@link FileProcessor#modifyEntry(DocumentName, String)}
    • - *
    • further modifies the entry by calling {@link FileProcessor#localizePattern(DocumentName, String)}
    • - *
    • retrieving the name from the resulting DocumentName
    • - *
    - * @param documentName the file to read. - * @return the list of properly formatted patterns - */ - protected List process(final DocumentName documentName) { - return ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) - .map(entry -> this.modifyEntry(documentName, entry)) - .filter(Objects::nonNull) - .map(entry -> this.localizePattern(documentName, entry)) - .addTo(new ArrayList<>()); - } - - /** - * Create a list of files by applying the filter to the specified directory. - * @param dir the directory. - * @param filter the filter. - * @return an array of files. May be empty but will not be null. - */ - private File[] listFiles(final File dir, final FileFilter filter) { - File[] result = dir.listFiles(filter); - return result == null ? new File[0] : result; - } - - /** - * Process the directory tree looking for files that match the filter. Process any matching file and return - * a list of fully qualified patterns. - * @param directory The name of the directory to process. - * @param fileFilter the filter to detect processable files with. - * @return the list of fully qualified file patterns. - */ - protected List checkDirectory(final DocumentName directory, final FileFilter fileFilter) { - List fileNames = new ArrayList<>(); - File dirFile = new File(directory.getName()); - for (File f : listFiles(dirFile, fileFilter)) { - fileNames.addAll(process(DocumentName.builder(f).setBaseName(directory.getBaseName()).build())); - } - for (File dir : listFiles(dirFile, DirectoryFileFilter.DIRECTORY)) { - fileNames.addAll(checkDirectory(DocumentName.builder(dir).build(), fileFilter)); - } - return fileNames; - } - - @Override - public List apply(final DocumentName dir) { - return checkDirectory(dir, new NameFileFilter(fileName)); - } -} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessor.java deleted file mode 100644 index 37af81b61..000000000 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessor.java +++ /dev/null @@ -1,75 +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.config.exclusion.fileProcessors; - -import java.io.File; - -import org.apache.rat.config.exclusion.plexus.MatchPatterns; -import org.apache.rat.document.DocumentName; -import org.apache.rat.document.DocumentNameMatcher; - -/** - * Processes the .gitignore file. - * @see .gitignore documentation - */ -public class GitFileProcessor extends DescendingFileProcessor { - // create a list of levels that a list of processors at that level. - // will return a custom matcher that from an overridden FileProcessor.customDocumentNameMatchers method - // build LevelMatcher as a system that returns Include, Exclude or no status for each check. - // put the level matcher in an array with other level matchers at the specific level below the root - // When searching start at the lowest level and work up the tree. - - /** - * Constructs a file processor that processes a .gitignore file and ignores any lines starting with "#". - */ - public GitFileProcessor() { - super(".gitignore", "#"); - } - - @Override - public String modifyEntry(final DocumentName documentName, final String entry) { - // An optional prefix "!" which negates the pattern; - boolean prefix = entry.startsWith("!"); - String pattern = prefix || entry.startsWith("\\#") || entry.startsWith("\\!") ? entry.substring(1) : entry; - - // If there is a separator at the beginning or middle (or both) of the pattern, then - // the pattern is relative to the directory level of the particular .gitignore file itself. - // Otherwise, the pattern may also match at any level below the .gitignore level. - int slashPos = pattern.indexOf("/"); - // no slash or at end already - if (slashPos == -1 || slashPos == pattern.length() - 1) { - pattern = "**/" + pattern; - } - if (slashPos == 0) { - pattern = pattern.substring(1); - } - // If there is a separator at the end of the pattern then the pattern will only match directories, - // otherwise the pattern can match both files and directories. - if (pattern.endsWith("/")) { - pattern = pattern.substring(0, pattern.length() - 1); - String name = prefix ? "!" + pattern : pattern; - DocumentName matcherPattern = DocumentName.builder(documentName).setName(name.replace("/", documentName.getDirectorySeparator())) - .build(); - customMatchers.add(DocumentNameMatcher.and(new DocumentNameMatcher("isDirectory", File::isDirectory), - new DocumentNameMatcher(name, MatchPatterns.from(matcherPattern.localized("/"))))); - return null; - } - return prefix ? "!" + pattern : pattern; - } -} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java new file mode 100644 index 000000000..319f2a137 --- /dev/null +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java @@ -0,0 +1,180 @@ +/* + * 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.config.exclusion.fileProcessors; + +import java.io.File; + +import java.io.FileFilter; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.function.Consumer; +import org.apache.commons.io.filefilter.DirectoryFileFilter; +import org.apache.rat.config.exclusion.ExclusionUtils; +import org.apache.rat.config.exclusion.MatcherSet; +import org.apache.rat.config.exclusion.plexus.MatchPatterns; +import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; + +import static org.apache.rat.config.exclusion.ExclusionUtils.NEGATION_PREFIX; + +/** + * Processes the .gitignore file. + * @see .gitignore documentation + */ +public class GitIgnoreBuilder extends MatcherSet.Builder { + // create a list of levels that a list of processors at that level. + // will return a custom matcher that from an overridden MatcherSet.customDocumentNameMatchers method + // build LevelMatcher as a system that returns Include, Exclude or no status for each check. + // put the level matcher in an array with other level matchers at the specific level below the root + // When searching start at the lowest level and work up the tree. + + private static final String IGNORE_FILE = ".gitignore"; + private static final String COMMENT_PREFIX = "#"; + private static final String ESCAPED_COMMENT = "\\#"; + private static final String ESCAPED_NEGATION = "\\!"; + private static final String SLASH = "/"; + + private SortedMap levelBuilders = new TreeMap<>(); + + + /** + * Constructs a file processor that processes a .gitignore file and ignores any lines starting with "#". + */ + public GitIgnoreBuilder() { + super(IGNORE_FILE, COMMENT_PREFIX); + } + + /** + * Process the directory tree looking for files that match the filter. Process any matching file and return + * a list of fully qualified patterns. + * @param directory The name of the directory to process. + * @param fileFilter the filter to detect processable files with. + * @return the list of fully qualified file patterns. + */ + protected void checkDirectory(final DocumentName directory, final FileFilter fileFilter) { + checkDirectory(0, directory, fileFilter); + List keys = new ArrayList<>(levelBuilders.keySet()); + keys.sort( (a, b) -> -1 * a.compareTo(b)); + for (int level : keys) { + LevelBuilder levelBuilder = levelBuilders.get(level); + MatcherSet fileProcessor = levelBuilder.build(directory); + fileProcessor.excludes().ifPresent(this::addExcluded); + fileProcessor.includes().ifPresent(this::addIncluded); + } + } + + private void checkDirectory(final int level, final DocumentName directory, final FileFilter fileFilter) { + File dirFile = new File(directory.getName()); + for (File f : listFiles(dirFile, fileFilter)) { + LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(level, LevelBuilder::new); + DocumentName dirBasedName = DocumentName.builder(f).setBaseName(directory.getBaseName()).build(); + levelBuilder.process(dirBasedName, DocumentName.builder(f).setBaseName(directory.getName()).build()); + } + for (File dir : listFiles(dirFile, DirectoryFileFilter.DIRECTORY)) { + checkDirectory(level + 1, DocumentName.builder(dir).setBaseName(directory.getBaseName()).build(), fileFilter); + } + } + /** + * package private for testing. + * @return the included DocumentNameMatcher. + */ + DocumentNameMatcher getIncluded() { + return included; + } + + /** + * package private for testing. + * @return the excluded DocumentNameMatcher. + */ + DocumentNameMatcher getExcluded() { + return excluded; + } + + @Override + public String modifyEntry(final DocumentName documentName, final String entry) { + return modifyEntry(documentName, entry, this::addIncluded, this::addExcluded); + } + + private static String modifyEntry(final DocumentName documentName, final String entry, Consumer include, + Consumer exclude) { + // An optional prefix "!" which negates the pattern; + boolean prefix = entry.startsWith(NEGATION_PREFIX); + String pattern = prefix || entry.startsWith(ESCAPED_COMMENT) || entry.startsWith(ESCAPED_NEGATION) ? + entry.substring(1) : entry; + + // If there is a separator at the beginning or middle (or both) of the pattern, then + // the pattern is relative to the directory level of the particular .gitignore file itself. + // Otherwise, the pattern may also match at any level below the .gitignore level. + int slashPos = pattern.indexOf(SLASH); + // no slash or at end already + if (slashPos == -1 || slashPos == pattern.length() - 1) { + pattern = "**/" + pattern; + } + if (slashPos == 0) { + pattern = pattern.substring(1); + } + // If there is a separator at the end of the pattern then the pattern will only match directories, + // otherwise the pattern can match both files and directories. + if (pattern.endsWith(SLASH)) { + pattern = pattern.substring(0, pattern.length() - 1); + String name = prefix ? NEGATION_PREFIX + pattern : pattern; + DocumentName matcherPattern = DocumentName.builder(documentName).setName(name.replace(SLASH, documentName.getDirectorySeparator())) + .build(); + DocumentNameMatcher matcher = DocumentNameMatcher.and(new DocumentNameMatcher("isDirectory", File::isDirectory), + new DocumentNameMatcher(name, MatchPatterns.from(matcherPattern.localized(SLASH)))); + if (prefix) { + exclude.accept(matcher); + } else { + include.accept(matcher); + } + return null; + } + return prefix ? NEGATION_PREFIX + pattern : pattern; + } + + private class LevelBuilder extends MatcherSet.Builder { + LevelBuilder(int level) { + super(IGNORE_FILE+"-"+level, COMMENT_PREFIX); + } + + public String modifyEntry(final DocumentName documentName, final String entry) { + return GitIgnoreBuilder.modifyEntry(documentName, entry, this::addIncluded, this::addExcluded); + } + + public void process(DocumentName directory, DocumentName documentName) { + Set included = new HashSet<>(); + Set excluded = new HashSet<>(); + List iterable = new ArrayList<>(); + ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) + .map(entry -> modifyEntry(documentName, entry)) + .filter(Objects::nonNull) + .map(entry -> localizePattern(documentName, entry)) + .forEachRemaining(iterable::add); + segregateList(included, excluded, iterable); + addExcluded(directory, excluded); + addIncluded(directory, included); + + } + } +} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java similarity index 90% rename from apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreProcessor.java rename to apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java index d88e60c50..036333ea6 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreProcessor.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java @@ -18,11 +18,11 @@ */ package org.apache.rat.config.exclusion.fileProcessors; -import java.util.List; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; import static java.lang.String.format; @@ -30,7 +30,7 @@ /** * A processor for the {@code .hgignore} files. */ -public final class HgIgnoreProcessor extends DescendingFileProcessor { +public final class HgIgnoreBuilder extends MatcherSet.Builder { /** * The state enumeration for the processor. When processing the file the processor changes * syntax state depending on the input. @@ -50,15 +50,15 @@ enum Syntax { /** * Constructs the .hgignore processor. */ - public HgIgnoreProcessor() { + public HgIgnoreBuilder() { super(".hgignore", "#"); state = Syntax.REGEXP; } @Override - protected List process(final DocumentName baseName) { + protected void process(final DocumentName baseName) { state = Syntax.REGEXP; - return super.process(baseName); + super.process(baseName); } @Override diff --git a/apache-rat-core/src/main/java/org/apache/rat/help/Help.java b/apache-rat-core/src/main/java/org/apache/rat/help/Help.java index 06202375e..8623c175d 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/help/Help.java +++ b/apache-rat-core/src/main/java/org/apache/rat/help/Help.java @@ -85,7 +85,7 @@ public void printUsage(final Options opts) { helpFormatter.printWrapped(writer, helpFormatter.getWidth(), helpFormatter.getLeftPadding() + HELP_PADDING + HELP_PADDING, argumentPadding + "Provides a path matcher: " + sc.hasStaticDocumentNameMatcher()); helpFormatter.printWrapped(writer, helpFormatter.getWidth(), helpFormatter.getLeftPadding() + HELP_PADDING + HELP_PADDING, - argumentPadding + "Provides a file processor: " + sc.fileProcessor().hasNext()); + argumentPadding + "Provides a file processor: " + sc.fileProcessorBuilder().hasNext()); } writer.println("\nA path matcher will match specific information about the file."); writer.println("\nA file processor will process the associated \"ignore\" file for include and exclude directives"); diff --git a/apache-rat-core/src/site/markdown/development/write_file_processor.md b/apache-rat-core/src/site/markdown/development/write_file_processor.md index 77d843b70..11fb3e620 100644 --- a/apache-rat-core/src/site/markdown/development/write_file_processor.md +++ b/apache-rat-core/src/site/markdown/development/write_file_processor.md @@ -22,7 +22,7 @@ > * Rat [Exclude Expressions](../exclusion_expression.html): The expressions that are used to match file names -A FileProcessor is a module that locates files with a specific name in the directory tree and reads from them file patterns that are translated into Rat exclude expressions. These files are normally found in the file directory tree and their restrictions normally only applies to files at the same directory level as the processed file or below. This type of file is implemented by the `org.apache.rat.config.exclusion.fileProcessors.DescendingFileProcessor`. +A FileProcessor is a module that locates files with a specific name in the directory tree and reads from them file patterns that are translated into Rat exclude expressions. These files are normally found in the file directory tree and their restrictions normally only applies to files at the same directory level as the processed file or below. This type of file is implemented by the `org.apache.rat.config.exclusion.MatcherSet.Builder`. The `DescendingFileProcessor` takes a file name and one or more comment prefixes as in the constructor. The file name is normally a file that is generally hidden on Linux systems like ".gitignore" or ".hgignore". The `DescendingFileProcessor` will scan the directories looking for files with the specified name. If one is found it is passed to the `process(DocumentName)` method which reads the document and returns a list of exclude expressions. 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 327aa9051..11a8ce013 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 @@ -89,8 +89,9 @@ public void cleanup() { @Test public void testAddIncludedFilter() { + DocumentName dirName = DocumentName.builder(tempDir).build(); underTest.addExcludedFilter(DirectoryFileFilter.INSTANCE); - DocumentNameMatcher exlcuder = underTest.getDocumentExcluder(DocumentName.builder(new File(File.separator)).build()); + DocumentNameMatcher exlcuder = underTest.getDocumentExcluder(dirName); assertEquals("not(DirectoryFileFilter)", exlcuder.toString()); assertFalse(exlcuder.matches(DocumentName.builder(tempDir).build())); File f = new File(tempDir, "foo.txt"); diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java index 922912674..995ad407c 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java @@ -36,7 +36,7 @@ public class FileProcessorTest { @ParameterizedTest(name="{index} {1}") @MethodSource("localizePatternData") void localizePatternTest(DocumentName baseName, String pattern, String expectedStr) { - assertThat(FileProcessor.EMPTY.localizePattern(baseName, pattern)).isEqualTo(expectedStr); + assertThat(MatcherSet.Builder.localizePattern(baseName, pattern)).isEqualTo(expectedStr); } public static Stream localizePatternData() { diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/StandardCollectionTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/StandardCollectionTest.java index 5a9186f83..9f62c6fc3 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/StandardCollectionTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/StandardCollectionTest.java @@ -36,7 +36,7 @@ public class StandardCollectionTest { @ParameterizedTest @MethodSource("collectionData") public void testState(StandardCollection scm, boolean hasFileProcessor, boolean hasPathMatchSupplier, boolean hasPatterns) { - assertEquals(hasFileProcessor, scm.fileProcessor().hasNext(), () -> scm.name() + " FileProcessor state wrong."); + assertEquals(hasFileProcessor, scm.fileProcessorBuilder().hasNext(), () -> scm.name() + " MatcherSet state wrong."); assertEquals(hasPathMatchSupplier, scm.hasStaticDocumentNameMatcher(), () -> scm.name() + " PathMatcherSupplier state wrong."); assertEquals(hasPatterns, !scm.patterns().isEmpty(), () -> scm.name() + " patterns state wrong."); } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java similarity index 97% rename from apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreProcessorTest.java rename to apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java index 741a1ab44..9a9e3898c 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java @@ -30,7 +30,7 @@ import java.io.IOException; import java.io.PrintWriter; -public class AbstractIgnoreProcessorTest { +public class AbstractIgnoreBuilderTest { @TempDir protected File baseDir; diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java new file mode 100644 index 000000000..f2a860161 --- /dev/null +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java @@ -0,0 +1,59 @@ +/* + * 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.config.exclusion.fileProcessors; + +import java.util.ArrayList; +import org.apache.rat.config.exclusion.MatcherSet; +import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; +import org.apache.rat.utils.ExtendedIterator; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class BazaarIgnoreBuilderTest extends AbstractIgnoreBuilderTest { + + @Test + public void processExampleFileTest() throws IOException { + String[] lines = { + "# a comment", "*.elc", "*.pyc", "*~", System.lineSeparator(), + "# switch to regexp syntax.", "RE:^\\.pc" }; + + List expected = Arrays.asList("test.elc", "test.pyc", "test.thing~", ".pc"); + + writeFile(".bzrignore", Arrays.asList(lines)); + + BazaarIgnoreBuilder processor = new BazaarIgnoreBuilder(); + MatcherSet matcherSet = processor.build(baseName); + assertThat(matcherSet.includes()).isPresent(); + assertThat(matcherSet.excludes()).isNotPresent(); + DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + for (String name : expected) { + DocumentName docName = baseName.resolve(name); + assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); + } + } + +} diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSFileProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java similarity index 59% rename from apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSFileProcessorTest.java rename to apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java index 7900fd7e7..2edcb9572 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSFileProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java @@ -19,7 +19,9 @@ package org.apache.rat.config.exclusion.fileProcessors; import java.util.ArrayList; - +import org.apache.rat.config.exclusion.MatcherSet; +import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.utils.ExtendedIterator; import org.junit.jupiter.api.Test; @@ -28,22 +30,28 @@ import java.util.Arrays; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; -public class CVSFileProcessorTest extends AbstractIgnoreProcessorTest { +public class CVSIgnoreBuilderTest extends AbstractIgnoreBuilderTest { @Test public void processExampleFileTest() throws IOException { String[] lines = { "thingone thingtwo", System.lineSeparator(), "one_fish", "two_fish", "", "red_* blue_*"}; - List expected = ExtendedIterator.create(Arrays.asList("thingone", "thingtwo", "one_fish", "two_fish", "red_*", "blue_*").iterator()) - .map(s -> new File(baseDir, s).getPath()).addTo(new ArrayList<>()); + List expected = Arrays.asList("thingone", "thingtwo", "one_fish", "two_fish", "red_fish", "blue_fish"); writeFile(".cvsignore", Arrays.asList(lines)); - CVSFileProcessor processor = new CVSFileProcessor(); - List actual = processor.apply(baseName); - assertEquals(expected, actual); + CVSIgnoreBuilder processor = new CVSIgnoreBuilder(); + MatcherSet matcherSet = processor.build(baseName); + + assertThat(matcherSet.includes()).isPresent(); + assertThat(matcherSet.excludes()).isNotPresent(); + DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + for (String name : expected) { + DocumentName docName = baseName.resolve(name); + assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); + } } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/DescendingFileProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/DescendingFileProcessorTest.java deleted file mode 100644 index e3343c1d5..000000000 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/DescendingFileProcessorTest.java +++ /dev/null @@ -1,70 +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.config.exclusion.fileProcessors; - -import java.util.ArrayList; -import org.apache.rat.document.DocumentName; -import org.apache.rat.utils.ExtendedIterator; -import org.junit.jupiter.api.Test; - -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -public class DescendingFileProcessorTest extends AbstractIgnoreProcessorTest { - - @Test - public void singleDirectoryTest() throws IOException { - String[] lines = {"*.ext", "fname.*", "**/fname.ext"}; - - List expected = ExtendedIterator.create(Arrays.asList(lines).iterator()) - .map(s -> new File(baseDir, s).getPath()).addTo(new ArrayList<>()); - - writeFile("test.txt", Arrays.asList(lines)); - DocumentName documentName = DocumentName.builder(baseDir).build(); - - DescendingFileProcessor processor = new DescendingFileProcessor("test.txt", "#"); - List actual = processor.apply(baseName); - assertThat(actual).isEqualTo(expected); - } - - @Test - public void layeredDirectoryTest() throws IOException { - String[] lines = {"*.ext", "fname.*", "**/fname.ext"}; - - List expected = ExtendedIterator.create(Arrays.asList(lines).iterator()) - .map(s -> new File(baseDir, s).getPath()).addTo(new ArrayList<>()); - - writeFile("test.txt", Arrays.asList(lines)); - - File subdir = new File(baseDir, "subdir"); - assertThat(subdir.mkdirs()).as("Could not make subdirectory").isTrue(); - - writeFile("subdir/test.txt", Collections.singletonList("foo.*")); - expected.add(new File(subdir, "foo.*").getPath()); - - DescendingFileProcessor processor = new DescendingFileProcessor("test.txt", "#"); - List actual = processor.apply(baseName); - assertThat(actual).isEqualTo(expected); - } -} diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessorTest.java deleted file mode 100644 index 3166b4ca7..000000000 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitFileProcessorTest.java +++ /dev/null @@ -1,118 +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.config.exclusion.fileProcessors; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.stream.Stream; -import org.apache.rat.document.DocumentName; -import org.apache.rat.document.DocumentNameMatcher; -import org.apache.rat.utils.ExtendedIterator; -import org.junit.Ignore; -import org.junit.jupiter.api.Test; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.util.Arrays; -import java.util.List; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import static org.assertj.core.api.Assertions.assertThat; - -public class GitFileProcessorTest extends AbstractIgnoreProcessorTest { - - @Test - public void processExampleFileTest() throws IOException { - String[] lines = { - "# somethings", - "!thingone", "thing*", System.lineSeparator(), - "# some fish", - "**/fish", "*_fish", - "# some colorful directories", - "red/", "blue/*/"}; - - List expected = ExtendedIterator.create(Arrays.asList("**/thing*", "**/fish", "**/*_fish").iterator()) - .map(s -> new File(baseDir, s).getPath()).addTo(new ArrayList<>()); - expected.add(0, "!"+new File(baseDir, "**/thingone").getPath()); - // "thingone", - writeFile(".gitignore", Arrays.asList(lines)); - - GitFileProcessor processor = new GitFileProcessor(); - List actual = processor.apply(baseName); - assertThat(actual).isEqualTo(expected); - - actual.clear(); - processor.customDocumentNameMatchers().forEach(x -> actual.add(x.toString())); - expected.clear(); - ExtendedIterator.create(Arrays.asList("**/red", "blue/*").iterator()) - .map(s -> String.format("and(isDirectory, %s)", s)) - .forEachRemaining(expected::add); - assertThat(actual).isEqualTo(expected); - } - - // see https://git-scm.com/docs/gitignore - @ParameterizedTest - @MethodSource("modifyEntryData") - public void modifyEntryTest(String source, String expected) { - GitFileProcessor underTest = new GitFileProcessor(); - DocumentName testName = DocumentName.builder().setName("GitFileProcessorTest").setBaseName("testDir").build(); - if (source.endsWith("/")) { - assertThat(underTest.modifyEntry(testName, source)).isEqualTo(null); - Iterator iter = underTest.customDocumentNameMatchers().iterator(); - assertThat(iter).hasNext(); - assertThat(iter.next().toString()).isEqualTo(String.format("and(isDirectory, %s)", expected)); - } else { - assertThat(underTest.modifyEntry(testName, source)).isEqualTo(expected); - assertThat(underTest.customDocumentNameMatchers().iterator().hasNext()).isFalse(); - } - } - - private static Stream modifyEntryData() { - List lst = new ArrayList<>(); - - lst.add(Arguments.of("\\#filename", "**/#filename")); - - lst.add(Arguments.of("!#filename", "!**/#filename")); - lst.add(Arguments.of("\\#filename", "**/#filename")); - lst.add(Arguments.of("!#filename", "!**/#filename")); - lst.add(Arguments.of("/filename", "filename")); - lst.add(Arguments.of("file/name", "file/name")); - lst.add(Arguments.of("/file/name", "file/name")); - lst.add(Arguments.of("filename", "**/filename")); - lst.add(Arguments.of("filename/", "**/filename")); - lst.add(Arguments.of("/filename/", "filename")); - - return lst.stream(); - } - - @Test - @Ignore("RAT-335 ") - public void test_RAT_335() { - GitFileProcessor underTest = new GitFileProcessor(); - URL url = GitFileProcessorTest.class.getClassLoader().getResource("RAT_355/src/"); - File file = new File(url.getFile()); - - DocumentName documentName = DocumentName.builder(file).setBaseName(File.separator).build(); - List lst = underTest.apply(documentName); - System.out.println(lst); - } -} diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java new file mode 100644 index 000000000..3156eae19 --- /dev/null +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java @@ -0,0 +1,147 @@ +/* + * 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.config.exclusion.fileProcessors; + +import java.io.File; +import java.util.ArrayList; +import java.util.stream.Stream; +import org.apache.rat.config.exclusion.MatcherSet; +import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.URL; +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.assertj.core.api.Assertions.assertThat; + +public class GitIgnoreBuilderTest extends AbstractIgnoreBuilderTest { + + @Test + public void processExampleFileTest() throws IOException { + String[] lines = { + "# somethings", + "!thingone", "thing*", System.lineSeparator(), + "# some fish", + "**/fish", "*_fish", + "# some colorful directories", + "red/", "blue/*/"}; + + List expected = Arrays.asList("some/things", "some/fish", "another/red_fish"); + + List ignored = Arrays.asList("some/thinggone"); + + // "thingone", + writeFile(".gitignore", Arrays.asList(lines)); + + GitIgnoreBuilder processor = new GitIgnoreBuilder(); + MatcherSet matcherSet = processor.build(baseName); + assertThat(matcherSet.includes()).isPresent(); + assertThat(matcherSet.excludes()).isPresent(); + + DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + for (String name : expected) { + DocumentName docName = baseName.resolve(name); + assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); + } + + matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); + for (String name : ignored) { + DocumentName docName = baseName.resolve(name); + assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); + } + } + + // see https://git-scm.com/docs/gitignore + @ParameterizedTest + @MethodSource("modifyEntryData") + public void modifyEntryTest(String source, String expected) { + GitIgnoreBuilder underTest = new GitIgnoreBuilder(); + DocumentName testName = DocumentName.builder().setName("GitIgnoreBuilderTest").setBaseName("testDir").build(); + if (source.endsWith("/")) { + assertThat(underTest.modifyEntry(testName, source)).isEqualTo(null); + assertThat(underTest.getIncluded().toString()).isEqualTo(expected); + } else { + assertThat(underTest.modifyEntry(testName, source)).isEqualTo(expected); + } + } + + private static Stream modifyEntryData() { + List lst = new ArrayList<>(); + + lst.add(Arguments.of("\\#filename", "**/#filename")); + + lst.add(Arguments.of("!#filename", "!**/#filename")); + lst.add(Arguments.of("\\#filename", "**/#filename")); + lst.add(Arguments.of("!#filename", "!**/#filename")); + lst.add(Arguments.of("/filename", "filename")); + lst.add(Arguments.of("file/name", "file/name")); + lst.add(Arguments.of("/file/name", "file/name")); + lst.add(Arguments.of("filename", "**/filename")); + lst.add(Arguments.of("filename/", "and(isDirectory, **/filename)")); + lst.add(Arguments.of("/filename/", "and(isDirectory, filename)")); + + return lst.stream(); + } + + @Test + public void test_RAT_335() { + GitIgnoreBuilder underTest = new GitIgnoreBuilder(); + URL url = GitIgnoreBuilderTest.class.getClassLoader().getResource("RAT_355/src/"); + File file = new File(url.getFile()); + + DocumentName documentName = DocumentName.builder(file).build(); + MatcherSet matcherSet = underTest.build(documentName); + assertThat(matcherSet.excludes()).isPresent(); + assertThat(matcherSet.includes()).isPresent(); + DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + assertThat(matcher.toString()).isEqualTo("or(/dir1/.gitignore, /.gitignore)"); + + DocumentName name = documentName.resolve("subdir/file1.log" ); + assertThat(matcher.matches(name)).isTrue(); + name = documentName.resolve("subdir/joe.txt" ); + assertThat(matcher.matches(name)).isFalse(); + name = documentName.resolve("subdir/file1.log" ); + assertThat(matcher.matches(name)).isTrue(); + name = documentName.resolve("subdir/joe.md" ); + assertThat(matcher.matches(name)).isTrue(); + + name = documentName.resolve("dir1/joe.txt" ); + assertThat(matcher.matches(name)).isTrue(); + name = documentName.resolve("dir1/file1.md" ); + assertThat(matcher.matches(name)).isTrue(); + + matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); + assertThat(matcher.toString()).isEqualTo("or(/dir1/.gitignore, /.gitignore)"); + + name = documentName.resolve("dir1/dir1.md" ); + assertThat(matcher.matches(name)).isTrue(); + name = documentName.resolve("subdir/dir1.md" ); + assertThat(matcher.matches(name)).isFalse(); + name = documentName.resolve("dir1/file1.log" ); + assertThat(matcher.matches(name)).isTrue(); + name = documentName.resolve("subdir/file1.log" ); + assertThat(matcher.matches(name)).isTrue(); + } +} diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java new file mode 100644 index 000000000..0b23e90d1 --- /dev/null +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java @@ -0,0 +1,82 @@ +/* + * 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.config.exclusion.fileProcessors; + +import java.util.ArrayList; +import org.apache.rat.config.exclusion.MatcherSet; +import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; +import org.apache.rat.utils.ExtendedIterator; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class HgIgnoreBuilderTest extends AbstractIgnoreBuilderTest { + + @Test + public void processExampleFileTest() throws IOException { + String[] lines = { + "# use glob syntax.", "syntax: glob", "*.elc", "*.pyc", "*~", System.lineSeparator(), + "# switch to regexp syntax.", "syntax: regexp", "^\\.pc" }; + + List expected = Arrays.asList("test.elc", "test.pyc", "test.thing~", ".pc"); + + writeFile(".hgignore", Arrays.asList(lines)); + + HgIgnoreBuilder processor = new HgIgnoreBuilder(); + MatcherSet matcherSet = processor.build(baseName); + assertThat(matcherSet.includes()).isPresent(); + assertThat(matcherSet.excludes()).isNotPresent(); + DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + for (String name : expected) { + DocumentName docName = baseName.resolve(name); + assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); + } + } + + @Test + public void processDefaultFileTest() throws IOException { + String[] lines = {"^[A-Z]*\\.txt", "[0-9]*\\.txt"}; + + List expected = Arrays.asList("ABIGNAME.txt", "endsIn9.txt"); + + + List denied = Arrays.asList("asmallName.txt", "endsin.doc"); + writeFile(".hgignore", Arrays.asList(lines)); + + HgIgnoreBuilder processor = new HgIgnoreBuilder(); + MatcherSet matcherSet = processor.build(baseName); + DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + for (String name : expected) { + DocumentName docName = baseName.resolve(name); + assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); + } + for (String name : denied) { + DocumentName docName = DocumentName.builder().setName(name).setBaseName(baseDir).build(); + assertThat(matcher.matches(docName)).as(docName.getName()).isFalse(); + } + } +} diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreProcessorTest.java deleted file mode 100644 index 3085792c5..000000000 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreProcessorTest.java +++ /dev/null @@ -1,66 +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.config.exclusion.fileProcessors; - -import java.util.ArrayList; -import org.apache.rat.utils.ExtendedIterator; -import org.junit.jupiter.api.Test; - -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; - -import static java.lang.String.format; -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class HgIgnoreProcessorTest extends AbstractIgnoreProcessorTest { - - @Test - public void processExampleFileTest() throws IOException { - String[] lines = { - "# use glob syntax.", "syntax: glob", "*.elc", "*.pyc", "*~", System.lineSeparator(), - "# switch to regexp syntax.", "syntax: regexp", "^\\.pc/" }; - - List expected = ExtendedIterator.create(Arrays.asList("*.elc", "*.pyc", "*~").iterator()) - .map(s -> new File(baseDir, s).getPath()).addTo(new ArrayList<>()); - expected.add(format("%%regex[\\Q%s%s\\E%s]", baseDir.getPath(), File.separatorChar, "\\.pc/")); - - writeFile(".hgignore", Arrays.asList(lines)); - - HgIgnoreProcessor processor = new HgIgnoreProcessor(); - List actual = processor.apply(baseName); - assertEquals(expected, actual); - } - - @Test - public void processDefaultFileTest() throws IOException { - String[] lines = {"^[A-Z]*\\.txt", "[0-9]*\\.txt"}; - - List expected = ExtendedIterator.create(Arrays.asList("[A-Z]*\\.txt", ".*[0-9]*\\.txt").iterator()) - .map(s -> format("%%regex[\\Q%s%s\\E%s]", baseDir.getPath(), File.separatorChar, s)) - .addTo(new ArrayList<>()); - - writeFile(".hgignore", Arrays.asList(lines)); - - HgIgnoreProcessor processor = new HgIgnoreProcessor(); - List actual = processor.apply(baseName); - assertEquals(expected, actual); - } -} From 89e4e9cd8adc2d698193dc6eab5f60d821e0a9a9 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 22 Dec 2024 13:38:09 +0000 Subject: [PATCH 072/123] fixes for RAT-335 --- .../RAT_335/{ignore.txt => commandLine.txt} | 2 - .../ReportTest/RAT_335/src/.gitignore | 7 ++ .../ReportTest/RAT_335/src/dir1/.gitignore | 3 + .../ReportTest/RAT_335/src/dir1/dir1.txt} | 0 .../ReportTest/RAT_335/src/dir1/file1.log} | 0 .../ReportTest/RAT_335/src/dir2/dir2.md} | 0 .../ReportTest/RAT_335/src/dir3/dir3.log | 1 + .../resources/ReportTest/RAT_335/src/root.md | 1 + .../ReportTest/RAT_335/verify.groovy | 29 ++++++ .../config/exclusion/ExclusionProcessor.java | 88 ++++++++++++------- .../rat/config/exclusion/ExclusionUtils.java | 29 ++++++ .../rat/config/exclusion/MatcherSet.java | 69 +++++---------- .../fileProcessors/AbstractBuilder.java | 44 ++++++++++ .../fileProcessors/BazaarIgnoreBuilder.java | 9 +- .../fileProcessors/CVSIgnoreBuilder.java | 6 +- .../fileProcessors/GitIgnoreBuilder.java | 42 +++++---- .../fileProcessors/HgIgnoreBuilder.java | 11 +-- .../rat/document/DocumentNameMatcher.java | 12 +-- .../config/exclusion/FileProcessorTest.java | 2 +- .../BazaarIgnoreBuilderTest.java | 6 +- .../fileProcessors/CVSIgnoreBuilderTest.java | 6 +- .../fileProcessors/GitIgnoreBuilderTest.java | 64 +++++++------- .../fileProcessors/HgIgnoreBuilderTest.java | 17 ++-- .../rat/test/AbstractOptionsProvider.java | 3 +- .../commandLine.txt | 0 .../expected-message.txt | 0 .../{RAT_355 => GitIgnoreBuilderTest}/pom.xml | 0 .../src/README.txt | 0 .../GitIgnoreBuilderTest/src/dir1/dir1.md | 1 + .../GitIgnoreBuilderTest/src/dir2/dir2.txt | 1 + .../GitIgnoreBuilderTest/src/dir3/file3.log | 1 + .../src/invoker.properties | 0 .../verify.groovy | 0 .../resources/RAT_355/src/invoker.properties | 16 ---- 34 files changed, 285 insertions(+), 185 deletions(-) rename apache-rat-core/src/it/resources/ReportTest/RAT_335/{ignore.txt => commandLine.txt} (63%) create mode 100644 apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore create mode 100644 apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore rename apache-rat-core/src/{test/resources/RAT_355/src/dir1/dir1.md => it/resources/ReportTest/RAT_335/src/dir1/dir1.txt} (100%) rename apache-rat-core/src/{test/resources/RAT_355/src/dir2/dir2.txt => it/resources/ReportTest/RAT_335/src/dir1/file1.log} (100%) rename apache-rat-core/src/{test/resources/RAT_355/src/dir3/file3.log => it/resources/ReportTest/RAT_335/src/dir2/dir2.md} (100%) create mode 100644 apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir3/dir3.log create mode 100644 apache-rat-core/src/it/resources/ReportTest/RAT_335/src/root.md create mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractBuilder.java rename apache-rat-core/src/test/resources/{RAT_355 => GitIgnoreBuilderTest}/commandLine.txt (100%) rename apache-rat-core/src/test/resources/{RAT_355 => GitIgnoreBuilderTest}/expected-message.txt (100%) rename apache-rat-core/src/test/resources/{RAT_355 => GitIgnoreBuilderTest}/pom.xml (100%) rename apache-rat-core/src/test/resources/{RAT_355 => GitIgnoreBuilderTest}/src/README.txt (100%) create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/dir1.md create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir2/dir2.txt create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir3/file3.log rename apache-rat-core/src/{it/resources/ReportTest/RAT_335 => test/resources/GitIgnoreBuilderTest}/src/invoker.properties (100%) rename apache-rat-core/src/test/resources/{RAT_355 => GitIgnoreBuilderTest}/verify.groovy (100%) delete mode 100644 apache-rat-core/src/test/resources/RAT_355/src/invoker.properties diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/ignore.txt b/apache-rat-core/src/it/resources/ReportTest/RAT_335/commandLine.txt similarity index 63% rename from apache-rat-core/src/it/resources/ReportTest/RAT_335/ignore.txt rename to apache-rat-core/src/it/resources/ReportTest/RAT_335/commandLine.txt index df056a6fa..0a6cbd339 100644 --- a/apache-rat-core/src/it/resources/ReportTest/RAT_335/ignore.txt +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/commandLine.txt @@ -1,7 +1,5 @@ --output-style xml ---input-exclude -**/.gitignore --input-exclude-parsed-scm GIT -- diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore new file mode 100644 index 000000000..8855fa805 --- /dev/null +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore @@ -0,0 +1,7 @@ +*.md + +# This makes it ignore dir3/dir3.log and dir3/file3.log +*.log + +# This makes it "unignore" dir3/file3.log +!file*.log diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore new file mode 100644 index 000000000..26fd5c956 --- /dev/null +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore @@ -0,0 +1,3 @@ +*.txt +!dir1.md +file1.log \ No newline at end of file diff --git a/apache-rat-core/src/test/resources/RAT_355/src/dir1/dir1.md b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/dir1.txt similarity index 100% rename from apache-rat-core/src/test/resources/RAT_355/src/dir1/dir1.md rename to apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/dir1.txt diff --git a/apache-rat-core/src/test/resources/RAT_355/src/dir2/dir2.txt b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/file1.log similarity index 100% rename from apache-rat-core/src/test/resources/RAT_355/src/dir2/dir2.txt rename to apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/file1.log diff --git a/apache-rat-core/src/test/resources/RAT_355/src/dir3/file3.log b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir2/dir2.md similarity index 100% rename from apache-rat-core/src/test/resources/RAT_355/src/dir3/file3.log rename to apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir2/dir2.md diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir3/dir3.log b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir3/dir3.log new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir3/dir3.log @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/root.md b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/root.md new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/root.md @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy index 8a3e07657..36da7e7d0 100644 --- a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy @@ -75,6 +75,35 @@ XPath xPath = XPathFactory.newInstance().newXPath() //XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseName[@name='Unknown license']", // mapOf("count", "4" )) + + +//Note the output when running in the real commandline version of git +// +//# Files that must be ignored (dropping the gitignore matches outside of this test tree) +//$ git check-ignore --no-index --verbose $(find . -type f|sort) +// +// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore:2:!dir1.md ./dir1/dir1.md +// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore:1:*.txt ./dir1/dir1.txt +// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore:3:file1.log ./dir1/file1.log +// .gitignore:20:**/.gitignore ./dir1/.gitignore +// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore:1:*.md ./dir2/dir2.md +// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore:4:*.log ./dir3/dir3.log +// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore:7:!file*.log ./dir3/file3.log +// .gitignore:20:**/.gitignore ./.gitignore +// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore:1:*.md ./root.md + +/* list of excluded files: + +./dir1/dir1.txt +./dir1/file1.log +./dir1/.gitignore +./dir2/dir2.md +./dir3/dir3.log +./.gitignore +./root.md + + */ + List ignoredFiles = new ArrayList<>(Arrays.asList( "/dir1/dir1.txt", "/dir1/file1.log", 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 918b2e163..514834d65 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 @@ -25,6 +25,8 @@ import java.util.Set; import java.util.TreeSet; +import java.util.function.Predicate; +import java.util.stream.Collectors; import org.apache.rat.config.exclusion.plexus.MatchPatterns; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; @@ -87,10 +89,8 @@ private void resetLastMatcher() { * @return this */ public ExclusionProcessor addIncludedPatterns(final Iterable patterns) { - List lst = new ArrayList<>(); - patterns.forEach(lst::add); - DefaultLog.getInstance().info(format("Including patterns: %s", String.join(", ", lst))); - includedPatterns.addAll(lst); + DefaultLog.getInstance().info(format("Including patterns: %s", String.join(", ", patterns))); + patterns.forEach(includedPatterns::add); resetLastMatcher(); return this; } @@ -142,10 +142,8 @@ public ExclusionProcessor addIncludedCollection(final StandardCollection collect * @return this */ public ExclusionProcessor addExcludedPatterns(final Iterable patterns) { - List lst = new ArrayList<>(); - patterns.forEach(lst::add); - DefaultLog.getInstance().info(format("Excluding patterns: %s", String.join(", ", lst))); - excludedPatterns.addAll(lst); + DefaultLog.getInstance().info(format("Excluding patterns: %s", String.join(", ", patterns))); + patterns.forEach(excludedPatterns::add); resetLastMatcher(); return this; } @@ -207,12 +205,10 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { lastMatcherBaseDir = basedir; // add the file processors - final List fileProcessors = extractFileProcessors(basedir, new ArrayList<>()); - + final List fileProcessors = extractFileProcessors(basedir); + final MatcherSet.Builder fromCommandLine = new MatcherSet.Builder(); DocumentName.Builder nameBuilder = DocumentName.builder().setBaseName(basedir); - MatcherSet.Builder fromCommandLine = new MatcherSet.Builder() - .addExcluded(nameBuilder.setName("excludedPatterns").build(), excludedPatterns) - .addIncluded(nameBuilder.setName("includedPatterns").build(), includedPatterns); + extractPatterns(nameBuilder, fromCommandLine); extractCollectionPatterns(nameBuilder, fromCommandLine); extractCollectionMatchers(fromCommandLine); extractPaths(fromCommandLine); @@ -224,7 +220,13 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { return lastMatcher; } - private List extractFileProcessors(final DocumentName basedir, final List fileProcessorList) { + /** + * Extracts the file processors from {@link #fileProcessors}. + * @param basedir The directory to base the file processors on. + * @return a list of MatcherSets that are created for each {@link #fileProcessors} entry. + */ + private List extractFileProcessors(final DocumentName basedir) { + final List fileProcessorList = new ArrayList<>(); for (StandardCollection sc : fileProcessors) { ExtendedIterator iter = sc.fileProcessorBuilder().map(builder -> builder.build(basedir)); if (iter.hasNext()) { @@ -236,14 +238,28 @@ private List extractFileProcessors(final DocumentName basedir, final return fileProcessorList; } - private void extractPatterns(final DocumentName commandLine, final MatcherSet.Builder fromCommandLine) { - fromCommandLine - .addExcluded(commandLine, excludedPatterns) - .addIncluded(commandLine, includedPatterns); + /** + * Extracts {@link #includedPatterns} and {@link #excludedPatterns} into the specified matcherBuilder. + * @param nameBuilder The name builder for the pattern. File names are resolved against the generated name. + * @param matcherBuilder the MatcherSet.Builder to add the patterns to. + */ + private void extractPatterns(DocumentName.Builder nameBuilder, MatcherSet.Builder matcherBuilder) { + DocumentName name = nameBuilder.setName("Patterns").build(); + if (!excludedPatterns.isEmpty()) { + matcherBuilder.addExcluded(name, excludedPatterns.stream().map(s -> ExclusionUtils.localizePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); + } + if (!includedPatterns.isEmpty()) { + + matcherBuilder.addIncluded(name, includedPatterns.stream().map(s -> ExclusionUtils.localizePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); + } } - private void extractCollectionPatterns(final DocumentName.Builder nameBuilder, final MatcherSet.Builder fileProcessorBuilder) { - // add the collection patterns + /** + * Extracts {@link #includedCollections} and {@link #excludedCollections} patterns into the specified matcherBuilder. + * @param nameBuilder the name builder for the pattern names. + * @param matcherBuilder the MatcherSet.Builder to add the collections to. + */ + private void extractCollectionPatterns(final DocumentName.Builder nameBuilder, final MatcherSet.Builder matcherBuilder) { final Set incl = new TreeSet<>(); final Set excl = new TreeSet<>(); for (StandardCollection sc : includedCollections) { @@ -262,41 +278,47 @@ private void extractCollectionPatterns(final DocumentName.Builder nameBuilder, f MatcherSet.Builder.segregateList(excl, incl, sc.patterns()); } } - nameBuilder.setName("collections"); - fileProcessorBuilder - .addExcluded(nameBuilder.setName("excludedCollections").build(), excl) - .addIncluded(nameBuilder.setName("includedCollections").build(), incl); + DocumentName name = nameBuilder.setName("Collections").build(); + matcherBuilder + .addExcluded(name, excl) + .addIncluded(name, incl); } - private void extractCollectionMatchers(final MatcherSet.Builder fromCommandLine) { - // add the matchers + /** + * Extracts {@link #includedCollections} and {@link #excludedCollections} matchers into the specified matcherBuilder. + * @param matcherBuilder the MatcherSet.Builder to add the collections to. + */ + private void extractCollectionMatchers(final MatcherSet.Builder matcherBuilder) { ExtendedIterator.create(includedCollections.iterator()) .map(StandardCollection::staticDocumentNameMatcher) .filter(Objects::nonNull) - .forEachRemaining(fromCommandLine::addIncluded); + .forEachRemaining(matcherBuilder::addIncluded); ExtendedIterator.create(excludedCollections.iterator()) .map(StandardCollection::staticDocumentNameMatcher) .filter(Objects::nonNull) - .forEachRemaining(fromCommandLine::addExcluded); + .forEachRemaining(matcherBuilder::addExcluded); } - private void extractPaths(final MatcherSet.Builder fromCommandLine) { + /** + * Extracts {@link #includedPaths} and {@link #excludedPaths} patterns into the specified matcherBuilder. + * @param matcherBuilder the MatcherSet.Builder to add the collections to. + */ + private void extractPaths(final MatcherSet.Builder matcherBuilder) { if (!includedPaths.isEmpty()) { for (DocumentNameMatcher matcher : includedPaths) { DefaultLog.getInstance().info(format("Including path matcher %s", matcher)); - fromCommandLine.addIncluded(matcher); + matcherBuilder.addIncluded(matcher); } } if (!excludedPaths.isEmpty()) { for (DocumentNameMatcher matcher : excludedPaths) { DefaultLog.getInstance().info(format("Excluding path matcher %s", matcher)); - fromCommandLine.addExcluded(matcher); + matcherBuilder.addExcluded(matcher); } } - } private DocumentNameMatcher createMatcher(List fileProcessors) { @@ -331,7 +353,7 @@ private DocumentNameMatcher createMatcher(List fileProcessors) { } return true; }; - final String name = format("or(%s, not(%s)", included, excluded); + final String name = DocumentNameMatcher.or(included, DocumentNameMatcher.not(excluded)).toString(); return new DocumentNameMatcher(name, pred); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java index 98e005285..a47434627 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java @@ -34,6 +34,8 @@ import org.apache.commons.io.LineIterator; import org.apache.commons.lang3.StringUtils; import org.apache.rat.ConfigurationException; +import org.apache.rat.config.exclusion.plexus.MatchPattern; +import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.utils.ExtendedIterator; @@ -189,6 +191,33 @@ private static void verifyFile(final File file) { } } + /** + * Modifies the {@link MatchPattern} formatted {@code pattern} argument by expanding the pattern and + * by adjusting the pattern to include the basename from the {@code documentName} argument. + * @param documentName the name of the file being read. + * @param pattern the pattern to format. + * @return the completely formatted pattern + */ + public static String localizePattern(final DocumentName documentName, final String pattern) { + boolean prefix = pattern.startsWith(NEGATION_PREFIX); + String workingPattern = prefix ? pattern.substring(1) : pattern; + String normalizedPattern = SelectorUtils.extractPattern(workingPattern, documentName.getDirectorySeparator()); + StringBuilder sb = new StringBuilder(); + if (SelectorUtils.isRegexPrefixedPattern(workingPattern)) { + sb.append(prefix ? NEGATION_PREFIX : "") + .append(SelectorUtils.REGEX_HANDLER_PREFIX) + .append("\\Q").append(documentName.getBaseName()) + .append(documentName.getDirectorySeparator()) + .append("\\E").append(normalizedPattern) + .append(SelectorUtils.PATTERN_HANDLER_SUFFIX); + return sb.toString(); + } else { + sb.append(documentName.getBaseName()) + .append(documentName.getDirectorySeparator()).append(normalizedPattern); + return (prefix ? NEGATION_PREFIX : "") + DocumentName.builder(documentName).setName(sb.toString()).build().getName(); + } + } + /** * Tokenizes the string based on the directory separator. * @param source the source to tokenize. diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java index c13b1cee9..73cde5741 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -37,7 +37,6 @@ import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; -import org.apache.rat.utils.ExtendedIterator; /** * The file processor reads the file specified in the DocumentName. @@ -57,34 +56,7 @@ public interface MatcherSet { class Builder { /** A String format pattern to print a regex string */ - public static final String REGEX_FMT = "%%regex[%s]"; - - /** - * Modifies the {@link MatchPattern} formatted {@code pattern} argument by expanding the pattern and - * by adjusting the pattern to include the basename from the {@code documentName} argument. - * @param documentName the name of the file being read. - * @param pattern the pattern to format. - * @return the completely formatted pattern - */ - public static String localizePattern(final DocumentName documentName, final String pattern) { - boolean prefix = pattern.startsWith(ExclusionUtils.NEGATION_PREFIX); - String workingPattern = prefix ? pattern.substring(1) : pattern; - String normalizedPattern = SelectorUtils.extractPattern(workingPattern, documentName.getDirectorySeparator()); - StringBuilder sb = new StringBuilder(); - if (SelectorUtils.isRegexPrefixedPattern(workingPattern)) { - sb.append(prefix ? ExclusionUtils.NEGATION_PREFIX : "") - .append(SelectorUtils.REGEX_HANDLER_PREFIX) - .append("\\Q").append(documentName.getBaseName()) - .append(documentName.getDirectorySeparator()) - .append("\\E").append(normalizedPattern) - .append(SelectorUtils.PATTERN_HANDLER_SUFFIX); - return sb.toString(); - } else { - sb.append(documentName.getBaseName()) - .append(documentName.getDirectorySeparator()).append(normalizedPattern); - return (prefix ? ExclusionUtils.NEGATION_PREFIX : "") + DocumentName.builder(documentName).setName(sb.toString()).build().getName(); - } - } + protected static final String REGEX_FMT = "%%regex[%s]"; /** * Adds to lists of qualified file patterns. Non-matching patterns start with a {@code !}. @@ -118,15 +90,6 @@ public static void segregateList(final Set matching, final Set n commentFilter = StringUtils::isNotBlank; } - /** - * Constructor. - * @param fileName The name of the file to process. - * @param commentPrefix the comment prefix - */ - protected Builder(final String fileName, final String commentPrefix) { - this(fileName, commentPrefix == null ? null : Collections.singletonList(commentPrefix)); - } - /** * Constructor. * @param fileName name of the file to process @@ -144,22 +107,24 @@ protected Builder(final String fileName, final Iterable commentPrefixes) * Default implementation returns the @{code entry} argument. * @param documentName the name of the document that the file was read from. * @param entry the entry from that document. - * @return the modified string or null to skip the string. + * @return the modified string or an empty Optional to skip the string. */ - protected String modifyEntry(final DocumentName documentName, final String entry) { - return entry; + protected Optional modifyEntry(final DocumentName documentName, final String entry) { + return Optional.of(entry); } public Builder addIncluded(DocumentName fromDocument, Set names) { if (!names.isEmpty()) { - addIncluded(new DocumentNameMatcher(fromDocument.localized("/"), MatchPatterns.from(names), fromDocument.getBaseDocumentName())); + String name = String.format("'included %s'", fromDocument.localized("/").substring(1)); + addIncluded(new DocumentNameMatcher(name, MatchPatterns.from(names), fromDocument.getBaseDocumentName())); } return this; } public Builder addExcluded(DocumentName fromDocument, Set names) { if (!names.isEmpty()) { - addExcluded(new DocumentNameMatcher(fromDocument.localized("/"), MatchPatterns.from(names), fromDocument.getBaseDocumentName())); + String name = String.format("'excluded %s'", fromDocument.localized("/").substring(1)); + addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(names), fromDocument.getBaseDocumentName())); } return this; } @@ -179,14 +144,24 @@ public Builder addExcluded(DocumentNameMatcher matcher) { * @param documentName the file to read. */ protected void process(final DocumentName documentName) { - Set included = new HashSet<>(); - Set excluded = new HashSet<>(); List iterable = new ArrayList<>(); ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) - .map(entry -> modifyEntry(documentName, entry)) + .map(entry -> modifyEntry(documentName, entry).orElse(null)) .filter(Objects::nonNull) - .map(entry -> localizePattern(documentName, entry)) + .map(entry -> ExclusionUtils.localizePattern(documentName, entry)) .forEachRemaining(iterable::add); + segregateProcessResult(documentName, iterable); + } + + /** + * Moves properly formatted file names includes, excludes into the proper + * {@link #included} and {@link #excluded} DocumentMatchers. + * @param documentName the nome of the document being processed. + * @param iterable the list of properly formatted include and excludes from the input. + */ + protected void segregateProcessResult(final DocumentName documentName, List iterable) { + Set included = new HashSet<>(); + Set excluded = new HashSet<>(); segregateList(included, excluded, iterable); addExcluded(documentName, excluded); addIncluded(documentName, included); diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractBuilder.java new file mode 100644 index 000000000..59fcfd06f --- /dev/null +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractBuilder.java @@ -0,0 +1,44 @@ +package org.apache.rat.config.exclusion.fileProcessors; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.apache.rat.config.exclusion.MatcherSet; +import org.apache.rat.document.DocumentName; + +public class AbstractBuilder extends MatcherSet.Builder { + + /** + * Constructor. + * @param fileName The name of the file to process. + * @param commentPrefix the comment prefix + */ + protected AbstractBuilder(final String fileName, final String commentPrefix) { + this(fileName, commentPrefix == null ? null : Collections.singletonList(commentPrefix)); + } + + /** + * Constructor. + * @param fileName name of the file to process + * @param commentPrefixes a collection of comment prefixes. + */ + protected AbstractBuilder(final String fileName, final Iterable commentPrefixes) { + super(fileName, commentPrefixes); + } + + /** + * Moves properly formatted file names includes, excludes into the proper + * {@link #included} and {@link #excluded} DocumentMatchers. This differs from the parent implementation + * in that patterns that match the process are excluded. + * @param documentName the nome of the document being processed. + * @param iterable the list of properly formatted include and excludes from the input. + */ + protected void segregateProcessResult(final DocumentName documentName, List iterable) { + Set included = new HashSet<>(); + Set excluded = new HashSet<>(); + segregateList(excluded, included, iterable); + addExcluded(documentName, excluded); + addIncluded(documentName, included); + } +} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java index 315ec99dc..a8b65c960 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java @@ -18,6 +18,7 @@ */ package org.apache.rat.config.exclusion.fileProcessors; +import java.util.Optional; import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; @@ -26,7 +27,7 @@ /** * A processor for {@code .bzrignore} files. */ -public final class BazaarIgnoreBuilder extends MatcherSet.Builder { +public final class BazaarIgnoreBuilder extends AbstractBuilder { /** * Constructor. */ @@ -35,12 +36,12 @@ public BazaarIgnoreBuilder() { } @Override - public String modifyEntry(final DocumentName baseName, final String entry) { + public Optional modifyEntry(final DocumentName baseName, final String entry) { if (entry.startsWith("RE:")) { String line = entry.substring("RE:".length()).trim(); String pattern = line.startsWith("^") ? line.substring(1) : line; - return format(REGEX_FMT, pattern); + return Optional.of(format(REGEX_FMT, pattern)); } - return entry; + return Optional.of(entry); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java index cd308e923..3aae5765e 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java @@ -31,7 +31,7 @@ /** * A file processor for the {@code .csvignore} file. */ -public class CVSIgnoreBuilder extends MatcherSet.Builder { +public class CVSIgnoreBuilder extends AbstractBuilder { /** * The constructor. */ @@ -49,10 +49,10 @@ protected void process(final DocumentName documentName) { String[] parts = line.split("\\s+"); for (String part : parts) { if (!part.isEmpty()) { - result.add(localizePattern(documentName, part)); + result.add(ExclusionUtils.localizePattern(documentName, part)); } } } - addIncluded(documentName.getBaseDocumentName(), result); + addExcluded(documentName, result); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java index 319f2a137..0c931d796 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java @@ -22,10 +22,9 @@ import java.io.FileFilter; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.Objects; -import java.util.Set; +import java.util.Optional; import java.util.SortedMap; import java.util.TreeMap; import java.util.function.Consumer; @@ -42,7 +41,7 @@ * Processes the .gitignore file. * @see .gitignore documentation */ -public class GitIgnoreBuilder extends MatcherSet.Builder { +public class GitIgnoreBuilder extends AbstractBuilder { // create a list of levels that a list of processors at that level. // will return a custom matcher that from an overridden MatcherSet.customDocumentNameMatchers method // build LevelMatcher as a system that returns Include, Exclude or no status for each check. @@ -112,12 +111,24 @@ DocumentNameMatcher getExcluded() { } @Override - public String modifyEntry(final DocumentName documentName, final String entry) { + public Optional modifyEntry(final DocumentName documentName, final String entry) { return modifyEntry(documentName, entry, this::addIncluded, this::addExcluded); } - private static String modifyEntry(final DocumentName documentName, final String entry, Consumer include, - Consumer exclude) { + /** + * Convert the string entry. + * If the string ends with a slash an {@link DocumentNameMatcher#and} is constructed from a directory check and the file + * name matcher. In this case an empty Optional is returned. + * If the string starts with {@link ExclusionUtils#NEGATION_PREFIX} then the entry is placed in the include list, otherwise + * the entry is placed in the exclude list and the name of the check returned. + * @param documentName The name of the document being processed. + * @param entry The entry from the document + * @param include A consumer to accept the included DocumentNameMatchers. + * @param exclude A consumer to accept the excluded DocumentNameMatchers. + * @return and Optional containing the name of the matcher. + */ + private static Optional modifyEntry(final DocumentName documentName, final String entry, Consumer include, + Consumer exclude) { // An optional prefix "!" which negates the pattern; boolean prefix = entry.startsWith(NEGATION_PREFIX); String pattern = prefix || entry.startsWith(ESCAPED_COMMENT) || entry.startsWith(ESCAPED_NEGATION) ? @@ -148,33 +159,28 @@ private static String modifyEntry(final DocumentName documentName, final String } else { include.accept(matcher); } - return null; + return Optional.empty(); } - return prefix ? NEGATION_PREFIX + pattern : pattern; + return Optional.of(prefix ? NEGATION_PREFIX + pattern : pattern); } - private class LevelBuilder extends MatcherSet.Builder { + private static class LevelBuilder extends AbstractBuilder { LevelBuilder(int level) { super(IGNORE_FILE+"-"+level, COMMENT_PREFIX); } - public String modifyEntry(final DocumentName documentName, final String entry) { + public Optional modifyEntry(final DocumentName documentName, final String entry) { return GitIgnoreBuilder.modifyEntry(documentName, entry, this::addIncluded, this::addExcluded); } public void process(DocumentName directory, DocumentName documentName) { - Set included = new HashSet<>(); - Set excluded = new HashSet<>(); List iterable = new ArrayList<>(); ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) - .map(entry -> modifyEntry(documentName, entry)) + .map(entry -> modifyEntry(documentName, entry).orElse(null)) .filter(Objects::nonNull) - .map(entry -> localizePattern(documentName, entry)) + .map(entry -> ExclusionUtils.localizePattern(documentName, entry)) .forEachRemaining(iterable::add); - segregateList(included, excluded, iterable); - addExcluded(directory, excluded); - addIncluded(directory, included); - + segregateProcessResult(directory, iterable); } } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java index 036333ea6..86e8253c0 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java @@ -19,6 +19,7 @@ package org.apache.rat.config.exclusion.fileProcessors; import java.util.Locale; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -30,7 +31,7 @@ /** * A processor for the {@code .hgignore} files. */ -public final class HgIgnoreBuilder extends MatcherSet.Builder { +public final class HgIgnoreBuilder extends AbstractBuilder { /** * The state enumeration for the processor. When processing the file the processor changes * syntax state depending on the input. @@ -62,16 +63,16 @@ protected void process(final DocumentName baseName) { } @Override - public String modifyEntry(final DocumentName baseName, final String entry) { + public Optional modifyEntry(final DocumentName baseName, final String entry) { Matcher m = SYNTAX_CHECK.matcher(entry.toLowerCase(Locale.ROOT)); if (m.matches()) { state = Syntax.valueOf(m.group(1).toUpperCase()); - return null; + return Optional.empty(); } if (state == Syntax.REGEXP) { String pattern = entry.startsWith("^") ? entry.substring(1) : ".*" + entry; - return format(REGEX_FMT, pattern); + return Optional.of(format(REGEX_FMT, pattern)); } - return entry; + return Optional.of(entry); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 6b3c31bd0..902834517 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -23,7 +23,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; @@ -66,7 +65,7 @@ public final class DocumentNameMatcher { public DocumentNameMatcher(final String name, final Predicate predicate) { this.name = name; this.predicate = predicate; - this.isCollection = predicate instanceof CollectionPredicateImpl; + this.isCollection = predicate instanceof CollectionPredicate; } /** @@ -85,7 +84,9 @@ public DocumentNameMatcher(final String name, final DocumentNameMatcher delegate * @param basedir the base directory for the scanning. */ public DocumentNameMatcher(final String name, final MatchPatterns patterns, final DocumentName basedir) { - this(name, new MatchPatternsPredicate(basedir, patterns)); + this(name, (Predicate) documentName -> patterns.matches(documentName.getName(), + tokenize(documentName.getName(), basedir.getDirectorySeparator()), + basedir.isCaseSensitive())); } /** @@ -94,7 +95,7 @@ public DocumentNameMatcher(final String name, final MatchPatterns patterns, fina * @param dirSeparator the directory separator. * @return the tokenized name. */ - private static char[][] tokenize(final String name, final String dirSeparator) { + private static char[][] tokenize(String name, String dirSeparator) { String[] tokenizedName = MatchPattern.tokenizePathToString(name, dirSeparator); char[][] tokenizedNameChar = new char[tokenizedName.length][]; for (int i = 0; i < tokenizedName.length; i++) { @@ -211,8 +212,7 @@ private static String join(final Collection matchers) { return String.join(", ", children); } - private static Optional standardCollectionCheck(final Collection matchers, - final DocumentNameMatcher override) { + private static Optional standardCollectionCheck(final Collection matchers, final DocumentNameMatcher override) { if (matchers.isEmpty()) { throw new ConfigurationException("Empty matcher collection"); } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java index 995ad407c..be3d9970f 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java @@ -36,7 +36,7 @@ public class FileProcessorTest { @ParameterizedTest(name="{index} {1}") @MethodSource("localizePatternData") void localizePatternTest(DocumentName baseName, String pattern, String expectedStr) { - assertThat(MatcherSet.Builder.localizePattern(baseName, pattern)).isEqualTo(expectedStr); + assertThat(ExclusionUtils.localizePattern(baseName, pattern)).isEqualTo(expectedStr); } public static Stream localizePatternData() { diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java index f2a860161..fe5cec339 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java @@ -47,9 +47,9 @@ public void processExampleFileTest() throws IOException { BazaarIgnoreBuilder processor = new BazaarIgnoreBuilder(); MatcherSet matcherSet = processor.build(baseName); - assertThat(matcherSet.includes()).isPresent(); - assertThat(matcherSet.excludes()).isNotPresent(); - DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + assertThat(matcherSet.excludes()).isPresent(); + assertThat(matcherSet.includes()).isNotPresent(); + DocumentNameMatcher matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); for (String name : expected) { DocumentName docName = baseName.resolve(name); assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java index 2edcb9572..929209138 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java @@ -46,9 +46,9 @@ public void processExampleFileTest() throws IOException { CVSIgnoreBuilder processor = new CVSIgnoreBuilder(); MatcherSet matcherSet = processor.build(baseName); - assertThat(matcherSet.includes()).isPresent(); - assertThat(matcherSet.excludes()).isNotPresent(); - DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + assertThat(matcherSet.excludes()).isPresent(); + assertThat(matcherSet.includes()).isNotPresent(); + DocumentNameMatcher matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); for (String name : expected) { DocumentName docName = baseName.resolve(name); assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java index 3156eae19..d3591967f 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java @@ -35,6 +35,7 @@ import org.junit.jupiter.params.provider.MethodSource; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.not; public class GitIgnoreBuilderTest extends AbstractIgnoreBuilderTest { @@ -48,11 +49,10 @@ public void processExampleFileTest() throws IOException { "# some colorful directories", "red/", "blue/*/"}; - List expected = Arrays.asList("some/things", "some/fish", "another/red_fish"); + List excluded = Arrays.asList("some/things", "some/fish", "another/red_fish"); - List ignored = Arrays.asList("some/thinggone"); + List included = Arrays.asList("some/thingone"); - // "thingone", writeFile(".gitignore", Arrays.asList(lines)); GitIgnoreBuilder processor = new GitIgnoreBuilder(); @@ -61,13 +61,13 @@ public void processExampleFileTest() throws IOException { assertThat(matcherSet.excludes()).isPresent(); DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : expected) { + for (String name : included) { DocumentName docName = baseName.resolve(name); assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); } matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : ignored) { + for (String name : excluded) { DocumentName docName = baseName.resolve(name); assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); } @@ -80,10 +80,10 @@ public void modifyEntryTest(String source, String expected) { GitIgnoreBuilder underTest = new GitIgnoreBuilder(); DocumentName testName = DocumentName.builder().setName("GitIgnoreBuilderTest").setBaseName("testDir").build(); if (source.endsWith("/")) { - assertThat(underTest.modifyEntry(testName, source)).isEqualTo(null); + assertThat(underTest.modifyEntry(testName, source)).isNotPresent(); assertThat(underTest.getIncluded().toString()).isEqualTo(expected); } else { - assertThat(underTest.modifyEntry(testName, source)).isEqualTo(expected); + assertThat(underTest.modifyEntry(testName, source)).contains(expected); } } @@ -105,43 +105,41 @@ private static Stream modifyEntryData() { return lst.stream(); } + private void assertMatches(DocumentName documentName, DocumentNameMatcher matcher, String[] matching, String[] notMatching) { + for (String test : matching) { + DocumentName name = documentName.resolve(test); + assertThat(matcher.matches(name)).as(test).isTrue(); + } + for (String test: notMatching) { + DocumentName name = documentName.resolve(test); + assertThat(matcher.matches(name)).as(test).isFalse(); + } + } + @Test public void test_RAT_335() { GitIgnoreBuilder underTest = new GitIgnoreBuilder(); - URL url = GitIgnoreBuilderTest.class.getClassLoader().getResource("RAT_355/src/"); + URL url = GitIgnoreBuilderTest.class.getClassLoader().getResource("GitIgnoreBuilderTest/src/"); File file = new File(url.getFile()); DocumentName documentName = DocumentName.builder(file).build(); MatcherSet matcherSet = underTest.build(documentName); assertThat(matcherSet.excludes()).isPresent(); assertThat(matcherSet.includes()).isPresent(); + + // includes test DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); - assertThat(matcher.toString()).isEqualTo("or(/dir1/.gitignore, /.gitignore)"); - - DocumentName name = documentName.resolve("subdir/file1.log" ); - assertThat(matcher.matches(name)).isTrue(); - name = documentName.resolve("subdir/joe.txt" ); - assertThat(matcher.matches(name)).isFalse(); - name = documentName.resolve("subdir/file1.log" ); - assertThat(matcher.matches(name)).isTrue(); - name = documentName.resolve("subdir/joe.md" ); - assertThat(matcher.matches(name)).isTrue(); - - name = documentName.resolve("dir1/joe.txt" ); - assertThat(matcher.matches(name)).isTrue(); - name = documentName.resolve("dir1/file1.md" ); - assertThat(matcher.matches(name)).isTrue(); + assertThat(matcher.toString()).isEqualTo("or('included dir1/.gitignore', 'included .gitignore')"); + assertMatches(documentName, matcher, new String[]{"subdir/file1.log", "dir1/dir1.md", "dir1/somedir/dir1.md", + "dir1/file1.log"}, + new String[]{"dir1/joe.txt", "subdir/joe.txt", "subdir/joe.md", "dir1/joe.md" }); + // excludes tests matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); - assertThat(matcher.toString()).isEqualTo("or(/dir1/.gitignore, /.gitignore)"); - - name = documentName.resolve("dir1/dir1.md" ); - assertThat(matcher.matches(name)).isTrue(); - name = documentName.resolve("subdir/dir1.md" ); - assertThat(matcher.matches(name)).isFalse(); - name = documentName.resolve("dir1/file1.log" ); - assertThat(matcher.matches(name)).isTrue(); - name = documentName.resolve("subdir/file1.log" ); - assertThat(matcher.matches(name)).isTrue(); + assertThat(matcher.toString()).isEqualTo("or('excluded dir1/.gitignore', 'excluded .gitignore')"); + assertMatches(documentName, matcher, new String[]{ "dir1/file1.txt", "dir1/somedir/file1.txt", "dir1/file1.log", + "dir1/somedir/file1.log", "subdir/dir1.md", "subdir/some.log"}, + new String[]{"subdir/afile.txt" }); + } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java index 0b23e90d1..a56c26eba 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java @@ -48,9 +48,9 @@ public void processExampleFileTest() throws IOException { HgIgnoreBuilder processor = new HgIgnoreBuilder(); MatcherSet matcherSet = processor.build(baseName); - assertThat(matcherSet.includes()).isPresent(); - assertThat(matcherSet.excludes()).isNotPresent(); - DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); + assertThat(matcherSet.excludes()).isPresent(); + assertThat(matcherSet.includes()).isNotPresent(); + DocumentNameMatcher matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); for (String name : expected) { DocumentName docName = baseName.resolve(name); assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); @@ -61,20 +61,19 @@ public void processExampleFileTest() throws IOException { public void processDefaultFileTest() throws IOException { String[] lines = {"^[A-Z]*\\.txt", "[0-9]*\\.txt"}; - List expected = Arrays.asList("ABIGNAME.txt", "endsIn9.txt"); + List match = Arrays.asList("ABIGNAME.txt", "endsIn9.txt"); + List notMatch = Arrays.asList("asmallName.txt", "endsin.doc"); - - List denied = Arrays.asList("asmallName.txt", "endsin.doc"); writeFile(".hgignore", Arrays.asList(lines)); HgIgnoreBuilder processor = new HgIgnoreBuilder(); MatcherSet matcherSet = processor.build(baseName); - DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : expected) { + DocumentNameMatcher matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); + for (String name : match) { DocumentName docName = baseName.resolve(name); assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); } - for (String name : denied) { + for (String name : notMatch) { DocumentName docName = DocumentName.builder().setName(name).setBaseName(baseDir).build(); assertThat(matcher.matches(docName)).as(docName.getName()).isFalse(); } 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 8a34245e9..f0e6e120b 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 @@ -79,7 +79,7 @@ */ 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 */ @@ -329,7 +329,6 @@ protected void inputExcludeParsedScmTest() { "**/fish", "*_fish", "# some colorful directories", "red/", "blue/*/"}; - String[] notExcluded = {"thingone", "dir/fish_two", "some/thingone", "blue/fish/dory" }; String[] excluded = {"thingtwo", "some/things", "dir/fish", "red/fish", "blue/fish", "some/fish", "another/red_fish"}; diff --git a/apache-rat-core/src/test/resources/RAT_355/commandLine.txt b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/commandLine.txt similarity index 100% rename from apache-rat-core/src/test/resources/RAT_355/commandLine.txt rename to apache-rat-core/src/test/resources/GitIgnoreBuilderTest/commandLine.txt diff --git a/apache-rat-core/src/test/resources/RAT_355/expected-message.txt b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/expected-message.txt similarity index 100% rename from apache-rat-core/src/test/resources/RAT_355/expected-message.txt rename to apache-rat-core/src/test/resources/GitIgnoreBuilderTest/expected-message.txt diff --git a/apache-rat-core/src/test/resources/RAT_355/pom.xml b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/pom.xml similarity index 100% rename from apache-rat-core/src/test/resources/RAT_355/pom.xml rename to apache-rat-core/src/test/resources/GitIgnoreBuilderTest/pom.xml diff --git a/apache-rat-core/src/test/resources/RAT_355/src/README.txt b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/README.txt similarity index 100% rename from apache-rat-core/src/test/resources/RAT_355/src/README.txt rename to apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/README.txt diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/dir1.md b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/dir1.md new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/dir1.md @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir2/dir2.txt b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir2/dir2.txt new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir2/dir2.txt @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir3/file3.log b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir3/file3.log new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir3/file3.log @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/src/invoker.properties b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/invoker.properties similarity index 100% rename from apache-rat-core/src/it/resources/ReportTest/RAT_335/src/invoker.properties rename to apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/invoker.properties diff --git a/apache-rat-core/src/test/resources/RAT_355/verify.groovy b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/verify.groovy similarity index 100% rename from apache-rat-core/src/test/resources/RAT_355/verify.groovy rename to apache-rat-core/src/test/resources/GitIgnoreBuilderTest/verify.groovy diff --git a/apache-rat-core/src/test/resources/RAT_355/src/invoker.properties b/apache-rat-core/src/test/resources/RAT_355/src/invoker.properties deleted file mode 100644 index 6e8c3479e..000000000 --- a/apache-rat-core/src/test/resources/RAT_355/src/invoker.properties +++ /dev/null @@ -1,16 +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. - -invoker.goals = clean apache-rat:check From d0d7b54227c77e5dd43377cc9855b2b71e35d274 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Wed, 25 Dec 2024 15:47:10 +0000 Subject: [PATCH 073/123] fixes for. gitignore and other descending processors --- .../ReportTest/RAT_335/verify.groovy | 24 +- .../config/exclusion/ExclusionProcessor.java | 51 +--- .../rat/config/exclusion/MatcherSet.java | 126 ++-------- .../config/exclusion/StandardCollection.java | 9 +- .../fileProcessors/AbstractBuilder.java | 44 ---- .../AbstractFileProcessorBuilder.java | 235 ++++++++++++++++++ .../fileProcessors/BazaarIgnoreBuilder.java | 7 +- .../fileProcessors/CVSIgnoreBuilder.java | 13 +- .../fileProcessors/GitIgnoreBuilder.java | 104 +------- .../fileProcessors/HgIgnoreBuilder.java | 21 +- .../apache/rat/ReportConfigurationTest.java | 106 ++++---- .../AbstractIgnoreBuilderTest.java | 44 ++++ .../BazaarIgnoreBuilderTest.java | 18 +- .../fileProcessors/CVSIgnoreBuilderTest.java | 15 +- .../fileProcessors/GitIgnoreBuilderTest.java | 77 +++--- .../fileProcessors/HgIgnoreBuilderTest.java | 33 +-- .../rat/test/AbstractOptionsProvider.java | 17 +- 17 files changed, 462 insertions(+), 482 deletions(-) delete mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractBuilder.java create mode 100644 apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy index 36da7e7d0..3774f283d 100644 --- a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy @@ -125,30 +125,10 @@ assertThat(ignoredFiles).isEmpty() // Document types XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='IGNORED']", - mapOf("count", "6" )) + mapOf("count", "7" )) XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='NOTICE']", mapOf("count", "1" )) XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='STANDARD']", - mapOf("count", "6" )) - -/* -TextUtils.assertPatternInTarget("^ Approved:\\s+8 ", content) -TextUtils.assertPatternInTarget("^ Archives:\\s+1 ", content) -TextUtils.assertPatternInTarget("^ Binaries:\\s+2 ", content) -TextUtils.assertPatternInTarget("^ Document types:\\s+5 ", content) -TextUtils.assertPatternInTarget("^ Ignored:\\s+1 ", content) -TextUtils.assertPatternInTarget("^ License categories:\\s+4 ", content) -TextUtils.assertPatternInTarget("^ License names:\\s+5", content) -TextUtils.assertPatternInTarget("^ Notices:\\s+2 ", content) -TextUtils.assertPatternInTarget("^ Standards:\\s+8 ", content) -TextUtils.assertPatternInTarget("^ Unapproved:\\s+2 ", content) -TextUtils.assertPatternInTarget("^ Unknown:\\s+2 ", content) - -logOutput = new File(args[1]) -log = logOutput.text - -TextUtils.assertPatternNotInTarget("^ERROR:", log) -TextUtils.assertPatternNotInTarget("^WARN:", log) -*/ + mapOf("count", "3" )) 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 514834d65..e05c2fa1c 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 @@ -25,7 +25,6 @@ import java.util.Set; import java.util.TreeSet; -import java.util.function.Predicate; import java.util.stream.Collectors; import org.apache.rat.config.exclusion.plexus.MatchPatterns; import org.apache.rat.document.DocumentName; @@ -34,8 +33,6 @@ import org.apache.rat.utils.ExtendedIterator; import static java.lang.String.format; -import static org.apache.rat.document.DocumentNameMatcher.MATCHES_ALL; -import static org.apache.rat.document.DocumentNameMatcher.MATCHES_NONE; /** * Processes the include and exclude patterns and applies the result against a base directory @@ -205,17 +202,16 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { lastMatcherBaseDir = basedir; // add the file processors - final List fileProcessors = extractFileProcessors(basedir); + final List matchers = extractFileProcessors(basedir); final MatcherSet.Builder fromCommandLine = new MatcherSet.Builder(); DocumentName.Builder nameBuilder = DocumentName.builder().setBaseName(basedir); extractPatterns(nameBuilder, fromCommandLine); extractCollectionPatterns(nameBuilder, fromCommandLine); extractCollectionMatchers(fromCommandLine); extractPaths(fromCommandLine); + matchers.add(fromCommandLine.build()); - fileProcessors.add(fromCommandLine.build(basedir)); - - lastMatcher = createMatcher(fileProcessors); + lastMatcher = MatcherSet.merge(matchers).createMatcher(); } return lastMatcher; } @@ -228,9 +224,9 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { private List extractFileProcessors(final DocumentName basedir) { final List fileProcessorList = new ArrayList<>(); for (StandardCollection sc : fileProcessors) { - ExtendedIterator iter = sc.fileProcessorBuilder().map(builder -> builder.build(basedir)); + ExtendedIterator> iter = sc.fileProcessorBuilder().map(builder -> builder.build(basedir)); if (iter.hasNext()) { - iter.forEachRemaining(fileProcessorList::add); + iter.forEachRemaining(fileProcessorList::addAll); } else { DefaultLog.getInstance().debug(String.format("%s does not have a fileProcessor.", sc)); } @@ -320,41 +316,4 @@ private void extractPaths(final MatcherSet.Builder matcherBuilder) { } } } - - private DocumentNameMatcher createMatcher(List fileProcessors) { - - List includedList = new ArrayList<>(); - List excludedList = new ArrayList<>(); - - for (MatcherSet processor : fileProcessors) { - if (processor.includes().isPresent()) { - includedList.add(processor.includes().get()); - } - if (processor.excludes().isPresent()) { - excludedList.add(processor.excludes().get()); - } - } - - final DocumentNameMatcher included = includedList.isEmpty() ? MATCHES_NONE : DocumentNameMatcher.or(includedList); - final DocumentNameMatcher excluded = excludedList.isEmpty() ? MATCHES_NONE : DocumentNameMatcher.or(excludedList); - - if (excluded == MATCHES_NONE) { - return (included == MATCHES_NONE) ? MATCHES_ALL : included; - } else { - if (included == MATCHES_NONE) { - return DocumentNameMatcher.not(excluded); - } - Predicate pred = documentName -> { - if (included.matches(documentName)) { - return true; - } - if (excluded.matches(documentName)) { - return false; - } - return true; - }; - final String name = DocumentNameMatcher.or(included, DocumentNameMatcher.not(excluded)).toString(); - return new DocumentNameMatcher(name, pred); - } - } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java index 73cde5741..d0f8b94e7 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -18,26 +18,21 @@ */ package org.apache.rat.config.exclusion; -import java.io.File; -import java.io.FileFilter; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; -import org.apache.commons.io.filefilter.DirectoryFileFilter; -import org.apache.commons.io.filefilter.NameFileFilter; -import org.apache.commons.lang3.StringUtils; import org.apache.rat.config.exclusion.plexus.MatchPattern; import org.apache.rat.config.exclusion.plexus.MatchPatterns; import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; +import static org.apache.rat.document.DocumentNameMatcher.MATCHES_ALL; +import static org.apache.rat.document.DocumentNameMatcher.MATCHES_NONE; + /** * The file processor reads the file specified in the DocumentName. * It must return a list of fully qualified strings for the {@link MatchPattern} to process. @@ -49,15 +44,29 @@ public interface MatcherSet { Optional includes(); Optional excludes(); + /** + * Creates a DocumentNameMatcher from an iterable of MatcherSets. + * @return A DocumentNameMatcher that processes the matcher sets. + */ + default DocumentNameMatcher createMatcher() { + return DocumentNameMatcher.matcherSet(includes().orElse(MATCHES_NONE), excludes().orElse(MATCHES_NONE)); + } + + static MatcherSet merge(List matcherSets) { + Builder builder = new Builder(); + for (MatcherSet matcherSet : matcherSets) { + matcherSet.includes().ifPresent(builder::addIncluded); + matcherSet.excludes().ifPresent(builder::addExcluded); + } + return builder.build(); + } + /** * A MatcherSet that assumes the files contain the already formatted strings and just need to be * localized for the fileName. */ class Builder { - /** A String format pattern to print a regex string */ - protected static final String REGEX_FMT = "%%regex[%s]"; - /** * Adds to lists of qualified file patterns. Non-matching patterns start with a {@code !}. * @param matching the list to put matching file patterns into. @@ -75,42 +84,12 @@ public static void segregateList(final Set matching, final Set n }); } - /** The name of the file being processed */ - protected final String fileName; - - /** The predicate that will return {@code false} for any comment line in the file. */ - protected final Predicate commentFilter; - + /** the DocumentNameMatcher that specifies included files */ protected DocumentNameMatcher included; - + /** The DocumentNameMatcher that specifies excluded files */ protected DocumentNameMatcher excluded; - Builder() { - fileName = StringUtils.EMPTY; - commentFilter = StringUtils::isNotBlank; - } - - /** - * Constructor. - * @param fileName name of the file to process - * @param commentPrefixes a collection of comment prefixes. - */ - protected Builder(final String fileName, final Iterable commentPrefixes) { - super(); - this.fileName = fileName; - // null prefixes = check prefix may not be blank. - this.commentFilter = commentPrefixes == null ? StringUtils::isNotBlank : ExclusionUtils.commentFilter(commentPrefixes); - } - - /** - * Allows modification of the file entry to match the {@link MatchPattern} format. - * Default implementation returns the @{code entry} argument. - * @param documentName the name of the document that the file was read from. - * @param entry the entry from that document. - * @return the modified string or an empty Optional to skip the string. - */ - protected Optional modifyEntry(final DocumentName documentName, final String entry) { - return Optional.of(entry); + public Builder() { } public Builder addIncluded(DocumentName fromDocument, Set names) { @@ -139,63 +118,7 @@ public Builder addExcluded(DocumentNameMatcher matcher) { return this; } - /** - * Process by reading the file setting the {@link #included} and {@link #excluded} DocumentMatchers. - * @param documentName the file to read. - */ - protected void process(final DocumentName documentName) { - List iterable = new ArrayList<>(); - ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) - .map(entry -> modifyEntry(documentName, entry).orElse(null)) - .filter(Objects::nonNull) - .map(entry -> ExclusionUtils.localizePattern(documentName, entry)) - .forEachRemaining(iterable::add); - segregateProcessResult(documentName, iterable); - } - - /** - * Moves properly formatted file names includes, excludes into the proper - * {@link #included} and {@link #excluded} DocumentMatchers. - * @param documentName the nome of the document being processed. - * @param iterable the list of properly formatted include and excludes from the input. - */ - protected void segregateProcessResult(final DocumentName documentName, List iterable) { - Set included = new HashSet<>(); - Set excluded = new HashSet<>(); - segregateList(included, excluded, iterable); - addExcluded(documentName, excluded); - addIncluded(documentName, included); - } - - /** - * Create a list of files by applying the filter to the specified directory. - * @param dir the directory. - * @param filter the filter. - * @return an array of files. May be empty but will not be null. - */ - protected File[] listFiles(final File dir, final FileFilter filter) { - File[] result = dir.listFiles(filter); - return result == null ? new File[0] : result; - } - - /** - * Process the directory tree looking for files that match the filter. Call {@link #process} on any matching file. - * @param directory The name of the directory to process. - * @param fileFilter the filter to detect processable files with. - */ - protected void checkDirectory(final DocumentName directory, final FileFilter fileFilter) { - File dirFile = new File(directory.getName()); - for (File f : listFiles(dirFile, fileFilter)) { - process(DocumentName.builder(f).setBaseName(directory.getBaseName()).build()); - } - for (File dir : listFiles(dirFile, DirectoryFileFilter.DIRECTORY)) { - checkDirectory(DocumentName.builder(dir).build(), fileFilter); - } - } - - public MatcherSet build(final DocumentName dir) { - checkDirectory(dir, new NameFileFilter(fileName)); - + public MatcherSet build() { MatcherSet result = new MatcherSet() { final DocumentNameMatcher myIncluded = included; final DocumentNameMatcher myExcluded = excluded; @@ -214,6 +137,5 @@ public Optional excludes() { excluded = null; return result; } - } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java index 9d6874c40..46fe649e0 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java @@ -28,6 +28,7 @@ import java.util.Set; import java.util.function.Predicate; +import org.apache.rat.config.exclusion.fileProcessors.AbstractFileProcessorBuilder; import org.apache.rat.config.exclusion.fileProcessors.BazaarIgnoreBuilder; import org.apache.rat.config.exclusion.fileProcessors.CVSIgnoreBuilder; import org.apache.rat.config.exclusion.fileProcessors.GitIgnoreBuilder; @@ -200,12 +201,12 @@ null, new CVSIgnoreBuilder()), /** A document name matcher supplier to create a document name matcher. May be null */ private final DocumentNameMatcher staticDocumentNameMatcher; /** The MatcherSet to process the exclude file associated with this exclusion. May be null. */ - private final MatcherSet.Builder fileProcessorBuilder; + private final AbstractFileProcessorBuilder fileProcessorBuilder; /** The description of this collection */ private final String desc; StandardCollection(final String desc, final Collection patterns, final DocumentNameMatcher documentNameMatcher, - final MatcherSet.Builder fileProcessorBuilder) { + final AbstractFileProcessorBuilder fileProcessorBuilder) { this.desc = desc; this.patterns = patterns == null ? Collections.emptyList() : new HashSet<>(patterns); this.staticDocumentNameMatcher = documentNameMatcher; @@ -263,8 +264,8 @@ public Set patterns() { * * @return the fileProcessor if it exists, {@code null} otherwise. */ - public ExtendedIterator fileProcessorBuilder() { - List lst = new ArrayList<>(); + public ExtendedIterator fileProcessorBuilder() { + List lst = new ArrayList<>(); for (StandardCollection sc : getCollections()) { if (sc.fileProcessorBuilder != null) { lst.add(sc.fileProcessorBuilder); diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractBuilder.java deleted file mode 100644 index 59fcfd06f..000000000 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractBuilder.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.apache.rat.config.exclusion.fileProcessors; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import org.apache.rat.config.exclusion.MatcherSet; -import org.apache.rat.document.DocumentName; - -public class AbstractBuilder extends MatcherSet.Builder { - - /** - * Constructor. - * @param fileName The name of the file to process. - * @param commentPrefix the comment prefix - */ - protected AbstractBuilder(final String fileName, final String commentPrefix) { - this(fileName, commentPrefix == null ? null : Collections.singletonList(commentPrefix)); - } - - /** - * Constructor. - * @param fileName name of the file to process - * @param commentPrefixes a collection of comment prefixes. - */ - protected AbstractBuilder(final String fileName, final Iterable commentPrefixes) { - super(fileName, commentPrefixes); - } - - /** - * Moves properly formatted file names includes, excludes into the proper - * {@link #included} and {@link #excluded} DocumentMatchers. This differs from the parent implementation - * in that patterns that match the process are excluded. - * @param documentName the nome of the document being processed. - * @param iterable the list of properly formatted include and excludes from the input. - */ - protected void segregateProcessResult(final DocumentName documentName, List iterable) { - Set included = new HashSet<>(); - Set excluded = new HashSet<>(); - segregateList(excluded, included, iterable); - addExcluded(documentName, excluded); - addIncluded(documentName, included); - } -} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java new file mode 100644 index 000000000..b3e703aa6 --- /dev/null +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java @@ -0,0 +1,235 @@ +/* + * 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.config.exclusion.fileProcessors; + +import java.io.File; +import java.io.FileFilter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import org.apache.commons.io.filefilter.DirectoryFileFilter; +import org.apache.commons.io.filefilter.NameFileFilter; +import org.apache.commons.lang3.StringUtils; +import org.apache.rat.config.exclusion.ExclusionUtils; +import org.apache.rat.config.exclusion.MatcherSet; +import org.apache.rat.config.exclusion.plexus.MatchPattern; +import org.apache.rat.config.exclusion.plexus.MatchPatterns; +import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; + +/** + * // create a list of levels that a list of processors at that level. + * // will return a custom matcher that from an overridden MatcherSet.customDocumentNameMatchers method + * // build LevelMatcher as a system that returns Include, Exclude or no status for each check. + * // put the level matcher in an array with other level matchers at the specific level below the root + * // When searching start at the lowest level and work up the tree. + */ +public abstract class AbstractFileProcessorBuilder { + /** A String format pattern to print a regex string */ + protected static final String REGEX_FMT = "%%regex[%s]"; + + /** The name of the file being processed */ + protected final String fileName; + + /** The predicate that will return {@code false} for any comment line in the file. */ + protected final Predicate commentFilter; + + private final SortedMap levelBuilders; + + private final boolean includeProcessorFile; + + /** + * Constructor for multiple comment prefixes. + * @param fileName The name of the file being read. + * @param commentPrefixes the collection of comment prefixes. + */ + protected AbstractFileProcessorBuilder(final String fileName, final Iterable commentPrefixes, final boolean includeProcessorFile) { + this(fileName, commentPrefixes == null ? StringUtils::isNotBlank : ExclusionUtils.commentFilter(commentPrefixes), includeProcessorFile); + } + + /** + * Constructor for single comment prefix + * @param fileName The name of the file to process. + * @param commentPrefix the comment prefix + */ + protected AbstractFileProcessorBuilder(final String fileName, final String commentPrefix, final boolean includeProcessorFile) { + this(fileName, commentPrefix == null ? null : Collections.singletonList(commentPrefix), includeProcessorFile); + } + + /** + * Constructor for single comment prefix + * @param fileName The name of the file to process. + * @param commentFilter the comment prefix filter. + */ + protected AbstractFileProcessorBuilder(final String fileName, final Predicate commentFilter, final boolean includeProcessorFile) { + this.levelBuilders = new TreeMap<>(); + this.fileName = fileName; + this.commentFilter = commentFilter; + this.includeProcessorFile = includeProcessorFile; + } + + private List createMatcherSetList(DocumentName dir) { + List keys = new ArrayList<>(levelBuilders.keySet()); + keys.sort((a, b) -> -1 * Integer.compare(a, b)); + return keys.stream().map( key -> levelBuilders.get(key).asMatcherSet(dir)).collect(Collectors.toList()); + } + + public final List build(final DocumentName dir) { + if (includeProcessorFile) { + String name = String.format("**/%s", fileName); + String pattern = ExclusionUtils.localizePattern(dir, name); + MatcherSet matcherSet = new MatcherSet.Builder() + .addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(Collections.singletonList(pattern)), dir)) + .build(); + LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(0, LevelBuilder::new); + levelBuilder.add(matcherSet); + } + + checkDirectory(0, dir, new NameFileFilter(fileName)); + + List result = null; + if (levelBuilders.size() == 1) { + result = Collections.singletonList(levelBuilders.get(0).asMatcherSet(dir)); + } else { + result = createMatcherSetList(dir); + } + levelBuilders.clear(); + return result; + } + + /** + * Process by reading the file, creating a MatcherSet, and adding it to the + * matcherSets. + * @param documentName the file to read. + */ + protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName dirBasedName, final DocumentName documentName) { + final MatcherSet.Builder matcherSetBuilder = new MatcherSet.Builder(); + final List iterable = new ArrayList<>(); + ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) + .map(entry -> modifyEntry(matcherSetConsumer, documentName, entry).orElse(null)) + .filter(Objects::nonNull) + .map(entry -> ExclusionUtils.localizePattern(documentName, entry)) + .forEachRemaining(iterable::add); + + Set included = new HashSet<>(); + Set excluded = new HashSet<>(); + MatcherSet.Builder.segregateList(excluded, included, iterable); + matcherSetBuilder.addExcluded(dirBasedName, excluded); + matcherSetBuilder.addIncluded(dirBasedName, included); + return matcherSetBuilder.build(); + } + + /** + * Process the directory tree looking for files that match the filter. Call {@link #process} on any matching file. + * @param directory The name of the directory to process. + * @param fileFilter the filter to detect processable files with. + */ + private void checkDirectory(final int level, final DocumentName directory, final FileFilter fileFilter) { + File dirFile = new File(directory.getName()); + for (File f : listFiles(dirFile, fileFilter)) { + LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(level, LevelBuilder::new); + DocumentName dirBasedName = DocumentName.builder(f).setBaseName(directory.getBaseName()).build(); + levelBuilder.add(process(levelBuilder::add, dirBasedName, DocumentName.builder(f).setBaseName(directory.getName()).build())); + } + for (File dir : listFiles(dirFile, DirectoryFileFilter.DIRECTORY)) { + checkDirectory(level + 1, DocumentName.builder(dir).setBaseName(directory.getBaseName()).build(), fileFilter); + } + } + + /** + * Allows modification of the file entry to match the {@link MatchPattern} format. + * Default implementation returns the @{code entry} argument. + * @param documentName the name of the document that the file was read from. + * @param entry the entry from that document. + * @return the modified string or an empty Optional to skip the string. + */ + protected Optional modifyEntry(final Consumer matcherSetConsumer, final DocumentName documentName, final String entry) { + return Optional.of(entry); + } + + /** + * Create a list of files by applying the filter to the specified directory. + * @param dir the directory. + * @param filter the filter. + * @return an array of files. May be empty but will not be null. + */ + protected File[] listFiles(final File dir, final FileFilter filter) { + File[] result = dir.listFiles(filter); + return result == null ? new File[0] : result; + } + + protected static class FileProcessorPredicate implements Predicate { + private final Collection matcherSets; + FileProcessorPredicate(Collection matcherSets) { + this.matcherSets = matcherSets; + } + + public Collection getMatcherSets() { + return matcherSets; + } + + @Override + public boolean test(DocumentName documentName) { + for (MatcherSet matcherSet : matcherSets) { + if (matcherSet.includes().orElse(DocumentNameMatcher.MATCHES_NONE).matches(documentName)) { + return true; + } + if (matcherSet.excludes().orElse(DocumentNameMatcher.MATCHES_NONE).matches(documentName)) { + return false; + } + } + return true; + } + } + + static class LevelBuilder { + /** + * The list of MatcherSets that this builder produced. + */ + private final MatcherSet.Builder builder; + + public LevelBuilder(Integer integer) { + int level = integer; + builder = new MatcherSet.Builder(); + } + + public void add(MatcherSet matcherSet) { + if (matcherSet.includes().isPresent()) { + builder.addIncluded(matcherSet.includes().get()); + } + if (matcherSet.excludes().isPresent()) { + builder.addExcluded(matcherSet.excludes().get()); + } + } + + public MatcherSet asMatcherSet(DocumentName dir) { + return builder.build(); + } + } +} diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java index a8b65c960..787564d35 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java @@ -19,6 +19,7 @@ package org.apache.rat.config.exclusion.fileProcessors; import java.util.Optional; +import java.util.function.Consumer; import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; @@ -27,16 +28,16 @@ /** * A processor for {@code .bzrignore} files. */ -public final class BazaarIgnoreBuilder extends AbstractBuilder { +public final class BazaarIgnoreBuilder extends AbstractFileProcessorBuilder { /** * Constructor. */ public BazaarIgnoreBuilder() { - super(".bzrignore", "#"); + super(".bzrignore", "#", true); } @Override - public Optional modifyEntry(final DocumentName baseName, final String entry) { + public Optional modifyEntry(final Consumer matcherSetConsumer, final DocumentName baseName, final String entry) { if (entry.startsWith("RE:")) { String line = entry.substring("RE:".length()).trim(); String pattern = line.startsWith("^") ? line.substring(1) : line; diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java index 3aae5765e..69e6aba3a 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java @@ -23,6 +23,7 @@ import java.util.Iterator; import java.util.Set; +import java.util.function.Consumer; import org.apache.commons.lang3.StringUtils; import org.apache.rat.config.exclusion.ExclusionUtils; import org.apache.rat.config.exclusion.MatcherSet; @@ -30,17 +31,21 @@ /** * A file processor for the {@code .csvignore} file. + * @see Ignoring files via cvsignore + *

    + * The patterns found in .cvsignore are only valid for the directory that contains them, not for any sub-directories. + *

    */ -public class CVSIgnoreBuilder extends AbstractBuilder { +public class CVSIgnoreBuilder extends AbstractFileProcessorBuilder { /** * The constructor. */ public CVSIgnoreBuilder() { - super(".cvsignore", (String) null); + super(".cvsignore", (String) null, true); } @Override - protected void process(final DocumentName documentName) { + protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName dirBasedName, final DocumentName documentName) { final File dir = new File(documentName.getName()); Set result = new HashSet<>(); Iterator iter = ExclusionUtils.asIterator(dir, StringUtils::isNotBlank); @@ -53,6 +58,6 @@ protected void process(final DocumentName documentName) { } } } - addExcluded(documentName, result); + return new MatcherSet.Builder().addExcluded(documentName, result).build(); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java index 0c931d796..af5545e67 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java @@ -20,15 +20,8 @@ import java.io.File; -import java.io.FileFilter; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; import java.util.Optional; -import java.util.SortedMap; -import java.util.TreeMap; import java.util.function.Consumer; -import org.apache.commons.io.filefilter.DirectoryFileFilter; import org.apache.rat.config.exclusion.ExclusionUtils; import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.config.exclusion.plexus.MatchPatterns; @@ -41,78 +34,18 @@ * Processes the .gitignore file. * @see .gitignore documentation */ -public class GitIgnoreBuilder extends AbstractBuilder { - // create a list of levels that a list of processors at that level. - // will return a custom matcher that from an overridden MatcherSet.customDocumentNameMatchers method - // build LevelMatcher as a system that returns Include, Exclude or no status for each check. - // put the level matcher in an array with other level matchers at the specific level below the root - // When searching start at the lowest level and work up the tree. - +public class GitIgnoreBuilder extends AbstractFileProcessorBuilder { private static final String IGNORE_FILE = ".gitignore"; private static final String COMMENT_PREFIX = "#"; private static final String ESCAPED_COMMENT = "\\#"; private static final String ESCAPED_NEGATION = "\\!"; private static final String SLASH = "/"; - private SortedMap levelBuilders = new TreeMap<>(); - - /** * Constructs a file processor that processes a .gitignore file and ignores any lines starting with "#". */ public GitIgnoreBuilder() { - super(IGNORE_FILE, COMMENT_PREFIX); - } - - /** - * Process the directory tree looking for files that match the filter. Process any matching file and return - * a list of fully qualified patterns. - * @param directory The name of the directory to process. - * @param fileFilter the filter to detect processable files with. - * @return the list of fully qualified file patterns. - */ - protected void checkDirectory(final DocumentName directory, final FileFilter fileFilter) { - checkDirectory(0, directory, fileFilter); - List keys = new ArrayList<>(levelBuilders.keySet()); - keys.sort( (a, b) -> -1 * a.compareTo(b)); - for (int level : keys) { - LevelBuilder levelBuilder = levelBuilders.get(level); - MatcherSet fileProcessor = levelBuilder.build(directory); - fileProcessor.excludes().ifPresent(this::addExcluded); - fileProcessor.includes().ifPresent(this::addIncluded); - } - } - - private void checkDirectory(final int level, final DocumentName directory, final FileFilter fileFilter) { - File dirFile = new File(directory.getName()); - for (File f : listFiles(dirFile, fileFilter)) { - LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(level, LevelBuilder::new); - DocumentName dirBasedName = DocumentName.builder(f).setBaseName(directory.getBaseName()).build(); - levelBuilder.process(dirBasedName, DocumentName.builder(f).setBaseName(directory.getName()).build()); - } - for (File dir : listFiles(dirFile, DirectoryFileFilter.DIRECTORY)) { - checkDirectory(level + 1, DocumentName.builder(dir).setBaseName(directory.getBaseName()).build(), fileFilter); - } - } - /** - * package private for testing. - * @return the included DocumentNameMatcher. - */ - DocumentNameMatcher getIncluded() { - return included; - } - - /** - * package private for testing. - * @return the excluded DocumentNameMatcher. - */ - DocumentNameMatcher getExcluded() { - return excluded; - } - - @Override - public Optional modifyEntry(final DocumentName documentName, final String entry) { - return modifyEntry(documentName, entry, this::addIncluded, this::addExcluded); + super(IGNORE_FILE, COMMENT_PREFIX, true); } /** @@ -123,12 +56,10 @@ public Optional modifyEntry(final DocumentName documentName, final Strin * the entry is placed in the exclude list and the name of the check returned. * @param documentName The name of the document being processed. * @param entry The entry from the document - * @param include A consumer to accept the included DocumentNameMatchers. - * @param exclude A consumer to accept the excluded DocumentNameMatchers. * @return and Optional containing the name of the matcher. */ - private static Optional modifyEntry(final DocumentName documentName, final String entry, Consumer include, - Consumer exclude) { + @Override + protected Optional modifyEntry(final Consumer matcherSetConsumer, final DocumentName documentName, final String entry) { // An optional prefix "!" which negates the pattern; boolean prefix = entry.startsWith(NEGATION_PREFIX); String pattern = prefix || entry.startsWith(ESCAPED_COMMENT) || entry.startsWith(ESCAPED_NEGATION) ? @@ -154,33 +85,16 @@ private static Optional modifyEntry(final DocumentName documentName, fin .build(); DocumentNameMatcher matcher = DocumentNameMatcher.and(new DocumentNameMatcher("isDirectory", File::isDirectory), new DocumentNameMatcher(name, MatchPatterns.from(matcherPattern.localized(SLASH)))); + + MatcherSet.Builder builder = new MatcherSet.Builder(); if (prefix) { - exclude.accept(matcher); + builder.addIncluded(matcher); } else { - include.accept(matcher); + builder.addExcluded(matcher); } + matcherSetConsumer.accept(builder.build()); return Optional.empty(); } return Optional.of(prefix ? NEGATION_PREFIX + pattern : pattern); } - - private static class LevelBuilder extends AbstractBuilder { - LevelBuilder(int level) { - super(IGNORE_FILE+"-"+level, COMMENT_PREFIX); - } - - public Optional modifyEntry(final DocumentName documentName, final String entry) { - return GitIgnoreBuilder.modifyEntry(documentName, entry, this::addIncluded, this::addExcluded); - } - - public void process(DocumentName directory, DocumentName documentName) { - List iterable = new ArrayList<>(); - ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) - .map(entry -> modifyEntry(documentName, entry).orElse(null)) - .filter(Objects::nonNull) - .map(entry -> ExclusionUtils.localizePattern(documentName, entry)) - .forEachRemaining(iterable::add); - segregateProcessResult(directory, iterable); - } - } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java index 86e8253c0..ca8ca1344 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java @@ -20,6 +20,7 @@ import java.util.Locale; import java.util.Optional; +import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -30,8 +31,10 @@ /** * A processor for the {@code .hgignore} files. + * @see Mecurial how to ignore files + * @see syntax for Mercurial ignore files */ -public final class HgIgnoreBuilder extends AbstractBuilder { +public final class HgIgnoreBuilder extends AbstractFileProcessorBuilder { /** * The state enumeration for the processor. When processing the file the processor changes * syntax state depending on the input. @@ -52,26 +55,34 @@ enum Syntax { * Constructs the .hgignore processor. */ public HgIgnoreBuilder() { - super(".hgignore", "#"); + super(".hgignore", "#", true); state = Syntax.REGEXP; } @Override - protected void process(final DocumentName baseName) { + protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName dirBasedName, final DocumentName documentName) { state = Syntax.REGEXP; - super.process(baseName); + return super.process(matcherSetConsumer, dirBasedName, documentName); } @Override - public Optional modifyEntry(final DocumentName baseName, final String entry) { + public Optional modifyEntry(final Consumer matcherSetConsumer, final DocumentName documentName, final String entry) { Matcher m = SYNTAX_CHECK.matcher(entry.toLowerCase(Locale.ROOT)); if (m.matches()) { state = Syntax.valueOf(m.group(1).toUpperCase()); return Optional.empty(); } + /* + Neither glob nor regexp patterns are rooted. A glob-syntax pattern of the form *.c will match a file ending in .c + in any directory, and a regexp pattern of the form \.c$ will do the same. To root a regexp pattern, start it with ^. + */ if (state == Syntax.REGEXP) { String pattern = entry.startsWith("^") ? entry.substring(1) : ".*" + entry; return Optional.of(format(REGEX_FMT, pattern)); + } else { + if (entry.startsWith("*")) { + return Optional.of("**/"+entry); + } } return Optional.of(entry); } 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 11a8ce013..581d474b5 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 @@ -19,10 +19,7 @@ package org.apache.rat; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -91,11 +88,13 @@ public void cleanup() { public void testAddIncludedFilter() { DocumentName dirName = DocumentName.builder(tempDir).build(); underTest.addExcludedFilter(DirectoryFileFilter.INSTANCE); - DocumentNameMatcher exlcuder = underTest.getDocumentExcluder(dirName); - assertEquals("not(DirectoryFileFilter)", exlcuder.toString()); - assertFalse(exlcuder.matches(DocumentName.builder(tempDir).build())); + DocumentNameMatcher matcher = underTest.getDocumentExcluder(dirName); + + assertThat(matcher.toString()).isEqualTo("not(DirectoryFileFilter)"); + assertThat(matcher.matches(DocumentName.builder(tempDir).build())).isFalse(); + File f = new File(tempDir, "foo.txt"); - assertTrue(exlcuder.matches(DocumentName.builder(f).build())); + assertThat(exlcuder.matches(DocumentName.builder(f).build())).isTrue(); } @Test @@ -104,17 +103,16 @@ public void testAddFamilies() { ILicenseFamily fam2 = ILicenseFamily.builder().setLicenseFamilyCategory("BAR").setLicenseFamilyName("big and round").build(); underTest.addFamilies(Arrays.asList(fam1, fam2)); SortedSet result = underTest.getLicenseIds(LicenseFilter.ALL); - assertTrue(result.contains(ILicenseFamily.makeCategory("FOO")), "Missing FOO"); - assertTrue(result.contains(ILicenseFamily.makeCategory("BAR")), "Missing BAR"); - assertEquals(2, result.size()); + assertThat(result).contains(ILicenseFamily.makeCategory("FOO")); + assertThat(result).contains(ILicenseFamily.makeCategory("BAR")); + assertThat(result).hasSize(2); } @Test public void testAddApprovedLicenseId() { underTest.addApprovedLicenseId("FOO"); SortedSet result = underTest.getLicenseIds(LicenseFilter.APPROVED); - assertTrue(result.contains("FOO")); - assertEquals(1, result.size()); + assertThat(result).hasSize(1).contains("FOO"); } @Test public void testAddAndRemoveApproveLicenseCategories() { @@ -367,27 +365,28 @@ DocumentName mkDocumentName(File f) { @Test public void exclusionTest() { DocumentName baseDir = DocumentName.builder(tempDir).build(); - assertTrue(underTest.getDocumentExcluder(baseDir).matches(mkDocumentName(new File(tempDir,"foo")))); - assertTrue(underTest.getDocumentExcluder(baseDir).matches(mkDocumentName(new File("foo")))); + DocumentName foo = mkDocumentName(new File(tempDir,"foo")); + assertThat(underTest.getDocumentExcluder(baseDir).matches(foo)).isTrue(); underTest.setFrom(Defaults.builder().build()); File f = new File(tempDir, ".hiddenDir"); - assertTrue(f.mkdir(), () -> "Could not create directory " + f); - - assertFalse(underTest.getDocumentExcluder(baseDir).matches(mkDocumentName(new File(tempDir, ".hiddenDir")))); + assertThat(f.mkdir()).as(() -> "Could not create directory " + f).isTrue(); + DocumentName hiddenDir = mkDocumentName(new File(tempDir, ".hiddenDir")); + DocumentNameMatcher excluder = underTest.getDocumentExcluder(baseDir); + assertThat(excluder.matches(hiddenDir)).isFalse(); underTest.addIncludedCollection(StandardCollection.HIDDEN_DIR); - assertTrue(underTest.getDocumentExcluder(baseDir).matches(mkDocumentName(new File(tempDir, ".hiddenDir")))); + assertThat(underTest.getDocumentExcluder(baseDir).matches(hiddenDir)).isTrue(); underTest.addExcludedCollection(StandardCollection.HIDDEN_DIR); - assertTrue(underTest.getDocumentExcluder(baseDir).matches(mkDocumentName(new File(tempDir, ".hiddenDir")))); + assertThat(underTest.getDocumentExcluder(baseDir).matches(hiddenDir)).isTrue(); underTest.addExcludedFilter(DirectoryFileFilter.DIRECTORY); File file = new File(tempDir, "newDir"); - assertTrue(file.mkdirs(), () -> "Could not create directory " + file); - assertFalse(underTest.getDocumentExcluder(baseDir).matches(mkDocumentName(file))); + assertThat(file.mkdirs()).as(() -> "Could not create directory " + file).isTrue(); + assertThat(underTest.getDocumentExcluder(baseDir).matches(mkDocumentName(file))).isFalse(); } @Test @@ -472,8 +471,8 @@ public void reportableTest() { IReportable reportable = mock(IReportable.class); underTest.addSource(reportable); assertThat(underTest.hasSource()).isTrue(); - Exception thrown = assertThrows(ConfigurationException.class, () -> underTest.addSource((IReportable)null)); - assertThat(thrown.getMessage()).contains("Reportable may not be null."); + assertThatThrownBy(() -> underTest.addSource((IReportable)null)).isExactlyInstanceOf(ConfigurationException.class) + .hasMessageContaining("Reportable may not be null."); } @Test @@ -518,18 +517,17 @@ public void testFlags() { public void testValidate() { final StringBuilder sb = new StringBuilder(); String msg = "At least one source must be specified"; - Exception thrown = assertThrows(ConfigurationException.class, - () -> underTest.validate(sb::append)); - assertThat(thrown.getMessage()).isEqualTo(msg); + assertThatThrownBy(() -> underTest.validate(sb::append)).isExactlyInstanceOf(ConfigurationException.class) + .hasMessageContaining(msg); assertThat(sb.toString()).isEqualTo(msg); sb.setLength(0); msg = "You must specify at least one license"; underTest.addSource(mock(IReportable.class)); - thrown = assertThrows(ConfigurationException.class, - () -> underTest.validate(sb::append)); - assertThat(thrown.getMessage()).isEqualTo(msg); + + assertThatThrownBy(() -> underTest.validate(sb::append)).isExactlyInstanceOf(ConfigurationException.class) + .hasMessageContaining(msg); assertThat(sb.toString()).isEqualTo(msg); sb.setLength(0); @@ -559,45 +557,48 @@ public void testSetOut() throws IOException { public void logFamilyCollisionTest() { // setup underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name")); - assertFalse(log.getCaptured().contains("CAT")); + assertThat(log.getCaptured()).doesNotContain("CAT"); // verify default collision logs WARNING underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name2")); - assertTrue(log.getCaptured().contains("WARN"), "default value not WARN"); - assertTrue(log.getCaptured().contains("CAT"), "'CAT' not found"); + assertThat(log.getCaptured().contains("WARN")).as("default value not WARN").isTrue(); + assertThat(log.getCaptured().contains("CAT")).as("'CAT' not found").isTrue(); // verify level setting works. for (Level l : Level.values()) { log.clear(); underTest.logFamilyCollisions(l); underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name2")); - assertTrue(log.getCaptured().contains("CAT"), "'CAT' not found"); - assertTrue(log.getCaptured().contains(l.name()), "logging not set to "+l); + assertThat(log.getCaptured().contains("CAT")).as("'CAT' not found").isTrue(); + assertThat(log.getCaptured().contains(l.name())).as("logging not set to "+l).isTrue(); } } @Test public void familyDuplicateOptionsTest() { underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name")); - assertFalse(log.getCaptured().contains("CAT")); + assertThat(log.getCaptured()).doesNotContain("CAT"); // verify default second setting ignores change underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name2")); - assertTrue(log.getCaptured().contains("CAT")); - assertEquals("name", underTest.getLicenseFamilies(LicenseFilter.ALL).stream() - .filter(s -> s.getFamilyCategory().equals("CAT ")).map(ILicenseFamily::getFamilyName).findFirst().get()); + assertThat(log.getCaptured()).contains("CAT"); + assertThat(underTest.getLicenseFamilies(LicenseFilter.ALL).stream() + .filter(s -> s.getFamilyCategory().equals("CAT ")).map(ILicenseFamily::getFamilyName).findFirst()) + .contains("name"); underTest.familyDuplicateOption(Options.OVERWRITE); // verify second setting ignores change underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name2")); - assertTrue(log.getCaptured().contains("CAT")); - assertEquals("name2", underTest.getLicenseFamilies(LicenseFilter.ALL).stream() - .filter(s -> s.getFamilyCategory().equals("CAT ")).map(ILicenseFamily::getFamilyName).findFirst().get()); + assertThat(log.getCaptured()).contains("CAT"); + assertThat(underTest.getLicenseFamilies(LicenseFilter.ALL).stream() + .filter(s -> s.getFamilyCategory().equals("CAT ")).map(ILicenseFamily::getFamilyName).findFirst()) + .contains("name2"); // verify fail throws exception underTest.familyDuplicateOption(Options.FAIL); - assertThrows( IllegalArgumentException.class, ()->underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name2"))); - + assertThatThrownBy(()->underTest.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory("CAT").setLicenseFamilyName("name2"))) + .isExactlyInstanceOf(IllegalArgumentException.class); + underTest.familyDuplicateOption(Options.IGNORE); } @@ -617,7 +618,7 @@ public void logLicenseCollisionTest() { underTest.addLicense(ILicense.builder().setId("ID").setName("license name2").setFamily(family.getFamilyCategory()) .setMatcher( matcher ).setLicenseFamilies(underTest.getLicenseFamilies(LicenseFilter.ALL)) .build()); - assertTrue(log.getCaptured().contains("WARN")); + assertThat(log.getCaptured()).contains("WARN"); log.clear(); underTest.logLicenseCollisions(Level.ERROR); @@ -626,7 +627,7 @@ public void logLicenseCollisionTest() { underTest.addLicense(ILicense.builder().setId("ID").setName("license name2").setFamily(family.getFamilyCategory()) .setMatcher( matcher ).setLicenseFamilies(underTest.getLicenseFamilies(LicenseFilter.ALL)) .build()); - assertTrue(log.getCaptured().contains("ERROR")); + assertThat(log.getCaptured()).contains("ERROR"); } @Test @@ -644,18 +645,19 @@ public void licenseDuplicateOptionsTest() { // verify default second setting ignores change underTest.addLicense(makeLicense.apply("license name2")); - assertTrue(log.getCaptured().contains("WARN")); - assertEquals("license name", - underTest.getLicenses(LicenseFilter.ALL).stream().map(ILicense::getName).findFirst().get()); + assertThat(log.getCaptured()).contains("WARN"); + assertThat(underTest.getLicenses(LicenseFilter.ALL).stream().map(ILicense::getName).findFirst()) + .contains("license name"); underTest.licenseDuplicateOption(Options.OVERWRITE); underTest.addLicense(makeLicense.apply("license name2")); - assertEquals("license name2", - underTest.getLicenses(LicenseFilter.ALL).stream().map(ILicense::getName).findFirst().get()); + assertThat(underTest.getLicenses(LicenseFilter.ALL).stream().map(ILicense::getName).findFirst()) + .contains("license name2"); // verify fail throws exception underTest.licenseDuplicateOption(Options.FAIL); - assertThrows( IllegalArgumentException.class, ()-> underTest.addLicense(makeLicense.apply("another name"))); + assertThatThrownBy(()-> underTest.addLicense(makeLicense.apply("another name"))) + .isExactlyInstanceOf(IllegalArgumentException.class); } /** diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java index 9a9e3898c..44338358c 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java @@ -18,7 +18,10 @@ */ package org.apache.rat.config.exclusion.fileProcessors; +import java.util.List; +import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcher; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.condition.EnabledOnOs; @@ -30,6 +33,12 @@ import java.io.IOException; import java.io.PrintWriter; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * The base class for FileProcessor builder tests. + * Provides supporting methods for creating test files and for validating results. + */ public class AbstractIgnoreBuilderTest { @TempDir @@ -51,6 +60,13 @@ void cleanUp() { System.gc(); } + /** + * Writes a text file to the baseDir directory. + * @param name the name of the file. + * @param lines the lines to write to the file. + * @return the File that was written. + * @throws IOException if file cannot be created. + */ protected File writeFile(String name, Iterable lines) throws IOException { File file = new File(baseDir, name); try (PrintWriter writer = new PrintWriter(new FileWriter(file))) { @@ -59,4 +75,32 @@ protected File writeFile(String name, Iterable lines) throws IOException return file; } + /** + * Asserts the correctness of the exlcuder. An excluder returns false if the document name is matched. + * @param builder An FileProcessorBuilder that will create the excluder. + * @param matching the matching strings. + * @param notMatching the non-matching strings. + */ + protected void assertCorrect(AbstractFileProcessorBuilder builder, Iterable matching, Iterable notMatching) { + assertCorrect(builder.build(baseName), baseName, matching, notMatching); + } + + /** + * Asserts the correctness of the excluder. An excluder returns false if the document name is matched. + * @param matcherSets the list of matchers to create the DocumentNameMatcher from. + * @param baseDir the base directory for the excluder test. + * @param matching the matching strings. + * @param notMatching the non-matching strings. + */ + protected void assertCorrect(List matcherSets, DocumentName baseDir, Iterable matching, Iterable notMatching) { + DocumentNameMatcher excluder = MatcherSet.merge(matcherSets).createMatcher(); + for (String name : matching) { + DocumentName docName = baseDir.resolve(name); + assertThat(excluder.matches(docName)).as(docName.getName()).isFalse(); + } + for (String name : notMatching) { + DocumentName docName = baseDir.resolve(name); + assertThat(excluder.matches(docName)).as(docName.getName()).isTrue(); + } + } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java index fe5cec339..820e798e7 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilderTest.java @@ -18,17 +18,12 @@ */ package org.apache.rat.config.exclusion.fileProcessors; -import java.util.ArrayList; -import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; -import org.apache.rat.utils.ExtendedIterator; import org.junit.jupiter.api.Test; -import java.io.File; import java.io.IOException; import java.util.Arrays; -import java.util.Collections; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -41,19 +36,12 @@ public void processExampleFileTest() throws IOException { "# a comment", "*.elc", "*.pyc", "*~", System.lineSeparator(), "# switch to regexp syntax.", "RE:^\\.pc" }; - List expected = Arrays.asList("test.elc", "test.pyc", "test.thing~", ".pc"); + List matching = Arrays.asList("test.elc", "test.pyc", "test.thing~", ".pc"); + List notMatching = Arrays.asList("test.foo", ".pc/stuff", "subidr/test.elc"); writeFile(".bzrignore", Arrays.asList(lines)); - BazaarIgnoreBuilder processor = new BazaarIgnoreBuilder(); - MatcherSet matcherSet = processor.build(baseName); - assertThat(matcherSet.excludes()).isPresent(); - assertThat(matcherSet.includes()).isNotPresent(); - DocumentNameMatcher matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : expected) { - DocumentName docName = baseName.resolve(name); - assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); - } + assertCorrect(new BazaarIgnoreBuilder(), matching, notMatching); } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java index 929209138..8c8628287 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilderTest.java @@ -39,19 +39,14 @@ public void processExampleFileTest() throws IOException { String[] lines = { "thingone thingtwo", System.lineSeparator(), "one_fish", "two_fish", "", "red_* blue_*"}; - List expected = Arrays.asList("thingone", "thingtwo", "one_fish", "two_fish", "red_fish", "blue_fish"); + List matching = Arrays.asList("thingone", "thingtwo", "one_fish", "two_fish", "red_fish", "blue_fish"); + List notMatching = Arrays.asList("thing", "two", "fish_red", "subdir/two_fish", "subdir/red_fish", "subdir/blue_fish"); writeFile(".cvsignore", Arrays.asList(lines)); CVSIgnoreBuilder processor = new CVSIgnoreBuilder(); - MatcherSet matcherSet = processor.build(baseName); - - assertThat(matcherSet.excludes()).isPresent(); - assertThat(matcherSet.includes()).isNotPresent(); - DocumentNameMatcher matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : expected) { - DocumentName docName = baseName.resolve(name); - assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); - } + DocumentNameMatcher matcher = MatcherSet.merge(processor.build(baseName)).createMatcher(); + + assertCorrect(new CVSIgnoreBuilder(), matching, notMatching); } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java index d3591967f..5527e5623 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java @@ -20,10 +20,16 @@ import java.io.File; import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.stream.Stream; import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; +import org.apache.rat.document.DocumentNameMatcherTest; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -36,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.not; +import static org.assertj.core.api.Fail.fail; public class GitIgnoreBuilderTest extends AbstractIgnoreBuilderTest { @@ -49,28 +56,13 @@ public void processExampleFileTest() throws IOException { "# some colorful directories", "red/", "blue/*/"}; - List excluded = Arrays.asList("some/things", "some/fish", "another/red_fish"); + List matches = Arrays.asList("some/things", "some/fish", "another/red_fish"); - List included = Arrays.asList("some/thingone"); + List notMatches = Arrays.asList("some/thingone", "thingone"); writeFile(".gitignore", Arrays.asList(lines)); - GitIgnoreBuilder processor = new GitIgnoreBuilder(); - MatcherSet matcherSet = processor.build(baseName); - assertThat(matcherSet.includes()).isPresent(); - assertThat(matcherSet.excludes()).isPresent(); - - DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : included) { - DocumentName docName = baseName.resolve(name); - assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); - } - - matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : excluded) { - DocumentName docName = baseName.resolve(name); - assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); - } + assertCorrect(new GitIgnoreBuilder(), matches, notMatches); } // see https://git-scm.com/docs/gitignore @@ -79,11 +71,17 @@ public void processExampleFileTest() throws IOException { public void modifyEntryTest(String source, String expected) { GitIgnoreBuilder underTest = new GitIgnoreBuilder(); DocumentName testName = DocumentName.builder().setName("GitIgnoreBuilderTest").setBaseName("testDir").build(); + List matcherSets = new ArrayList<>(); + Optional entry = underTest.modifyEntry(matcherSets::add, testName, source); + + if (source.endsWith("/")) { - assertThat(underTest.modifyEntry(testName, source)).isNotPresent(); - assertThat(underTest.getIncluded().toString()).isEqualTo(expected); + assertThat(entry).isNotPresent(); + assertThat(matcherSets).hasSize(1); + DocumentNameMatcher matcher = matcherSets.get(0).createMatcher(); + assertThat(matcher.toString()).isEqualTo(expected); } else { - assertThat(underTest.modifyEntry(testName, source)).contains(expected); + assertThat(entry.get()).isEqualTo(expected); } } @@ -99,8 +97,10 @@ private static Stream modifyEntryData() { lst.add(Arguments.of("file/name", "file/name")); lst.add(Arguments.of("/file/name", "file/name")); lst.add(Arguments.of("filename", "**/filename")); - lst.add(Arguments.of("filename/", "and(isDirectory, **/filename)")); - lst.add(Arguments.of("/filename/", "and(isDirectory, filename)")); + lst.add(Arguments.of("filename/", "not(and(isDirectory, **/filename))")); + lst.add(Arguments.of("/filename/", "not(and(isDirectory, filename))")); + // inclusion by itself becomes nothing. + lst.add(Arguments.of("!filename/", "TRUE")); return lst.stream(); } @@ -123,23 +123,20 @@ public void test_RAT_335() { File file = new File(url.getFile()); DocumentName documentName = DocumentName.builder(file).build(); - MatcherSet matcherSet = underTest.build(documentName); - assertThat(matcherSet.excludes()).isPresent(); - assertThat(matcherSet.includes()).isPresent(); - - // includes test - DocumentNameMatcher matcher = matcherSet.includes().orElseThrow(() -> new IllegalStateException("How?")); - assertThat(matcher.toString()).isEqualTo("or('included dir1/.gitignore', 'included .gitignore')"); - assertMatches(documentName, matcher, new String[]{"subdir/file1.log", "dir1/dir1.md", "dir1/somedir/dir1.md", - "dir1/file1.log"}, - new String[]{"dir1/joe.txt", "subdir/joe.txt", "subdir/joe.md", "dir1/joe.md" }); - - // excludes tests - matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); - assertThat(matcher.toString()).isEqualTo("or('excluded dir1/.gitignore', 'excluded .gitignore')"); - assertMatches(documentName, matcher, new String[]{ "dir1/file1.txt", "dir1/somedir/file1.txt", "dir1/file1.log", - "dir1/somedir/file1.log", "subdir/dir1.md", "subdir/some.log"}, - new String[]{"subdir/afile.txt" }); + List matcherSets = underTest.build(documentName); + DocumentNameMatcher matcher = MatcherSet.merge(matcherSets).createMatcher(); + + DocumentName candidate = DocumentName.builder() + .setName("/home/claude/apache/creadur-rat/apache-rat-core/target/test-classes/GitIgnoreBuilderTest/src/dir1/file1.log") + .setBaseName("home/claude/apache/creadur-rat/apache-rat-core/target/test-classes/GitIgnoreBuilderTest/src/").build(); + DocumentNameMatcherTest.decompose(matcher, candidate); + + assertThat(matcher.toString()).isEqualTo("matcherSet(or('included dir1/.gitignore', 'included .gitignore'), or('excluded dir1/.gitignore', **/.gitignore, 'excluded .gitignore'))"); + + List notMatching = Arrays.asList("README.txt", "dir1/dir1.md", "dir2/dir2.txt", "dir3/file3.log", "dir1/file1.log"); + + List matching = Arrays.asList(".gitignore", "root.md", "dir1/.gitignore", "dir1/dir1.txt", "dir2/dir2.md", "dir3/dir3.log"); + assertCorrect(matcherSets, documentName.getBaseDocumentName(), matching, notMatching); } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java index a56c26eba..d5b9edcb7 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilderTest.java @@ -39,43 +39,26 @@ public class HgIgnoreBuilderTest extends AbstractIgnoreBuilderTest { @Test public void processExampleFileTest() throws IOException { String[] lines = { - "# use glob syntax.", "syntax: glob", "*.elc", "*.pyc", "*~", System.lineSeparator(), + "# use glob syntax.", "syntax: glob", "*.elc", "*.pyc", "*~", "*.c", System.lineSeparator(), "# switch to regexp syntax.", "syntax: regexp", "^\\.pc" }; - List expected = Arrays.asList("test.elc", "test.pyc", "test.thing~", ".pc"); + List matching = Arrays.asList("test.elc", "test.pyc", "subdir/test.pyc", "test.thing~", ".pc", "foo.c", "/subdir/foo.c" ); + List notMatching = Arrays.asList("test.foo", "test.thing~/subdir", ".pc/subdir"); writeFile(".hgignore", Arrays.asList(lines)); - HgIgnoreBuilder processor = new HgIgnoreBuilder(); - MatcherSet matcherSet = processor.build(baseName); - assertThat(matcherSet.excludes()).isPresent(); - assertThat(matcherSet.includes()).isNotPresent(); - DocumentNameMatcher matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : expected) { - DocumentName docName = baseName.resolve(name); - assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); - } + assertCorrect(new HgIgnoreBuilder(), matching, notMatching); } @Test public void processDefaultFileTest() throws IOException { - String[] lines = {"^[A-Z]*\\.txt", "[0-9]*\\.txt"}; + String[] lines = {"^[A-Z]*\\.txt", "[0-9]+\\.txt"}; - List match = Arrays.asList("ABIGNAME.txt", "endsIn9.txt"); - List notMatch = Arrays.asList("asmallName.txt", "endsin.doc"); + List matching = Arrays.asList("ABIGNAME.txt", "endsIn9.txt"); + List notMatching = Arrays.asList("asmallName.txt", "endsin.doc"); writeFile(".hgignore", Arrays.asList(lines)); - HgIgnoreBuilder processor = new HgIgnoreBuilder(); - MatcherSet matcherSet = processor.build(baseName); - DocumentNameMatcher matcher = matcherSet.excludes().orElseThrow(() -> new IllegalStateException("How?")); - for (String name : match) { - DocumentName docName = baseName.resolve(name); - assertThat(matcher.matches(docName)).as(docName.getName()).isTrue(); - } - for (String name : notMatch) { - DocumentName docName = DocumentName.builder().setName(name).setBaseName(baseDir).build(); - assertThat(matcher.matches(docName)).as(docName.getName()).isFalse(); - } + assertCorrect(new HgIgnoreBuilder(), matching, notMatching); } } 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 f0e6e120b..717e0d13b 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 @@ -32,8 +32,8 @@ import org.apache.rat.commandline.StyleSheets; import org.apache.rat.config.exclusion.StandardCollection; import org.apache.rat.document.DocumentNameMatcher; -import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcherTest; +import org.apache.rat.document.DocumentName; import org.apache.rat.license.ILicense; import org.apache.rat.license.ILicenseFamily; import org.apache.rat.license.LicenseSetFactory; @@ -247,7 +247,7 @@ protected DocumentName mkDocName(String name) { /* Tests to be implemented */ protected abstract void helpTest(); - /* Display the option and value under test */ + /** Display the option and value under test */ private String displayArgAndName(Option option, String fname) { return String.format("%s %s", option.getLongOpt(), fname); } @@ -339,16 +339,9 @@ protected void inputExcludeParsedScmTest() { dir = new File(dir, "fish"); dir.mkdirs(); - try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); - for (String fname : notExcluded) { - final DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)) - .as(() -> String.format("option: %s name: %s%n%s", option.getKey(), fname, excluder.decompose(docName))) - .isTrue(); - } for (String fname : excluded) { DocumentName docName = mkDocName(fname); assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isFalse(); @@ -397,12 +390,6 @@ private void execIncludeTest(Option option, String[] args) { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args), ImmutablePair.of(excludeOption, EXCLUDE_ARGS)); DocumentNameMatcher excluder = config.getDocumentExcluder(baseName()); - for (String fname : notExcluded) { - final DocumentName docName = mkDocName(fname); - assertThat(excluder.matches(docName)) - .as(() -> String.format("option: %s name: %s%n%s", option.getKey(), fname, excluder.decompose(docName))) - .isTrue(); - } for (String fname : excluded) { DocumentName docName = mkDocName(fname); assertThat(excluder.matches(docName)).as(() -> dump(option, fname, excluder, docName)).isFalse(); From df6412cb33e1db63c3b4ac932e1c9cd1c5edef16 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Wed, 25 Dec 2024 16:35:55 +0000 Subject: [PATCH 074/123] cleaned up checkstyle issues --- .../ReportTest/RAT_335/verify.groovy | 1 - .../config/exclusion/ExclusionProcessor.java | 11 +- .../rat/config/exclusion/MatcherSet.java | 48 ++++++-- .../AbstractFileProcessorBuilder.java | 110 ++++++++---------- .../fileProcessors/BazaarIgnoreBuilder.java | 1 + .../fileProcessors/CVSIgnoreBuilder.java | 2 +- .../fileProcessors/GitIgnoreBuilder.java | 7 +- .../fileProcessors/HgIgnoreBuilder.java | 2 +- .../rat/document/DocumentNameMatcher.java | 2 +- 9 files changed, 104 insertions(+), 80 deletions(-) diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy index 3774f283d..07db17902 100644 --- a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy @@ -106,7 +106,6 @@ XPath xPath = XPathFactory.newInstance().newXPath() List ignoredFiles = new ArrayList<>(Arrays.asList( "/dir1/dir1.txt", - "/dir1/file1.log", "/dir1/.gitignore", "/dir2/dir2.md", "/dir3/dir3.log", 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 e05c2fa1c..b6ca2ce7c 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 @@ -24,8 +24,8 @@ import java.util.Objects; import java.util.Set; import java.util.TreeSet; - import java.util.stream.Collectors; + import org.apache.rat.config.exclusion.plexus.MatchPatterns; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; @@ -239,14 +239,15 @@ private List extractFileProcessors(final DocumentName basedir) { * @param nameBuilder The name builder for the pattern. File names are resolved against the generated name. * @param matcherBuilder the MatcherSet.Builder to add the patterns to. */ - private void extractPatterns(DocumentName.Builder nameBuilder, MatcherSet.Builder matcherBuilder) { + private void extractPatterns(final DocumentName.Builder nameBuilder, final MatcherSet.Builder matcherBuilder) { DocumentName name = nameBuilder.setName("Patterns").build(); if (!excludedPatterns.isEmpty()) { - matcherBuilder.addExcluded(name, excludedPatterns.stream().map(s -> ExclusionUtils.localizePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); + matcherBuilder.addExcluded(name, excludedPatterns.stream() + .map(s -> ExclusionUtils.localizePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); } if (!includedPatterns.isEmpty()) { - - matcherBuilder.addIncluded(name, includedPatterns.stream().map(s -> ExclusionUtils.localizePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); + matcherBuilder.addIncluded(name, includedPatterns.stream() + .map(s -> ExclusionUtils.localizePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java index d0f8b94e7..b5369c7ba 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -18,19 +18,16 @@ */ package org.apache.rat.config.exclusion; -import java.util.ArrayList; import java.util.List; import java.util.Optional; - import java.util.Set; -import java.util.function.Predicate; + import org.apache.rat.config.exclusion.plexus.MatchPattern; import org.apache.rat.config.exclusion.plexus.MatchPatterns; import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; -import static org.apache.rat.document.DocumentNameMatcher.MATCHES_ALL; import static org.apache.rat.document.DocumentNameMatcher.MATCHES_NONE; /** @@ -63,7 +60,7 @@ static MatcherSet merge(List matcherSets) { /** * A MatcherSet that assumes the files contain the already formatted strings and just need to be - * localized for the fileName. + * localized for the fileName. When {@link #build()} is called the builder is reset to the initial state. */ class Builder { @@ -92,7 +89,14 @@ public static void segregateList(final Set matching, final Set n public Builder() { } - public Builder addIncluded(DocumentName fromDocument, Set names) { + /** + * Adds included file names from the specified document. File names are resolved relative to the directory + * of the {@code fromDocument}. + * @param fromDocument the document the names were read from. + * @param names the names that were read from the document. + * @return this + */ + public Builder addIncluded(final DocumentName fromDocument, final Set names) { if (!names.isEmpty()) { String name = String.format("'included %s'", fromDocument.localized("/").substring(1)); addIncluded(new DocumentNameMatcher(name, MatchPatterns.from(names), fromDocument.getBaseDocumentName())); @@ -100,7 +104,14 @@ public Builder addIncluded(DocumentName fromDocument, Set names) { return this; } - public Builder addExcluded(DocumentName fromDocument, Set names) { + /** + * Adds excluded file names from the specified document. File names are resolved relative to the directory + * of the {@code fromDocument}. + * @param fromDocument the document the names were read from. + * @param names the names that were read from the document. + * @return this + */ + public Builder addExcluded(final DocumentName fromDocument, final Set names) { if (!names.isEmpty()) { String name = String.format("'excluded %s'", fromDocument.localized("/").substring(1)); addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(names), fromDocument.getBaseDocumentName())); @@ -108,20 +119,35 @@ public Builder addExcluded(DocumentName fromDocument, Set names) { return this; } - public Builder addIncluded(DocumentNameMatcher matcher) { + + /** + * Adds specified DocumentNameMatcher to the included matchers. + * @param matcher A document name matcher to add to the included set. + * @return this + */ + public Builder addIncluded(final DocumentNameMatcher matcher) { this.included = this.included == null ? matcher : DocumentNameMatcher.or(this.included, matcher); return this; } - public Builder addExcluded(DocumentNameMatcher matcher) { + /** + * Adds specified DocumentNameMatcher to the excluded matchers. + * @param matcher A document name matcher to add to the excluded set. + * @return this + */ + public Builder addExcluded(final DocumentNameMatcher matcher) { this.excluded = this.excluded == null ? matcher : DocumentNameMatcher.or(this.excluded, matcher); return this; } + /** + * Builds a MatcherSet. When {@link #build()} is called the builder is reset to the initial state. + * @return the MatcherSet based upon the included and excluded matchers. + */ public MatcherSet build() { MatcherSet result = new MatcherSet() { - final DocumentNameMatcher myIncluded = included; - final DocumentNameMatcher myExcluded = excluded; + private final DocumentNameMatcher myIncluded = included; + private final DocumentNameMatcher myExcluded = excluded; @Override public Optional includes() { diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java index b3e703aa6..42278f97c 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java @@ -21,7 +21,6 @@ import java.io.File; import java.io.FileFilter; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -33,6 +32,7 @@ import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Collectors; + import org.apache.commons.io.filefilter.DirectoryFileFilter; import org.apache.commons.io.filefilter.NameFileFilter; import org.apache.commons.lang3.StringUtils; @@ -44,24 +44,32 @@ import org.apache.rat.document.DocumentNameMatcher; /** - * // create a list of levels that a list of processors at that level. - * // will return a custom matcher that from an overridden MatcherSet.customDocumentNameMatchers method - * // build LevelMatcher as a system that returns Include, Exclude or no status for each check. - * // put the level matcher in an array with other level matchers at the specific level below the root - * // When searching start at the lowest level and work up the tree. + * Creates a List of {@link MatcherSet}s that represent the inclusions and exclusions of this file processor. + *

    + * By default this processor: + *

    + *
      + *
    • Creates a list of levels that correspond the depth of the directories where the specific include/exclude file is located. + * Directory depth is relative to the initially discovered include/exclude file.
    • + *
    • A MatcherSet is created for each include/exclude file located, and the MatcherSet is added to the proper level.
    • + *
    • During the build: + *
        + *
      • Each level creates a MatcherSet for the level.
      • + *
      • The MatcherSet for each level is returned in reverse order (deepest first). This ensures that most include/exclude + * files will be properly handled.
      • + *
    • + *
    */ public abstract class AbstractFileProcessorBuilder { /** A String format pattern to print a regex string */ protected static final String REGEX_FMT = "%%regex[%s]"; - /** The name of the file being processed */ protected final String fileName; - /** The predicate that will return {@code false} for any comment line in the file. */ protected final Predicate commentFilter; - + /** the collection of level builders */ private final SortedMap levelBuilders; - + /** if {@code true} then the processor file name will be included in the list of files to ignore */ private final boolean includeProcessorFile; /** @@ -94,12 +102,22 @@ protected AbstractFileProcessorBuilder(final String fileName, final Predicate createMatcherSetList(DocumentName dir) { + /** + * Creates the MatcherSet from each level and returns them in a list in reverse order. + * @return a list of MatcherSet + */ + + private List createMatcherSetList() { List keys = new ArrayList<>(levelBuilders.keySet()); keys.sort((a, b) -> -1 * Integer.compare(a, b)); - return keys.stream().map( key -> levelBuilders.get(key).asMatcherSet(dir)).collect(Collectors.toList()); + return keys.stream().map(key -> levelBuilders.get(key).asMatcherSet()).collect(Collectors.toList()); } + /** + * Builder the list of MatcherSet that define the inclusions/exclusions for the file processor. + * @param dir the directory agains which name resolution should be made. + * @return the List of MatcherSet that represent this file processor. + */ public final List build(final DocumentName dir) { if (includeProcessorFile) { String name = String.format("**/%s", fileName); @@ -107,18 +125,14 @@ public final List build(final DocumentName dir) { MatcherSet matcherSet = new MatcherSet.Builder() .addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(Collections.singletonList(pattern)), dir)) .build(); - LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(0, LevelBuilder::new); + LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(0, k -> new LevelBuilder()); levelBuilder.add(matcherSet); } checkDirectory(0, dir, new NameFileFilter(fileName)); - List result = null; - if (levelBuilders.size() == 1) { - result = Collections.singletonList(levelBuilders.get(0).asMatcherSet(dir)); - } else { - result = createMatcherSetList(dir); - } + List result = levelBuilders.size() == 1 ? Collections.singletonList(levelBuilders.get(0).asMatcherSet()) + : createMatcherSetList(); levelBuilders.clear(); return result; } @@ -153,7 +167,7 @@ protected MatcherSet process(final Consumer matcherSetConsumer, fina private void checkDirectory(final int level, final DocumentName directory, final FileFilter fileFilter) { File dirFile = new File(directory.getName()); for (File f : listFiles(dirFile, fileFilter)) { - LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(level, LevelBuilder::new); + LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(level, k -> new LevelBuilder()); DocumentName dirBasedName = DocumentName.builder(f).setBaseName(directory.getBaseName()).build(); levelBuilder.add(process(levelBuilder::add, dirBasedName, DocumentName.builder(f).setBaseName(directory.getName()).build())); } @@ -184,51 +198,29 @@ protected File[] listFiles(final File dir, final FileFilter filter) { return result == null ? new File[0] : result; } - protected static class FileProcessorPredicate implements Predicate { - private final Collection matcherSets; - FileProcessorPredicate(Collection matcherSets) { - this.matcherSets = matcherSets; - } - - public Collection getMatcherSets() { - return matcherSets; - } - - @Override - public boolean test(DocumentName documentName) { - for (MatcherSet matcherSet : matcherSets) { - if (matcherSet.includes().orElse(DocumentNameMatcher.MATCHES_NONE).matches(documentName)) { - return true; - } - if (matcherSet.excludes().orElse(DocumentNameMatcher.MATCHES_NONE).matches(documentName)) { - return false; - } - } - return true; - } - } - - static class LevelBuilder { + /** + * Manages the merging of {@link MatcherSet}s for the specified level. + */ + private static class LevelBuilder { /** * The list of MatcherSets that this builder produced. */ - private final MatcherSet.Builder builder; + private final MatcherSet.Builder builder = new MatcherSet.Builder(); - public LevelBuilder(Integer integer) { - int level = integer; - builder = new MatcherSet.Builder(); - } - - public void add(MatcherSet matcherSet) { - if (matcherSet.includes().isPresent()) { - builder.addIncluded(matcherSet.includes().get()); - } - if (matcherSet.excludes().isPresent()) { - builder.addExcluded(matcherSet.excludes().get()); - } + /** + * Adds a MatcherSet to this level. + * @param matcherSet the matcher set to add. + */ + public void add(final MatcherSet matcherSet) { + matcherSet.includes().ifPresent(builder::addIncluded); + matcherSet.excludes().ifPresent(builder::addExcluded); } - public MatcherSet asMatcherSet(DocumentName dir) { + /** + * Constructs the MatcherSet for this level. + * @return the MatcherSet. + */ + public MatcherSet asMatcherSet() { return builder.build(); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java index 787564d35..2be97f983 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/BazaarIgnoreBuilder.java @@ -20,6 +20,7 @@ import java.util.Optional; import java.util.function.Consumer; + import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java index 69e6aba3a..0f2ff1047 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java @@ -21,9 +21,9 @@ import java.io.File; import java.util.HashSet; import java.util.Iterator; - import java.util.Set; import java.util.function.Consumer; + import org.apache.commons.lang3.StringUtils; import org.apache.rat.config.exclusion.ExclusionUtils; import org.apache.rat.config.exclusion.MatcherSet; diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java index af5545e67..6c70fb736 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java @@ -19,9 +19,9 @@ package org.apache.rat.config.exclusion.fileProcessors; import java.io.File; - import java.util.Optional; import java.util.function.Consumer; + import org.apache.rat.config.exclusion.ExclusionUtils; import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.config.exclusion.plexus.MatchPatterns; @@ -35,10 +35,15 @@ * @see .gitignore documentation */ public class GitIgnoreBuilder extends AbstractFileProcessorBuilder { + /** The name of the file we read from */ private static final String IGNORE_FILE = ".gitignore"; + /** The comment prefix */ private static final String COMMENT_PREFIX = "#"; + /** An escaped comment in the .gitignore file. (Not a comment) */ private static final String ESCAPED_COMMENT = "\\#"; + /** An escaped negation in the .gitignore file. (Not a negation) */ private static final String ESCAPED_NEGATION = "\\!"; + /** The slash string */ private static final String SLASH = "/"; /** diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java index ca8ca1344..d7d0ad05b 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java @@ -81,7 +81,7 @@ public Optional modifyEntry(final Consumer matcherSetConsume return Optional.of(format(REGEX_FMT, pattern)); } else { if (entry.startsWith("*")) { - return Optional.of("**/"+entry); + return Optional.of("**/" + entry); } } return Optional.of(entry); diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 902834517..e05b505f7 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -95,7 +95,7 @@ public DocumentNameMatcher(final String name, final MatchPatterns patterns, fina * @param dirSeparator the directory separator. * @return the tokenized name. */ - private static char[][] tokenize(String name, String dirSeparator) { + private static char[][] tokenize(final String name, final String dirSeparator) { String[] tokenizedName = MatchPattern.tokenizePathToString(name, dirSeparator); char[][] tokenizedNameChar = new char[tokenizedName.length][]; for (int i = 0; i < tokenizedName.length; i++) { From 3456632f227ed98707b0c413f7b14c5a9a018b36 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Wed, 25 Dec 2024 16:36:46 +0000 Subject: [PATCH 075/123] cleaned up checkstyle issues --- .../src/it/resources/ReportTest/RAT_335/verify.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy index 07db17902..d660f59fd 100644 --- a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy @@ -124,10 +124,10 @@ assertThat(ignoredFiles).isEmpty() // Document types XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='IGNORED']", - mapOf("count", "7" )) + mapOf("count", "6" )) XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='NOTICE']", mapOf("count", "1" )) XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='STANDARD']", - mapOf("count", "3" )) + mapOf("count", "4" )) From cd416a94179f1270665e4b383465495e37c19a7d Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Thu, 26 Dec 2024 00:09:53 +0000 Subject: [PATCH 076/123] fixed and cleaned up plugin tests --- .../config/exclusion/ExclusionProcessor.java | 2 +- .../org/apache/rat/OptionCollectionTest.java | 18 +- .../org/apache/rat/mp/OptionMojoTest.java | 1 + .../org/apache/rat/mp/RatCheckMojoTest.java | 310 +++++++++--------- .../unit/RAT-335-GitIgnore/.gitignore | 7 - .../unit/RAT-335-GitIgnore/dir1/.gitignore | 3 - .../unit/RAT-335-GitIgnore/dir1/dir1.txt | 1 - .../unit/RAT-335-GitIgnore/dir1/file1.log | 1 - .../unit/RAT-335-GitIgnore/dir2/dir2.md | 1 - .../unit/RAT-335-GitIgnore/dir3/dir3.log | 1 - .../unit/RAT-335-GitIgnore/invoker.properties | 16 - .../resources/unit/RAT-335-GitIgnore/root.md | 1 - .../{RAT-335-GitIgnore => RAT-335}/README.txt | 0 .../dir1/dir1.md | 0 .../dir2/dir2.txt | 0 .../dir3/file3.log | 0 .../{RAT-335-GitIgnore => RAT-335}/pom.xml | 0 .../unit/RAT-362-GitIgnore/.gitignore | 2 - .../resources/unit/RAT-362-GitIgnore/foo.md | 1 - .../unit/RAT-362-GitIgnore/invoker.properties | 16 - .../{RAT-362-GitIgnore => RAT-362}/bar.md | 0 .../{RAT-362-GitIgnore => RAT-362}/pom.xml | 1 + .../src/test/resources/unit/it3/pom.xml | 1 + .../apache/rat/anttasks/ReportOptionTest.java | 8 +- 24 files changed, 168 insertions(+), 223 deletions(-) delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/.gitignore delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/.gitignore delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.txt delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/file1.log delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.md delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/dir3.log delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/invoker.properties delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/root.md rename apache-rat-plugin/src/test/resources/unit/{RAT-335-GitIgnore => RAT-335}/README.txt (100%) rename apache-rat-plugin/src/test/resources/unit/{RAT-335-GitIgnore => RAT-335}/dir1/dir1.md (100%) rename apache-rat-plugin/src/test/resources/unit/{RAT-335-GitIgnore => RAT-335}/dir2/dir2.txt (100%) rename apache-rat-plugin/src/test/resources/unit/{RAT-335-GitIgnore => RAT-335}/dir3/file3.log (100%) rename apache-rat-plugin/src/test/resources/unit/{RAT-335-GitIgnore => RAT-335}/pom.xml (100%) delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/.gitignore delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/foo.md delete mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/invoker.properties rename apache-rat-plugin/src/test/resources/unit/{RAT-362-GitIgnore => RAT-362}/bar.md (100%) rename apache-rat-plugin/src/test/resources/unit/{RAT-362-GitIgnore => RAT-362}/pom.xml (97%) 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 b6ca2ce7c..ca2ab06e7 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 @@ -270,7 +270,7 @@ private void extractCollectionPatterns(final DocumentName.Builder nameBuilder, f for (StandardCollection sc : excludedCollections) { Set patterns = sc.patterns(); if (patterns.isEmpty()) { - DefaultLog.getInstance().info(String.format("%s does not have a defined collection for exclusion.", sc)); + DefaultLog.getInstance().debug(String.format("%s does not have a defined collection for exclusion.", sc)); } else { MatcherSet.Builder.segregateList(excl, incl, sc.patterns()); } 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 c0d45c08a..7452d33b4 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 @@ -56,7 +56,6 @@ import static org.junit.jupiter.api.Assertions.fail; public class OptionCollectionTest { - @TempDir static Path testPath; @@ -65,21 +64,6 @@ static void preserveData() { AbstractOptionsProvider.preserveData(testPath.toFile(), "optionTest"); } - /** - * The base directory for the test. - * We do not use TempFile because we want the evidence of the run - * to exist after a failure. - */ - private final File baseDir; - - /** - * Constructor. - */ - public OptionCollectionTest() { - baseDir = new File("target/optionTools"); - baseDir.mkdirs(); - } - /** * Defines the test method that is stored in a map. */ @@ -128,7 +112,7 @@ public void testDirOptionCapturesDirectoryToScan() throws IOException { ReportConfiguration config; try { DefaultLog.setInstance(log); - String[] args = {"--dir", baseDir.getAbsolutePath()}; + String[] args = {"--dir", testPath.toFile().getAbsolutePath()}; config = OptionCollection.parseCommands(testPath.toFile(), args, (o) -> { }, true); } finally { diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java index 5f5eceb67..a96ab49ee 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java @@ -19,6 +19,7 @@ package org.apache.rat.mp; import org.apache.commons.cli.Option; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.maven.plugin.MojoExecutionException; diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java index e9a1ab8fb..dd2e7fcfe 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java @@ -16,18 +16,18 @@ */ package org.apache.rat.mp; +import static java.lang.String.format; import static java.nio.charset.StandardCharsets.UTF_8; import static org.apache.rat.mp.RatTestHelpers.ensureRatReportIsCorrect; -import static org.apache.rat.mp.RatTestHelpers.getSourceDirectory; -import static org.apache.rat.mp.RatTestHelpers.newArtifactFactory; -import static org.apache.rat.mp.RatTestHelpers.newArtifactRepository; -import static org.apache.rat.mp.RatTestHelpers.newSiteRenderer; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Fail.fail; import java.io.File; import java.io.FileInputStream; +import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -45,70 +45,88 @@ import org.apache.rat.license.LicenseSetFactory; import org.apache.rat.license.LicenseSetFactory.LicenseFilter; import org.apache.rat.report.claim.ClaimStatistic; +import org.apache.rat.test.AbstractOptionsProvider; +import org.apache.rat.test.utils.Resources; import org.apache.rat.testhelpers.TextUtils; import org.apache.rat.testhelpers.XmlUtils; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NodeList; /** * Test case for the {@link RatCheckMojo} and {@link RatReportMojo}. */ -public class RatCheckMojoTest extends BetterAbstractMojoTestCase { - /** - * Creates a new instance of {@link RatCheckMojo}. - * - * @param pDir The directory, where to look for a pom.xml file. - * @return The configured Mojo. - * @throws Exception An error occurred while creating the Mojo. - */ - private RatCheckMojo newRatCheckMojo(String pDir) throws Exception { - Arg.reset(); - return (RatCheckMojo) newRatMojo(pDir, "check", false); +public class RatCheckMojoTest { //extends BetterAbstractMojoTestCase { + + @TempDir + static Path tempDir; + + private static XPath xPath = XPathFactory.newInstance().newXPath(); + + @AfterAll + static void preserveData() { + AbstractOptionsProvider.preserveData(tempDir.toFile(), "unit"); + } + + + private RatCheckMojo getMojo(File pomFile) throws IOException { + try { + final RatCheckMojo mojo = new OptionMojoTest.SimpleMojoTestcase() { + }.getMojo(pomFile); + Assertions.assertNotNull(mojo); + return mojo; + } catch (IOException e) { + throw e; + } catch (Exception e) { + throw new IOException(format("Unable to generate mojo for %s", pomFile), e); + } } /** * Creates a new instance of {@link AbstractRatMojo}. * - * @param pDir The directory, where to look for a pom.xml file. - * @param pGoal The goal, which the Mojo must implement. - * @param pCreateCopy if {@code true} copy the directory contents and return the + * @param testDir The directory, where to look for a pom.xml file. * copy location. * @return The configured Mojo. * @throws Exception An error occurred while creating the Mojo. */ - private AbstractRatMojo newRatMojo(String pDir, String pGoal, boolean pCreateCopy) throws Exception { - final File baseDir = new File(getBasedir()); - final File testBaseDir = getSourceDirectory(getBasedir(), pDir, pCreateCopy, baseDir); - final File testPom = new File(testBaseDir, "pom.xml"); - final File buildDirectory = new File(new File(baseDir, "target/test"), pDir); - AbstractRatMojo mojo = (AbstractRatMojo) lookupConfiguredMojo(testPom, pGoal); - assertNotNull(mojo); - - assertNotNull("The mojo is missing its MavenProject, which will result in an NPE during RAT runs.", - mojo.getProject()); - - if (mojo instanceof RatReportMojo) { - setVariableValueToObject(mojo, "localRepository", newArtifactRepository(getContainer())); - setVariableValueToObject(mojo, "factory", newArtifactFactory()); - setVariableValueToObject(mojo, "siteRenderer", newSiteRenderer(getContainer())); - } else if (mojo instanceof RatCheckMojo) { - final File ratTxtFile = new File(buildDirectory, "rat.txt"); - FileUtils.write(ratTxtFile, "", UTF_8); // Ensure the output file exists and is empty (rerunning the test will append) - mojo.setOutputFile(ratTxtFile.getAbsolutePath()); - } + private RatCheckMojo newRatMojo(String testDir) throws Exception { + Arg.reset(); + final File pomFile = Resources.getResourceFile(format("unit/%s/pom.xml", testDir)); + final File sourceDir = pomFile.getParentFile(); + final File baseDir = tempDir.resolve(testDir).toFile(); + FileUtils.copyDirectory(sourceDir, baseDir); + + RatCheckMojo mojo = getMojo(pomFile); + assertThat(mojo).isNotNull(); + assertThat(mojo.getProject()) + .as("The mojo is missing its MavenProject, which will result in an NPE during RAT runs.") + .isNotNull(); + + File buildDirectory = new File(baseDir, "target"); + buildDirectory.mkdirs(); + final File ratTxtFile = new File(buildDirectory, "rat.txt"); + FileUtils.write(ratTxtFile, "", UTF_8); // Ensure the output file exists and is empty (rerunning the test will append) + mojo.setOutputFile(ratTxtFile.getAbsolutePath()); + return mojo; } private String getDir(RatCheckMojo mojo) { - return mojo.getProject().getBasedir().getAbsolutePath().replace("\\","/") + "/"; + return mojo.getProject().getBasedir().getAbsolutePath().replace("\\", "/") + "/"; } + /** * Runs a check, which should expose no problems. * * @throws Exception The test failed. */ - public void testIt1() throws Exception { - final RatCheckMojo mojo = newRatCheckMojo("it1"); + @Test + void it1() throws Exception { + final RatCheckMojo mojo = newRatMojo("it1"); final File ratTxtFile = mojo.getRatTxtFile(); ReportConfiguration config = mojo.getConfiguration(); @@ -147,8 +165,8 @@ public void testIt1() throws Exception { private static Map mapOf(String... parts) { Map map = new HashMap<>(); - for (int i=0; i mapOf(String... parts) { * * @throws Exception The test failed. */ - public void testIt2() throws Exception { - final RatCheckMojo mojo = newRatCheckMojo("it2"); + @Test + void it2() throws Exception { + final RatCheckMojo mojo = newRatMojo("it2"); final File ratTxtFile = mojo.getRatTxtFile(); final String[] expected = { "^Files with unapproved licenses\\s+\\*+\\s+\\Q/src.txt\\E\\s+", @@ -171,17 +190,19 @@ public void testIt2() throws Exception { ReporterTestUtils.apacheLicenseVersion2(1), ReporterTestUtils.unknownLicense(1), ReporterTestUtils.documentOut(false, Document.Type.STANDARD, "/src.txt") + - ReporterTestUtils.UNKNOWN_LICENSE, + ReporterTestUtils.UNKNOWN_LICENSE, ReporterTestUtils.documentOut(true, Document.Type.STANDARD, "/pom.xml") + - ReporterTestUtils.APACHE_LICENSE - }; + ReporterTestUtils.APACHE_LICENSE + }; try { mojo.execute(); fail("Expected RatCheckException"); } catch (RatCheckException e) { final String msg = e.getMessage(); - assertTrue("report filename was not contained in '" + msg + "'", msg.contains(ratTxtFile.getName())); - assertFalse("no null allowed in '" + msg + "'", (msg.toUpperCase().contains("NULL"))); + assertThat(msg.contains(ratTxtFile.getName())).as(() -> format("report filename was not contained in '%s'", msg)) + .isTrue(); + assertThat(msg.toUpperCase()).contains("UNAPPROVED EXCEEDED MINIMUM"); + ensureRatReportIsCorrect(ratTxtFile, expected, TextUtils.EMPTY); } } @@ -189,8 +210,9 @@ public void testIt2() throws Exception { /** * Tests adding license headers. */ - public void testIt3() throws Exception { - final RatCheckMojo mojo = (RatCheckMojo) newRatMojo("it3", "check", true); + @Test + void it3() throws Exception { + final RatCheckMojo mojo = newRatMojo("it3"); final File ratTxtFile = mojo.getRatTxtFile(); final String[] expected = { "^Files with unapproved licenses\\s+\\*+\\s+\\Q/src.apt\\E\\s+", @@ -202,37 +224,58 @@ public void testIt3() throws Exception { ReporterTestUtils.apacheLicenseVersion2(1), ReporterTestUtils.unknownLicense(1), ReporterTestUtils.documentOut(false, Document.Type.STANDARD, "/src.apt") + - ReporterTestUtils.UNKNOWN_LICENSE, + ReporterTestUtils.UNKNOWN_LICENSE, ReporterTestUtils.documentOut(true, Document.Type.STANDARD, "/pom.xml") + - ReporterTestUtils.APACHE_LICENSE + ReporterTestUtils.APACHE_LICENSE }; ReportConfiguration config = mojo.getConfiguration(); - assertTrue("should be adding licenses", config.isAddingLicenses()); - + assertThat(config.isAddingLicenses()).as("should be adding licenses").isTrue(); mojo.execute(); + org.w3c.dom.Document document = XmlUtils.toDom(Files.newInputStream(ratTxtFile.toPath())); - ensureRatReportIsCorrect(ratTxtFile, expected, TextUtils.EMPTY); + XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/pom.xml']", "type", + "STANDARD"); + XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/src.apt']", "type", + "STANDARD"); + XmlUtils.assertIsPresent(document, xPath, "/rat-report/resource[@name='/src.apt']/license[@approval='false']"); + + XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/src.apt']", "type", + "STANDARD"); + XmlUtils.assertIsPresent(document, xPath, "/rat-report/resource[@name='/src.apt.new']/license[@approval='true']"); + + XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='STANDARD']", "count", + "3"); + + for (Document.Type type : Document.Type.values()) { + if (type == Document.Type.STANDARD) { + XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='STANDARD']", "count", + "3"); + } else { + XmlUtils.assertIsNotPresent(document, xPath, format("/rat-report/statistics/documentType[@name='%s']", type)); + } + } } /** * Tests defining licenses in configuration */ - public void testIt5() throws Exception { - final RatCheckMojo mojo = (RatCheckMojo) newRatMojo("it5", "check", true); + @Test + void it5() throws Exception { + final RatCheckMojo mojo = newRatMojo("it5"); final File ratTxtFile = mojo.getRatTxtFile(); ReportConfiguration config = mojo.getConfiguration(); - assertFalse("Should not be adding licenses", config.isAddingLicenses()); - assertFalse("Should not be forcing licenses", config.isAddingLicensesForced()); + assertThat(config.isAddingLicenses()).as("Should not be adding licenses").isFalse(); + assertThat(config.isAddingLicensesForced()).as("Should not be forcing licenses").isFalse(); ReportConfigurationTest.validateDefaultApprovedLicenses(config); - assertFalse(config.getLicenseCategories(LicenseFilter.APPROVED).contains(ILicenseFamily.makeCategory("YAL"))); + assertThat(config.getLicenseCategories(LicenseFilter.APPROVED)).doesNotContain(ILicenseFamily.makeCategory("YAL")); ReportConfigurationTest.validateDefaultLicenseFamilies(config, "YAL"); - assertNotNull(LicenseSetFactory.familySearch("YAL", config.getLicenseFamilies(LicenseFilter.ALL))); + assertThat(LicenseSetFactory.familySearch("YAL", config.getLicenseFamilies(LicenseFilter.ALL))).isNotNull(); ReportConfigurationTest.validateDefaultLicenses(config, "MyLicense", "CpyrT", "RegxT", "SpdxT", "TextT", "Not", "All", "Any"); - assertTrue(LicenseSetFactory.search("YAL", "MyLicense", config.getLicenses(LicenseFilter.ALL)).isPresent()); + assertThat(LicenseSetFactory.search("YAL", "MyLicense", config.getLicenses(LicenseFilter.ALL))).isPresent(); try { mojo.execute(); fail("Should have thrown exception"); @@ -280,14 +323,15 @@ public void testIt5() throws Exception { XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/pom.xml']/license[@id='TextT']", mapOf("approval", "false", "family", "YAL ", "name", "Text with tag")); } - + /** * Runs a check, which should expose no problems. * * @throws Exception The test failed. */ - public void testRAT_343() throws Exception { - final RatCheckMojo mojo = newRatCheckMojo("RAT-343"); + @Test + void rat343() throws Exception { + final RatCheckMojo mojo = newRatMojo("RAT-343"); final File ratTxtFile = mojo.getRatTxtFile(); // POM reports AL, BSD and CC BYas BSD because it contains the BSD and CC BY strings final String[] expected = { @@ -314,7 +358,7 @@ public void testRAT_343() throws Exception { assertThat(config.isAddingLicensesForced()).isFalse(); assertThat(config.getCopyrightMessage()).isNull(); assertThat(config.getStyleSheet()).withFailMessage("Stylesheet should not be null").isNotNull(); - + ReportConfigurationTest.validateDefaultApprovedLicenses(config, 1); ReportConfigurationTest.validateDefaultLicenseFamilies(config, "BSD", "CC BY"); ReportConfigurationTest.validateDefaultLicenses(config, "BSD", "CC BY"); @@ -326,37 +370,20 @@ public void testRAT_343() throws Exception { /** * Tests verifying gitignore parsing */ - public void /*test*/RAT_335GitIgnoreParsing() throws Exception { - final RatCheckMojo mojo = newRatCheckMojo("RAT-335-GitIgnore"); + @Test + void rat335() throws Exception { + final RatCheckMojo mojo = newRatMojo("RAT-335"); final File ratTxtFile = mojo.getRatTxtFile(); -// final String[] expected = { -// ReporterTestUtils.counterText(ClaimStatistic.Counter.NOTICES, 1, false), -// ReporterTestUtils.counterText(ClaimStatistic.Counter.BINARIES, 0, false), -// ReporterTestUtils.counterText(ClaimStatistic.Counter.ARCHIVES, 0, false), -// ReporterTestUtils.counterText(ClaimStatistic.Counter.STANDARDS, 6, false), -// ReporterTestUtils.counterText(ClaimStatistic.Counter.IGNORED, 0, false), -// ReporterTestUtils.counterText(ClaimStatistic.Counter.UNKNOWN, 4, false), -// ReporterTestUtils.apacheLicenseVersion2(2), -// ReporterTestUtils.unknownLicense(4), -// ReporterTestUtils.documentOut(true, Document.Type.STANDARD, "/pom.xml") + -// ReporterTestUtils.APACHE_LICENSE, -// ReporterTestUtils.documentOut(false, Document.Type.STANDARD, "/dir1/dir1.md") + -// ReporterTestUtils.UNKNOWN_LICENSE, -// ReporterTestUtils.documentOut(false, Document.Type.STANDARD, "/dir2/dir2.txt") + -// ReporterTestUtils.UNKNOWN_LICENSE, -// ReporterTestUtils.documentOut(false, Document.Type.STANDARD, "/dir3/file3.log") + -// ReporterTestUtils.UNKNOWN_LICENSE, -// }; try { mojo.execute(); fail("Expected RatCheckException"); } catch (RatCheckException e) { final String msg = e.getMessage(); - assertTrue("report filename was not contained in '" + msg + "'", msg.contains(ratTxtFile.getName())); - assertFalse("no null allowed in '" + msg + "'", (msg.toUpperCase().contains("NULL"))); + assertThat(msg).contains(ratTxtFile.getName()); + assertThat(msg).contains("UNAPPROVED exceeded minimum"); Map data = new HashMap<>(); - data.put(ClaimStatistic.Counter.APPROVED, "2"); + data.put(ClaimStatistic.Counter.APPROVED, "1"); data.put(ClaimStatistic.Counter.ARCHIVES, "0"); data.put(ClaimStatistic.Counter.BINARIES, "0"); data.put(ClaimStatistic.Counter.DOCUMENT_TYPES, "3"); @@ -364,12 +391,11 @@ public void testRAT_343() throws Exception { data.put(ClaimStatistic.Counter.LICENSE_CATEGORIES, "2"); data.put(ClaimStatistic.Counter.LICENSE_NAMES, "2"); data.put(ClaimStatistic.Counter.NOTICES, "1"); - data.put(ClaimStatistic.Counter.STANDARDS, "6"); + data.put(ClaimStatistic.Counter.STANDARDS, "5"); data.put(ClaimStatistic.Counter.UNAPPROVED, "4"); data.put(ClaimStatistic.Counter.UNKNOWN, "4"); org.w3c.dom.Document document = XmlUtils.toDom(Files.newInputStream(ratTxtFile.toPath())); - XPath xPath = XPathFactory.newInstance().newXPath(); for (ClaimStatistic.Counter counter : ClaimStatistic.Counter.values()) { String xpath = String.format("/rat-report/statistics/statistic[@name='%s']", counter.displayName()); @@ -382,31 +408,30 @@ public void testRAT_343() throws Exception { // license categories XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseCategory[@name='?????']", - mapOf("count", "4" )); + mapOf("count", "4")); XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseCategory[@name='AL ']", - mapOf("count", "2" )); + mapOf("count", "1")); // license names XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseName[@name='Apache License Version 2.0']", - mapOf("count", "2" )); + mapOf("count", "1")); XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseName[@name='Unknown license']", - mapOf("count", "4" )); + mapOf("count", "4")); // Document types XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='IGNORED']", - mapOf("count", "6" )); + mapOf("count", "6")); XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='NOTICE']", - mapOf("count", "1" )); + mapOf("count", "1")); XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='STANDARD']", - mapOf("count", "6" )); + mapOf("count", "5")); List ignoredFiles = new ArrayList<>(Arrays.asList( "/dir1/dir1.txt", - "/dir1/file1.log", "/dir1/.gitignore", "/dir2/dir2.md", "/dir3/dir3.log", @@ -414,7 +439,7 @@ public void testRAT_343() throws Exception { "/root.md")); NodeList nodeList = XmlUtils.getNodeList(document, xPath, "/rat-report/resource[@type='IGNORED']"); - for (int i=0;i< nodeList.getLength(); i++) { + for (int i = 0; i < nodeList.getLength(); i++) { NamedNodeMap attr = nodeList.item(i).getAttributes(); String s = attr.getNamedItem("name").getNodeValue(); assertThat(ignoredFiles).contains(s); @@ -431,62 +456,45 @@ public void testRAT_343() throws Exception { * So for this test we must create such a file which is specific for the current * working directory. */ - public void /*test*/RAT362GitIgnore() throws Exception { - final RatCheckMojo mojo = newRatCheckMojo("RAT-362-GitIgnore"); + @Test + void rat362() throws Exception { + final RatCheckMojo mojo = newRatMojo("RAT-362"); final File ratTxtFile = mojo.getRatTxtFile(); - final String dirStr = getDir(mojo); - - if (dirStr.contains(":")) { - // The problem this is testing for cannot happen if there is - // a Windows drive letter in the name of the directory. - // Any duplication of a ':' will make it all fail always. - // So there is no point in continuing this test. - return; - } - File dir = new File(dirStr); - - // Make the target directory for the test file - assertTrue(dir.isDirectory()); - - // Create the test file with a content on which it must fail - File barFile = new File(dir, "bar.md"); - assertThat(barFile).exists(); - final String[] expected = { - ReporterTestUtils.counterText(ClaimStatistic.Counter.NOTICES, 0, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.BINARIES, 0, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.ARCHIVES, 0, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.STANDARDS, 3, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.IGNORED, 0, false), - ReporterTestUtils.apacheLicenseVersion2(2), - ReporterTestUtils.unknownLicense(1), - ReporterTestUtils.documentOut(false, Document.Type.STANDARD, "/bar.md") + - ReporterTestUtils.UNKNOWN_LICENSE - }; try { mojo.execute(); - fail("Expected RatCheckException: This check should have failed on the invalid test file"); + fail("Expected RatCheckException"); } catch (RatCheckException e) { final String msg = e.getMessage(); - assertTrue("report filename was not contained in '" + msg + "'", msg.contains(ratTxtFile.getName())); - assertFalse("no null allowed in '" + msg + "'", (msg.toUpperCase().contains("NULL"))); - ensureRatReportIsCorrect(ratTxtFile, expected, TextUtils.EMPTY); + assertThat(msg).contains(ratTxtFile.getName()); + assertThat(msg).contains("UNAPPROVED exceeded minimum"); + + org.w3c.dom.Document document = XmlUtils.toDom(Files.newInputStream(ratTxtFile.toPath())); + // Document types + XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='IGNORED']", + "count", "2"); + + XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/bar.md']", + "type", "STANDARD"); + XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/foo.md']", + "type", "IGNORED"); } } /** - * Tests implicit excludes apply to submodules too - */ - public void testRAT_107() throws Exception { - final RatCheckMojo mojo = (RatCheckMojo) newRatMojo("RAT-107", "check", true); - final File ratTxtFile = mojo.getRatTxtFile(); - final String[] expected = {}; - final String[] notExpected = {}; - setVariableValueToObject(mojo, "excludeSubProjects", Boolean.FALSE); - mojo.setInputExcludeParsedScm("MAVEN"); - mojo.setInputExcludeParsedScm("idea"); - mojo.setInputExcludeParsedScm("eclipse"); - mojo.execute(); - - ensureRatReportIsCorrect(ratTxtFile, expected, notExpected); - } + * Tests implicit excludes apply to submodules too + */ + @Test + void rat107() throws Exception { + final RatCheckMojo mojo = newRatMojo("RAT-107"); + final File ratTxtFile = mojo.getRatTxtFile(); + final String[] expected = {}; + final String[] notExpected = {}; + //setVariableValueToObject(mojo, "excludeSubProjects", Boolean.FALSE); + mojo.setInputExcludeParsedScm("MAVEN"); + mojo.setInputExcludeParsedScm("idea"); + mojo.setInputExcludeParsedScm("eclipse"); + mojo.execute(); + + ensureRatReportIsCorrect(ratTxtFile, expected, notExpected); + } } diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/.gitignore b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/.gitignore deleted file mode 100644 index 8855fa805..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -*.md - -# This makes it ignore dir3/dir3.log and dir3/file3.log -*.log - -# This makes it "unignore" dir3/file3.log -!file*.log diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/.gitignore b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/.gitignore deleted file mode 100644 index 26fd5c956..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.txt -!dir1.md -file1.log \ No newline at end of file diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.txt b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.txt deleted file mode 100644 index a31cbc897..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.txt +++ /dev/null @@ -1 +0,0 @@ -File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/file1.log b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/file1.log deleted file mode 100644 index a31cbc897..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/file1.log +++ /dev/null @@ -1 +0,0 @@ -File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.md b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.md deleted file mode 100644 index a31cbc897..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.md +++ /dev/null @@ -1 +0,0 @@ -File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/dir3.log b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/dir3.log deleted file mode 100644 index a31cbc897..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/dir3.log +++ /dev/null @@ -1 +0,0 @@ -File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/invoker.properties b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/invoker.properties deleted file mode 100644 index 6e8c3479e..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/invoker.properties +++ /dev/null @@ -1,16 +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. - -invoker.goals = clean apache-rat:check diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/root.md b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/root.md deleted file mode 100644 index a31cbc897..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/root.md +++ /dev/null @@ -1 +0,0 @@ -File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/README.txt b/apache-rat-plugin/src/test/resources/unit/RAT-335/README.txt similarity index 100% rename from apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/README.txt rename to apache-rat-plugin/src/test/resources/unit/RAT-335/README.txt diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.md b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/dir1.md similarity index 100% rename from apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.md rename to apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/dir1.md diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.txt b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir2/dir2.txt similarity index 100% rename from apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.txt rename to apache-rat-plugin/src/test/resources/unit/RAT-335/dir2/dir2.txt diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/file3.log b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir3/file3.log similarity index 100% rename from apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/file3.log rename to apache-rat-plugin/src/test/resources/unit/RAT-335/dir3/file3.log diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/pom.xml b/apache-rat-plugin/src/test/resources/unit/RAT-335/pom.xml similarity index 100% rename from apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/pom.xml rename to apache-rat-plugin/src/test/resources/unit/RAT-335/pom.xml diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/.gitignore b/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/.gitignore deleted file mode 100644 index 4912996bc..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/foo.md -target \ No newline at end of file diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/foo.md b/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/foo.md deleted file mode 100644 index a31cbc897..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/foo.md +++ /dev/null @@ -1 +0,0 @@ -File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/invoker.properties b/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/invoker.properties deleted file mode 100644 index 6e8c3479e..000000000 --- a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/invoker.properties +++ /dev/null @@ -1,16 +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. - -invoker.goals = clean apache-rat:check diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/bar.md b/apache-rat-plugin/src/test/resources/unit/RAT-362/bar.md similarity index 100% rename from apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/bar.md rename to apache-rat-plugin/src/test/resources/unit/RAT-362/bar.md diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/pom.xml b/apache-rat-plugin/src/test/resources/unit/RAT-362/pom.xml similarity index 97% rename from apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/pom.xml rename to apache-rat-plugin/src/test/resources/unit/RAT-362/pom.xml index 71669aa32..af34ad819 100644 --- a/apache-rat-plugin/src/test/resources/unit/RAT-362-GitIgnore/pom.xml +++ b/apache-rat-plugin/src/test/resources/unit/RAT-362/pom.xml @@ -27,6 +27,7 @@ apache-rat-plugin @pom.version@ + xml **/.gitignore diff --git a/apache-rat-plugin/src/test/resources/unit/it3/pom.xml b/apache-rat-plugin/src/test/resources/unit/it3/pom.xml index f6982e399..1188a2d28 100644 --- a/apache-rat-plugin/src/test/resources/unit/it3/pom.xml +++ b/apache-rat-plugin/src/test/resources/unit/it3/pom.xml @@ -29,6 +29,7 @@ 1 true + xml
    diff --git a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java index cc465da37..cee3922f1 100644 --- a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java +++ b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java @@ -17,7 +17,6 @@ package org.apache.rat.anttasks; import java.nio.file.Path; -import java.util.List; import org.apache.commons.cli.Option; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; @@ -28,6 +27,7 @@ import org.apache.rat.utils.DefaultLog; import org.apache.rat.utils.Log; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsProvider; @@ -73,12 +73,12 @@ public void execute() { } } - final static class AntOptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { + final class AntOptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { final AtomicBoolean helpCalled = new AtomicBoolean(false); - public AntOptionsProvider() { - super(BaseAntTask.unsupportedArgs(), testPath.toFile()); + public OptionsProvider() { + super(BaseAntTask.unsupportedArgs()); } protected ReportConfiguration generateConfig(List> args) { From 5d5dab4c2af2bc835a6a35a02604a4ff6ab88a9a Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Thu, 26 Dec 2024 00:10:58 +0000 Subject: [PATCH 077/123] fixed and cleaned up plugin tests --- apache-rat-plugin/src/test/resources/unit/RAT-362/.gitignore | 2 ++ apache-rat-plugin/src/test/resources/unit/RAT-362/foo.md | 1 + 2 files changed, 3 insertions(+) create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-362/.gitignore create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-362/foo.md diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-362/.gitignore b/apache-rat-plugin/src/test/resources/unit/RAT-362/.gitignore new file mode 100644 index 000000000..4912996bc --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-362/.gitignore @@ -0,0 +1,2 @@ +/foo.md +target \ No newline at end of file diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-362/foo.md b/apache-rat-plugin/src/test/resources/unit/RAT-362/foo.md new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-362/foo.md @@ -0,0 +1 @@ +File without a valid license From 4c4c97e601397de7833c2b65a56b641e170cc89a Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Thu, 26 Dec 2024 00:12:05 +0000 Subject: [PATCH 078/123] fixed and cleaned up plugin tests --- .../src/test/resources/unit/RAT-335/.gitignore | 7 +++++++ .../src/test/resources/unit/RAT-335/dir1/.gitignore | 3 +++ .../src/test/resources/unit/RAT-335/dir1/dir1.txt | 1 + .../src/test/resources/unit/RAT-335/dir1/file1.log | 1 + .../src/test/resources/unit/RAT-335/dir2/dir2.md | 1 + .../src/test/resources/unit/RAT-335/dir3/dir3.log | 1 + apache-rat-plugin/src/test/resources/unit/RAT-335/root.md | 1 + 7 files changed, 15 insertions(+) create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335/.gitignore create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/.gitignore create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/dir1.txt create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/file1.log create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335/dir2/dir2.md create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335/dir3/dir3.log create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-335/root.md diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335/.gitignore b/apache-rat-plugin/src/test/resources/unit/RAT-335/.gitignore new file mode 100644 index 000000000..8855fa805 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-335/.gitignore @@ -0,0 +1,7 @@ +*.md + +# This makes it ignore dir3/dir3.log and dir3/file3.log +*.log + +# This makes it "unignore" dir3/file3.log +!file*.log diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/.gitignore b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/.gitignore new file mode 100644 index 000000000..26fd5c956 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/.gitignore @@ -0,0 +1,3 @@ +*.txt +!dir1.md +file1.log \ No newline at end of file diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/dir1.txt b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/dir1.txt new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/dir1.txt @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/file1.log b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/file1.log new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir1/file1.log @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335/dir2/dir2.md b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir2/dir2.md new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir2/dir2.md @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335/dir3/dir3.log b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir3/dir3.log new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-335/dir3/dir3.log @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335/root.md b/apache-rat-plugin/src/test/resources/unit/RAT-335/root.md new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-335/root.md @@ -0,0 +1 @@ +File without a valid license From 4daa9c96b80112ef39ce8365c36a3fae8eeb062a Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Thu, 26 Dec 2024 00:14:37 +0000 Subject: [PATCH 079/123] fixed and cleaned up plugin tests --- .../test/resources/unit/RAT-107/.classpath | 1 + .../src/test/resources/unit/RAT-107/.project | 1 + .../resources/unit/RAT-107/.settings/dummy | 0 .../src/test/resources/unit/RAT-107/dummy.ipr | 1 + .../unit/RAT-107/submodule/.classpath | 1 + .../resources/unit/RAT-107/submodule/.project | 1 + .../unit/RAT-107/submodule/.settings/dummy | 0 .../unit/RAT-107/submodule/dummy.iml | 1 + .../unit/RAT-107/submodule/dummy.ipr | 1 + .../unit/RAT-107/submodule/dummy.iws | 1 + .../src/test/resources/unit/it5/.bzrignore | 5 - .../src/test/resources/unit/it5/pom.xml | 97 ------------------- 12 files changed, 8 insertions(+), 102 deletions(-) create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/.classpath create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/.project create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/.settings/dummy create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/dummy.ipr create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.classpath create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.project create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.settings/dummy create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.iml create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.ipr create mode 100644 apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.iws delete mode 100644 apache-rat-plugin/src/test/resources/unit/it5/.bzrignore delete mode 100644 apache-rat-plugin/src/test/resources/unit/it5/pom.xml diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/.classpath b/apache-rat-plugin/src/test/resources/unit/RAT-107/.classpath new file mode 100644 index 000000000..b77e339f2 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-107/.classpath @@ -0,0 +1 @@ +This file intentionally has no Apache License Header. diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/.project b/apache-rat-plugin/src/test/resources/unit/RAT-107/.project new file mode 100644 index 000000000..b77e339f2 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-107/.project @@ -0,0 +1 @@ +This file intentionally has no Apache License Header. diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/.settings/dummy b/apache-rat-plugin/src/test/resources/unit/RAT-107/.settings/dummy new file mode 100644 index 000000000..e69de29bb diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/dummy.ipr b/apache-rat-plugin/src/test/resources/unit/RAT-107/dummy.ipr new file mode 100644 index 000000000..b77e339f2 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-107/dummy.ipr @@ -0,0 +1 @@ +This file intentionally has no Apache License Header. diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.classpath b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.classpath new file mode 100644 index 000000000..b77e339f2 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.classpath @@ -0,0 +1 @@ +This file intentionally has no Apache License Header. diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.project b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.project new file mode 100644 index 000000000..b77e339f2 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.project @@ -0,0 +1 @@ +This file intentionally has no Apache License Header. diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.settings/dummy b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/.settings/dummy new file mode 100644 index 000000000..e69de29bb diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.iml b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.iml new file mode 100644 index 000000000..b77e339f2 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.iml @@ -0,0 +1 @@ +This file intentionally has no Apache License Header. diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.ipr b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.ipr new file mode 100644 index 000000000..b77e339f2 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.ipr @@ -0,0 +1 @@ +This file intentionally has no Apache License Header. diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.iws b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.iws new file mode 100644 index 000000000..b77e339f2 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/RAT-107/submodule/dummy.iws @@ -0,0 +1 @@ +This file intentionally has no Apache License Header. diff --git a/apache-rat-plugin/src/test/resources/unit/it5/.bzrignore b/apache-rat-plugin/src/test/resources/unit/it5/.bzrignore deleted file mode 100644 index f59acc081..000000000 --- a/apache-rat-plugin/src/test/resources/unit/it5/.bzrignore +++ /dev/null @@ -1,5 +0,0 @@ -## RAT-171: Add rubbish and ensure that the plugin behaves properly -DoesNotExistAtALL/** -*\IllegalStuffNotExisting -Lets-See*+?!OrWhat -\\nDoesThatWorkAsWell\/ diff --git a/apache-rat-plugin/src/test/resources/unit/it5/pom.xml b/apache-rat-plugin/src/test/resources/unit/it5/pom.xml deleted file mode 100644 index 9cb1327b1..000000000 --- a/apache-rat-plugin/src/test/resources/unit/it5/pom.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - 4.0.0 - org.codehaus.mojo.rat.test - it1 - 1.0 - - - - org.apache.rat - apache-rat-plugin - @pom.version@ - - xml - - - YAL - Yet another license - - - YAL - - - MyLicense - YAL - Yet Another License - - - YAL - CpyrT - Copyright with tags - - - 1990 - 1991 - foo - - - - YAL - RegxT - Regex with tag - - regex tag - - - YAL - SpdxT - Spdx with tag - - spxd-tag - - - YAL - TextT - Text with tag - - text-tag - - - YAL - Not - Not testing - - - not test text - - - - YAL - All - All testing - - - all test text - all spdx text - - - - YAL - Any - Any testing - - - any test text - any spdx text - - - - - src.apt - - - - - - From 2bc6556da09026360f34dea204cd1dc145f14ed0 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Fri, 27 Dec 2024 00:28:03 +0000 Subject: [PATCH 080/123] updated and fixed plugin tests --- .../java/org/apache/rat/commandline/Arg.java | 27 +-- .../config/exclusion/ExclusionProcessor.java | 2 + .../rat/config/exclusion/ExclusionUtils.java | 17 +- .../rat/config/exclusion/MatcherSet.java | 3 + .../configuration/XMLConfigurationReader.java | 162 +++++++++++------- .../rat/report/xml/writer/XmlWriter.java | 4 +- .../main/java/org/apache/rat/utils/Log.java | 14 +- .../fileProcessors/GitIgnoreBuilderTest.java | 7 +- .../rat/test/AbstractOptionsProvider.java | 5 +- apache-rat-plugin/.gitignore | 1 + apache-rat-plugin/pom.xml | 14 +- .../it/CustomLicense/.rat/customConfig.xml | 17 ++ .../src/it/CustomLicense/invoker.properties | 2 +- .../src/it/CustomLicense/pom.xml | 28 +-- apache-rat-plugin/src/it/RAT-268/pom.xml | 10 +- .../org/apache/rat/mp/OptionMojoTest.java | 1 - .../org/apache/rat/mp/RatCheckMojoTest.java | 97 +++++------ .../resources/unit/it5/.rat/customConfig.xml | 23 +++ .../src/test/resources/unit/it5/pom.xml | 41 +++++ .../java/nl/basjes/something/Something.java | 26 +++ .../apache/rat/anttasks/ReportOptionTest.java | 7 +- 21 files changed, 331 insertions(+), 177 deletions(-) create mode 100644 apache-rat-plugin/src/it/CustomLicense/.rat/customConfig.xml create mode 100644 apache-rat-plugin/src/test/resources/unit/it5/.rat/customConfig.xml create mode 100644 apache-rat-plugin/src/test/resources/unit/it5/pom.xml create mode 100644 apache-rat-plugin/src/test/resources/unit/it5/src/main/java/nl/basjes/something/Something.java 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 3ba85b95a..b975e4150 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 @@ -586,7 +586,8 @@ private static void processConfigurationArgs(final ArgumentContext context) thro Defaults.Builder defaultBuilder = Defaults.builder(); if (CONFIGURATION.isSelected()) { for (String fn : context.getCommandLine().getOptionValues(CONFIGURATION.getSelected())) { - defaultBuilder.add(fn); + File file = context.resolve(fn); + defaultBuilder.add(file); } } if (CONFIGURATION_NO_DEFAULTS.isSelected()) { @@ -603,11 +604,12 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (FAMILIES_APPROVED_FILE.isSelected()) { try { - File f = context.getCommandLine().getParsedOptionValue(FAMILIES_APPROVED_FILE.getSelected()); + String fileName = context.getCommandLine().getOptionValue(FAMILIES_APPROVED_FILE.getSelected()); + File f = context.resolve(fileName); try (InputStream in = Files.newInputStream(f.toPath())) { context.getConfiguration().addApprovedLicenseCategories(IOUtils.readLines(in, StandardCharsets.UTF_8)); } - } catch (IOException | ParseException e) { + } catch (IOException e) { throw new ConfigurationException(e); } } @@ -618,11 +620,12 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (FAMILIES_DENIED_FILE.isSelected()) { try { - File f = context.getCommandLine().getParsedOptionValue(FAMILIES_DENIED_FILE.getSelected()); + String fileName = context.getCommandLine().getOptionValue(FAMILIES_DENIED_FILE.getSelected()); + File f = context.resolve(fileName); try (InputStream in = Files.newInputStream(f.toPath())) { context.getConfiguration().removeApprovedLicenseCategories(IOUtils.readLines(in, StandardCharsets.UTF_8)); } - } catch (IOException | ParseException e) { + } catch (IOException e) { throw new ConfigurationException(e); } } @@ -634,11 +637,12 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (LICENSES_APPROVED_FILE.isSelected()) { try { - File f = context.getCommandLine().getParsedOptionValue(LICENSES_APPROVED_FILE.getSelected()); - try (InputStream in = Files.newInputStream(f.toPath())) { + String fileName = context.getCommandLine().getOptionValue(LICENSES_APPROVED_FILE.getSelected()); + File file = context.resolve(fileName); + try (InputStream in = Files.newInputStream(file.toPath())) { context.getConfiguration().addApprovedLicenseIds(IOUtils.readLines(in, StandardCharsets.UTF_8)); } - } catch (IOException | ParseException e) { + } catch (IOException e) { throw new ConfigurationException(e); } } @@ -649,11 +653,12 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (LICENSES_DENIED_FILE.isSelected()) { try { - File f = context.getCommandLine().getParsedOptionValue(LICENSES_DENIED_FILE.getSelected()); - try (InputStream in = Files.newInputStream(f.toPath())) { + String fileName = context.getCommandLine().getOptionValue(LICENSES_DENIED_FILE.getSelected()); + File file = context.resolve(fileName); + try (InputStream in = Files.newInputStream(file.toPath())) { context.getConfiguration().removeApprovedLicenseIds(IOUtils.readLines(in, StandardCharsets.UTF_8)); } - } catch (IOException | ParseException e) { + } catch (IOException e) { throw new ConfigurationException(e); } } 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 ca2ab06e7..4e0e05713 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 @@ -212,6 +212,8 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { matchers.add(fromCommandLine.build()); lastMatcher = MatcherSet.merge(matchers).createMatcher(); + DefaultLog.getInstance().debug(format("Created matcher set for %s%n%s", basedir.getName(), + lastMatcher)); } return lastMatcher; } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java index a47434627..2c51af58c 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java @@ -38,7 +38,9 @@ import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; +import org.apache.rat.utils.DefaultLog; import org.apache.rat.utils.ExtendedIterator; +import org.apache.rat.utils.Log; import static java.lang.String.format; @@ -117,7 +119,20 @@ public static Predicate commentFilter(final String commentPrefix) { * @return a FileFilter. */ public static FileFilter asFileFilter(final DocumentName parent, final DocumentNameMatcher nameMatcher) { - return file -> nameMatcher.matches(DocumentName.builder(file).setBaseName(parent.getBaseName()).build()); + return file -> { + DocumentName candidate = DocumentName.builder(file).setBaseName(parent.getBaseName()).build(); + boolean result = nameMatcher.matches(candidate); + Log log = DefaultLog.getInstance(); + if (log.isEnabled(Log.Level.DEBUG)) { + log.debug(format("FILTER TEST for %s -> %s", file, result)); + if (!result) { + List< DocumentNameMatcher.DecomposeData> data = nameMatcher.decompose(candidate); + log.debug("Decomposition for " + candidate); + data.forEach(log::debug); + } + } + return result; + }; } /** diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java index b5369c7ba..81188cc7c 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -41,6 +41,9 @@ public interface MatcherSet { Optional includes(); Optional excludes(); + default String getDescription() { + return String.format("MatcherSet: include [%s] exclude [%s]", includes().orElse(MATCHES_NONE), excludes().orElse(MATCHES_NONE)); + } /** * Creates a DocumentNameMatcher from an iterable of MatcherSets. * @return A DocumentNameMatcher that processes the matcher sets. diff --git a/apache-rat-core/src/main/java/org/apache/rat/configuration/XMLConfigurationReader.java b/apache-rat-core/src/main/java/org/apache/rat/configuration/XMLConfigurationReader.java index 0bf2dda8d..bab5d7f1a 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/configuration/XMLConfigurationReader.java +++ b/apache-rat-core/src/main/java/org/apache/rat/configuration/XMLConfigurationReader.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; @@ -126,6 +127,21 @@ public SortedSet licenseFamilies() { }; } + /** + * Creates textual representation of a node for display. + * @param node the node to create the textual representation of. + * @return The textual representation of the node for display. + */ + private String nodeText(final Node node) { + StringWriter stringWriter = new StringWriter().append("<").append(node.getNodeName()); + NamedNodeMap attr = node.getAttributes(); + for (int i = 0; i < attr.getLength(); i++) { + Node n = attr.item(i); + stringWriter.append(String.format(" %s='%s'", n.getNodeName(), n.getNodeValue())); + } + return stringWriter.append(">").toString(); + } + @Override public void addLicenses(final URI uri) { read(uri); @@ -327,22 +343,27 @@ private void setValue(final Description description, final Description childDesc */ private Pair> processChildNodes(final Description description, final Node parent, final BiPredicate childProcessor) { - boolean foundChildren = false; - List children = new ArrayList<>(); - // check XML child nodes. - if (parent.hasChildNodes()) { - - nodeListConsumer(parent.getChildNodes(), n -> { - if (n.getNodeType() == Node.ELEMENT_NODE) { - children.add(n); + try { + boolean foundChildren = false; + List children = new ArrayList<>(); + // check XML child nodes. + if (parent.hasChildNodes()) { + + nodeListConsumer(parent.getChildNodes(), n -> { + if (n.getNodeType() == Node.ELEMENT_NODE) { + children.add(n); + } + }); + foundChildren = !children.isEmpty(); + if (foundChildren) { + processChildren(description, children, childProcessor); } - }); - foundChildren = !children.isEmpty(); - if (foundChildren) { - processChildren(description, children, childProcessor); } + return new ImmutablePair<>(foundChildren, children); + } catch (RuntimeException exception) { + DefaultLog.getInstance().error(String.format("Child node extraction error in: '%s'", nodeText(parent))); + throw exception; } - return new ImmutablePair<>(foundChildren, children); } /** @@ -408,6 +429,7 @@ private AbstractBuilder parseMatcher(final Node matcherNode) { } } catch (DOMException e) { + DefaultLog.getInstance().error(String.format("Matcher error in: '%s'", nodeText(matcherNode))); throw new ConfigurationException(e); } return builder.hasId() ? new IDRecordingBuilder(matchers, builder) : builder; @@ -445,34 +467,39 @@ private BiPredicate licenseChildNodeProcessor(final ILicense. * @return the License definition. */ private ILicense parseLicense(final Node licenseNode) { - ILicense.Builder builder = ILicense.builder(); - // get the description for the builder - Description description = builder.getDescription(); - // set the BUILDER_PARAM options from the description - processBuilderParams(description, builder); - // set the children from attributes. - description.setChildren(builder, attributes(licenseNode)); - // set children from the child nodes - Pair> pair = processChildNodes(description, licenseNode, - licenseChildNodeProcessor(builder, description)); - List children = pair.getRight(); - - // check for inline nodes that can accept child nodes. - List childDescriptions = description.getChildren().values().stream() - .filter(d -> XMLConfig.isLicenseInline(d.getCommonName())).collect(Collectors.toList()); - for (Description childDescription : childDescriptions) { - Iterator iter = children.iterator(); - while (iter.hasNext()) { - callSetter(childDescription, builder, parseMatcher(iter.next())); - iter.remove(); + try { + ILicense.Builder builder = ILicense.builder(); + // get the description for the builder + Description description = builder.getDescription(); + // set the BUILDER_PARAM options from the description + processBuilderParams(description, builder); + // set the children from attributes. + description.setChildren(builder, attributes(licenseNode)); + // set children from the child nodes + Pair> pair = processChildNodes(description, licenseNode, + licenseChildNodeProcessor(builder, description)); + List children = pair.getRight(); + + // check for inline nodes that can accept child nodes. + List childDescriptions = description.getChildren().values().stream() + .filter(d -> XMLConfig.isLicenseInline(d.getCommonName())).collect(Collectors.toList()); + for (Description childDescription : childDescriptions) { + Iterator iter = children.iterator(); + while (iter.hasNext()) { + callSetter(childDescription, builder, parseMatcher(iter.next())); + iter.remove(); + } } - } - if (!children.isEmpty()) { - children.forEach(n -> DefaultLog.getInstance().warn(String.format("unrecognised child node '%s' in node '%s'%n", - n.getNodeName(), licenseNode.getNodeName()))); + if (!children.isEmpty()) { + children.forEach(n -> DefaultLog.getInstance().warn(String.format("unrecognised child node '%s' in node '%s'%n", + n.getNodeName(), licenseNode.getNodeName()))); + } + return builder.build(); + } catch (RuntimeException exception) { + DefaultLog.getInstance().error(String.format("License error in: '%s'", nodeText(licenseNode))); + throw exception; } - return builder.build(); } @Override @@ -519,12 +546,17 @@ private ILicenseFamily parseFamily(final Map attributes) { */ private void parseFamily(final Node familyNode) { if (XMLConfig.FAMILY.equals(familyNode.getNodeName())) { - ILicenseFamily result = parseFamily(attributes(familyNode)); - if (result == null) { - throw new ConfigurationException( - String.format("families/family tag requires %s attribute", XMLConfig.ATT_ID)); + try { + ILicenseFamily result = parseFamily(attributes(familyNode)); + if (result == null) { + throw new ConfigurationException( + String.format("families/family tag requires %s attribute", XMLConfig.ATT_ID)); + } + licenseFamilies.add(result); + } catch (RuntimeException exception) { + DefaultLog.getInstance().error(String.format("Family error in: '%s'", nodeText(familyNode))); + throw exception; } - licenseFamilies.add(result); } } @@ -535,21 +567,26 @@ private void parseFamily(final Node familyNode) { */ private void parseApproved(final Node approvedNode) { if (XMLConfig.FAMILY.equals(approvedNode.getNodeName())) { - Map attributes = attributes(approvedNode); - if (attributes.containsKey(XMLConfig.ATT_LICENSE_REF)) { - approvedFamilies.add(attributes.get(XMLConfig.ATT_LICENSE_REF)); - } else if (attributes.containsKey(XMLConfig.ATT_ID)) { - ILicenseFamily target = parseFamily(attributes); - if (target != null) { - licenseFamilies.add(target); - String familyCategory = target.getFamilyCategory(); - if (StringUtils.isNotBlank(familyCategory)) { - approvedFamilies.add(familyCategory); + try { + Map attributes = attributes(approvedNode); + if (attributes.containsKey(XMLConfig.ATT_LICENSE_REF)) { + approvedFamilies.add(attributes.get(XMLConfig.ATT_LICENSE_REF)); + } else if (attributes.containsKey(XMLConfig.ATT_ID)) { + ILicenseFamily target = parseFamily(attributes); + if (target != null) { + licenseFamilies.add(target); + String familyCategory = target.getFamilyCategory(); + if (StringUtils.isNotBlank(familyCategory)) { + approvedFamilies.add(familyCategory); + } } + } else { + throw new ConfigurationException(String.format("family tag requires %s or %s attribute", + XMLConfig.ATT_LICENSE_REF, XMLConfig.ATT_ID)); } - } else { - throw new ConfigurationException(String.format("family tag requires %s or %s attribute", - XMLConfig.ATT_LICENSE_REF, XMLConfig.ATT_ID)); + } catch (RuntimeException exception) { + DefaultLog.getInstance().error(String.format("Approved error in: '%s'", nodeText(approvedNode))); + throw exception; } } } @@ -569,11 +606,16 @@ public SortedSet approvedLicenseId() { } private void parseMatcherBuilder(final Node classNode) { - Map attributes = attributes(classNode); - if (attributes.get(XMLConfig.ATT_CLASS_NAME) == null) { - throw new ConfigurationException("matcher must have a " + XMLConfig.ATT_CLASS_NAME + " attribute"); + try { + Map attributes = attributes(classNode); + if (attributes.get(XMLConfig.ATT_CLASS_NAME) == null) { + throw new ConfigurationException("matcher must have a " + XMLConfig.ATT_CLASS_NAME + " attribute"); + } + MatcherBuilderTracker.addBuilder(attributes.get(XMLConfig.ATT_CLASS_NAME), attributes.get(XMLConfig.ATT_NAME)); + } catch (RuntimeException exception) { + DefaultLog.getInstance().error(String.format("Matcher error in: '%s'", nodeText(classNode))); + throw exception; } - MatcherBuilderTracker.addBuilder(attributes.get(XMLConfig.ATT_CLASS_NAME), attributes.get(XMLConfig.ATT_NAME)); } @Override diff --git a/apache-rat-core/src/main/java/org/apache/rat/report/xml/writer/XmlWriter.java b/apache-rat-core/src/main/java/org/apache/rat/report/xml/writer/XmlWriter.java index 53a0dfb61..128f32f6f 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/report/xml/writer/XmlWriter.java +++ b/apache-rat-core/src/main/java/org/apache/rat/report/xml/writer/XmlWriter.java @@ -482,7 +482,7 @@ public IXmlWriter comment(final CharSequence text) throws IOException { /** * Writes an attribute of an element. Note that this is only allowed directly - * after {@link #openElement(CharSequence)} or {@link #attribute}. + * after {@link #openElement(CharSequence)} or a previous {@code attribute} call. * * @param name the attribute name, not null * @param value the attribute value, not null @@ -717,7 +717,7 @@ private boolean isValidNameBody(final char character) { } @Override - public void close() throws Exception { + public void close() throws IOException { closeDocument(); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/utils/Log.java b/apache-rat-core/src/main/java/org/apache/rat/utils/Log.java index d12db3e6c..9a9461c7f 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/utils/Log.java +++ b/apache-rat-core/src/main/java/org/apache/rat/utils/Log.java @@ -184,6 +184,15 @@ default void error(Object message, Throwable throwable) { * @return the Writer backed by this log. */ default Writer asWriter() { + return asWriter(Level.INFO); + } + + /** + * Returns a Writer backed by this log. All messages are logged at "INFO" level. + * @return the Writer backed by this log. + * @param level the Log level to write at. + */ + default Writer asWriter(Level level) { return new Writer() { private StringBuilder sb = new StringBuilder(); @@ -195,7 +204,7 @@ public void write(final char[] cbuf, final int off, final int len) { sb.append(txt); } else { while (pos > -1) { - Log.this.info(sb.append(txt, 0, pos).toString()); + Log.this.log(level, sb.append(txt, 0, pos).toString()); sb.delete(0, sb.length()); txt = txt.substring(pos + 1); pos = txt.indexOf(System.lineSeparator()); @@ -207,7 +216,7 @@ public void write(final char[] cbuf, final int off, final int len) { @Override public void flush() { if (sb.length() > 0) { - Log.this.info(sb.toString()); + Log.this.log(level, sb.toString()); } sb = new StringBuilder(); } @@ -218,4 +227,5 @@ public void close() throws IOException { } }; } + } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java index 5527e5623..f372f129f 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java @@ -20,16 +20,11 @@ import java.io.File; import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; import java.util.Optional; -import java.util.function.Consumer; -import java.util.function.Predicate; import java.util.stream.Stream; import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; -import org.apache.rat.document.DocumentNameMatcherTest; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -129,7 +124,7 @@ public void test_RAT_335() { DocumentName candidate = DocumentName.builder() .setName("/home/claude/apache/creadur-rat/apache-rat-core/target/test-classes/GitIgnoreBuilderTest/src/dir1/file1.log") .setBaseName("home/claude/apache/creadur-rat/apache-rat-core/target/test-classes/GitIgnoreBuilderTest/src/").build(); - DocumentNameMatcherTest.decompose(matcher, candidate); + System.out.println("Decomposition for "+candidate); assertThat(matcher.toString()).isEqualTo("matcherSet(or('included dir1/.gitignore', 'included .gitignore'), or('excluded dir1/.gitignore', **/.gitignore, 'excluded .gitignore'))"); 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 717e0d13b..1c661286b 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 @@ -32,7 +32,6 @@ import org.apache.rat.commandline.StyleSheets; import org.apache.rat.config.exclusion.StandardCollection; import org.apache.rat.document.DocumentNameMatcher; -import org.apache.rat.document.DocumentNameMatcherTest; import org.apache.rat.document.DocumentName; import org.apache.rat.license.ILicense; import org.apache.rat.license.ILicenseFamily; @@ -119,7 +118,7 @@ protected DocumentName baseName() { * @param baseDir the directory to copy the /src/test/resources to. * @return the {@code baseDir} argument. */ - public static File setup(File baseDir) { + public static File setup(final File baseDir) { try { final File sourceDir = Resources.getResourceDirectory("OptionTools"); FileUtils.copyDirectory(sourceDir, new File(baseDir,"/src/test/resources/OptionTools")); @@ -244,7 +243,7 @@ protected DocumentName mkDocName(String name) { return DocumentName.builder(new File(baseDir, name)).build(); } - /* Tests to be implemented */ + /* Help test */ protected abstract void helpTest(); /** Display the option and value under test */ diff --git a/apache-rat-plugin/.gitignore b/apache-rat-plugin/.gitignore index d302b51b5..47d015ffc 100644 --- a/apache-rat-plugin/.gitignore +++ b/apache-rat-plugin/.gitignore @@ -1,3 +1,4 @@ /target/ +/invoker_target/ /src/site/apt/argument_types.txt /invoker_target/ diff --git a/apache-rat-plugin/pom.xml b/apache-rat-plugin/pom.xml index cabee5ccf..9bd8a2962 100644 --- a/apache-rat-plugin/pom.xml +++ b/apache-rat-plugin/pom.xml @@ -99,6 +99,7 @@ src/it/CustomLicense/src/**/ **/.bzrignore + invoker_target/** src/test/resources/XmlOutputExamples/**/*
    @@ -246,7 +247,7 @@ org.apache.maven.plugins maven-invoker-plugin - ${project.build.directory}/invoker + ${project.basedir}/invoker_target ${project.build.directory}/local-repo true src/it/settings.xml @@ -262,6 +263,17 @@ + + maven-clean-plugin + + + + invoker_target + false + + + + org.apache.maven.plugins maven-checkstyle-plugin diff --git a/apache-rat-plugin/src/it/CustomLicense/.rat/customConfig.xml b/apache-rat-plugin/src/it/CustomLicense/.rat/customConfig.xml new file mode 100644 index 000000000..9f0ab7fb9 --- /dev/null +++ b/apache-rat-plugin/src/it/CustomLicense/.rat/customConfig.xml @@ -0,0 +1,17 @@ + + + + " + + + + + Attribution-NonCommercial-NoDerivatives + + + + + + + diff --git a/apache-rat-plugin/src/it/CustomLicense/invoker.properties b/apache-rat-plugin/src/it/CustomLicense/invoker.properties index 6e8c3479e..123118983 100644 --- a/apache-rat-plugin/src/it/CustomLicense/invoker.properties +++ b/apache-rat-plugin/src/it/CustomLicense/invoker.properties @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -invoker.goals = clean apache-rat:check +invoker.goals = -X clean apache-rat:check diff --git a/apache-rat-plugin/src/it/CustomLicense/pom.xml b/apache-rat-plugin/src/it/CustomLicense/pom.xml index 4a03c4872..474872128 100644 --- a/apache-rat-plugin/src/it/CustomLicense/pom.xml +++ b/apache-rat-plugin/src/it/CustomLicense/pom.xml @@ -27,31 +27,13 @@ apache-rat-plugin @pom.version@ - false - - - CC - Creative Commons - - - - - CC - CC-BY-NC-ND - - Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International - - Attribution-NonCommercial-NoDerivatives - - - - - CC - - + xml + .rat/customConfig.xml + + .rat/** pom.xml invoker.properties - + diff --git a/apache-rat-plugin/src/it/RAT-268/pom.xml b/apache-rat-plugin/src/it/RAT-268/pom.xml index 2084bef08..9a42f6d02 100644 --- a/apache-rat-plugin/src/it/RAT-268/pom.xml +++ b/apache-rat-plugin/src/it/RAT-268/pom.xml @@ -33,12 +33,12 @@ apache-rat-plugin @pom.version@ - - STANDARDS:0 - - + + STANDARDS:0 + + **/src.apt - + diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java index a96ab49ee..5f5eceb67 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java @@ -19,7 +19,6 @@ package org.apache.rat.mp; import org.apache.commons.cli.Option; -import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.maven.plugin.MojoExecutionException; diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java index dd2e7fcfe..1e8c6c1e4 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java @@ -24,7 +24,6 @@ import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -64,7 +63,7 @@ public class RatCheckMojoTest { //extends BetterAbstractMojoTestCase { @TempDir static Path tempDir; - private static XPath xPath = XPathFactory.newInstance().newXPath(); + private final static XPath xPath = XPathFactory.newInstance().newXPath(); @AfterAll static void preserveData() { @@ -95,11 +94,10 @@ private RatCheckMojo getMojo(File pomFile) throws IOException { */ private RatCheckMojo newRatMojo(String testDir) throws Exception { Arg.reset(); - final File pomFile = Resources.getResourceFile(format("unit/%s/pom.xml", testDir)); - final File sourceDir = pomFile.getParentFile(); + final File sourceDir = Resources.getResourceDirectory(format("unit/%s", testDir)); final File baseDir = tempDir.resolve(testDir).toFile(); FileUtils.copyDirectory(sourceDir, baseDir); - + final File pomFile = new File(baseDir, "pom.xml"); RatCheckMojo mojo = getMojo(pomFile); assertThat(mojo).isNotNull(); assertThat(mojo.getProject()) @@ -107,18 +105,13 @@ private RatCheckMojo newRatMojo(String testDir) throws Exception { .isNotNull(); File buildDirectory = new File(baseDir, "target"); - buildDirectory.mkdirs(); + assertThat(buildDirectory.mkdirs()).isTrue(); final File ratTxtFile = new File(buildDirectory, "rat.txt"); FileUtils.write(ratTxtFile, "", UTF_8); // Ensure the output file exists and is empty (rerunning the test will append) mojo.setOutputFile(ratTxtFile.getAbsolutePath()); - return mojo; } - private String getDir(RatCheckMojo mojo) { - return mojo.getProject().getBasedir().getAbsolutePath().replace("\\", "/") + "/"; - } - /** * Runs a check, which should expose no problems. * @@ -138,7 +131,7 @@ void it1() throws Exception { data.put(ClaimStatistic.Counter.APPROVED, "1"); data.put(ClaimStatistic.Counter.BINARIES, "0"); data.put(ClaimStatistic.Counter.DOCUMENT_TYPES, "2"); - data.put(ClaimStatistic.Counter.IGNORED, "1"); + data.put(ClaimStatistic.Counter.IGNORED, "2"); data.put(ClaimStatistic.Counter.LICENSE_CATEGORIES, "1"); data.put(ClaimStatistic.Counter.LICENSE_NAMES, "1"); data.put(ClaimStatistic.Counter.NOTICES, "0"); @@ -186,7 +179,7 @@ void it2() throws Exception { ReporterTestUtils.counterText(ClaimStatistic.Counter.BINARIES, 0, false), ReporterTestUtils.counterText(ClaimStatistic.Counter.ARCHIVES, 0, false), ReporterTestUtils.counterText(ClaimStatistic.Counter.STANDARDS, 2, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.IGNORED, 0, false), + ReporterTestUtils.counterText(ClaimStatistic.Counter.IGNORED, 1, false), ReporterTestUtils.apacheLicenseVersion2(1), ReporterTestUtils.unknownLicense(1), ReporterTestUtils.documentOut(false, Document.Type.STANDARD, "/src.txt") + @@ -214,20 +207,6 @@ void it2() throws Exception { void it3() throws Exception { final RatCheckMojo mojo = newRatMojo("it3"); final File ratTxtFile = mojo.getRatTxtFile(); - final String[] expected = { - "^Files with unapproved licenses\\s+\\*+\\s+\\Q/src.apt\\E\\s+", - ReporterTestUtils.counterText(ClaimStatistic.Counter.NOTICES, 0, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.BINARIES, 0, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.ARCHIVES, 0, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.STANDARDS, 2, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.IGNORED, 0, false), - ReporterTestUtils.apacheLicenseVersion2(1), - ReporterTestUtils.unknownLicense(1), - ReporterTestUtils.documentOut(false, Document.Type.STANDARD, "/src.apt") + - ReporterTestUtils.UNKNOWN_LICENSE, - ReporterTestUtils.documentOut(true, Document.Type.STANDARD, "/pom.xml") + - ReporterTestUtils.APACHE_LICENSE - }; ReportConfiguration config = mojo.getConfiguration(); assertThat(config.isAddingLicenses()).as("should be adding licenses").isTrue(); @@ -251,6 +230,9 @@ void it3() throws Exception { if (type == Document.Type.STANDARD) { XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='STANDARD']", "count", "3"); + } else if (type == Document.Type.IGNORED) { + XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='IGNORED']", "count", + "1"); } else { XmlUtils.assertIsNotPresent(document, xPath, format("/rat-report/statistics/documentType[@name='%s']", type)); } @@ -269,31 +251,35 @@ void it5() throws Exception { assertThat(config.isAddingLicenses()).as("Should not be adding licenses").isFalse(); assertThat(config.isAddingLicensesForced()).as("Should not be forcing licenses").isFalse(); - ReportConfigurationTest.validateDefaultApprovedLicenses(config); - assertThat(config.getLicenseCategories(LicenseFilter.APPROVED)).doesNotContain(ILicenseFamily.makeCategory("YAL")); - ReportConfigurationTest.validateDefaultLicenseFamilies(config, "YAL"); + ReportConfigurationTest.validateDefaultApprovedLicenses(config, 1); + assertThat(config.getLicenseCategories(LicenseFilter.APPROVED)).doesNotContain(ILicenseFamily.makeCategory("YAL")) + .contains(ILicenseFamily.makeCategory("CC")); + ReportConfigurationTest.validateDefaultLicenseFamilies(config, "YAL", "CC"); + assertThat(LicenseSetFactory.familySearch("YAL", config.getLicenseFamilies(LicenseFilter.APPROVED))).isNull(); assertThat(LicenseSetFactory.familySearch("YAL", config.getLicenseFamilies(LicenseFilter.ALL))).isNotNull(); - ReportConfigurationTest.validateDefaultLicenses(config, "MyLicense", "CpyrT", "RegxT", "SpdxT", "TextT", - "Not", "All", "Any"); - assertThat(LicenseSetFactory.search("YAL", "MyLicense", config.getLicenses(LicenseFilter.ALL))).isPresent(); - try { + assertThat(LicenseSetFactory.familySearch("CC", config.getLicenseFamilies(LicenseFilter.APPROVED))).isNotNull(); + assertThat(LicenseSetFactory.familySearch("CC", config.getLicenseFamilies(LicenseFilter.ALL))).isNotNull(); + + ReportConfigurationTest.validateDefaultLicenses(config, "CC-BY-NC-ND", "YAL"); + assertThat(LicenseSetFactory.search("YAL", "YAL", config.getLicenses(LicenseFilter.ALL))).isPresent(); + //try { mojo.execute(); - fail("Should have thrown exception"); - } catch (RatCheckException e) { - assertThat(e.getMessage()).contains("UNAPPROVED"); - } + // fail("Should have thrown exception"); +// } catch (RatCheckException e) { +// assertThat(e.getMessage()).contains("LICENSE_CATEGORIES, LICENSE_NAMES, STANDARDS exceeded"); +// } Map data = new HashMap<>(); - data.put(ClaimStatistic.Counter.APPROVED, "0"); + data.put(ClaimStatistic.Counter.APPROVED, "1"); data.put(ClaimStatistic.Counter.ARCHIVES, "0"); data.put(ClaimStatistic.Counter.BINARIES, "0"); data.put(ClaimStatistic.Counter.DOCUMENT_TYPES, "2"); - data.put(ClaimStatistic.Counter.IGNORED, "1"); + data.put(ClaimStatistic.Counter.IGNORED, "3"); data.put(ClaimStatistic.Counter.LICENSE_CATEGORIES, "1"); - data.put(ClaimStatistic.Counter.LICENSE_NAMES, "4"); + data.put(ClaimStatistic.Counter.LICENSE_NAMES, "1"); data.put(ClaimStatistic.Counter.NOTICES, "0"); data.put(ClaimStatistic.Counter.STANDARDS, "1"); - data.put(ClaimStatistic.Counter.UNAPPROVED, "4"); + data.put(ClaimStatistic.Counter.UNAPPROVED, "0"); data.put(ClaimStatistic.Counter.UNKNOWN, "0"); org.w3c.dom.Document document = XmlUtils.toDom(Files.newInputStream(ratTxtFile.toPath())); @@ -302,26 +288,21 @@ void it5() throws Exception { for (ClaimStatistic.Counter counter : ClaimStatistic.Counter.values()) { String xpath = String.format("/rat-report/statistics/statistic[@name='%s']", counter.displayName()); Map map = mapOf("approval", - counter == ClaimStatistic.Counter.UNAPPROVED ? "false" : "true", + "true", "count", data.get(counter), "description", counter.getDescription()); XmlUtils.assertAttributes(document, xPath, xpath, map); } - XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/.bzrignore']", - mapOf("mediaType", "application/octet-stream", "type", "IGNORED")); - + XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/.rat']", + "mediaType", "application/octet-stream", "type", "IGNORED", "isDirectory", "true"); XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/pom.xml']", - mapOf("mediaType", "application/xml", "type", "STANDARD", "encoding", "ISO-8859-1")); - - XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/pom.xml']/license[@id='Any']", - mapOf("approval", "false", "family", "YAL ", "name", "Any testing")); - XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/pom.xml']/license[@id='MyLicense']", - mapOf("approval", "false", "family", "YAL ", "name", "Yet another license")); - XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/pom.xml']/license[@id='RegxT']", - mapOf("approval", "false", "family", "YAL ", "name", "Regex with tag")); - XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/pom.xml']/license[@id='TextT']", - mapOf("approval", "false", "family", "YAL ", "name", "Text with tag")); + "mediaType", "application/xml", "type", "IGNORED", "isDirectory", "false"); + XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/src/main/java/nl/basjes/something/Something.java']", + "mediaType", "text/x-java-source", "type", "STANDARD", "encoding", "ISO-8859-1"); + XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/src/main/java/nl/basjes/something/Something.java']/license", + "approval", "true", "family", ILicenseFamily.makeCategory("CC"), "id", "CC-BY-NC-ND", "name", + "Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International"); } /** @@ -343,7 +324,7 @@ void rat343() throws Exception { ReporterTestUtils.counterText(ClaimStatistic.Counter.BINARIES, 0, false), ReporterTestUtils.counterText(ClaimStatistic.Counter.ARCHIVES, 0, false), ReporterTestUtils.counterText(ClaimStatistic.Counter.STANDARDS, 1, false), - ReporterTestUtils.counterText(ClaimStatistic.Counter.IGNORED, 0, false), + ReporterTestUtils.counterText(ClaimStatistic.Counter.IGNORED, 1, false), ReporterTestUtils.apacheLicenseVersion2(1), "^BSD: 1 ", "^Creative Commons Attribution: 1 ", @@ -471,7 +452,7 @@ void rat362() throws Exception { org.w3c.dom.Document document = XmlUtils.toDom(Files.newInputStream(ratTxtFile.toPath())); // Document types XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='IGNORED']", - "count", "2"); + "count", "3"); XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/bar.md']", "type", "STANDARD"); diff --git a/apache-rat-plugin/src/test/resources/unit/it5/.rat/customConfig.xml b/apache-rat-plugin/src/test/resources/unit/it5/.rat/customConfig.xml new file mode 100644 index 000000000..6eea4db67 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/it5/.rat/customConfig.xml @@ -0,0 +1,23 @@ + + + + " + " + + + + Attribution-NonCommercial-NoDerivatives + + + + Yet another license + + + + + + + + diff --git a/apache-rat-plugin/src/test/resources/unit/it5/pom.xml b/apache-rat-plugin/src/test/resources/unit/it5/pom.xml new file mode 100644 index 000000000..474872128 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/it5/pom.xml @@ -0,0 +1,41 @@ + + + + 4.0.0 + org.apache.rat.test + custom-license + 1.0 + + + + org.apache.rat + apache-rat-plugin + @pom.version@ + + xml + .rat/customConfig.xml + + .rat/** + pom.xml + invoker.properties + + + + + + diff --git a/apache-rat-plugin/src/test/resources/unit/it5/src/main/java/nl/basjes/something/Something.java b/apache-rat-plugin/src/test/resources/unit/it5/src/main/java/nl/basjes/something/Something.java new file mode 100644 index 000000000..4a7f38d95 --- /dev/null +++ b/apache-rat-plugin/src/test/resources/unit/it5/src/main/java/nl/basjes/something/Something.java @@ -0,0 +1,26 @@ +/* + * *********************************************************************** + * Ok, this file is really Apache _ licensed but it has a fake header + * that does not match the Apache rules to test custom license validation. + * *********************************************************************** + * + * Something toolkit + * Copyright (C) 2019-2024 Niels Basjes + * + * This work is licensed under the Creative Commons + * Attribution-NonCommercial-NoDerivatives 4.0 International License. + * + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by-nc-nd/4.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. + */ +package nl.basjes.something; + +public class Something { + private static final String something = "No real code"; +} diff --git a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java index cee3922f1..fd8721aaa 100644 --- a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java +++ b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java @@ -17,6 +17,7 @@ package org.apache.rat.anttasks; import java.nio.file.Path; +import java.util.List; import org.apache.commons.cli.Option; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; @@ -77,11 +78,11 @@ final class AntOptionsProvider extends AbstractOptionsProvider implements Argume final AtomicBoolean helpCalled = new AtomicBoolean(false); - public OptionsProvider() { - super(BaseAntTask.unsupportedArgs()); + public AntOptionsProvider() { + super(BaseAntTask.unsupportedArgs(), testPath.toFile()); } - protected ReportConfiguration generateConfig(List> args) { + protected final ReportConfiguration generateConfig(final List> args) { BuildTask task = args.get(0).getKey() == null ? new BuildTask() : new BuildTask(args.get(0).getKey()); task.setUp(args); task.buildRule.executeTarget(task.name); From 4a7a5a757e98d4f9f720d86ccb23e20a5ef69ca4 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Fri, 27 Dec 2024 00:40:54 +0000 Subject: [PATCH 081/123] fixed last tests in plugin module --- apache-rat-plugin/src/it/CustomLicense/invoker.properties | 2 +- .../src/test/java/org/apache/rat/mp/RatCheckMojoTest.java | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/apache-rat-plugin/src/it/CustomLicense/invoker.properties b/apache-rat-plugin/src/it/CustomLicense/invoker.properties index 123118983..6e8c3479e 100644 --- a/apache-rat-plugin/src/it/CustomLicense/invoker.properties +++ b/apache-rat-plugin/src/it/CustomLicense/invoker.properties @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -invoker.goals = -X clean apache-rat:check +invoker.goals = clean apache-rat:check diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java index 1e8c6c1e4..c10b10bb6 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java @@ -221,15 +221,11 @@ void it3() throws Exception { XmlUtils.assertAttributes(document, xPath, "/rat-report/resource[@name='/src.apt']", "type", "STANDARD"); - XmlUtils.assertIsPresent(document, xPath, "/rat-report/resource[@name='/src.apt.new']/license[@approval='true']"); - - XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='STANDARD']", "count", - "3"); for (Document.Type type : Document.Type.values()) { if (type == Document.Type.STANDARD) { XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='STANDARD']", "count", - "3"); + "2"); } else if (type == Document.Type.IGNORED) { XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/documentType[@name='IGNORED']", "count", "1"); From 3bd8ae9409f09a5525b7ceadc1db97c8906a9d8c Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Fri, 27 Dec 2024 00:49:26 +0000 Subject: [PATCH 082/123] fixed Ant task issues --- .../src/test/java/org/apache/rat/anttasks/ReportOptionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java index fd8721aaa..5e6dc8892 100644 --- a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java +++ b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java @@ -74,7 +74,7 @@ public void execute() { } } - final class AntOptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { + final static class AntOptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider { final AtomicBoolean helpCalled = new AtomicBoolean(false); From 1fd25506e96d50c4bb714f049fc3a24ef52ac5b5 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Fri, 27 Dec 2024 15:22:20 +0000 Subject: [PATCH 083/123] added missing files --- .../exclusion/fileProcessors/GitIgnoreBuilderTest.java | 3 --- .../src/test/resources/GitIgnoreBuilderTest/src/.gitignore | 7 +++++++ .../resources/GitIgnoreBuilderTest/src/dir1/.gitignore | 3 +++ .../test/resources/GitIgnoreBuilderTest/src/dir1/dir1.txt | 1 + .../test/resources/GitIgnoreBuilderTest/src/dir1/file1.log | 1 + .../test/resources/GitIgnoreBuilderTest/src/dir2/dir2.md | 1 + .../test/resources/GitIgnoreBuilderTest/src/dir3/dir3.log | 1 + .../src/test/resources/GitIgnoreBuilderTest/src/root.md | 1 + 8 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/.gitignore create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/.gitignore create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/dir1.txt create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/file1.log create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir2/dir2.md create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir3/dir3.log create mode 100644 apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/root.md diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java index f372f129f..b98c446e7 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java @@ -36,8 +36,6 @@ import org.junit.jupiter.params.provider.MethodSource; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.not; -import static org.assertj.core.api.Fail.fail; public class GitIgnoreBuilderTest extends AbstractIgnoreBuilderTest { @@ -69,7 +67,6 @@ public void modifyEntryTest(String source, String expected) { List matcherSets = new ArrayList<>(); Optional entry = underTest.modifyEntry(matcherSets::add, testName, source); - if (source.endsWith("/")) { assertThat(entry).isNotPresent(); assertThat(matcherSets).hasSize(1); diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/.gitignore b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/.gitignore new file mode 100644 index 000000000..8855fa805 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/.gitignore @@ -0,0 +1,7 @@ +*.md + +# This makes it ignore dir3/dir3.log and dir3/file3.log +*.log + +# This makes it "unignore" dir3/file3.log +!file*.log diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/.gitignore b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/.gitignore new file mode 100644 index 000000000..26fd5c956 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/.gitignore @@ -0,0 +1,3 @@ +*.txt +!dir1.md +file1.log \ No newline at end of file diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/dir1.txt b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/dir1.txt new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/dir1.txt @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/file1.log b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/file1.log new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir1/file1.log @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir2/dir2.md b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir2/dir2.md new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir2/dir2.md @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir3/dir3.log b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir3/dir3.log new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/dir3/dir3.log @@ -0,0 +1 @@ +File without a valid license diff --git a/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/root.md b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/root.md new file mode 100644 index 000000000..a31cbc897 --- /dev/null +++ b/apache-rat-core/src/test/resources/GitIgnoreBuilderTest/src/root.md @@ -0,0 +1 @@ +File without a valid license From 060a4a934eec378cf3b2463d06f6d680ab7d768d Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Fri, 27 Dec 2024 17:01:19 +0000 Subject: [PATCH 084/123] fixed tests on Windows --- .../apache/rat/config/exclusion/plexus/MatchPattern.java | 3 +-- .../exclusion/fileProcessors/AbstractIgnoreBuilderTest.java | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java index 9932376ff..11b71445d 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java @@ -117,8 +117,7 @@ public boolean startsWith(final String string) { @Override public String toString() { - return Arrays.asList(tokenized) - .toString(); + return Arrays.asList(tokenized).toString(); } public String source() { diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java index 44338358c..4c4f03e8d 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java @@ -19,7 +19,9 @@ package org.apache.rat.config.exclusion.fileProcessors; import java.util.List; +import org.apache.rat.config.exclusion.ExclusionUtils; import org.apache.rat.config.exclusion.MatcherSet; +import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; import org.junit.jupiter.api.AfterEach; @@ -95,11 +97,11 @@ protected void assertCorrect(AbstractFileProcessorBuilder builder, Iterable matcherSets, DocumentName baseDir, Iterable matching, Iterable notMatching) { DocumentNameMatcher excluder = MatcherSet.merge(matcherSets).createMatcher(); for (String name : matching) { - DocumentName docName = baseDir.resolve(name); + DocumentName docName = baseDir.resolve(SelectorUtils.extractPattern(name, File.separator)); assertThat(excluder.matches(docName)).as(docName.getName()).isFalse(); } for (String name : notMatching) { - DocumentName docName = baseDir.resolve(name); + DocumentName docName = baseDir.resolve(SelectorUtils.extractPattern(name, File.separator)); assertThat(excluder.matches(docName)).as(docName.getName()).isTrue(); } } From 24a397411da424a7969c8d2436486bd04c8aed9f Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Fri, 27 Dec 2024 17:12:19 +0000 Subject: [PATCH 085/123] turned on mvn debugging --- .github/workflows/maven.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index b5f7b2ddf..3167a10cd 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -62,7 +62,7 @@ jobs: cache: 'maven' - name: Build with Maven - run: ./mvnw -e -B -V -ntp clean install + run: ./mvnw -X -e -B -V -ntp clean install - name: Generate javadoc run: ./mvnw -e -B -V -ntp javadoc:javadoc From 2f57b8df52152cbf1c6cdb21ccd46d2ad6d7f804 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 28 Dec 2024 09:42:29 +0000 Subject: [PATCH 086/123] Fixed command line file name processing --- .../java/org/apache/rat/commandline/Arg.java | 23 ++++---- .../apache/rat/commandline/Converters.java | 53 ++++++++++++++++++- .../org/apache/rat/commandline/ArgTests.java | 7 +-- .../rat/test/AbstractOptionsProvider.java | 4 +- 4 files changed, 70 insertions(+), 17 deletions(-) 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 b975e4150..f916e3843 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 @@ -119,10 +119,14 @@ public enum Arg { CONFIGURATION(new OptionGroup() .addOption(Option.builder().longOpt("config").hasArgs().argName("File") .desc("File names for system configuration.") + .converter(Converters.FILE_CONVERTER) + .type(File.class) .build()) .addOption(Option.builder().longOpt("licenses").hasArgs().argName("File") .desc("File names for system configuration.") .deprecated(DeprecatedAttributes.builder().setSince("0.17").setForRemoval(true).setDescription(StdMsgs.useMsg("--config")).get()) + .converter(Converters.FILE_CONVERTER) + .type(File.class) .build())), /** @@ -186,7 +190,6 @@ public enum Arg { .hasArg().argName("File").type(File.class) .converter(Converters.FILE_CONVERTER) .desc("Name of file containing the denied license IDs.") - .converter(Converters.FILE_CONVERTER) .build())), /** @@ -234,6 +237,7 @@ public enum Arg { "File names must use linux directory separator ('/') or none at all. " + "File names that do not start with '/' are relative to the directory where the " + "argument is located.") + .converter(Converters.FILE_CONVERTER) .type(File.class) .build())), @@ -585,8 +589,8 @@ private static void processConfigurationArgs(final ArgumentContext context) thro try { Defaults.Builder defaultBuilder = Defaults.builder(); if (CONFIGURATION.isSelected()) { - for (String fn : context.getCommandLine().getOptionValues(CONFIGURATION.getSelected())) { - File file = context.resolve(fn); + File[] files = CONFIGURATION.getParsedOptionValues(context.getCommandLine()); + for (File file : files) { defaultBuilder.add(file); } } @@ -604,8 +608,7 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (FAMILIES_APPROVED_FILE.isSelected()) { try { - String fileName = context.getCommandLine().getOptionValue(FAMILIES_APPROVED_FILE.getSelected()); - File f = context.resolve(fileName); + File f = context.getCommandLine().getParsedOptionValue(FAMILIES_APPROVED_FILE.getSelected()); try (InputStream in = Files.newInputStream(f.toPath())) { context.getConfiguration().addApprovedLicenseCategories(IOUtils.readLines(in, StandardCharsets.UTF_8)); } @@ -620,8 +623,7 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (FAMILIES_DENIED_FILE.isSelected()) { try { - String fileName = context.getCommandLine().getOptionValue(FAMILIES_DENIED_FILE.getSelected()); - File f = context.resolve(fileName); + File f = context.getCommandLine().getParsedOptionValue(FAMILIES_DENIED_FILE.getSelected()); try (InputStream in = Files.newInputStream(f.toPath())) { context.getConfiguration().removeApprovedLicenseCategories(IOUtils.readLines(in, StandardCharsets.UTF_8)); } @@ -637,8 +639,7 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (LICENSES_APPROVED_FILE.isSelected()) { try { - String fileName = context.getCommandLine().getOptionValue(LICENSES_APPROVED_FILE.getSelected()); - File file = context.resolve(fileName); + File file = context.getCommandLine().getParsedOptionValue(LICENSES_APPROVED_FILE.getSelected()); try (InputStream in = Files.newInputStream(file.toPath())) { context.getConfiguration().addApprovedLicenseIds(IOUtils.readLines(in, StandardCharsets.UTF_8)); } @@ -653,8 +654,7 @@ private static void processConfigurationArgs(final ArgumentContext context) thro } if (LICENSES_DENIED_FILE.isSelected()) { try { - String fileName = context.getCommandLine().getOptionValue(LICENSES_DENIED_FILE.getSelected()); - File file = context.resolve(fileName); + File file = context.getCommandLine().getParsedOptionValue(LICENSES_DENIED_FILE.getSelected()); try (InputStream in = Files.newInputStream(file.toPath())) { context.getConfiguration().removeApprovedLicenseIds(IOUtils.readLines(in, StandardCharsets.UTF_8)); } @@ -800,6 +800,7 @@ public static void processLogLevel(final CommandLine commandLine) { * @throws ConfigurationException on error */ public static void processArgs(final ArgumentContext context) throws ConfigurationException { + Converters.FILE_CONVERTER.setWorkingDirectory(context.getWorkingDirectory()); processOutputArgs(context); processEditArgs(context); processInputArgs(context); 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 197703f93..61f27cdbe 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 @@ -19,10 +19,12 @@ package org.apache.rat.commandline; import java.io.File; +import java.io.IOException; import org.apache.commons.cli.Converter; import org.apache.commons.lang3.tuple.Pair; import org.apache.rat.ConfigurationException; +import org.apache.rat.document.DocumentName; import org.apache.rat.report.claim.ClaimStatistic; import static java.lang.String.format; @@ -39,7 +41,8 @@ private Converters() { /** * Creates a File with fully qualified name */ - public static final Converter FILE_CONVERTER = s -> new File(s).getAbsoluteFile(); + public static final FileConverter FILE_CONVERTER = new FileConverter(); + /** * converts the Converter pattern into a Converter, count pair. */ @@ -55,4 +58,52 @@ private Converters() { throw new ConfigurationException(format("'%s' is not a valid Counter", parts[0]), e); } }; + + /** + * A converter that can handle relative or absolute files. + */ + public static final class FileConverter implements Converter { + /** The working directory to resolve relative files agains */ + private DocumentName workingDirectory; + + /** + * The constructor. + */ + private FileConverter() { + // private construction only. + } + + /** + * Sets the working directory for the conversion. + * @param workingDirectory + */ + public void setWorkingDirectory(final DocumentName workingDirectory) { + this.workingDirectory = workingDirectory; + } + + /** + * Applies the conversion function to the specified file name. + * @param fileName the file name to create a file from. + * @return a File. + * @throws NullPointerException if {@code fileName} is null. + */ + public File apply(final String fileName) throws NullPointerException { + File file = new File(fileName); + // is this a relative file? + if (!fileName.startsWith(File.separator)) { + // check for a root provided (e.g. C:\\)" + DocumentName.Builder builder = DocumentName.builder(file); + final DocumentName name = builder.build(); + if (name.getRoot().isEmpty()) { + // no root, resolve against workingDirectory + file = new File(workingDirectory.resolve(fileName).getName()).getAbsoluteFile(); + } + } + try { + return file.getCanonicalFile(); + } catch (IOException e) { + return file.getAbsoluteFile(); + } + } + } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java index 7472a0a9e..484f8a632 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java +++ b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java @@ -18,6 +18,7 @@ */ package org.apache.rat.commandline; +import java.io.IOException; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.Options; @@ -30,7 +31,7 @@ import java.io.File; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; public class ArgTests { @@ -42,7 +43,7 @@ private CommandLine createCommandLine(String[] args) throws ParseException { @ParameterizedTest @ValueSource(strings = { "rat.txt", "./rat.txt", "/rat.txt", "target/rat.test" }) - public void outputFleNameNoDirectoryTest(String name) throws ParseException { + public void outputFleNameNoDirectoryTest(String name) throws ParseException, IOException { class OutputFileConfig extends ReportConfiguration { private File actual = null; @Override @@ -57,6 +58,6 @@ public void setOut(File file) { OutputFileConfig configuration = new OutputFileConfig(); ArgumentContext ctxt = new ArgumentContext(new File("."), configuration, commandLine); Arg.processArgs(ctxt); - assertEquals(expected.getAbsolutePath(), configuration.actual.getAbsolutePath()); + assertThat(configuration.actual.getAbsolutePath()).isEqualTo(expected.getCanonicalPath()); } } 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 1c661286b..8b9a5acad 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 @@ -128,7 +128,7 @@ public static File setup(final File baseDir) { return baseDir; } - protected AbstractOptionsProvider(Collection unsupportedArgs, File baseDir) { + protected AbstractOptionsProvider(final Collection unsupportedArgs, final File baseDir) { this.baseDir = setup(baseDir); testMap.put("addLicense", this::addLicenseTest); testMap.put("config", this::configTest); @@ -243,7 +243,7 @@ protected DocumentName mkDocName(String name) { return DocumentName.builder(new File(baseDir, name)).build(); } - /* Help test */ + /** Help test */ protected abstract void helpTest(); /** Display the option and value under test */ From c48936339722ca1726dad943444c6ccfb391c5c3 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 28 Dec 2024 12:11:22 +0000 Subject: [PATCH 087/123] added test failure info --- .github/workflows/maven.yml | 2 +- .../rat/test/AbstractOptionsProvider.java | 22 ++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 3167a10cd..b5f7b2ddf 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -62,7 +62,7 @@ jobs: cache: 'maven' - name: Build with Maven - run: ./mvnw -X -e -B -V -ntp clean install + run: ./mvnw -e -B -V -ntp clean install - name: Generate javadoc run: ./mvnw -e -B -V -ntp javadoc:javadoc 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 8b9a5acad..51eba706c 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 @@ -184,7 +184,7 @@ protected AbstractOptionsProvider(final Collection unsupportedArgs, fina verifyAllMethodsDefinedAndNeeded(unsupportedArgs); } - private void verifyAllMethodsDefinedAndNeeded(Collection unsupportedArgs) { + private void verifyAllMethodsDefinedAndNeeded(final Collection unsupportedArgs) { // verify all options have functions. final List argNames = new ArrayList<>(); Arg.getOptions().getOptions().forEach(o -> { @@ -214,7 +214,7 @@ private void verifyAllMethodsDefinedAndNeeded(Collection unsupportedArgs } @SafeVarargs - protected final ReportConfiguration generateConfig(Pair... args) throws IOException { + protected final ReportConfiguration generateConfig(final Pair... args) throws IOException { List> options = Arrays.asList(args); return generateConfig(options); } @@ -227,9 +227,9 @@ protected final ReportConfiguration generateConfig(Pair... arg * @return The generated ReportConfiguration. * @throws IOException on error. */ - protected abstract ReportConfiguration generateConfig(List> args) throws IOException; + protected abstract ReportConfiguration generateConfig(final List> args) throws IOException; - protected File writeFile(String name, Iterable lines) { + protected File writeFile(final String name, final Iterable lines) { File file = new File(baseDir, name); try (PrintWriter writer = new PrintWriter(new FileWriter(file))) { lines.forEach(writer::println); @@ -239,7 +239,7 @@ protected File writeFile(String name, Iterable lines) { return file; } - protected DocumentName mkDocName(String name) { + protected DocumentName mkDocName(final String name) { return DocumentName.builder(new File(baseDir, name)).build(); } @@ -247,17 +247,23 @@ protected DocumentName mkDocName(String name) { protected abstract void helpTest(); /** Display the option and value under test */ - private String displayArgAndName(Option option, String fname) { + private String displayArgAndName(final Option option, final String fname) { return String.format("%s %s", option.getLongOpt(), fname); } - private String dump(Option option, String fname, DocumentNameMatcher matcher, DocumentName name) { + private String dump(final DocumentNameMatcher nameMatcher, final DocumentName name) { + StringBuilder sb = new StringBuilder(); + nameMatcher.decompose(name).forEach(s -> sb.append(s).append("\n")); + return sb.toString(); + } + + private String dump(final Option option, final String fname, final DocumentNameMatcher matcher, final DocumentName name) { return String.format("Argument and Name: %s%nMatcher decomposition:%n%s", displayArgAndName(option, fname), DocumentNameMatcherTest.processDecompose(matcher, name)); } // exclude tests - private void execExcludeTest(Option option, String[] args) { + private void execExcludeTest(final Option option, final String[] args) { String[] notExcluded = {"notbaz", "well._afile"}; String[] excluded = {"some.foo", "B.bar", "justbaz"}; try { From eeecd8d856a7274a21b4bb09e0fcb24a4b5e9b2d Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 28 Dec 2024 13:15:32 +0000 Subject: [PATCH 088/123] Added more info to decompose messages --- .../java/org/apache/rat/document/DocumentNameMatcher.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index e05b505f7..cc4741fc6 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -84,9 +84,7 @@ public DocumentNameMatcher(final String name, final DocumentNameMatcher delegate * @param basedir the base directory for the scanning. */ public DocumentNameMatcher(final String name, final MatchPatterns patterns, final DocumentName basedir) { - this(name, (Predicate) documentName -> patterns.matches(documentName.getName(), - tokenize(documentName.getName(), basedir.getDirectorySeparator()), - basedir.isCaseSensitive())); + this(name, new MatchPatternsPredicate(basedir, patterns)); } /** From f6c69924136422c187492f87e9371e7a2a4e4345 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Wed, 1 Jan 2025 15:12:26 +0000 Subject: [PATCH 089/123] updated some tests --- .../config/exclusion/ExclusionProcessor.java | 16 +- .../rat/config/exclusion/ExclusionUtils.java | 16 +- .../rat/config/exclusion/MatcherSet.java | 4 +- .../config/exclusion/StandardCollection.java | 30 +- .../AbstractFileProcessorBuilder.java | 32 +- .../fileProcessors/CVSIgnoreBuilder.java | 2 +- .../fileProcessors/HgIgnoreBuilder.java | 4 +- .../exclusion/plexus/MatchPatterns.java | 2 +- .../org/apache/rat/document/DocumentName.java | 41 ++- .../exclusion/ExclusionProcessorTest.java | 161 ++++++--- .../config/exclusion/FileProcessorTest.java | 43 ++- .../rat/document/DocumentNameBuilderTest.java | 322 ++++++++++++++++++ .../apache/rat/document/DocumentNameTest.java | 1 + .../rat/document/guesser/NoteGuesserTest.java | 29 +- 14 files changed, 587 insertions(+), 116 deletions(-) create mode 100644 apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java 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 4e0e05713..5bdeaa283 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 @@ -204,7 +204,7 @@ public DocumentNameMatcher getNameMatcher(final DocumentName basedir) { // add the file processors final List matchers = extractFileProcessors(basedir); final MatcherSet.Builder fromCommandLine = new MatcherSet.Builder(); - DocumentName.Builder nameBuilder = DocumentName.builder().setBaseName(basedir); + DocumentName.Builder nameBuilder = DocumentName.builder(basedir).setBaseName(basedir); extractPatterns(nameBuilder, fromCommandLine); extractCollectionPatterns(nameBuilder, fromCommandLine); extractCollectionMatchers(fromCommandLine); @@ -236,6 +236,10 @@ private List extractFileProcessors(final DocumentName basedir) { return fileProcessorList; } + private String preparePattern(DocumentName documentName, String pattern) { + return ExclusionUtils.localizePattern(documentName, + ExclusionUtils.convertSeparator(pattern, "/", documentName.getDirectorySeparator())); + } /** * Extracts {@link #includedPatterns} and {@link #excludedPatterns} into the specified matcherBuilder. * @param nameBuilder The name builder for the pattern. File names are resolved against the generated name. @@ -245,11 +249,12 @@ private void extractPatterns(final DocumentName.Builder nameBuilder, final Match DocumentName name = nameBuilder.setName("Patterns").build(); if (!excludedPatterns.isEmpty()) { matcherBuilder.addExcluded(name, excludedPatterns.stream() - .map(s -> ExclusionUtils.localizePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); + .map(s -> preparePattern(name, s)) + .collect(Collectors.toSet())); } if (!includedPatterns.isEmpty()) { matcherBuilder.addIncluded(name, includedPatterns.stream() - .map(s -> ExclusionUtils.localizePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); + .map(s -> preparePattern(name, s)).collect(Collectors.toSet())); } } @@ -279,9 +284,8 @@ private void extractCollectionPatterns(final DocumentName.Builder nameBuilder, f } DocumentName name = nameBuilder.setName("Collections").build(); matcherBuilder - .addExcluded(name, excl) - .addIncluded(name, incl); - + .addExcluded(name, excl.stream().map(s -> preparePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())) + .addIncluded(name, incl.stream().map(s -> preparePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet())); } /** diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java index 2c51af58c..e712bcac3 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java @@ -192,12 +192,20 @@ protected boolean isValidLine(final String line) { /** * Returns {@code true} if the file name represents a hidden file. - * @param f the file to check. + * @param file the file to check. * @return {@code true} if it is the name of a hidden file. */ - public static boolean isHidden(final File f) { - String s = f.getName(); - return s.startsWith(".") && !(s.equals(".") || s.equals("..")); + public static boolean isHidden(final File file) { + return isHidden(file.getName()); + } + + /** + * Returns {@code true} if the filename represents a hidden file + * @param fileName the file to check. + * @return true if it is the name of a hidden file. + */ + public static boolean isHidden(final String fileName) { + return fileName.startsWith(".") && !(fileName.equals(".") || fileName.equals("..")); } private static void verifyFile(final File file) { diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java index 81188cc7c..da6ed194e 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -102,7 +102,7 @@ public Builder() { public Builder addIncluded(final DocumentName fromDocument, final Set names) { if (!names.isEmpty()) { String name = String.format("'included %s'", fromDocument.localized("/").substring(1)); - addIncluded(new DocumentNameMatcher(name, MatchPatterns.from(names), fromDocument.getBaseDocumentName())); + addIncluded(new DocumentNameMatcher(name, MatchPatterns.from("/", names), fromDocument.getBaseDocumentName())); } return this; } @@ -117,7 +117,7 @@ public Builder addIncluded(final DocumentName fromDocument, final Set na public Builder addExcluded(final DocumentName fromDocument, final Set names) { if (!names.isEmpty()) { String name = String.format("'excluded %s'", fromDocument.localized("/").substring(1)); - addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(names), fromDocument.getBaseDocumentName())); + addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(fromDocument.getDirectorySeparator(), names), fromDocument.getBaseDocumentName())); } return this; } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java index 46fe649e0..5921ecaa7 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java @@ -101,20 +101,34 @@ null, new CVSIgnoreBuilder()), */ HIDDEN_DIR("The hidden directories. Directories with names that start with '.'", null, - new DocumentNameMatcher("HIDDEN_DIR", (Predicate) documentName -> { - File f = new File(documentName.getName()); - return f.isDirectory() && ExclusionUtils.isHidden(f); - }), null + new DocumentNameMatcher("HIDDEN_DIR", new Predicate() { + @Override + public boolean test(DocumentName documentName) { + File file = documentName.asFile(); + return file.isDirectory() && ExclusionUtils.isHidden(documentName.getShortName()); + } + @Override + public String toString() { + return "HIDDEN_DIR"; + } + }), null ), /** * The hidden files. Directories with names that start with '.' */ HIDDEN_FILE("The hidden files. Directories with names that start with '.'", null, - new DocumentNameMatcher("HIDDEN_FILE", (Predicate) documentName -> { - File f = new File(documentName.getName()); - return f.isFile() && ExclusionUtils.isHidden(f); - }), null + new DocumentNameMatcher("HIDDEN_FILE", new Predicate() { + @Override + public boolean test(DocumentName documentName) { + File file = documentName.asFile(); + return file.isFile() && ExclusionUtils.isHidden(documentName.getShortName()); + } + @Override + public String toString() { + return "HIDDEN_FILE"; + } + }), null ), /** * The files and directories created by an IDEA IDE based tool. diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java index 42278f97c..c5f7470e9 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java @@ -115,21 +115,21 @@ private List createMatcherSetList() { /** * Builder the list of MatcherSet that define the inclusions/exclusions for the file processor. - * @param dir the directory agains which name resolution should be made. + * @param root the directory against which name resolution should be made. * @return the List of MatcherSet that represent this file processor. */ - public final List build(final DocumentName dir) { + public final List build(final DocumentName root) { if (includeProcessorFile) { String name = String.format("**/%s", fileName); - String pattern = ExclusionUtils.localizePattern(dir, name); + String pattern = ExclusionUtils.localizePattern(root, name); MatcherSet matcherSet = new MatcherSet.Builder() - .addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(Collections.singletonList(pattern)), dir)) + .addExcluded(new DocumentNameMatcher(name, MatchPatterns.from("/", Collections.singletonList(pattern)), root)) .build(); LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(0, k -> new LevelBuilder()); levelBuilder.add(matcherSet); } - checkDirectory(0, dir, new NameFileFilter(fileName)); + checkDirectory(0, root, root, new NameFileFilter(fileName)); List result = levelBuilders.size() == 1 ? Collections.singletonList(levelBuilders.get(0).asMatcherSet()) : createMatcherSetList(); @@ -140,9 +140,12 @@ public final List build(final DocumentName dir) { /** * Process by reading the file, creating a MatcherSet, and adding it to the * matcherSets. + * @param matcherSetConsumer the consumer to add the custom matcher sets to. + * @param root The root against which to resolve names. * @param documentName the file to read. + * @return A matcher set based on the strings in the file. */ - protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName dirBasedName, final DocumentName documentName) { + protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName root, final DocumentName documentName) { final MatcherSet.Builder matcherSetBuilder = new MatcherSet.Builder(); final List iterable = new ArrayList<>(); ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) @@ -154,25 +157,26 @@ protected MatcherSet process(final Consumer matcherSetConsumer, fina Set included = new HashSet<>(); Set excluded = new HashSet<>(); MatcherSet.Builder.segregateList(excluded, included, iterable); - matcherSetBuilder.addExcluded(dirBasedName, excluded); - matcherSetBuilder.addIncluded(dirBasedName, included); + matcherSetBuilder.addExcluded(root, excluded); + matcherSetBuilder.addIncluded(root, included); return matcherSetBuilder.build(); } /** * Process the directory tree looking for files that match the filter. Call {@link #process} on any matching file. + * @param level the level being precessed + * @param root the directory against which names should be resolved. * @param directory The name of the directory to process. * @param fileFilter the filter to detect processable files with. */ - private void checkDirectory(final int level, final DocumentName directory, final FileFilter fileFilter) { - File dirFile = new File(directory.getName()); - for (File f : listFiles(dirFile, fileFilter)) { + private void checkDirectory(final int level, final DocumentName root, final DocumentName directory, final FileFilter fileFilter) { + File dirFile = directory.asFile(); + for (File file : listFiles(dirFile, fileFilter)) { LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(level, k -> new LevelBuilder()); - DocumentName dirBasedName = DocumentName.builder(f).setBaseName(directory.getBaseName()).build(); - levelBuilder.add(process(levelBuilder::add, dirBasedName, DocumentName.builder(f).setBaseName(directory.getName()).build())); + levelBuilder.add(process(levelBuilder::add, root, DocumentName.builder(file).build())); } for (File dir : listFiles(dirFile, DirectoryFileFilter.DIRECTORY)) { - checkDirectory(level + 1, DocumentName.builder(dir).setBaseName(directory.getBaseName()).build(), fileFilter); + checkDirectory(level + 1, root, DocumentName.builder(dir).setBaseName(directory.getBaseName()).build(), fileFilter); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java index 0f2ff1047..0f6a7b26d 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java @@ -45,7 +45,7 @@ public CVSIgnoreBuilder() { } @Override - protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName dirBasedName, final DocumentName documentName) { + protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName root, final DocumentName documentName) { final File dir = new File(documentName.getName()); Set result = new HashSet<>(); Iterator iter = ExclusionUtils.asIterator(dir, StringUtils::isNotBlank); diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java index d7d0ad05b..ec238090c 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/HgIgnoreBuilder.java @@ -60,9 +60,9 @@ public HgIgnoreBuilder() { } @Override - protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName dirBasedName, final DocumentName documentName) { + protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName root, final DocumentName documentName) { state = Syntax.REGEXP; - return super.process(matcherSetConsumer, dirBasedName, documentName); + return super.process(matcherSetConsumer, root, documentName); } @Override diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java index 0a6703934..de59defe2 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java @@ -87,7 +87,7 @@ public boolean matches(final String name, final char[][] tokenizedNameChar, fina return false; } - public static MatchPatterns from(final String separator, final String... sources) { + public static MatchPatterns from(final String separator, final String separator, final String... sources) { final int length = sources.length; MatchPattern[] result = new MatchPattern[length]; for (int i = 0; i < length; i++) { diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java index d5cc1126c..4fb57c9ff 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java @@ -132,7 +132,7 @@ public static Builder builder(final FileSystem fileSystem) { } /** - * Creates a builder from a File. The {@link #baseName} is set to the file name if it is a directory otherwise + * Creates a builder from a File. The {@link #baseName} is set to the file name if it is a directory otherwise * it is set to the directory containing the file. * @param file The file to set defaults from. * @return the Builder. @@ -188,7 +188,7 @@ public DocumentName resolve(final String child) { if (StringUtils.isBlank(child)) { return this; } - String separator = fsInfo.dirSeparator(); + String separator = getDirectorySeparator(); String pattern = separator.equals("/") ? child.replace('\\', '/') : child.replace('/', '\\'); @@ -196,7 +196,24 @@ public DocumentName resolve(final String child) { pattern = name + separator + pattern; } - return new Builder(this).setName(pattern).build(); + return new Builder(this).setName(normalize(pattern)).build(); + } + + private String normalize(String pattern) { + List parts = new ArrayList<>(Arrays.asList(tokenize(pattern))); + for (int i=0; i rootFor(final String name) { } } return Optional.empty(); - } + public boolean equals(final Object other) { + return EqualsBuilder.reflectionEquals(this, other); + } + + @Override + public int hashCode() { + return HashCodeBuilder.reflectionHashCode(this); /** * Tokenizes the string based on the directory separator of this DocumentName. @@ -465,7 +497,6 @@ public String normalize(final String pattern) { public int compareTo(final FSInfo other) { return CompareToBuilder.reflectionCompare(this, other); } - @Override public boolean equals(final Object other) { return EqualsBuilder.reflectionEquals(this, other); diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/ExclusionProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/ExclusionProcessorTest.java index f8535a90b..96d059c74 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/ExclusionProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/ExclusionProcessorTest.java @@ -18,9 +18,20 @@ */ package org.apache.rat.config.exclusion; +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; import org.apache.commons.io.FileUtils; +import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.document.DocumentName; +import org.apache.rat.document.FSInfoTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -31,26 +42,29 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mockito; import static java.lang.String.format; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Fail.fail; +import static org.apache.rat.document.FSInfoTest.OSX; +import static org.apache.rat.document.FSInfoTest.UNIX; +import static org.apache.rat.document.FSInfoTest.WINDOWS; + public class ExclusionProcessorTest { final private static DocumentNameMatcher TRUE = DocumentNameMatcher.MATCHES_ALL; final private static DocumentNameMatcher FALSE = DocumentNameMatcher.MATCHES_NONE; - /** The base directory for the test. */ + @TempDir - private File basedirFile; - private DocumentName basedir; + private static Path tempDir; - @BeforeEach - public void setup() { - basedir = DocumentName.builder(basedirFile).build(); - } - private void testParseExclusion(DocumentNameMatcher nameMatcher, DocumentName name, boolean expected) { + private void testParseExclusion(DocumentName basedir, DocumentNameMatcher nameMatcher, DocumentName name, boolean expected) { assertThat(nameMatcher.matches(name)).as(() -> format("Failed on [%s %s]%n%s", basedir, name, dump(nameMatcher, name))).isEqualTo(expected); } @@ -60,48 +74,63 @@ private String dump(DocumentNameMatcher nameMatcher, DocumentName name) { return sb.toString(); } - private DocumentName mkName(String pth) { - File f = new File(basedirFile, pth); - try { - FileUtils.cleanDirectory(basedirFile); - FileUtils.touch(f); - } catch (IOException e) { - fail(e); + private DocumentName mkName(DocumentName baseDir, String pth) throws IOException { + DocumentName result = baseDir.resolve(ExclusionUtils.convertSeparator(pth, "/", baseDir.getDirectorySeparator())); + DocumentName mocked = Mockito.spy(result); + + String fn = result.localized(FileSystems.getDefault().getSeparator()); + File file = tempDir.resolve(fn.substring(1)).toFile(); + File parent = file.getParentFile(); + if (parent.exists() && !parent.isDirectory()) { + parent.delete(); } - return DocumentName.builder(f).setBaseName(basedir.getBaseName()).build(); + parent.mkdirs(); + if (file.exists()) { + if (file.isDirectory()) { + FileUtils.deleteDirectory(file); + } else { + FileUtils.delete(file); + } + } + file.createNewFile(); + Mockito.when(mocked.asFile()).thenReturn(file); + return mocked; } - @Test - public void defaultTest() { + @ParameterizedTest + @MethodSource("getDocumentNames") + void defaultTest(DocumentName basedir) throws IOException { ExclusionProcessor p = new ExclusionProcessor(); - testParseExclusion(p.getNameMatcher(basedir), mkName("hello"), true); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, "hello"), true); } - @Test - public void addExcludedCollectionTest() { + @ParameterizedTest + @MethodSource("getDocumentNames") + void addExcludedCollectionTest(DocumentName basedir) throws IOException { ExclusionProcessor p = new ExclusionProcessor().addExcludedCollection(StandardCollection.MISC); // "**/*~", "**/#*#", "**/.#*", "**/%*%", "**/._*" - testParseExclusion(p.getNameMatcher(basedir), mkName("hello"), true); - testParseExclusion(p.getNameMatcher(basedir), mkName("hello~"), false); - testParseExclusion(p.getNameMatcher(basedir), mkName("#hello#"), false); - testParseExclusion(p.getNameMatcher(basedir), mkName(".#hello"), false); - testParseExclusion(p.getNameMatcher(basedir), mkName("%hello%"), false); - testParseExclusion(p.getNameMatcher(basedir), mkName("._hello"), false); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir,"hello"), true); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir,"hello~"), false); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, "#hello#"), false); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, ".#hello"), false); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, "%hello%"), false); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, "._hello"), false); } - @Test - public void addExcludedAndIncludedCollectionTest() { + @ParameterizedTest + @MethodSource("getDocumentNames") + void addExcludedAndIncludedCollectionTest(DocumentName basedir) throws IOException { ExclusionProcessor p = new ExclusionProcessor().addExcludedCollection(StandardCollection.MISC) .addIncludedCollection(StandardCollection.HIDDEN_FILE); - testParseExclusion(p.getNameMatcher(basedir), mkName("hello"), true); - testParseExclusion(p.getNameMatcher(basedir), mkName("hello~"), false); - testParseExclusion(p.getNameMatcher(basedir), mkName("#hello#"), false); - testParseExclusion(p.getNameMatcher(basedir), mkName(".#hello"), true); - testParseExclusion(p.getNameMatcher(basedir), mkName("%hello%"), false); - testParseExclusion(p.getNameMatcher(basedir), mkName("._hello"), true); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir,"hello"), true); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, "hello~"), false); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, "#hello#"), false); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, ".#hello"), true); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, "%hello%"), false); + testParseExclusion(basedir, p.getNameMatcher(basedir), mkName(basedir, "._hello"), true); } - private void assertExclusions(String pattern, Map expectedMap) { + private void assertExclusions(DocumentName basedir, String pattern, Map expectedMap) throws IOException { String[] paths = {"a/b/foo", "b/foo", "foo", "foo/x", "foo/x/y", "b/foo/x", "b/foo/x/y", "a/b/foo/x", "a/b/foo/x/y"}; ExclusionProcessor p = new ExclusionProcessor().addExcludedPatterns(Collections.singletonList(pattern)); @@ -111,13 +140,13 @@ private void assertExclusions(String pattern, Map expectedMap) { if (expected == null) { throw new RuntimeException("Missing expected value for " + pth + " in pattern " + pattern); } - DocumentName dn = mkName(pth); - testParseExclusion(pathMatcher, mkName(pth), expected); + testParseExclusion(basedir, pathMatcher, mkName(basedir, pth), expected); } } - @Test - public void addExcludedPatternsTest() { + @ParameterizedTest + @MethodSource("getDocumentNames") + void addExcludedPatternsTest(DocumentName basedir) throws IOException { Map expectedMap = new HashMap<>(); expectedMap.put("a/b/foo", true); @@ -129,7 +158,7 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", true); expectedMap.put("a/b/foo/x", true); expectedMap.put("a/b/foo/x/y",true); - assertExclusions("foo", expectedMap); + assertExclusions(basedir, "foo", expectedMap); expectedMap.clear(); expectedMap.put("a/b/foo", true); @@ -141,7 +170,7 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", true); expectedMap.put("a/b/foo/x", true); expectedMap.put("a/b/foo/x/y",true); - assertExclusions("foo/*", expectedMap); + assertExclusions(basedir, "foo/*", expectedMap); expectedMap.clear(); expectedMap.put("a/b/foo", true); @@ -153,7 +182,7 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", true); expectedMap.put("a/b/foo/x", true); expectedMap.put("a/b/foo/x/y",true); - assertExclusions("foo/**", expectedMap); + assertExclusions(basedir, "foo/**", expectedMap); expectedMap.clear(); expectedMap.put("a/b/foo", true); @@ -165,7 +194,7 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", true); expectedMap.put("a/b/foo/x", true); expectedMap.put("a/b/foo/x/y",true); - assertExclusions("*/foo", expectedMap); + assertExclusions(basedir, "*/foo", expectedMap); expectedMap.clear(); expectedMap.put("a/b/foo", true); @@ -177,7 +206,7 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", true); expectedMap.put("a/b/foo/x", true); expectedMap.put("a/b/foo/x/y",true); - assertExclusions("*/foo/*", expectedMap); + assertExclusions(basedir, "*/foo/*", expectedMap); expectedMap.clear(); expectedMap.put("a/b/foo", true); @@ -189,7 +218,7 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", false); expectedMap.put("a/b/foo/x", true); expectedMap.put("a/b/foo/x/y",true); - assertExclusions("*/foo/**", expectedMap); + assertExclusions(basedir, "*/foo/**", expectedMap); expectedMap.clear(); expectedMap.put("a/b/foo", false); @@ -201,7 +230,7 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", true); expectedMap.put("a/b/foo/x", true); expectedMap.put("a/b/foo/x/y",true); - assertExclusions("**/foo", expectedMap); + assertExclusions(basedir, "**/foo", expectedMap); expectedMap.clear(); expectedMap.put("a/b/foo", true); @@ -213,7 +242,7 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", true); expectedMap.put("a/b/foo/x", false); expectedMap.put("a/b/foo/x/y",true); - assertExclusions("**/foo/*", expectedMap); + assertExclusions(basedir, "**/foo/*", expectedMap); expectedMap.clear(); expectedMap.put("a/b/foo", false); @@ -225,11 +254,12 @@ public void addExcludedPatternsTest() { expectedMap.put("b/foo/x/y", false); expectedMap.put("a/b/foo/x", false); expectedMap.put("a/b/foo/x/y",false); - assertExclusions("**/foo/**", expectedMap); + assertExclusions(basedir, "**/foo/**", expectedMap); } - @Test - public void orTest() { + @ParameterizedTest + @MethodSource("getDocumentNames") + void orTest(DocumentName basedir) { ExclusionProcessor underTest = new ExclusionProcessor(); assertThat(DocumentNameMatcher.or(Arrays.asList(TRUE, FALSE)).matches(basedir)).isTrue(); assertThat(DocumentNameMatcher.or(Arrays.asList(FALSE, TRUE)).matches(basedir)).isTrue(); @@ -237,8 +267,9 @@ public void orTest() { assertThat(DocumentNameMatcher.or(Arrays.asList(FALSE, FALSE)).matches(basedir)).isFalse(); } - @Test - public void andTest() { + @ParameterizedTest + @MethodSource("getDocumentNames") + void andTest(DocumentName basedir) { ExclusionProcessor underTest = new ExclusionProcessor(); assertThat(DocumentNameMatcher.and(TRUE, FALSE).matches(basedir)).isFalse(); assertThat(DocumentNameMatcher.and(FALSE, TRUE).matches(basedir)).isFalse(); @@ -246,10 +277,30 @@ public void andTest() { assertThat(DocumentNameMatcher.and(FALSE, FALSE).matches(basedir)).isFalse(); } - @Test - public void notTest() { + @ParameterizedTest + @MethodSource("getDocumentNames") + void notTest(DocumentName basedir) { ExclusionProcessor underTest = new ExclusionProcessor(); assertThat(DocumentNameMatcher.not(TRUE).matches(basedir)).isFalse(); assertThat(DocumentNameMatcher.not(FALSE).matches(basedir)).isTrue(); } + + private static Stream getDocumentNames() throws IOException { + List lst = new ArrayList<>(); + + DocumentName.Builder builder = DocumentName.builder().setName("default"); + lst.add(Arguments.of(builder.setBaseName(builder.directorySeparator()).build())); + + builder = DocumentName.builder(WINDOWS).setName("windows"); + lst.add(Arguments.of(builder.setBaseName(builder.directorySeparator()).build())); + + builder = DocumentName.builder(UNIX).setName("unix"); + lst.add(Arguments.of(builder.setBaseName(builder.directorySeparator()).build())); + + builder = DocumentName.builder(OSX).setName("osx"); + lst.add(Arguments.of(builder.setBaseName(builder.directorySeparator()).build())); + + + return lst.stream(); + } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java index be3d9970f..338b34eae 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java @@ -39,24 +39,39 @@ void localizePatternTest(DocumentName baseName, String pattern, String expectedS assertThat(ExclusionUtils.localizePattern(baseName, pattern)).isEqualTo(expectedStr); } - public static Stream localizePatternData() { - List lst = new ArrayList<>(); + public static Stream localizePatternData() throws IOException { + List lst = new ArrayList<>(); + Map patterns = new HashMap<>(); + patterns.put("file", "%1$sbaseDir%1$sfile"); + patterns.put("!file", "!%1$sbaseDir%1$sfile"); + patterns.put("%regex[file]", "%%regex[\\Q%1$sbaseDir%1$s\\Efile]"); + patterns.put("!%regex[file]", "!%%regex[\\Q%1$sbaseDir%1$s\\Efile]"); + patterns.put("%ant[file]", "%1$sbaseDir%1$sfile"); + patterns.put("!%ant[file]", "!%1$sbaseDir%1$sfile"); + + patterns.put("file/**", "%1$sbaseDir%1$sfile%1$s**"); + patterns.put("!file/**", "!%1$sbaseDir%1$sfile%1$s**"); + patterns.put("%regex[file/.*]", "%%regex[\\Q%1$sbaseDir%1$s\\Efile/.*]"); + patterns.put("!%regex[file/.*]", "!%%regex[\\Q%1$sbaseDir%1$s\\Efile/.*]"); + patterns.put("%ant[file/**]", "%1$sbaseDir%1$sfile%1$s**"); + patterns.put("!%ant[file/**]", "!%1$sbaseDir%1$sfile%1$s**"); + + DocumentName baseName = DocumentName.builder(FSInfoTest.UNIX).setName("fileBeingRead").setBaseName("baseDir").build(); + for (Map.Entry pattern : patterns.entrySet()) { + lst.add(Arguments.of(baseName, pattern.getKey(), String.format(pattern.getValue(), UNIX.dirSeparator()))); + } - lst.add(Arguments.of(baseName, "file", "/baseDir/file")); - lst.add(Arguments.of(baseName, "!file", "!/baseDir/file")); - lst.add(Arguments.of(baseName, "%regex[file]", "%regex[\\Q/baseDir/\\Efile]")); - lst.add(Arguments.of(baseName, "!%regex[file]", "!%regex[\\Q/baseDir/\\Efile]")); - lst.add(Arguments.of(baseName, "%ant[file]", "/baseDir/file")); - lst.add(Arguments.of(baseName, "!%ant[file]", "!/baseDir/file")); - lst.add(Arguments.of(baseName, "file/**", "/baseDir/file/**")); - lst.add(Arguments.of(baseName, "!file/**", "!/baseDir/file/**")); - lst.add(Arguments.of(baseName, "%regex[file/.*]", "%regex[\\Q/baseDir/\\Efile/.*]")); - lst.add(Arguments.of(baseName, "!%regex[file/.*]", "!%regex[\\Q/baseDir/\\Efile/.*]")); - lst.add(Arguments.of(baseName, "%ant[file/**]", "/baseDir/file/**")); - lst.add(Arguments.of(baseName, "!%ant[file/**]", "!/baseDir/file/**")); + baseName = DocumentName.builder(FSInfoTest.WINDOWS).setName("fileBeingRead").setBaseName("baseDir").build(); + for (Map.Entry pattern : patterns.entrySet()) { + lst.add(Arguments.of(baseName, pattern.getKey(), String.format(pattern.getValue(), WINDOWS.dirSeparator()))); + } + baseName = DocumentName.builder(FSInfoTest.OSX).setName("fileBeingRead").setBaseName("baseDir").build(); + for (Map.Entry pattern : patterns.entrySet()) { + lst.add(Arguments.of(baseName, pattern.getKey(), String.format(pattern.getValue(), OSX.dirSeparator()))); + } return lst.stream(); } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java new file mode 100644 index 000000000..0531897da --- /dev/null +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java @@ -0,0 +1,322 @@ +/* + * 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 com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.FileStore; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.builder.CompareToBuilder; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.rat.utils.DefaultLog; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.apache.rat.document.FSInfoTest.OSX; +import static org.apache.rat.document.FSInfoTest.UNIX; +import static org.apache.rat.document.FSInfoTest.WINDOWS; + + +public class DocumentNameBuilderTest { + + @ParameterizedTest(name="{0}") + @MethodSource("buildTestData") + void buildTest(String testName, DocumentName documentName, String name, String shortName, String baseName, String root, + String directorySeparator, Boolean isCaseSensitive, String localized, String localizedArg) { + assertThat(documentName.getName()).as("Invalid name").isEqualTo(name); + assertThat(documentName.getShortName()).as("Invalid short name").isEqualTo(shortName); + assertThat(documentName.getBaseName()).as("Invalid base name").isEqualTo(baseName); + assertThat(documentName.getRoot()).as("Invalid root").isEqualTo(root); + assertThat(documentName.getDirectorySeparator()).as("Invalid directory separator").isEqualTo(directorySeparator); + if (isCaseSensitive) { + assertThat(documentName.isCaseSensitive()).as("Invalid case sensitivity").isTrue(); + } else { + assertThat(documentName.isCaseSensitive()).as("Invalid case sensitivity").isFalse(); + } + assertThat(documentName.localized()).as("Invalid localized ").isEqualTo(localized); + final String sep = documentName.getDirectorySeparator().equals("/") ? "\\" : "/"; + assertThat(documentName.localized(sep)).as(() -> String.format("Invalid localized('%s')", sep)).isEqualTo(localizedArg); + } + + + static Stream buildTestData() throws IOException { + List lst = new ArrayList<>(); + + // + String testName = "windows\\foo direct"; + DocumentName documentName = DocumentName.builder(WINDOWS).setName("C:\\\\windows\\foo").setBaseName("C:\\\\windows").build(); + lst.add(Arguments.of( testName, documentName, "C:\\\\windows\\foo", "foo", "C:\\\\windows", "C:\\", "\\", false, + "\\foo", "/foo")); + DocumentName baseName = documentName; + + // + testName = "builder(docName)"; + documentName = DocumentName.builder(baseName).build(); + lst.add(Arguments.of( testName, documentName, "C:\\\\windows\\foo", "foo", "C:\\\\windows", "C:\\", "\\", false, + "\\foo", "/foo")); + + // + testName = "windows\\foo\\bar by resolve"; + documentName = baseName.resolve("bar"); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows", "C:\\", "\\", false, + "\\foo\\bar", "/foo/bar")); + + // + testName = "windows\\foo\\direct by basename"; + documentName = DocumentName.builder(baseName).setName("windows\\foo\\direct").build(); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\direct", "direct", "C:\\\\windows", "C:\\", "\\", false, + "\\foo\\direct", "/foo/direct")); + + // + testName = "windows\\foo\\bar by file"; + File file = mock(File.class); + File parent = mock(File.class); + when(file.getAbsolutePath()).thenReturn("C:\\\\windows\\foo\\bar"); + when(file.getParentFile()).thenReturn(parent); + when(file.isDirectory()).thenReturn(false); + when(parent.getAbsolutePath()).thenReturn("C:\\\\windows\\foo"); + when(parent.isDirectory()).thenReturn(true); + documentName = new DocumentName.Builder(WINDOWS, file).build(); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows\\foo", "C:\\", "\\", false, + "\\bar", "/bar")); + + // + testName = "windows\\foo\\bar by directory"; + file = mock(File.class); + parent = mock(File.class); + when(file.getAbsolutePath()).thenReturn("C:\\\\windows\\foo\\bar"); + when(file.getParentFile()).thenReturn(parent); + when(file.isDirectory()).thenReturn(true); + when(parent.getAbsolutePath()).thenReturn("C:\\\\windows\\foo"); + when(parent.isDirectory()).thenReturn(true); + documentName = new DocumentName.Builder(WINDOWS, file).build(); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows\\foo\\bar", "C:\\", "\\", false, + "\\", "/")); + + // + testName = "windows setRoot"; + documentName = DocumentName.builder(baseName).setRoot("D:\\").build(); + lst.add(Arguments.of(testName, documentName, "D:\\\\windows\\foo", "foo", "C:\\\\windows", "D:\\", "\\", false, + "D:\\\\windows\\foo", "D://windows/foo")); + + testName = "windows setRoot(null)"; + documentName = DocumentName.builder(baseName).setRoot(null).build(); + lst.add(Arguments.of(testName, documentName, "\\windows\\foo", "foo", "C:\\\\windows", "", "\\", false, + "\\windows\\foo", "/windows/foo")); + + testName = "windows setRoot('')"; + documentName = DocumentName.builder(baseName).setRoot("").build(); + lst.add(Arguments.of(testName, documentName, "\\windows\\foo", "foo", "C:\\\\windows", "", "\\", false, + "\\windows\\foo", "/windows/foo")); + + // + testName = "windows setName('baz')"; + documentName = DocumentName.builder(baseName).setName("baz").build(); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\baz", "baz", "C:\\\\windows", "C:\\", "\\", false, + "\\baz", "/baz")); + + testName = "windows setName((String)null)"; + documentName = DocumentName.builder(baseName).setName((String)null).build(); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows", "windows", "C:\\\\windows", "C:\\", "\\", false, + "\\", "/")); + + testName = "windows setName('')"; + documentName = DocumentName.builder(baseName).setName("").build(); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows", "windows", "C:\\\\windows", "C:\\", "\\", false, + "\\", "/")); + + file = mock(File.class); + parent = mock(File.class); + when(file.getAbsolutePath()).thenReturn("C:\\\\windows\\foo\\bar"); + when(file.getParentFile()).thenReturn(parent); + when(file.isDirectory()).thenReturn(false); + when(parent.getAbsolutePath()).thenReturn("C:\\\\windows\\foo"); + when(parent.isDirectory()).thenReturn(true); + testName = "windows setName(file)"; + documentName = DocumentName.builder(baseName).setName(file).build(); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows\\foo", "C:\\", "\\", false, + "\\bar", "/bar")); + + file = mock(File.class); + parent = mock(File.class); + when(file.getAbsolutePath()).thenReturn("C:\\\\windows\\foo\\bar"); + when(file.getParentFile()).thenReturn(parent); + when(file.isDirectory()).thenReturn(true); + when(parent.getAbsolutePath()).thenReturn("C:\\\\windows\\foo"); + when(parent.isDirectory()).thenReturn(true); + testName = "windows setName(directory)"; + documentName = DocumentName.builder(baseName).setName(file).build(); + lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows\\foo\\bar", "C:\\", "\\", false, + "\\", "/")); + + return lst.stream(); + + +// +// /** +// * Sets the baseName. +// * Will set the root if it is not set. +// *

    +// * To correctly parse the string it must use the directory separator specified by this builder. +// *

    +// * @param baseName the basename to use. +// * @return this. +// */ +// public DocumentName.Builder setBaseName(final String baseName) { +// DocumentName.Builder builder = DocumentName.builder(fsInfo).setName(baseName); +// builder.sameNameFlag = true; +// setBaseName(builder); +// return this; +// } +// +// /** +// * Sets the basename from the {@link #name} of the specified DocumentName. +// * Will set the root the baseName has the root set. +// * @param baseName the DocumentName to set the basename from. +// * @return this. +// */ +// public DocumentName.Builder setBaseName(final DocumentName baseName) { +// this.baseName = baseName; +// if (!baseName.getRoot().isEmpty()) { +// this.root = baseName.getRoot(); +// } +// return this; +// } +// +// /** +// * Executes the builder, sets the base name and clears the sameName flag. +// * @param builder the builder for the base name. +// */ +// private void setBaseName(DocumentName.Builder builder) { +// this.baseName = builder.build(); +// this.sameNameFlag = false; +// } +// +// /** +// * Sets the basename from a File. Sets {@link #root} and the {@link #baseName} +// * Will set the root. +// * @param file the file to set the base name from. +// * @return this. +// */ +// public DocumentName.Builder setBaseName(final File file) { +// DocumentName.Builder builder = DocumentName.builder(fsInfo).setName(file); +// builder.sameNameFlag = true; +// setBaseName(builder); +// return this; +// } +// +// /** +// * Build a DocumentName from this builder. +// * @return A new DocumentName. +// */ +// public DocumentName build() { +// verify(); +// return new DocumentName(this); +// } + +// +// assertThat(documentName.getName()).isEqualTo("C:\\\\windows\\foo") +// +// +// assertThat(documentName.getRoot()).isEqualTo("C:\\"); +// assertThat(documentName.isCaseSensitive()).isFalse(); +// assertThat(documentName.getShortName()).isEqualTo("foo"); +// assertThat(documentName.localized("/")).isEqualTo("/windows/foo"); +// assertThat(documentName.getBaseName()).isEqualTo("C:\\\\windows"); +// documentName.getBaseDocumentName(); +// documentName.getDirectorySeparator(); +// +// +// public String getName() +// +// +// public String getBaseName() +// +// +// public String getRoot() +// +// +// public DocumentName getBaseDocumentName +// +// public String getDirectorySeparator( +// +// +// public String localized() +// +// public String localized(final String dirSeparator) +// +// +// public String[] tokenize(final String source) { +// // return source.split("\\Q" + fsInfo.dirSeparator() + "\\E"); +// +// +// +// public String getShortName() +// +// public boolean isCaseSensitive() + + +/* + @Override + public int compareTo(final DocumentName other) { + return CompareToBuilder.reflectionCompare(this, other); + } + + @Override + public boolean equals(final Object other) { + return EqualsBuilder.reflectionEquals(this, other); + } + + @Override + public int hashCode() { + return HashCodeBuilder.reflectionHashCode(this); + } + +*/ + + } + + +} diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java index beeeeca94..5b0f227e6 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameTest.java @@ -18,6 +18,7 @@ */ package org.apache.rat.document; + import java.io.File; import java.io.FileFilter; import java.io.FilenameFilter; diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java index 87d157a0e..a4a2d9976 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java @@ -18,17 +18,21 @@ */ package org.apache.rat.document.guesser; +import java.io.IOException; +import java.nio.file.FileSystem; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; import org.apache.rat.document.DocumentName; -import org.apache.rat.document.FSInfoTest; import org.apache.rat.testhelpers.TestingDocument; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.apache.rat.document.FSInfoTest.OSX; +import static org.apache.rat.document.FSInfoTest.UNIX; +import static org.apache.rat.document.FSInfoTest.WINDOWS; public class NoteGuesserTest { @@ -39,11 +43,12 @@ public void testMatches(DocumentName testingName, boolean expected) { assertEquals(expected, actual, testingName::getName); } - private static Stream nameData() { + private static Stream nameData() throws IOException { List lst = new ArrayList<>(); - final DocumentName linuxBaseName = DocumentName.builder(FSInfoTest.UNIX).setName("/").setBaseName("/").build(); - final DocumentName windowsBaseName = DocumentName.builder(FSInfoTest.WINDOWS).setName("\\").setBaseName("\\").build(); + final DocumentName osxBaseName = DocumentName.builder(OSX).setName("/").setBaseName("/").build(); + final DocumentName linuxBaseName = DocumentName.builder(UNIX).setName("/").setBaseName("/").build(); + final DocumentName windowsBaseName = DocumentName.builder(WINDOWS).setName("\\").setBaseName("\\").build(); lst.add(Arguments.of(linuxBaseName.resolve("DEPENDENCIES"), true)); lst.add(Arguments.of(linuxBaseName.resolve("LICENSE"), true)); @@ -77,6 +82,22 @@ private static Stream nameData() { lst.add(Arguments.of(windowsBaseName.resolve("src\\test\\README.txt"), true)); lst.add(Arguments.of(windowsBaseName.resolve("src\\test\\README.shouldFail"), false)); + lst.add(Arguments.of(osxBaseName.resolve("DEPENDENCIES"), true)); + lst.add(Arguments.of(osxBaseName.resolve("LICENSE"), true)); + lst.add(Arguments.of(osxBaseName.resolve("LICENSE.txt"), true)); + lst.add(Arguments.of(osxBaseName.resolve("NOTICE"), true)); + lst.add(Arguments.of(osxBaseName.resolve("NOTICE.txt"), true)); + lst.add(Arguments.of(osxBaseName.resolve("README"), true)); + lst.add(Arguments.of(osxBaseName.resolve("README.txt"), true)); + lst.add(Arguments.of(osxBaseName.resolve("src/test/DEPENDENCIES"), true)); + lst.add(Arguments.of(osxBaseName.resolve("src/test/LICENSE"), true)); + lst.add(Arguments.of(osxBaseName.resolve("src/test/LICENSE.txt"), true)); + lst.add(Arguments.of(osxBaseName.resolve("src/test/NOTICE"), true)); + lst.add(Arguments.of(osxBaseName.resolve("src/test/NOTICE.txt"), true)); + lst.add(Arguments.of(osxBaseName.resolve("src/test/README"), true)); + lst.add(Arguments.of(osxBaseName.resolve("src/test/README.txt"), true)); + lst.add(Arguments.of(osxBaseName.resolve("src/test/README.shouldFail"), false)); + return lst.stream(); } } From 79a2b4484949ea25f715e3981d34740142b49889 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Thu, 2 Jan 2025 21:51:39 +0000 Subject: [PATCH 090/123] clean up of remaingin core tests --- .../main/java/org/apache/rat/document/DocumentName.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java index 4fb57c9ff..e2df0dbb4 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java @@ -451,13 +451,7 @@ public Optional rootFor(final String name) { } } return Optional.empty(); - public boolean equals(final Object other) { - return EqualsBuilder.reflectionEquals(this, other); - } - - @Override - public int hashCode() { - return HashCodeBuilder.reflectionHashCode(this); + } /** * Tokenizes the string based on the directory separator of this DocumentName. @@ -497,6 +491,7 @@ public String normalize(final String pattern) { public int compareTo(final FSInfo other) { return CompareToBuilder.reflectionCompare(this, other); } + @Override public boolean equals(final Object other) { return EqualsBuilder.reflectionEquals(this, other); From cc16bd93f74eb856cda742918f606206a3b35cba Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Thu, 2 Jan 2025 21:51:39 +0000 Subject: [PATCH 091/123] clean up of remaingin core tests --- .../apache/rat/commandline/Converters.java | 5 ++-- .../rat/config/exclusion/ExclusionUtils.java | 12 ++++---- .../AbstractFileProcessorBuilder.java | 5 ++-- .../rat/analysis/AnalyserFactoryTest.java | 2 +- .../apache/rat/document/FileDocumentTest.java | 30 ++++++++++++------- 5 files changed, 31 insertions(+), 23 deletions(-) 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 61f27cdbe..ce5291de0 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 @@ -21,6 +21,7 @@ import java.io.File; import java.io.IOException; +import java.nio.file.FileSystems; import org.apache.commons.cli.Converter; import org.apache.commons.lang3.tuple.Pair; import org.apache.rat.ConfigurationException; @@ -92,9 +93,7 @@ public File apply(final String fileName) throws NullPointerException { // is this a relative file? if (!fileName.startsWith(File.separator)) { // check for a root provided (e.g. C:\\)" - DocumentName.Builder builder = DocumentName.builder(file); - final DocumentName name = builder.build(); - if (name.getRoot().isEmpty()) { + if (!DocumentName.DEFAULT_FSINFO.rootFor(file.getAbsolutePath()).isPresent()) { // no root, resolve against workingDirectory file = new File(workingDirectory.resolve(fileName).getName()).getAbsoluteFile(); } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java index e712bcac3..8c0b590f2 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java @@ -225,20 +225,18 @@ public static String localizePattern(final DocumentName documentName, final Stri boolean prefix = pattern.startsWith(NEGATION_PREFIX); String workingPattern = prefix ? pattern.substring(1) : pattern; String normalizedPattern = SelectorUtils.extractPattern(workingPattern, documentName.getDirectorySeparator()); - StringBuilder sb = new StringBuilder(); + + StringBuilder sb = new StringBuilder(prefix ? NEGATION_PREFIX : ""); if (SelectorUtils.isRegexPrefixedPattern(workingPattern)) { - sb.append(prefix ? NEGATION_PREFIX : "") - .append(SelectorUtils.REGEX_HANDLER_PREFIX) + sb.append(SelectorUtils.REGEX_HANDLER_PREFIX) .append("\\Q").append(documentName.getBaseName()) .append(documentName.getDirectorySeparator()) .append("\\E").append(normalizedPattern) .append(SelectorUtils.PATTERN_HANDLER_SUFFIX); - return sb.toString(); } else { - sb.append(documentName.getBaseName()) - .append(documentName.getDirectorySeparator()).append(normalizedPattern); - return (prefix ? NEGATION_PREFIX : "") + DocumentName.builder(documentName).setName(sb.toString()).build().getName(); + sb.append(documentName.getBaseDocumentName().resolve(normalizedPattern).getName()); } + return sb.toString(); } /** diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java index c5f7470e9..f6788f223 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java @@ -157,8 +157,9 @@ protected MatcherSet process(final Consumer matcherSetConsumer, fina Set included = new HashSet<>(); Set excluded = new HashSet<>(); MatcherSet.Builder.segregateList(excluded, included, iterable); - matcherSetBuilder.addExcluded(root, excluded); - matcherSetBuilder.addIncluded(root, included); + DocumentName displayName = DocumentName.builder(root).setName(documentName.getName()).build(); + matcherSetBuilder.addExcluded(displayName, excluded); + matcherSetBuilder.addIncluded(displayName, included); return matcherSetBuilder.build(); } 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 72ebff4be..067dc5f15 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 @@ -71,7 +71,7 @@ public void setUp() { @Test public void standardTypeAnalyser() throws Exception { - final Document document = new FileDocument(basedir, + final Document document = new FileDocument( Resources.getExampleResource("exampleData/Text.txt"), DocumentNameMatcher.MATCHES_ALL); analyser.analyse(document); assertThat(document.getMetaData().getDocumentType()).isEqualTo(Document.Type.STANDARD); diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/FileDocumentTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/FileDocumentTest.java index f1ebb38cf..d63dfe503 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/FileDocumentTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/FileDocumentTest.java @@ -18,6 +18,8 @@ */ package org.apache.rat.document; +import java.nio.file.Path; +import org.apache.commons.io.FileUtils; import org.apache.rat.api.Document; import org.apache.rat.test.utils.Resources; import org.assertj.core.util.Files; @@ -27,32 +29,40 @@ import java.io.BufferedReader; import java.io.File; import java.io.Reader; +import org.junit.jupiter.api.io.TempDir; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; public class FileDocumentTest { private Document document; private File file; - + + @TempDir + private static Path tempDir; + @BeforeEach public void setUp() throws Exception { - File basedir = new File(Files.currentFolder(), Resources.SRC_TEST_RESOURCES); - file = Resources.getExampleResource("exampleData/Source.java"); - document = new FileDocument(DocumentName.builder(basedir).build(), file, DocumentNameMatcher.MATCHES_ALL); + + File basedir = new File(tempDir.toFile(), Resources.SRC_TEST_RESOURCES); + basedir.mkdirs(); + File sourceData = Resources.getExampleResource("exampleData/Source.java"); + file = new File(basedir, "Source.java"); + FileUtils.copyFile(sourceData, file); + + DocumentName docName = DocumentName.builder(basedir).build(); + document = new FileDocument(docName, file, DocumentNameMatcher.MATCHES_ALL); } @Test public void reader() throws Exception { Reader reader = document.reader(); - assertNotNull(reader, "Reader should be returned"); - assertEquals("package elements;", - new BufferedReader(reader).readLine(), "First file line expected"); + assertThat(reader).isNotNull(); + assertThat(new BufferedReader(reader).readLine()).isEqualTo("package elements;"); } @Test public void getName() { final DocumentName name = document.getName(); - assertNotNull(name, "Name is set"); + assertThat(name).isNotNull(); } } From 08b11432a283ef3ed85ae2814cb558251cc433b0 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 13:26:09 +0000 Subject: [PATCH 092/123] fixed archive processing and naming issues --- .../apache/rat/analysis/TikaProcessor.java | 27 ++++++++++++++++--- .../java/org/apache/rat/commandline/Arg.java | 8 +++--- .../apache/rat/commandline/Converters.java | 2 +- .../rat/document/ArchiveEntryDocument.java | 6 ++--- .../org/apache/rat/OptionCollectionTest.java | 2 +- .../org/apache/rat/mp/RatCheckMojoTest.java | 8 ++---- 6 files changed, 34 insertions(+), 19 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/analysis/TikaProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/analysis/TikaProcessor.java index 5f128668d..065efcb6d 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/analysis/TikaProcessor.java +++ b/apache-rat-core/src/main/java/org/apache/rat/analysis/TikaProcessor.java @@ -122,6 +122,28 @@ public static InputStream markSupportedInputStream(final InputStream stream) { return stream.markSupported() ? stream : new BufferedInputStream(stream); } + /** + * Extracts the media type properly from zero length files. + * @param stream the InputStream from the file. + * @param documentName the name of the document + * @return the mime type for the document + * @throws IOException on error. + */ + private static String detectMediaType(InputStream stream, DocumentName documentName) throws IOException { + stream.mark(1); + int ch = stream.read(); + stream.reset(); + Metadata metadata = new Metadata(); + String name = documentName.localized(); + if (ch == -1) { + name = name.substring(name.lastIndexOf("/") + 1); + metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, name); + return TIKA.detect(null, metadata); + } + metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, name); + return TIKA.detect(stream, metadata); + } + /** * Process the input document. * @param document the Document to process. @@ -129,10 +151,8 @@ public static InputStream markSupportedInputStream(final InputStream stream) { * @throws RatDocumentAnalysisException on error. */ public static String process(final Document document) throws RatDocumentAnalysisException { - Metadata metadata = new Metadata(); try (InputStream stream = markSupportedInputStream(document.inputStream())) { - metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, document.getName().getName()); - String result = TIKA.detect(stream, metadata); + String result = detectMediaType(stream, document.getName()); String[] parts = result.split("/"); MediaType mediaType = new MediaType(parts[0], parts[1]); document.getMetaData().setMediaType(mediaType); @@ -146,7 +166,6 @@ public static String process(final Document document) throws RatDocumentAnalysis document.getMetaData().setDocumentType(Document.Type.NOTICE); } } - return result; } catch (IOException e) { throw new RatDocumentAnalysisException(e); 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 f916e3843..293b93bcd 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 @@ -849,12 +849,12 @@ private static void processOutputArgs(final ArgumentContext context) { if (OUTPUT_FILE.isSelected()) { try { - File f = context.getCommandLine().getParsedOptionValue(OUTPUT_FILE.getSelected()); - File parent = f.getParentFile(); + File file = context.getCommandLine().getParsedOptionValue(OUTPUT_FILE.getSelected()); + File parent = file.getParentFile(); if (!parent.mkdirs() && !parent.isDirectory()) { - DefaultLog.getInstance().error("Could not create report parent directory " + f); + DefaultLog.getInstance().error("Could not create report parent directory " + file); } - context.getConfiguration().setOut(f); + context.getConfiguration().setOut(file); } catch (ParseException e) { context.logParseException(e, OUTPUT_FILE.getSelected(), "System.out"); context.getConfiguration().setOut((IOSupplier) null); 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 ce5291de0..9e1cf88c2 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 @@ -93,7 +93,7 @@ public File apply(final String fileName) throws NullPointerException { // is this a relative file? if (!fileName.startsWith(File.separator)) { // check for a root provided (e.g. C:\\)" - if (!DocumentName.DEFAULT_FSINFO.rootFor(file.getAbsolutePath()).isPresent()) { + if (!DocumentName.DEFAULT_FSINFO.rootFor(fileName).isPresent()) { // no root, resolve against workingDirectory file = new File(workingDirectory.resolve(fileName).getName()).getAbsoluteFile(); } 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 index 0553e4339..dabc848bc 100644 --- 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 @@ -36,12 +36,12 @@ public class ArchiveEntryDocument extends Document { /** * Creates an Archive entry. - * @param outerName the name of this entry from outside the archive. + * @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 DocumentName outerName, final byte[] contents, final DocumentNameMatcher nameMatcher) { - super(outerName, nameMatcher); + public ArchiveEntryDocument(final ArchiveEntryName entryName, final byte[] contents, final DocumentNameMatcher nameMatcher) { + super(entryName, nameMatcher); this.contents = contents; } 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 7452d33b4..7f34fa2ee 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 @@ -53,7 +53,7 @@ import static java.lang.String.format; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.fail; +import static org.assertj.core.api.Fail.fail; public class OptionCollectionTest { @TempDir diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java index c10b10bb6..a260bca3e 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java @@ -258,12 +258,8 @@ void it5() throws Exception { ReportConfigurationTest.validateDefaultLicenses(config, "CC-BY-NC-ND", "YAL"); assertThat(LicenseSetFactory.search("YAL", "YAL", config.getLicenses(LicenseFilter.ALL))).isPresent(); - //try { - mojo.execute(); - // fail("Should have thrown exception"); -// } catch (RatCheckException e) { -// assertThat(e.getMessage()).contains("LICENSE_CATEGORIES, LICENSE_NAMES, STANDARDS exceeded"); -// } + + mojo.execute(); Map data = new HashMap<>(); data.put(ClaimStatistic.Counter.APPROVED, "1"); From 8a182232d9ad7f10c6f84206023d7b9e65f7dab3 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 14:03:03 +0000 Subject: [PATCH 093/123] fixed checkstyle issues --- .../apache/rat/analysis/TikaProcessor.java | 26 +++---------------- .../apache/rat/commandline/Converters.java | 1 - .../config/exclusion/ExclusionProcessor.java | 9 ++++++- .../config/exclusion/StandardCollection.java | 4 +-- 4 files changed, 13 insertions(+), 27 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/analysis/TikaProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/analysis/TikaProcessor.java index 065efcb6d..6991f4924 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/analysis/TikaProcessor.java +++ b/apache-rat-core/src/main/java/org/apache/rat/analysis/TikaProcessor.java @@ -122,28 +122,6 @@ public static InputStream markSupportedInputStream(final InputStream stream) { return stream.markSupported() ? stream : new BufferedInputStream(stream); } - /** - * Extracts the media type properly from zero length files. - * @param stream the InputStream from the file. - * @param documentName the name of the document - * @return the mime type for the document - * @throws IOException on error. - */ - private static String detectMediaType(InputStream stream, DocumentName documentName) throws IOException { - stream.mark(1); - int ch = stream.read(); - stream.reset(); - Metadata metadata = new Metadata(); - String name = documentName.localized(); - if (ch == -1) { - name = name.substring(name.lastIndexOf("/") + 1); - metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, name); - return TIKA.detect(null, metadata); - } - metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, name); - return TIKA.detect(stream, metadata); - } - /** * Process the input document. * @param document the Document to process. @@ -152,7 +130,9 @@ private static String detectMediaType(InputStream stream, DocumentName documentN */ public static String process(final Document document) throws RatDocumentAnalysisException { try (InputStream stream = markSupportedInputStream(document.inputStream())) { - String result = detectMediaType(stream, document.getName()); + Metadata metadata = new Metadata(); + metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, document.getName().getShortName()); + String result = TIKA.detect(stream, metadata); String[] parts = result.split("/"); MediaType mediaType = new MediaType(parts[0], parts[1]); document.getMetaData().setMediaType(mediaType); 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 9e1cf88c2..7375d44b5 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 @@ -21,7 +21,6 @@ import java.io.File; import java.io.IOException; -import java.nio.file.FileSystems; import org.apache.commons.cli.Converter; import org.apache.commons.lang3.tuple.Pair; import org.apache.rat.ConfigurationException; 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 5bdeaa283..62b33cdb3 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 @@ -236,7 +236,14 @@ private List extractFileProcessors(final DocumentName basedir) { return fileProcessorList; } - private String preparePattern(DocumentName documentName, String pattern) { + /** + * Converts the pattern to use the directory separator specified by the document name and localises it for + * exclusion processing. + * @param documentName The document name to adjust the pattern against. + * @param pattern the pattern. + * @return the prepared pattern. + */ + private String preparePattern(final DocumentName documentName, final String pattern) { return ExclusionUtils.localizePattern(documentName, ExclusionUtils.convertSeparator(pattern, "/", documentName.getDirectorySeparator())); } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java index 5921ecaa7..03f364112 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java @@ -103,7 +103,7 @@ null, new CVSIgnoreBuilder()), null, new DocumentNameMatcher("HIDDEN_DIR", new Predicate() { @Override - public boolean test(DocumentName documentName) { + public boolean test(final DocumentName documentName) { File file = documentName.asFile(); return file.isDirectory() && ExclusionUtils.isHidden(documentName.getShortName()); } @@ -120,7 +120,7 @@ public String toString() { null, new DocumentNameMatcher("HIDDEN_FILE", new Predicate() { @Override - public boolean test(DocumentName documentName) { + public boolean test(final DocumentName documentName) { File file = documentName.asFile(); return file.isFile() && ExclusionUtils.isHidden(documentName.getShortName()); } From 68f042545fad0c02afde49b502e609a254000ddf Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 17:55:47 +0000 Subject: [PATCH 094/123] Added detail to decomposition --- .../org/apache/rat/config/exclusion/plexus/MatchPatterns.java | 4 ++++ .../java/org/apache/rat/document/DocumentNameMatcher.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java index de59defe2..9b7bc57f8 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java @@ -56,6 +56,10 @@ public Iterable patterns() { return Arrays.asList(patterns); } + public Iterable patterns() { + return Arrays.asList(patterns); + } + /** *

    Checks these MatchPatterns against a specified string.

    * diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index cc4741fc6..52d1592ec 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -495,7 +495,7 @@ public static final class DecomposeData { private final DocumentNameMatcher matcher; /** The result of the check. */ private final boolean result; - /** The actual candidate. */ + /** The candidate */ private final DocumentName candidate; private DecomposeData(final int level, final DocumentNameMatcher matcher, final DocumentName candidate, final boolean result) { From 96c1613720c7dc4adb52ad6f5b779934e716ffe0 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 19:29:18 +0000 Subject: [PATCH 095/123] used decomposition in more tests --- .../AbstractIgnoreBuilderTest.java | 5 ++-- .../rat/document/DocumentNameBuilderTest.java | 26 ------------------- .../rat/test/AbstractOptionsProvider.java | 1 + 3 files changed, 4 insertions(+), 28 deletions(-) diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java index 4c4f03e8d..0cc39e8e7 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java @@ -24,6 +24,7 @@ import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; +import org.apache.rat.document.DocumentNameMatcherTest; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.condition.EnabledOnOs; @@ -98,11 +99,11 @@ protected void assertCorrect(List matcherSets, DocumentName baseDir, DocumentNameMatcher excluder = MatcherSet.merge(matcherSets).createMatcher(); for (String name : matching) { DocumentName docName = baseDir.resolve(SelectorUtils.extractPattern(name, File.separator)); - assertThat(excluder.matches(docName)).as(docName.getName()).isFalse(); + assertThat(excluder.matches(docName)).as(() -> DocumentNameMatcherTest.processDecompose(excluder, docName)).isFalse(); } for (String name : notMatching) { DocumentName docName = baseDir.resolve(SelectorUtils.extractPattern(name, File.separator)); - assertThat(excluder.matches(docName)).as(docName.getName()).isTrue(); + assertThat(excluder.matches(docName)).as(() -> DocumentNameMatcherTest.processDecompose(excluder, docName)).isTrue(); } } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java index 0531897da..47741fef0 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java @@ -18,44 +18,18 @@ */ package org.apache.rat.document; -import com.google.common.jimfs.Configuration; -import com.google.common.jimfs.Jimfs; import java.io.File; import java.io.IOException; -import java.net.URI; -import java.net.URL; -import java.nio.file.FileAlreadyExistsException; -import java.nio.file.FileStore; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang3.builder.CompareToBuilder; -import org.apache.commons.lang3.builder.EqualsBuilder; -import org.apache.commons.lang3.builder.HashCodeBuilder; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.rat.utils.DefaultLog; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import static java.lang.String.format; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.apache.rat.document.FSInfoTest.OSX; -import static org.apache.rat.document.FSInfoTest.UNIX; import static org.apache.rat.document.FSInfoTest.WINDOWS; 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 51eba706c..eafe04639 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 @@ -33,6 +33,7 @@ import org.apache.rat.config.exclusion.StandardCollection; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.document.DocumentName; +import org.apache.rat.document.DocumentNameMatcherTest; import org.apache.rat.license.ILicense; import org.apache.rat.license.ILicenseFamily; import org.apache.rat.license.LicenseSetFactory; From 9148cfe12ae6570f17afe294e17ff7fa07f59759 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 19:33:03 +0000 Subject: [PATCH 096/123] used decomposition in more tests --- .../main/java/org/apache/rat/document/DocumentNameMatcher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 52d1592ec..cc3b102e1 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -392,7 +392,7 @@ interface CollectionPredicate extends Predicate { } /** - * A marker class to indicate this predicate contains a collection of matchers. + * An implementation of CollectionPredicate. */ abstract static class CollectionPredicateImpl implements CollectionPredicate { /** The collection for matchers that make up this predicate */ From 9484e228e5bfee99745010d09b8f3fb2c51e7be1 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 21:21:10 +0000 Subject: [PATCH 097/123] Added wild logging to find Windows problem --- .../exclusion/plexus/MatchPatterns.java | 6 +- .../exclusion/plexus/SelectorUtils.java | 4 +- .../rat/document/DocumentNameBuilderTest.java | 176 +++--------------- 3 files changed, 29 insertions(+), 157 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java index 9b7bc57f8..0a6703934 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java @@ -56,10 +56,6 @@ public Iterable patterns() { return Arrays.asList(patterns); } - public Iterable patterns() { - return Arrays.asList(patterns); - } - /** *

    Checks these MatchPatterns against a specified string.

    * @@ -91,7 +87,7 @@ public boolean matches(final String name, final char[][] tokenizedNameChar, fina return false; } - public static MatchPatterns from(final String separator, final String separator, final String... sources) { + public static MatchPatterns from(final String separator, final String... sources) { final int length = sources.length; MatchPattern[] result = new MatchPattern[length]; for (int i = 0; i < length; i++) { diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java index 92c53528d..cd79f6322 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java @@ -54,12 +54,13 @@ * . * */ - import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; +import org.apache.rat.utils.DefaultLog; + @SuppressWarnings({"checkstyle:RegexpSingleLine", "checkstyle:JavadocVariable"}) /** *

    This is a utility class used by selectors and DirectoryScanner. The functionality more properly belongs just to @@ -397,6 +398,7 @@ static boolean matchAntPathPattern(final String[] patDirs, final String[] strDir } static boolean matchAntPathPattern(final char[][] patDirs, final char[][] strDirs, final boolean isCaseSensitive) { + DefaultLog.getInstance().warn(String.format("... Comparing against %s", (Object) patDirs)); int patIdxStart = 0; int patIdxEnd = patDirs.length - 1; int strIdxStart = 0; diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java index 47741fef0..a9e2ae385 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/DocumentNameBuilderTest.java @@ -60,237 +60,111 @@ static Stream buildTestData() throws IOException { // String testName = "windows\\foo direct"; - DocumentName documentName = DocumentName.builder(WINDOWS).setName("C:\\\\windows\\foo").setBaseName("C:\\\\windows").build(); - lst.add(Arguments.of( testName, documentName, "C:\\\\windows\\foo", "foo", "C:\\\\windows", "C:\\", "\\", false, + DocumentName documentName = DocumentName.builder(WINDOWS).setName("C:\\windows\\foo").setBaseName("C:\\windows").build(); + lst.add(Arguments.of( testName, documentName, "C:\\windows\\foo", "foo", "C:\\windows", "C:", "\\", false, "\\foo", "/foo")); DocumentName baseName = documentName; // testName = "builder(docName)"; documentName = DocumentName.builder(baseName).build(); - lst.add(Arguments.of( testName, documentName, "C:\\\\windows\\foo", "foo", "C:\\\\windows", "C:\\", "\\", false, + lst.add(Arguments.of( testName, documentName, "C:\\windows\\foo", "foo", "C:\\windows", "C:", "\\", false, "\\foo", "/foo")); // testName = "windows\\foo\\bar by resolve"; documentName = baseName.resolve("bar"); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows\\foo\\bar", "bar", "C:\\windows", "C:", "\\", false, "\\foo\\bar", "/foo/bar")); // testName = "windows\\foo\\direct by basename"; documentName = DocumentName.builder(baseName).setName("windows\\foo\\direct").build(); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\direct", "direct", "C:\\\\windows", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows\\foo\\direct", "direct", "C:\\windows", "C:", "\\", false, "\\foo\\direct", "/foo/direct")); // testName = "windows\\foo\\bar by file"; File file = mock(File.class); File parent = mock(File.class); - when(file.getAbsolutePath()).thenReturn("C:\\\\windows\\foo\\bar"); + when(file.getAbsolutePath()).thenReturn("C:\\windows\\foo\\bar"); when(file.getParentFile()).thenReturn(parent); when(file.isDirectory()).thenReturn(false); - when(parent.getAbsolutePath()).thenReturn("C:\\\\windows\\foo"); + when(parent.getAbsolutePath()).thenReturn("C:\\windows\\foo"); when(parent.isDirectory()).thenReturn(true); documentName = new DocumentName.Builder(WINDOWS, file).build(); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows\\foo", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows\\foo\\bar", "bar", "C:\\windows\\foo", "C:", "\\", false, "\\bar", "/bar")); // testName = "windows\\foo\\bar by directory"; file = mock(File.class); parent = mock(File.class); - when(file.getAbsolutePath()).thenReturn("C:\\\\windows\\foo\\bar"); + when(file.getAbsolutePath()).thenReturn("C:\\windows\\foo\\bar"); when(file.getParentFile()).thenReturn(parent); when(file.isDirectory()).thenReturn(true); - when(parent.getAbsolutePath()).thenReturn("C:\\\\windows\\foo"); + when(parent.getAbsolutePath()).thenReturn("C:\\windows\\foo"); when(parent.isDirectory()).thenReturn(true); documentName = new DocumentName.Builder(WINDOWS, file).build(); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows\\foo\\bar", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows\\foo\\bar", "bar", "C:\\windows\\foo\\bar", "C:", "\\", false, "\\", "/")); // testName = "windows setRoot"; - documentName = DocumentName.builder(baseName).setRoot("D:\\").build(); - lst.add(Arguments.of(testName, documentName, "D:\\\\windows\\foo", "foo", "C:\\\\windows", "D:\\", "\\", false, - "D:\\\\windows\\foo", "D://windows/foo")); + documentName = DocumentName.builder(baseName).setRoot("D:").build(); + lst.add(Arguments.of(testName, documentName, "D:\\windows\\foo", "foo", "C:\\windows", "D:", "\\", false, + "D:\\windows\\foo", "D:/windows/foo")); testName = "windows setRoot(null)"; documentName = DocumentName.builder(baseName).setRoot(null).build(); - lst.add(Arguments.of(testName, documentName, "\\windows\\foo", "foo", "C:\\\\windows", "", "\\", false, + lst.add(Arguments.of(testName, documentName, "\\windows\\foo", "foo", "C:\\windows", "", "\\", false, "\\windows\\foo", "/windows/foo")); testName = "windows setRoot('')"; documentName = DocumentName.builder(baseName).setRoot("").build(); - lst.add(Arguments.of(testName, documentName, "\\windows\\foo", "foo", "C:\\\\windows", "", "\\", false, + lst.add(Arguments.of(testName, documentName, "\\windows\\foo", "foo", "C:\\windows", "", "\\", false, "\\windows\\foo", "/windows/foo")); // testName = "windows setName('baz')"; documentName = DocumentName.builder(baseName).setName("baz").build(); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\baz", "baz", "C:\\\\windows", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows\\baz", "baz", "C:\\windows", "C:", "\\", false, "\\baz", "/baz")); testName = "windows setName((String)null)"; documentName = DocumentName.builder(baseName).setName((String)null).build(); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows", "windows", "C:\\\\windows", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows", "windows", "C:\\windows", "C:", "\\", false, "\\", "/")); testName = "windows setName('')"; documentName = DocumentName.builder(baseName).setName("").build(); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows", "windows", "C:\\\\windows", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows", "windows", "C:\\windows", "C:", "\\", false, "\\", "/")); file = mock(File.class); parent = mock(File.class); - when(file.getAbsolutePath()).thenReturn("C:\\\\windows\\foo\\bar"); + when(file.getAbsolutePath()).thenReturn("C:\\windows\\foo\\bar"); when(file.getParentFile()).thenReturn(parent); when(file.isDirectory()).thenReturn(false); - when(parent.getAbsolutePath()).thenReturn("C:\\\\windows\\foo"); + when(parent.getAbsolutePath()).thenReturn("C:\\windows\\foo"); when(parent.isDirectory()).thenReturn(true); testName = "windows setName(file)"; documentName = DocumentName.builder(baseName).setName(file).build(); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows\\foo", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows\\foo\\bar", "bar", "C:\\windows\\foo", "C:", "\\", false, "\\bar", "/bar")); file = mock(File.class); parent = mock(File.class); - when(file.getAbsolutePath()).thenReturn("C:\\\\windows\\foo\\bar"); + when(file.getAbsolutePath()).thenReturn("C:\\windows\\foo\\bar"); when(file.getParentFile()).thenReturn(parent); when(file.isDirectory()).thenReturn(true); - when(parent.getAbsolutePath()).thenReturn("C:\\\\windows\\foo"); + when(parent.getAbsolutePath()).thenReturn("C:\\windows\\foo"); when(parent.isDirectory()).thenReturn(true); testName = "windows setName(directory)"; documentName = DocumentName.builder(baseName).setName(file).build(); - lst.add(Arguments.of(testName, documentName, "C:\\\\windows\\foo\\bar", "bar", "C:\\\\windows\\foo\\bar", "C:\\", "\\", false, + lst.add(Arguments.of(testName, documentName, "C:\\windows\\foo\\bar", "bar", "C:\\windows\\foo\\bar", "C:", "\\", false, "\\", "/")); return lst.stream(); - - -// -// /** -// * Sets the baseName. -// * Will set the root if it is not set. -// *

    -// * To correctly parse the string it must use the directory separator specified by this builder. -// *

    -// * @param baseName the basename to use. -// * @return this. -// */ -// public DocumentName.Builder setBaseName(final String baseName) { -// DocumentName.Builder builder = DocumentName.builder(fsInfo).setName(baseName); -// builder.sameNameFlag = true; -// setBaseName(builder); -// return this; -// } -// -// /** -// * Sets the basename from the {@link #name} of the specified DocumentName. -// * Will set the root the baseName has the root set. -// * @param baseName the DocumentName to set the basename from. -// * @return this. -// */ -// public DocumentName.Builder setBaseName(final DocumentName baseName) { -// this.baseName = baseName; -// if (!baseName.getRoot().isEmpty()) { -// this.root = baseName.getRoot(); -// } -// return this; -// } -// -// /** -// * Executes the builder, sets the base name and clears the sameName flag. -// * @param builder the builder for the base name. -// */ -// private void setBaseName(DocumentName.Builder builder) { -// this.baseName = builder.build(); -// this.sameNameFlag = false; -// } -// -// /** -// * Sets the basename from a File. Sets {@link #root} and the {@link #baseName} -// * Will set the root. -// * @param file the file to set the base name from. -// * @return this. -// */ -// public DocumentName.Builder setBaseName(final File file) { -// DocumentName.Builder builder = DocumentName.builder(fsInfo).setName(file); -// builder.sameNameFlag = true; -// setBaseName(builder); -// return this; -// } -// -// /** -// * Build a DocumentName from this builder. -// * @return A new DocumentName. -// */ -// public DocumentName build() { -// verify(); -// return new DocumentName(this); -// } - -// -// assertThat(documentName.getName()).isEqualTo("C:\\\\windows\\foo") -// -// -// assertThat(documentName.getRoot()).isEqualTo("C:\\"); -// assertThat(documentName.isCaseSensitive()).isFalse(); -// assertThat(documentName.getShortName()).isEqualTo("foo"); -// assertThat(documentName.localized("/")).isEqualTo("/windows/foo"); -// assertThat(documentName.getBaseName()).isEqualTo("C:\\\\windows"); -// documentName.getBaseDocumentName(); -// documentName.getDirectorySeparator(); -// -// -// public String getName() -// -// -// public String getBaseName() -// -// -// public String getRoot() -// -// -// public DocumentName getBaseDocumentName -// -// public String getDirectorySeparator( -// -// -// public String localized() -// -// public String localized(final String dirSeparator) -// -// -// public String[] tokenize(final String source) { -// // return source.split("\\Q" + fsInfo.dirSeparator() + "\\E"); -// -// -// -// public String getShortName() -// -// public boolean isCaseSensitive() - - -/* - @Override - public int compareTo(final DocumentName other) { - return CompareToBuilder.reflectionCompare(this, other); - } - - @Override - public boolean equals(final Object other) { - return EqualsBuilder.reflectionEquals(this, other); - } - - @Override - public int hashCode() { - return HashCodeBuilder.reflectionHashCode(this); - } - -*/ - } - - } From b1e170e1675c87e74ae402c74f20684bdadcfe87 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 21:22:37 +0000 Subject: [PATCH 098/123] removed excess builds --- .github/workflows/maven.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index b5f7b2ddf..eda2194fe 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -31,12 +31,14 @@ jobs: strategy: matrix: - os: [ubuntu-latest, windows-latest] + #os: [ubuntu-latest, windows-latest] + os: [windows-latest] # RAT-296: disable JDK10 due to # Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target # # Java 17 disabled, because we are running into https://bugs.openjdk.java.net/browse/JDK-8270866 - java: [8, 11, 21] + #java: [8, 11, 21] + java: [8] fail-fast: false runs-on: ${{ matrix.os }} From bbdd9ad82683c5a3463bea135a1aac8560982a7e Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sat, 4 Jan 2025 21:32:16 +0000 Subject: [PATCH 099/123] Added wild logging to find Windows problem --- .../org/apache/rat/config/exclusion/plexus/SelectorUtils.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java index cd79f6322..cddf6a403 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java @@ -56,8 +56,10 @@ */ import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.StringTokenizer; +import java.util.stream.Collectors; import org.apache.rat.utils.DefaultLog; @@ -398,7 +400,7 @@ static boolean matchAntPathPattern(final String[] patDirs, final String[] strDir } static boolean matchAntPathPattern(final char[][] patDirs, final char[][] strDirs, final boolean isCaseSensitive) { - DefaultLog.getInstance().warn(String.format("... Comparing against %s", (Object) patDirs)); + DefaultLog.getInstance().warn(String.format("... Comparing against %s", Arrays.asList(patDirs).stream().map(String::new).collect(Collectors.toList()))); int patIdxStart = 0; int patIdxEnd = patDirs.length - 1; int strIdxStart = 0; From f7bc6e58babae2e98c512e7586c99d2b3773237a Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 14:30:56 +0000 Subject: [PATCH 100/123] debugging for tests --- .../apache/rat/commandline/Converters.java | 2 +- .../config/exclusion/ExclusionProcessor.java | 2 +- .../rat/config/exclusion/ExclusionUtils.java | 2 +- .../rat/config/exclusion/MatcherSet.java | 31 +++++--- .../AbstractFileProcessorBuilder.java | 6 +- .../fileProcessors/CVSIgnoreBuilder.java | 2 +- .../fileProcessors/GitIgnoreBuilder.java | 2 +- .../config/exclusion/FileProcessorTest.java | 3 + .../AbstractIgnoreBuilderTest.java | 27 +++++-- .../fileProcessors/GitIgnoreBuilderTest.java | 70 ++++++++++--------- 10 files changed, 89 insertions(+), 58 deletions(-) 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 7375d44b5..8f5fc1c66 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 @@ -92,7 +92,7 @@ public File apply(final String fileName) throws NullPointerException { // is this a relative file? if (!fileName.startsWith(File.separator)) { // check for a root provided (e.g. C:\\)" - if (!DocumentName.DEFAULT_FSINFO.rootFor(fileName).isPresent()) { + if (!DocumentName.FSInfo.getDefault().rootFor(fileName).isPresent()) { // no root, resolve against workingDirectory file = new File(workingDirectory.resolve(fileName).getName()).getAbsoluteFile(); } 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 62b33cdb3..8e299d05b 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 @@ -244,7 +244,7 @@ private List extractFileProcessors(final DocumentName basedir) { * @return the prepared pattern. */ private String preparePattern(final DocumentName documentName, final String pattern) { - return ExclusionUtils.localizePattern(documentName, + return ExclusionUtils.qualifyPattern(documentName, ExclusionUtils.convertSeparator(pattern, "/", documentName.getDirectorySeparator())); } /** diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java index 8c0b590f2..74305bfad 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionUtils.java @@ -221,7 +221,7 @@ private static void verifyFile(final File file) { * @param pattern the pattern to format. * @return the completely formatted pattern */ - public static String localizePattern(final DocumentName documentName, final String pattern) { + public static String qualifyPattern(final DocumentName documentName, final String pattern) { boolean prefix = pattern.startsWith(NEGATION_PREFIX); String workingPattern = prefix ? pattern.substring(1) : pattern; String normalizedPattern = SelectorUtils.extractPattern(workingPattern, documentName.getDirectorySeparator()); diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java index da6ed194e..f03d641f4 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.function.Consumer; import org.apache.rat.config.exclusion.plexus.MatchPattern; import org.apache.rat.config.exclusion.plexus.MatchPatterns; @@ -92,18 +93,29 @@ public static void segregateList(final Set matching, final Set n public Builder() { } + /** + * Converts a collection names into DocumentNameMatchers that use the {@code fromDocument} directory separator. + * @param dest the consumer to accept the DocumentNameMatcher. + * @param nameFmt the format for the matcher names. Requires '%s' for the {@code fromDocument} localized name. + * @param fromDocument the document that the patterns are associated with. + * @param names the list of patterns. If empty no action is taken. + */ + private void processNames(final Consumer dest, final String nameFmt, final DocumentName fromDocument, final Set names) { + if (!names.isEmpty()) { + String name = String.format(nameFmt, fromDocument.localized("/").substring(1)); + //Stream iter = names.stream().map(s ->ExclusionUtils.convertSeparator(s, "/", fromDocument.getDirectorySeparator())); + dest.accept(new DocumentNameMatcher(name, MatchPatterns.from(fromDocument.getDirectorySeparator(), names), fromDocument.getBaseDocumentName())); + } + } /** * Adds included file names from the specified document. File names are resolved relative to the directory * of the {@code fromDocument}. * @param fromDocument the document the names were read from. - * @param names the names that were read from the document. + * @param names the names that were read from the document. Must be use the separator specified by {@code fromDocument}. * @return this */ public Builder addIncluded(final DocumentName fromDocument, final Set names) { - if (!names.isEmpty()) { - String name = String.format("'included %s'", fromDocument.localized("/").substring(1)); - addIncluded(new DocumentNameMatcher(name, MatchPatterns.from("/", names), fromDocument.getBaseDocumentName())); - } + processNames(this::addIncluded, "'included %s'", fromDocument, names); return this; } @@ -111,14 +123,11 @@ public Builder addIncluded(final DocumentName fromDocument, final Set na * Adds excluded file names from the specified document. File names are resolved relative to the directory * of the {@code fromDocument}. * @param fromDocument the document the names were read from. - * @param names the names that were read from the document. + * @param names the names that were read from the document. Must be use the separator specified by {@code fromDocument}. * @return this */ public Builder addExcluded(final DocumentName fromDocument, final Set names) { - if (!names.isEmpty()) { - String name = String.format("'excluded %s'", fromDocument.localized("/").substring(1)); - addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(fromDocument.getDirectorySeparator(), names), fromDocument.getBaseDocumentName())); - } + processNames(this::addExcluded, "'excluded %s'", fromDocument, names); return this; } @@ -144,7 +153,7 @@ public Builder addExcluded(final DocumentNameMatcher matcher) { } /** - * Builds a MatcherSet. When {@link #build()} is called the builder is reset to the initial state. + * Builds a MatcherSet. When {@code build()} is called the builder is reset to the initial state. * @return the MatcherSet based upon the included and excluded matchers. */ public MatcherSet build() { diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java index f6788f223..4fc22e6aa 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java @@ -121,7 +121,7 @@ private List createMatcherSetList() { public final List build(final DocumentName root) { if (includeProcessorFile) { String name = String.format("**/%s", fileName); - String pattern = ExclusionUtils.localizePattern(root, name); + String pattern = ExclusionUtils.qualifyPattern(root, name); MatcherSet matcherSet = new MatcherSet.Builder() .addExcluded(new DocumentNameMatcher(name, MatchPatterns.from("/", Collections.singletonList(pattern)), root)) .build(); @@ -148,10 +148,10 @@ public final List build(final DocumentName root) { protected MatcherSet process(final Consumer matcherSetConsumer, final DocumentName root, final DocumentName documentName) { final MatcherSet.Builder matcherSetBuilder = new MatcherSet.Builder(); final List iterable = new ArrayList<>(); - ExclusionUtils.asIterator(new File(documentName.getName()), commentFilter) + ExclusionUtils.asIterator(documentName.asFile(), commentFilter) .map(entry -> modifyEntry(matcherSetConsumer, documentName, entry).orElse(null)) .filter(Objects::nonNull) - .map(entry -> ExclusionUtils.localizePattern(documentName, entry)) + .map(entry -> ExclusionUtils.qualifyPattern(documentName, entry)) .forEachRemaining(iterable::add); Set included = new HashSet<>(); diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java index 0f6a7b26d..16bf5f974 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/CVSIgnoreBuilder.java @@ -54,7 +54,7 @@ protected MatcherSet process(final Consumer matcherSetConsumer, fina String[] parts = line.split("\\s+"); for (String part : parts) { if (!part.isEmpty()) { - result.add(ExclusionUtils.localizePattern(documentName, part)); + result.add(ExclusionUtils.qualifyPattern(documentName, part)); } } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java index 6c70fb736..7b67ab53f 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilder.java @@ -89,7 +89,7 @@ protected Optional modifyEntry(final Consumer matcherSetCons DocumentName matcherPattern = DocumentName.builder(documentName).setName(name.replace(SLASH, documentName.getDirectorySeparator())) .build(); DocumentNameMatcher matcher = DocumentNameMatcher.and(new DocumentNameMatcher("isDirectory", File::isDirectory), - new DocumentNameMatcher(name, MatchPatterns.from(matcherPattern.localized(SLASH)))); + new DocumentNameMatcher(name, MatchPatterns.from(matcherPattern.localized(documentName.getDirectorySeparator())))); MatcherSet.Builder builder = new MatcherSet.Builder(); if (prefix) { diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java index 338b34eae..40b6f63c7 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java @@ -18,8 +18,11 @@ */ package org.apache.rat.config.exclusion; +import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Stream; import org.apache.rat.document.DocumentName; import org.apache.rat.document.FSInfoTest; diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java index 0cc39e8e7..68460e78d 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/AbstractIgnoreBuilderTest.java @@ -18,13 +18,15 @@ */ package org.apache.rat.config.exclusion.fileProcessors; +import java.nio.file.Path; import java.util.List; -import org.apache.rat.config.exclusion.ExclusionUtils; +import java.util.stream.Stream; import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.config.exclusion.plexus.SelectorUtils; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.document.DocumentNameMatcherTest; +import org.apache.rat.document.FSInfoTest; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.condition.EnabledOnOs; @@ -35,6 +37,7 @@ import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; +import org.junit.jupiter.params.provider.Arguments; import static org.assertj.core.api.Assertions.assertThat; @@ -45,12 +48,22 @@ public class AbstractIgnoreBuilderTest { @TempDir - protected File baseDir; + protected Path tmpPath; protected DocumentName baseName; @BeforeEach - public void setup() { - baseName = DocumentName.builder(baseDir).build(); + protected void setup() throws IOException { + baseName = DocumentName.builder(tmpPath.toFile()).build(); + } + + protected static Stream fsInfoArgs() { + return FSInfoTest.fsInfoArgs(); + } + + @AfterEach + @EnabledOnOs(OS.WINDOWS) + void reset() { + baseName = null; } /** @@ -71,7 +84,7 @@ void cleanUp() { * @throws IOException if file cannot be created. */ protected File writeFile(String name, Iterable lines) throws IOException { - File file = new File(baseDir, name); + File file = new File(tmpPath.toFile(), name); try (PrintWriter writer = new PrintWriter(new FileWriter(file))) { lines.forEach(writer::println); } @@ -98,11 +111,11 @@ protected void assertCorrect(AbstractFileProcessorBuilder builder, Iterable matcherSets, DocumentName baseDir, Iterable matching, Iterable notMatching) { DocumentNameMatcher excluder = MatcherSet.merge(matcherSets).createMatcher(); for (String name : matching) { - DocumentName docName = baseDir.resolve(SelectorUtils.extractPattern(name, File.separator)); + DocumentName docName = baseDir.resolve(SelectorUtils.extractPattern(name, baseDir.getDirectorySeparator())); assertThat(excluder.matches(docName)).as(() -> DocumentNameMatcherTest.processDecompose(excluder, docName)).isFalse(); } for (String name : notMatching) { - DocumentName docName = baseDir.resolve(SelectorUtils.extractPattern(name, File.separator)); + DocumentName docName = baseDir.resolve(SelectorUtils.extractPattern(name, baseDir.getDirectorySeparator())); assertThat(excluder.matches(docName)).as(() -> DocumentNameMatcherTest.processDecompose(excluder, docName)).isTrue(); } } diff --git a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java index b98c446e7..f3c7fc43e 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/config/exclusion/fileProcessors/GitIgnoreBuilderTest.java @@ -25,15 +25,18 @@ import org.apache.rat.config.exclusion.MatcherSet; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; +import org.apache.rat.document.FSInfoTest; import org.junit.jupiter.api.Test; import java.io.IOException; import java.net.URL; import java.util.Arrays; import java.util.List; +import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; import static org.assertj.core.api.Assertions.assertThat; @@ -41,29 +44,32 @@ public class GitIgnoreBuilderTest extends AbstractIgnoreBuilderTest { @Test public void processExampleFileTest() throws IOException { - String[] lines = { - "# somethings", - "!thingone", "thing*", System.lineSeparator(), - "# some fish", - "**/fish", "*_fish", - "# some colorful directories", - "red/", "blue/*/"}; - - List matches = Arrays.asList("some/things", "some/fish", "another/red_fish"); - - List notMatches = Arrays.asList("some/thingone", "thingone"); - - writeFile(".gitignore", Arrays.asList(lines)); - - assertCorrect(new GitIgnoreBuilder(), matches, notMatches); + try { + String[] lines = { + "# somethings", + "!thingone", "thing*", System.lineSeparator(), + "# some fish", + "**/fish", "*_fish", + "# some colorful directories", + "red/", "blue/*/"}; + List matches = Arrays.asList("some/things", "some/fish", "another/red_fish"); + + List notMatches = Arrays.asList("some/thingone", "thingone"); + + writeFile(".gitignore", Arrays.asList(lines)); + + assertCorrect(new GitIgnoreBuilder(), matches, notMatches); + } finally { + System.getProperties().remove("FSInfo"); + } } // see https://git-scm.com/docs/gitignore @ParameterizedTest @MethodSource("modifyEntryData") - public void modifyEntryTest(String source, String expected) { + public void modifyEntryTest(DocumentName.FSInfo fsInfo, String source, String expected) { GitIgnoreBuilder underTest = new GitIgnoreBuilder(); - DocumentName testName = DocumentName.builder().setName("GitIgnoreBuilderTest").setBaseName("testDir").build(); + DocumentName testName = DocumentName.builder(fsInfo).setName("GitIgnoreBuilderTest").setBaseName("testDir").build(); List matcherSets = new ArrayList<>(); Optional entry = underTest.modifyEntry(matcherSets::add, testName, source); @@ -79,21 +85,21 @@ public void modifyEntryTest(String source, String expected) { private static Stream modifyEntryData() { List lst = new ArrayList<>(); - - lst.add(Arguments.of("\\#filename", "**/#filename")); - - lst.add(Arguments.of("!#filename", "!**/#filename")); - lst.add(Arguments.of("\\#filename", "**/#filename")); - lst.add(Arguments.of("!#filename", "!**/#filename")); - lst.add(Arguments.of("/filename", "filename")); - lst.add(Arguments.of("file/name", "file/name")); - lst.add(Arguments.of("/file/name", "file/name")); - lst.add(Arguments.of("filename", "**/filename")); - lst.add(Arguments.of("filename/", "not(and(isDirectory, **/filename))")); - lst.add(Arguments.of("/filename/", "not(and(isDirectory, filename))")); - // inclusion by itself becomes nothing. - lst.add(Arguments.of("!filename/", "TRUE")); - + for (DocumentName.FSInfo fsInfo : FSInfoTest.TEST_SUITE) { + lst.add(Arguments.of(fsInfo, "\\#filename", "**/#filename")); + + lst.add(Arguments.of(fsInfo, "!#filename", "!**/#filename")); + lst.add(Arguments.of(fsInfo, "\\#filename", "**/#filename")); + lst.add(Arguments.of(fsInfo, "!#filename", "!**/#filename")); + lst.add(Arguments.of(fsInfo, "/filename", "filename")); + lst.add(Arguments.of(fsInfo, "file/name", "file/name")); + lst.add(Arguments.of(fsInfo, "/file/name", "file/name")); + lst.add(Arguments.of(fsInfo, "filename", "**/filename")); + lst.add(Arguments.of(fsInfo, "filename/", "not(and(isDirectory, **/filename))")); + lst.add(Arguments.of(fsInfo, "/filename/", "not(and(isDirectory, filename))")); + // inclusion by itself becomes nothing. + lst.add(Arguments.of(fsInfo, "!filename/", "TRUE")); + } return lst.stream(); } From c32b768c97636641608c901ddc511f37f69b0352 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 15:06:12 +0000 Subject: [PATCH 101/123] debugging for tests --- .../org/apache/rat/config/exclusion/plexus/MatchPattern.java | 1 + 1 file changed, 1 insertion(+) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java index 11b71445d..ea3621a71 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java @@ -67,6 +67,7 @@ public MatchPattern(final String source, final String separator) { for (int i = 0; i < tokenized.length; i++) { tokenizedChar[i] = tokenized[i].toCharArray(); } + DefaultLog.getInstance().warn("MatchPattern( " + source + ", " + separator + ") ... " + this.toString()); } public boolean matchPath(final String str, final boolean isCaseSensitive) { From 51a81d10bbb3caa3f480a44746d6766e51572c76 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 15:32:02 +0000 Subject: [PATCH 102/123] debugging for tests --- .../main/java/org/apache/rat/config/exclusion/MatcherSet.java | 1 - .../org/apache/rat/config/exclusion/plexus/SelectorUtils.java | 1 - 2 files changed, 2 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java index f03d641f4..c1c5b6dac 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -103,7 +103,6 @@ public Builder() { private void processNames(final Consumer dest, final String nameFmt, final DocumentName fromDocument, final Set names) { if (!names.isEmpty()) { String name = String.format(nameFmt, fromDocument.localized("/").substring(1)); - //Stream iter = names.stream().map(s ->ExclusionUtils.convertSeparator(s, "/", fromDocument.getDirectorySeparator())); dest.accept(new DocumentNameMatcher(name, MatchPatterns.from(fromDocument.getDirectorySeparator(), names), fromDocument.getBaseDocumentName())); } } diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java index cddf6a403..b53be7cf1 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java @@ -400,7 +400,6 @@ static boolean matchAntPathPattern(final String[] patDirs, final String[] strDir } static boolean matchAntPathPattern(final char[][] patDirs, final char[][] strDirs, final boolean isCaseSensitive) { - DefaultLog.getInstance().warn(String.format("... Comparing against %s", Arrays.asList(patDirs).stream().map(String::new).collect(Collectors.toList()))); int patIdxStart = 0; int patIdxEnd = patDirs.length - 1; int strIdxStart = 0; From d1fd7b2c1c83ffde101a2a8e955e524e781e8e12 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 15:36:28 +0000 Subject: [PATCH 103/123] removed unused imports --- .../org/apache/rat/config/exclusion/plexus/SelectorUtils.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java index b53be7cf1..923950f24 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/SelectorUtils.java @@ -56,12 +56,8 @@ */ import java.io.File; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.StringTokenizer; -import java.util.stream.Collectors; - -import org.apache.rat.utils.DefaultLog; @SuppressWarnings({"checkstyle:RegexpSingleLine", "checkstyle:JavadocVariable"}) /** From 401628c2b8fe6d0dfe0bcf9f9f6309632295fcb8 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 15:48:04 +0000 Subject: [PATCH 104/123] possible fix --- .../exclusion/fileProcessors/AbstractFileProcessorBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java index 4fc22e6aa..9e6b1a8ac 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileProcessors/AbstractFileProcessorBuilder.java @@ -123,7 +123,7 @@ public final List build(final DocumentName root) { String name = String.format("**/%s", fileName); String pattern = ExclusionUtils.qualifyPattern(root, name); MatcherSet matcherSet = new MatcherSet.Builder() - .addExcluded(new DocumentNameMatcher(name, MatchPatterns.from("/", Collections.singletonList(pattern)), root)) + .addExcluded(new DocumentNameMatcher(name, MatchPatterns.from(root.getDirectorySeparator(), Collections.singletonList(pattern)), root)) .build(); LevelBuilder levelBuilder = levelBuilders.computeIfAbsent(0, k -> new LevelBuilder()); levelBuilder.add(matcherSet); From cbc9e30e90e83e5bbab34c5f0d2b58015ecf9147 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 16:08:16 +0000 Subject: [PATCH 105/123] debugging for tests --- .../org/apache/rat/config/exclusion/plexus/MatchPattern.java | 1 - .../src/test/java/org/apache/rat/commandline/ArgTests.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java index ea3621a71..11b71445d 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPattern.java @@ -67,7 +67,6 @@ public MatchPattern(final String source, final String separator) { for (int i = 0; i < tokenized.length; i++) { tokenizedChar[i] = tokenized[i].toCharArray(); } - DefaultLog.getInstance().warn("MatchPattern( " + source + ", " + separator + ") ... " + this.toString()); } public boolean matchPath(final String str, final boolean isCaseSensitive) { diff --git a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java index 484f8a632..77148c18b 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java +++ b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java @@ -41,7 +41,7 @@ private CommandLine createCommandLine(String[] args) throws ParseException { .setAllowPartialMatching(true).build().parse(opts, args); } - @ParameterizedTest + @ParameterizedTest(name = "{0}") @ValueSource(strings = { "rat.txt", "./rat.txt", "/rat.txt", "target/rat.test" }) public void outputFleNameNoDirectoryTest(String name) throws ParseException, IOException { class OutputFileConfig extends ReportConfiguration { From 6b6aa38210ba95a547b5280c519649cd65a5f3cd Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 21:46:04 +0000 Subject: [PATCH 106/123] debugging for tests --- .../src/test/java/org/apache/rat/commandline/ArgTests.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java index 77148c18b..7f27cb8d1 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java +++ b/apache-rat-core/src/test/java/org/apache/rat/commandline/ArgTests.java @@ -26,6 +26,7 @@ import org.apache.rat.DeprecationReporter; import org.apache.rat.OptionCollection; import org.apache.rat.ReportConfiguration; +import org.apache.rat.document.DocumentName; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -51,10 +52,10 @@ public void setOut(File file) { actual = file; } } + String fileName = name.replace("/", DocumentName.FSInfo.getDefault().dirSeparator()); + File expected = new File(fileName); - File expected = new File(name); - - CommandLine commandLine = createCommandLine(new String[] {"--output-file", name}); + CommandLine commandLine = createCommandLine(new String[] {"--output-file", fileName}); OutputFileConfig configuration = new OutputFileConfig(); ArgumentContext ctxt = new ArgumentContext(new File("."), configuration, commandLine); Arg.processArgs(ctxt); From 1e06dae7f44e427318f40827b07b323a22b1b4d7 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 5 Jan 2025 21:51:47 +0000 Subject: [PATCH 107/123] put full testing back --- .github/workflows/maven.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index eda2194fe..b5f7b2ddf 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -31,14 +31,12 @@ jobs: strategy: matrix: - #os: [ubuntu-latest, windows-latest] - os: [windows-latest] + os: [ubuntu-latest, windows-latest] # RAT-296: disable JDK10 due to # Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target # # Java 17 disabled, because we are running into https://bugs.openjdk.java.net/browse/JDK-8270866 - #java: [8, 11, 21] - java: [8] + java: [8, 11, 21] fail-fast: false runs-on: ${{ matrix.os }} From d69d544de244a265b66ce029c2d8db0cb9523197 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Tue, 7 Jan 2025 15:17:52 +0000 Subject: [PATCH 108/123] Fix for windows bug --- .../test/java/org/apache/rat/mp/RatCheckMojoTest.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java index a260bca3e..533cdaff8 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java @@ -51,6 +51,8 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.io.TempDir; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NodeList; @@ -58,7 +60,7 @@ /** * Test case for the {@link RatCheckMojo} and {@link RatReportMojo}. */ -public class RatCheckMojoTest { //extends BetterAbstractMojoTestCase { +public class RatCheckMojoTest { @TempDir static Path tempDir; @@ -70,6 +72,11 @@ static void preserveData() { AbstractOptionsProvider.preserveData(tempDir.toFile(), "unit"); } + @AfterAll + @EnabledOnOs(OS.WINDOWS) + static void cleanup() { + System.gc(); // hacky workaround for windows bug. + } private RatCheckMojo getMojo(File pomFile) throws IOException { try { From b8b53db8d515cd956eadf783f808092ea0345bbb Mon Sep 17 00:00:00 2001 From: "P. Ottlinger" Date: Mon, 6 Jan 2025 17:44:40 +0100 Subject: [PATCH 109/123] Minor cleanup --- .../config/exclusion/ExclusionProcessor.java | 4 +--- .../apache/rat/config/exclusion/MatcherSet.java | 17 ++++++++--------- 2 files changed, 9 insertions(+), 12 deletions(-) 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 8e299d05b..d6c0f81e5 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 @@ -26,7 +26,6 @@ import java.util.TreeSet; import java.util.stream.Collectors; -import org.apache.rat.config.exclusion.plexus.MatchPatterns; import org.apache.rat.document.DocumentName; import org.apache.rat.document.DocumentNameMatcher; import org.apache.rat.utils.DefaultLog; @@ -249,7 +248,7 @@ private String preparePattern(final DocumentName documentName, final String patt } /** * Extracts {@link #includedPatterns} and {@link #excludedPatterns} into the specified matcherBuilder. - * @param nameBuilder The name builder for the pattern. File names are resolved against the generated name. + * @param nameBuilder The name builder for the pattern. File names are resolved against the generated name. * @param matcherBuilder the MatcherSet.Builder to add the patterns to. */ private void extractPatterns(final DocumentName.Builder nameBuilder, final MatcherSet.Builder matcherBuilder) { @@ -309,7 +308,6 @@ private void extractCollectionMatchers(final MatcherSet.Builder matcherBuilder) .map(StandardCollection::staticDocumentNameMatcher) .filter(Objects::nonNull) .forEachRemaining(matcherBuilder::addExcluded); - } /** diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java index c1c5b6dac..181b05569 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/MatcherSet.java @@ -46,7 +46,7 @@ default String getDescription() { return String.format("MatcherSet: include [%s] exclude [%s]", includes().orElse(MATCHES_NONE), excludes().orElse(MATCHES_NONE)); } /** - * Creates a DocumentNameMatcher from an iterable of MatcherSets. + * Creates a DocumentNameMatcher from an iterable of matcher sets. * @return A DocumentNameMatcher that processes the matcher sets. */ default DocumentNameMatcher createMatcher() { @@ -64,7 +64,7 @@ static MatcherSet merge(List matcherSets) { /** * A MatcherSet that assumes the files contain the already formatted strings and just need to be - * localized for the fileName. When {@link #build()} is called the builder is reset to the initial state. + * localized for the fileName. When {@link #build()} is called the builder is reset to the initial state. */ class Builder { @@ -98,7 +98,7 @@ public Builder() { * @param dest the consumer to accept the DocumentNameMatcher. * @param nameFmt the format for the matcher names. Requires '%s' for the {@code fromDocument} localized name. * @param fromDocument the document that the patterns are associated with. - * @param names the list of patterns. If empty no action is taken. + * @param names the list of patterns. If empty no action is taken. */ private void processNames(final Consumer dest, final String nameFmt, final DocumentName fromDocument, final Set names) { if (!names.isEmpty()) { @@ -107,10 +107,10 @@ private void processNames(final Consumer dest, final String } } /** - * Adds included file names from the specified document. File names are resolved relative to the directory + * Adds included file names from the specified document. File names are resolved relative to the directory * of the {@code fromDocument}. * @param fromDocument the document the names were read from. - * @param names the names that were read from the document. Must be use the separator specified by {@code fromDocument}. + * @param names the names that were read from the document. Must be use the separator specified by {@code fromDocument}. * @return this */ public Builder addIncluded(final DocumentName fromDocument, final Set names) { @@ -119,10 +119,10 @@ public Builder addIncluded(final DocumentName fromDocument, final Set na } /** - * Adds excluded file names from the specified document. File names are resolved relative to the directory + * Adds excluded file names from the specified document. File names are resolved relative to the directory * of the {@code fromDocument}. * @param fromDocument the document the names were read from. - * @param names the names that were read from the document. Must be use the separator specified by {@code fromDocument}. + * @param names the names that were read from the document. Must be use the separator specified by {@code fromDocument}. * @return this */ public Builder addExcluded(final DocumentName fromDocument, final Set names) { @@ -130,7 +130,6 @@ public Builder addExcluded(final DocumentName fromDocument, final Set na return this; } - /** * Adds specified DocumentNameMatcher to the included matchers. * @param matcher A document name matcher to add to the included set. @@ -152,7 +151,7 @@ public Builder addExcluded(final DocumentNameMatcher matcher) { } /** - * Builds a MatcherSet. When {@code build()} is called the builder is reset to the initial state. + * Builds a MatcherSet. When {@code build()} is called the builder is reset to the initial state. * @return the MatcherSet based upon the included and excluded matchers. */ public MatcherSet build() { From c2fcdefc1f2c16ce47c679c93afd7a53c67cff78 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Tue, 7 Jan 2025 15:52:28 +0000 Subject: [PATCH 110/123] removed dead lines / updated javadoc --- .../ReportTest/RAT_335/verify.groovy | 65 ------------------- .../config/exclusion/StandardCollection.java | 2 +- 2 files changed, 1 insertion(+), 66 deletions(-) diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy index d660f59fd..e3917feeb 100644 --- a/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy +++ b/apache-rat-core/src/it/resources/ReportTest/RAT_335/verify.groovy @@ -36,74 +36,9 @@ private static Map mapOf(String... parts) { output = new File(args[0]) content = output.text -//Map data = new HashMap<>() -//data.put(ClaimStatistic.Counter.APPROVED, "2") -//data.put(ClaimStatistic.Counter.ARCHIVES, "0") -//data.put(ClaimStatistic.Counter.BINARIES, "0") -//data.put(ClaimStatistic.Counter.DOCUMENT_TYPES, "3") -//data.put(ClaimStatistic.Counter.IGNORED, "6") -//data.put(ClaimStatistic.Counter.LICENSE_CATEGORIES, "2") -//data.put(ClaimStatistic.Counter.LICENSE_NAMES, "2") -//data.put(ClaimStatistic.Counter.NOTICES, "1") -//data.put(ClaimStatistic.Counter.STANDARDS, "6") -//data.put(ClaimStatistic.Counter.UNAPPROVED, "4") -//data.put(ClaimStatistic.Counter.UNKNOWN, "4") - Document document = XmlUtils.toDom(new FileInputStream(args[0])) XPath xPath = XPathFactory.newInstance().newXPath() -//for (ClaimStatistic.Counter counter : ClaimStatistic.Counter.values()) { -// String xpath = String.format("/rat-report/statistics/statistic[@name='%s']", counter.displayName()) -// Map map = mapOf("approval", -// counter == ClaimStatistic.Counter.UNAPPROVED ? "false" : "true", -// "count", data.get(counter), -// "description", counter.getDescription()) -// XmlUtils.assertAttributes(document, xPath, xpath, map) -//} - -//// license categories -//XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseCategory[@name='?????']", -// mapOf("count", "4" )) -// -//XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseCategory[@name='AL ']", -// mapOf("count", "2" )) -// -//// license names -//XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseName[@name='Apache License Version 2.0']", -// mapOf("count", "2" )) -// -//XmlUtils.assertAttributes(document, xPath, "/rat-report/statistics/licenseName[@name='Unknown license']", -// mapOf("count", "4" )) - - - -//Note the output when running in the real commandline version of git -// -//# Files that must be ignored (dropping the gitignore matches outside of this test tree) -//$ git check-ignore --no-index --verbose $(find . -type f|sort) -// -// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore:2:!dir1.md ./dir1/dir1.md -// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore:1:*.txt ./dir1/dir1.txt -// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/dir1/.gitignore:3:file1.log ./dir1/file1.log -// .gitignore:20:**/.gitignore ./dir1/.gitignore -// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore:1:*.md ./dir2/dir2.md -// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore:4:*.log ./dir3/dir3.log -// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore:7:!file*.log ./dir3/file3.log -// .gitignore:20:**/.gitignore ./.gitignore -// apache-rat-core/src/it/resources/ReportTest/RAT_335/src/.gitignore:1:*.md ./root.md - -/* list of excluded files: - -./dir1/dir1.txt -./dir1/file1.log -./dir1/.gitignore -./dir2/dir2.md -./dir3/dir3.log -./.gitignore -./root.md - - */ - List ignoredFiles = new ArrayList<>(Arrays.asList( "/dir1/dir1.txt", "/dir1/.gitignore", diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java index 03f364112..08bc3ec6d 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/StandardCollection.java @@ -214,7 +214,7 @@ public String toString() { private final Collection patterns; /** A document name matcher supplier to create a document name matcher. May be null */ private final DocumentNameMatcher staticDocumentNameMatcher; - /** The MatcherSet to process the exclude file associated with this exclusion. May be null. */ + /** The AbstractFileProcessorBuilder to process the exclude file associated with this exclusion. May be null. */ private final AbstractFileProcessorBuilder fileProcessorBuilder; /** The description of this collection */ private final String desc; From 10a9460fb01f64459c7ad54dcb18a49c352becc8 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Mon, 13 Jan 2025 23:24:31 +0000 Subject: [PATCH 111/123] fixed rebase errors --- .../test/java/org/apache/rat/ReportConfigurationTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 581d474b5..3de2faa5a 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 @@ -88,13 +88,13 @@ public void cleanup() { public void testAddIncludedFilter() { DocumentName dirName = DocumentName.builder(tempDir).build(); underTest.addExcludedFilter(DirectoryFileFilter.INSTANCE); - DocumentNameMatcher matcher = underTest.getDocumentExcluder(dirName); + DocumentNameMatcher excluder = underTest.getDocumentExcluder(dirName); - assertThat(matcher.toString()).isEqualTo("not(DirectoryFileFilter)"); - assertThat(matcher.matches(DocumentName.builder(tempDir).build())).isFalse(); + assertThat(excluder.toString()).isEqualTo("not(DirectoryFileFilter)"); + assertThat(excluder.matches(DocumentName.builder(tempDir).build())).isFalse(); File f = new File(tempDir, "foo.txt"); - assertThat(exlcuder.matches(DocumentName.builder(f).build())).isTrue(); + assertThat(excluder.matches(DocumentName.builder(f).build())).isTrue(); } @Test From 67b615fc51da852257722e162761e21385390449 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Mon, 27 Jan 2025 17:18:56 +0000 Subject: [PATCH 112/123] removed MatcherPredicate and inlined the code to make it easier to read --- .../rat/document/DocumentNameMatcher.java | 35 +++++++------------ 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index cc3b102e1..c6a427c6c 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -301,7 +301,19 @@ public static DocumentNameMatcher matcherSet(final DocumentNameMatcher includes, return MATCHES_ALL; } List workingSet = Arrays.asList(includes, excludes); - return new DocumentNameMatcher(format("matcherSet(%s)", join(workingSet)), new MatcherPredicate(workingSet)); + return new DocumentNameMatcher(format("matcherSet(%s)", join(workingSet)), + new CollectionPredicateImpl(Arrays.asList(includes, excludes)) { + @Override + public boolean test(final DocumentName documentName) { + if (includes.matches(documentName)) { + return true; + } + if (excludes.matches(documentName)) { + return false; + } + return true; + } + }); } /** @@ -464,27 +476,6 @@ public boolean test(final DocumentName documentName) { } } - /** - * An implementation of "or" logic across a collection of DocumentNameMatchers. - */ - // package private for testing access - static class MatcherPredicate extends CollectionPredicateImpl { - MatcherPredicate(final Iterable matchers) { - super(matchers); - } - - @Override - public boolean test(final DocumentName documentName) { - Iterator iter = getMatchers().iterator(); - // included - if (iter.next().matches(documentName)) { - return true; - } - // excluded - return !iter.next().matches(documentName); - } - } - /** * Data from a {@link DocumentNameMatcher#decompose(DocumentName)} call. */ From 6aee0aaf63de0c73c9af8795c6e7a33757a11c6f Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Mon, 13 Jan 2025 22:46:12 +0000 Subject: [PATCH 113/123] added working directory --- .../apache/rat/config/exclusion/plexus/MatchPatterns.java | 5 +---- .../src/test/java/org/apache/rat/mp/OptionMojoTest.java | 1 - .../test/java/org/apache/rat/anttasks/ReportOptionTest.java | 1 - 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java index 0a6703934..06c4672d6 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java +++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/plexus/MatchPatterns.java @@ -42,10 +42,7 @@ private MatchPatterns(final MatchPattern[] patterns) { @Override public String toString() { - return Arrays.stream(patterns) - .map(MatchPattern::toString) - .collect(Collectors.toList()) - .toString(); + return Arrays.stream(patterns).map(MatchPattern::toString).collect(Collectors.toList()).toString(); } public String source() { diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java index 5f5eceb67..cee3d92c5 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java @@ -32,7 +32,6 @@ import org.apache.rat.utils.DefaultLog; import org.codehaus.plexus.component.configurator.ComponentConfigurationException; import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.condition.EnabledOnOs; diff --git a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java index 5e6dc8892..258e8af86 100644 --- a/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java +++ b/apache-rat-tasks/src/test/java/org/apache/rat/anttasks/ReportOptionTest.java @@ -28,7 +28,6 @@ import org.apache.rat.utils.DefaultLog; import org.apache.rat.utils.Log; import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsProvider; From 3ff0436affa819f39d6d00c06a0882d705324a00 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Tue, 14 Jan 2025 17:50:37 +0000 Subject: [PATCH 114/123] fix for file delete on windows --- .../src/test/java/org/apache/rat/mp/OptionMojoTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java index cee3d92c5..5f5eceb67 100644 --- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java +++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/OptionMojoTest.java @@ -32,6 +32,7 @@ import org.apache.rat.utils.DefaultLog; import org.codehaus.plexus.component.configurator.ComponentConfigurationException; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.condition.EnabledOnOs; From c2088ee88ca9eccd7adedbc15f4b28de2327f642 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Sun, 12 Jan 2025 17:34:34 +0000 Subject: [PATCH 115/123] attempt to fix windows error --- .../test/java/org/apache/rat/walker/FileListWalkerTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java b/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java index ec739f643..6b69bb5c1 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java @@ -114,7 +114,8 @@ public static void setUp() throws Exception { @Test public void readFilesTest() throws RatException { - FileListWalker walker = new FileListWalker(new FileDocument(source, DocumentNameMatcher.MATCHES_ALL)); + FileDocument fileDocument = new FileDocument(source, DocumentNameMatcher.MATCHES_ALL); + FileListWalker walker = new FileListWalker(fileDocument); List scanned = new ArrayList<>(); walker.run(new TestRatReport(scanned)); String[] expected = {regularName.localized("/"), hiddenName.localized("/"), From 1ee90bad980bc93dc57879d9572bb0347f777e3a Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Mon, 13 Jan 2025 23:43:39 +0000 Subject: [PATCH 116/123] fixed pattern match --- .../main/java/org/apache/rat/document/DocumentNameMatcher.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index c6a427c6c..43e4e1e33 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -196,7 +196,8 @@ public static DocumentNameMatcher not(final DocumentNameMatcher nameMatcher) { return MATCHES_ALL; } - return new DocumentNameMatcher(format("not(%s)", nameMatcher), new NotPredicate(nameMatcher)); + return new DocumentNameMatcher(format("not(%s)", nameMatcher), + (Predicate) documentName -> !nameMatcher.matches(documentName)); } /** From e157dc589d694b50a1a07be346069623d443e2d0 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Thu, 16 Jan 2025 14:30:01 +0000 Subject: [PATCH 117/123] fixes file list walker --- .../test/java/org/apache/rat/walker/FileListWalkerTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java b/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java index 6b69bb5c1..ec739f643 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/walker/FileListWalkerTest.java @@ -114,8 +114,7 @@ public static void setUp() throws Exception { @Test public void readFilesTest() throws RatException { - FileDocument fileDocument = new FileDocument(source, DocumentNameMatcher.MATCHES_ALL); - FileListWalker walker = new FileListWalker(fileDocument); + FileListWalker walker = new FileListWalker(new FileDocument(source, DocumentNameMatcher.MATCHES_ALL)); List scanned = new ArrayList<>(); walker.run(new TestRatReport(scanned)); String[] expected = {regularName.localized("/"), hiddenName.localized("/"), From 7d0c64302419885023d8de6ea5097182d45c1d49 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Thu, 23 Jan 2025 15:59:11 +0000 Subject: [PATCH 118/123] implemented matcher set in ExclusionProcessor --- .../rat/config/exclusion/ExclusionProcessor.java | 16 ---------------- 1 file changed, 16 deletions(-) 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 d6c0f81e5..6c347ad57 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 @@ -171,22 +171,6 @@ public ExclusionProcessor addExcludedCollection(final StandardCollection collect return this; } - /** - * Adds to lists of qualified file patterns. Non-matching patterns start with a {@code !}. - * @param matching the list to put matching file patterns into. - * @param notMatching the list to put non-matching files patterns into. - * @param patterns the patterns to match. - */ - private void segregateList(final Set matching, final Set notMatching, - final Iterable patterns) { - if (patterns.iterator().hasNext()) { - ExtendedIterator.create(patterns.iterator()).filter(ExclusionUtils.MATCH_FILTER).forEachRemaining(matching::add); - ExtendedIterator.create(patterns.iterator()).filter(ExclusionUtils.NOT_MATCH_FILTER) - .map(s -> s.substring(1)) - .forEachRemaining(notMatching::add); - } - } - /** * Creates a Document name matcher that will return {@code false} on any * document that is excluded. From 483472857e2abd456fa37bc5aca10725a25eeebd Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Tue, 28 Jan 2025 08:34:50 +0000 Subject: [PATCH 119/123] fixed NoteGuesserTest --- .../java/org/apache/rat/document/guesser/NoteGuesserTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java b/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java index a4a2d9976..b175b82df 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/document/guesser/NoteGuesserTest.java @@ -19,7 +19,6 @@ package org.apache.rat.document.guesser; import java.io.IOException; -import java.nio.file.FileSystem; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; From 3364d2018d9937a2b93c79db45bdd7d4402fc026 Mon Sep 17 00:00:00 2001 From: "P. Ottlinger" Date: Tue, 14 Jan 2025 22:57:55 +0100 Subject: [PATCH 120/123] Minor cleanups --- .../rat/test/AbstractOptionsProvider.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) 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 eafe04639..684b7d26e 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 @@ -283,7 +283,7 @@ private void execExcludeTest(final Option option, final String[] args) { } } - private void excludeFileTest(Option option) { + private void excludeFileTest(final Option option) { File outputFile = writeFile("exclude.txt", Arrays.asList(EXCLUDE_ARGS)); execExcludeTest(option, new String[]{outputFile.getAbsolutePath()}); } @@ -388,7 +388,7 @@ private void inputExcludeSizeTest() { } // include tests - private void execIncludeTest(Option option, String[] args) { + private void execIncludeTest(final Option option, final String[] args) { Option excludeOption = Arg.EXCLUDE.option(); String[] notExcluded = {"B.bar", "justbaz", "notbaz"}; String[] excluded = {"some.foo"}; @@ -409,7 +409,7 @@ private void execIncludeTest(Option option, String[] args) { } } - private void includeFileTest(Option option) { + private void includeFileTest(final Option option) { File outputFile = writeFile("include.txt", Arrays.asList(INCLUDE_ARGS)); execIncludeTest(option, new String[]{outputFile.getAbsolutePath()}); } @@ -464,7 +464,7 @@ protected void inputSourceTest() { } // LICENSE tests - protected void execLicensesApprovedTest(Option option, String[] args) { + protected void execLicensesApprovedTest(final Option option, String[] args) { Pair arg1 = ImmutablePair.of(option, args); try { ReportConfiguration config = generateConfig(arg1); @@ -516,7 +516,7 @@ protected void licensesApprovedTest() { new String[]{"one", "two"}); } - private void execLicensesDeniedTest(Option option, String[] args) { + private void execLicensesDeniedTest(final Option option, final String[] args) { try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); assertThat(config.getLicenseIds(LicenseSetFactory.LicenseFilter.ALL)).contains("ILLUMOS"); @@ -537,7 +537,7 @@ protected void licensesDeniedFileTest() { new String[]{outputFile.getAbsolutePath()}); } - private void execLicenseFamiliesApprovedTest(Option option, String[] args) { + private void execLicenseFamiliesApprovedTest(final Option option, final String[] args) { String catz = ILicenseFamily.makeCategory("catz"); Pair arg1 = ImmutablePair.of(option, args); try { @@ -569,7 +569,7 @@ protected void licenseFamiliesApprovedTest() { new String[]{"catz"}); } - private void execLicenseFamiliesDeniedTest(Option option, String[] args) { + private void execLicenseFamiliesDeniedTest(final Option option, final String[] args) { String gpl = ILicenseFamily.makeCategory("GPL"); try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, args)); @@ -636,7 +636,7 @@ protected void counterMinTest() { } } - private void configTest(Option option) { + private void configTest(final Option option) { String[] args = {"src/test/resources/OptionTools/One.xml", "src/test/resources/OptionTools/Two.xml"}; Pair arg1 = ImmutablePair.of(option, args); try { @@ -666,7 +666,7 @@ protected void configTest() { configTest(Arg.CONFIGURATION.find("config")); } - private void noDefaultsTest(Option arg) { + private void noDefaultsTest(final Option arg) { try { ReportConfiguration config = generateConfig(ImmutablePair.of(arg, null)); assertThat(config.getLicenses(LicenseSetFactory.LicenseFilter.ALL)).isEmpty(); @@ -696,7 +696,7 @@ protected void dryRunTest() { } } - private void editCopyrightTest(Option option) { + private void editCopyrightTest(final Option option) { try { Pair arg1 = ImmutablePair.of(option, new String[]{"MyCopyright"}); ReportConfiguration config = generateConfig(arg1); @@ -717,7 +717,7 @@ protected void editCopyrightTest() { editCopyrightTest(Arg.EDIT_COPYRIGHT.find("edit-copyright")); } - private void editLicenseTest(Option option) { + private void editLicenseTest(final Option option) { try { ReportConfiguration config = generateConfig(ImmutablePair.of(option, null)); assertThat(config.isAddingLicenses()).isTrue(); @@ -736,7 +736,7 @@ protected void editLicensesTest() { editLicenseTest(Arg.EDIT_ADD.find("edit-license")); } - private void overwriteTest(Option option) { + private void overwriteTest(final Option option) { Pair arg1 = ImmutablePair.of(option, null); try { ReportConfiguration config = generateConfig(arg1); @@ -777,7 +777,7 @@ protected void logLevelTest() { } } - private void archiveTest(Option option) { + private void archiveTest(final Option option) { String[] args = {null}; try { for (ReportConfiguration.Processing proc : ReportConfiguration.Processing.values()) { @@ -794,7 +794,7 @@ protected void outputArchiveTest() { archiveTest(Arg.OUTPUT_ARCHIVE.find("output-archive")); } - private void listFamilies(Option option) { + private void listFamilies(final Option option) { String[] args = {null}; for (LicenseSetFactory.LicenseFilter filter : LicenseSetFactory.LicenseFilter.values()) { try { @@ -815,7 +815,7 @@ protected void outputFamiliesTest() { listFamilies(Arg.OUTPUT_FAMILIES.find("output-families")); } - private void outTest(Option option) { + private void outTest(final Option option) { File outFile = new File(baseDir, "outexample-" + option.getLongOpt()); String[] args = new String[]{outFile.getAbsolutePath()}; try { @@ -843,7 +843,7 @@ protected void outputFileTest() { outTest(Arg.OUTPUT_FILE.find("output-file")); } - private void listLicenses(Option option) { + private void listLicenses(final Option option) { String[] args = {null}; for (LicenseSetFactory.LicenseFilter filter : LicenseSetFactory.LicenseFilter.values()) { try { @@ -864,7 +864,7 @@ protected void outputLicensesTest() { listLicenses(Arg.OUTPUT_LICENSES.find("output-licenses")); } - private void standardTest(Option option) { + private void standardTest(final Option option) { String[] args = {null}; try { for (ReportConfiguration.Processing proc : ReportConfiguration.Processing.values()) { @@ -881,7 +881,7 @@ protected void outputStandardTest() { standardTest(Arg.OUTPUT_STANDARD.find("output-standard")); } - private void styleSheetTest(Option option) { + 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()); try ( @@ -938,7 +938,7 @@ protected void xmlTest() { } @Override - final public Stream provideArguments(ExtensionContext context) { + final public Stream provideArguments(final ExtensionContext context) { List lst = new ArrayList<>(); List missingTests = new ArrayList<>(); From 3e7d699a086bee8cf2f17a8f9ad393834a669d43 Mon Sep 17 00:00:00 2001 From: "P. Ottlinger" Date: Tue, 14 Jan 2025 23:36:38 +0100 Subject: [PATCH 121/123] Minor fixes --- .../java/org/apache/rat/document/DocumentNameMatcher.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java index 43e4e1e33..d19671240 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentNameMatcher.java @@ -196,8 +196,7 @@ public static DocumentNameMatcher not(final DocumentNameMatcher nameMatcher) { return MATCHES_ALL; } - return new DocumentNameMatcher(format("not(%s)", nameMatcher), - (Predicate) documentName -> !nameMatcher.matches(documentName)); + return new DocumentNameMatcher(format("not(%s)", nameMatcher), new NotPredicate(nameMatcher)); } /** @@ -403,9 +402,8 @@ public String toString() { interface CollectionPredicate extends Predicate { Iterable getMatchers(); } - /** - * An implementation of CollectionPredicate. + * CollectionPredicate implementation. */ abstract static class CollectionPredicateImpl implements CollectionPredicate { /** The collection for matchers that make up this predicate */ From 3e50462e1abb158e4fbe9ae9fd85dcf97f4e7921 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Mon, 3 Feb 2025 10:18:55 +0000 Subject: [PATCH 122/123] fixed javadoc --- .../src/main/java/org/apache/rat/document/DocumentName.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java index e2df0dbb4..04f52e1d2 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java @@ -258,7 +258,7 @@ public String getDirectorySeparator() { /** * Determines if the candidate starts with the root or separator strings. - * @param candidate the candidate ot check. If blank method will return {@code false}. + * @param candidate the candidate to check. If blank method will return {@code false}. * @param root the root to check. If blank the root check is skipped. * @param separator the separator to check. If blank the check is skipped. * @return true if either the root or separator check returned {@code true}. From ec474c3a80808c27e842deabf5e3c3ca4822d124 Mon Sep 17 00:00:00 2001 From: Claude Warren Date: Tue, 4 Feb 2025 00:12:46 +0000 Subject: [PATCH 123/123] fixed rebase issues --- .../org/apache/rat/document/DocumentName.java | 4 +- .../config/exclusion/FileProcessorTest.java | 80 ------------------- 2 files changed, 2 insertions(+), 82 deletions(-) delete mode 100644 apache-rat-core/src/test/java/org/apache/rat/config/exclusion/FileProcessorTest.java diff --git a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java index 04f52e1d2..e074e1c75 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java +++ b/apache-rat-core/src/main/java/org/apache/rat/document/DocumentName.java @@ -199,9 +199,9 @@ public DocumentName resolve(final String child) { return new Builder(this).setName(normalize(pattern)).build(); } - private String normalize(String pattern) { + private String normalize(final String pattern) { List parts = new ArrayList<>(Arrays.asList(tokenize(pattern))); - for (int i=0; i localizePatternData() throws IOException { - List lst = new ArrayList<>(); - Map patterns = new HashMap<>(); - patterns.put("file", "%1$sbaseDir%1$sfile"); - patterns.put("!file", "!%1$sbaseDir%1$sfile"); - patterns.put("%regex[file]", "%%regex[\\Q%1$sbaseDir%1$s\\Efile]"); - patterns.put("!%regex[file]", "!%%regex[\\Q%1$sbaseDir%1$s\\Efile]"); - patterns.put("%ant[file]", "%1$sbaseDir%1$sfile"); - patterns.put("!%ant[file]", "!%1$sbaseDir%1$sfile"); - - patterns.put("file/**", "%1$sbaseDir%1$sfile%1$s**"); - patterns.put("!file/**", "!%1$sbaseDir%1$sfile%1$s**"); - patterns.put("%regex[file/.*]", "%%regex[\\Q%1$sbaseDir%1$s\\Efile/.*]"); - patterns.put("!%regex[file/.*]", "!%%regex[\\Q%1$sbaseDir%1$s\\Efile/.*]"); - patterns.put("%ant[file/**]", "%1$sbaseDir%1$sfile%1$s**"); - patterns.put("!%ant[file/**]", "!%1$sbaseDir%1$sfile%1$s**"); - - - DocumentName baseName = DocumentName.builder(FSInfoTest.UNIX).setName("fileBeingRead").setBaseName("baseDir").build(); - for (Map.Entry pattern : patterns.entrySet()) { - lst.add(Arguments.of(baseName, pattern.getKey(), String.format(pattern.getValue(), UNIX.dirSeparator()))); - } - - - baseName = DocumentName.builder(FSInfoTest.WINDOWS).setName("fileBeingRead").setBaseName("baseDir").build(); - for (Map.Entry pattern : patterns.entrySet()) { - lst.add(Arguments.of(baseName, pattern.getKey(), String.format(pattern.getValue(), WINDOWS.dirSeparator()))); - } - - baseName = DocumentName.builder(FSInfoTest.OSX).setName("fileBeingRead").setBaseName("baseDir").build(); - for (Map.Entry pattern : patterns.entrySet()) { - lst.add(Arguments.of(baseName, pattern.getKey(), String.format(pattern.getValue(), OSX.dirSeparator()))); - } - return lst.stream(); - } -}