From 4c3862654a8888a85636acc38b0a2635babc6f35 Mon Sep 17 00:00:00 2001
From: Claude Warren
Date: Sun, 12 Jan 2025 16:01:43 +0000
Subject: [PATCH] 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 +-
.../analysis/DefaultAnalyserFactoryTest.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 8d2939c68..d1e9a3dad 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 extends ArchiveEntry> 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().getNameMatcher().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().getNameMatcher()));
+ ArchiveEntryName entryName = new ArchiveEntryName(getDocument().getName(), entry.getName());
+ result.add(new ArchiveEntryDocument(entryName, baos.toByteArray(), getDocument().getNameMatcher()));
}
}
}
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/DefaultAnalyserFactoryTest.java b/apache-rat-core/src/test/java/org/apache/rat/analysis/DefaultAnalyserFactoryTest.java
index bb2e515cc..4e29d6c1a 100644
--- a/apache-rat-core/src/test/java/org/apache/rat/analysis/DefaultAnalyserFactoryTest.java
+++ b/apache-rat-core/src/test/java/org/apache/rat/analysis/DefaultAnalyserFactoryTest.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 10a2ca457..806ba042a 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;
@@ -41,7 +42,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 7ab034a3e..26ba04c38 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
@@ -45,12 +45,12 @@ 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;
}
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;
}
diff --git a/pom.xml b/pom.xml
index a6c08c299..bf2aaabf5 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