This is an automated email from the ASF dual-hosted git repository.

Claudenw pushed a commit to branch fix-DocumentName-issues
in repository https://gitbox.apache.org/repos/asf/creadur-rat.git

commit 748f4baed34839482ede22da18b957d7484a4862
Author: Claude Warren <[email protected]>
AuthorDate: Tue Jun 9 14:45:38 2026 +0100

    fix DocumentName issues
---
 .../org/apache/rat/document/ArchiveEntryName.java  |  29 +-
 .../java/org/apache/rat/document/DocumentName.java | 138 ++++++--
 .../rat/document/DocumentNameBuilderTest.java      | 318 +++++++++++-------
 .../org/apache/rat/document/DocumentNameTest.java  | 368 ++++++++-------------
 4 files changed, 467 insertions(+), 386 deletions(-)

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 13b4668e..2a6d4739 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
@@ -23,18 +23,33 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Collections;
 
+/**
+ * The DocumentName for an ArchiveEntry.
+ */
 public class ArchiveEntryName extends DocumentName {
     /** The name of the document that contains this entry. */
     private final DocumentName archiveFileName;
 
+    /**
+     * Sets the builder so that a propery DocumentName is constructed.
+     * @param archiveFileName the archvie file DocumentName
+     * @param archiveEntryName the entry name
+     * @return the DocumentName.Builder for the archive entry.
+     */
     private static DocumentName.Builder prepareBuilder(final DocumentName 
archiveFileName, final String archiveEntryName) {
-        String root = archiveFileName.getName() + "#";
+        String root = archiveFileName.getName() + "#/";
         FSInfo fsInfo = new FSInfo("archiveEntry", "/", true, 
Collections.singletonList(root));
         return DocumentName.builder(fsInfo)
                 .setRoot(root)
-                .setBaseName(root + "/")
+                .setBaseName("/")
                 .setName(archiveEntryName);
     }
+
+    /**
+     * Constucts an archive file name from an archive file document name and 
an entry name.
+     * @param archiveFileName the archive file document name.
+     * @param archiveEntryName the archive entry name.
+     */
     public ArchiveEntryName(final DocumentName archiveFileName, final String 
archiveEntryName) {
         super(prepareBuilder(archiveFileName, archiveEntryName));
         this.archiveFileName = archiveFileName;
@@ -71,14 +86,4 @@ public class ArchiveEntryName extends DocumentName {
         superLocal = superLocal.substring(superLocal.lastIndexOf("#") + 1);
         return archiveFileName.localized(dirSeparator) + "#" + superLocal;
     }
-
-    @Override
-    public boolean equals(final 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 c2c0510e..7700ca04 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
@@ -45,8 +45,8 @@ import org.apache.commons.lang3.tuple.Pair;
  * The name for a document. The {@code DocumentName} is an immutable structure 
that handles all the intricacies of file
  * naming on various operating systems. DocumentNames have several components:
  * <ul>
- *     <li>{@code root} - where in the file system the name starts (e.g C: on 
windows). May be empty but not null.</li>
- *     <li>{@code dirSeparator} - the separator between name segments (e.g. 
"\\" on windows, "/" on linux). May not be
+ *     <li>{@code root} - where in the file system the name starts (e.g C:\ on 
Microsoft Windows). May be empty but not null.</li>
+ *     <li>{@code dirSeparator} - the separator between name segments (e.g. 
"\" on MicroSoft Windows, "/" on linux). May not be
  *     empty or null.</li>
  *     <li>{@code name} - the name of the file relative to the {@code root}. 
May not be null. Does NOT begin with a {@code dirSeparator}</li>
  *     <li>{@code baseName} - the name of a directory or file from which this 
file is reported. A DocumentName with a
@@ -65,7 +65,7 @@ public class DocumentName implements Comparable<DocumentName> 
{
     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. */
+    /** The root for the DocumentName. May be empty but not null. Must be one 
of the roots in fsInfo*/
     private final String root;
 
     /**
@@ -126,7 +126,7 @@ public class DocumentName implements 
Comparable<DocumentName> {
     }
 
     /**
-     * Creates a file from the document name.
+     * Creates a file from the fully qualified document name.
      * @return a new File object.
      */
     public File asFile() {
@@ -134,7 +134,8 @@ public class DocumentName implements 
Comparable<DocumentName> {
     }
 
     /**
-     * Creates a path from the document name.
+     * Creates a path from the document name.  This method uses the 
fullyqualified name without the root.
+     * this results in a relative file name from the root.
      * @return a new Path object.
      */
     public Path asPath() {
@@ -144,9 +145,23 @@ public class DocumentName implements 
Comparable<DocumentName> {
     /**
      * Creates a new DocumentName by adding the child to the current name.
      * Resulting documentName will have the same base name.
+     * Directory separator is normalized to the directory separator for this 
file system.
+     * If the child string:
+     * <dl>
+     *     <dt>Is blank</dt>
+     *     <dd>This DocumentName is returned.</dd>
+     *     <dt>Starts with the file system root</dt>
+     *     <dd>The root The root must match the root of this DocumentName and 
the directory structure
+     *     must start with the directory structure of the basename for this 
DocuemntName.</dd>
+     *     <dt>Starts with the directory separator character<dt>
+ *         <dd>Result will be a tree starting at the directory specified by 
the basename.</dd>
+     *     <dt>Does not start with a directory separator character</dt>
+     *     <dd>Result will be a tree starting at the directory specified by 
this DocumentName</dd>
+     * </dl>
      * @param child the child to add (must use directory separator from this 
document name).
      * @return the new document name with the same {@link #baseName}, 
directory sensitivity and case sensitivity as
      * this one.
+     * @throws IllegalArgumentException if the child specifies a different 
root from this document name.
      */
     public DocumentName resolve(final String child) {
         if (StringUtils.isBlank(child)) {
@@ -156,8 +171,25 @@ public class DocumentName implements 
Comparable<DocumentName> {
         String pattern = separator.equals("/") ? child.replace('\\', '/') :
                 child.replace('/', '\\');
 
+        Optional<String> root = fsInfo.rootFor(child);
+        if (root.isPresent()) {
+            if (!root.get().equals(getRoot())) {
+                throw new IllegalArgumentException(String.format("%s does not 
start with %s", pattern, getName()));
+            }
+            if (!getRoot().equals(separator)) {
+                // we have something like C:\ as the root so convert the 
pattern to start with the separator.
+                pattern = separator + pattern.substring(getRoot().length());
+                if (pattern.startsWith(baseName.name)) {
+                    pattern = pattern.substring(baseName.name.length());
+                }
+            }
+        }
+
+        // patterns with separators either start with the name of this 
document plus a relative
+        // name, or are just directory off the baseName.  In either case the 
name is correct.
+        // so just handle the relative case.
         if (!pattern.startsWith(separator)) {
-             pattern = name + separator + pattern;
+            pattern = name + separator + pattern;
         }
 
         return new Builder(this).setName(fsInfo.normalize(pattern)).build();
@@ -168,7 +200,7 @@ public class DocumentName implements 
Comparable<DocumentName> {
      * @return the fully qualified name of the document.
      */
     public String getName() {
-        return root + fsInfo.dirSeparator() + name;
+        return root + name;
     }
 
     /**
@@ -203,6 +235,14 @@ public class DocumentName implements 
Comparable<DocumentName> {
         return fsInfo.dirSeparator();
     }
 
+    /**
+     * Returns the FSInfo for this document name.
+     * @return the FSInfo for this document name.
+     */
+    public FSInfo fsInfo() {
+        return fsInfo;
+    }
+
     /**
      * Determines if the candidate starts with the root or separator strings.
      * @param candidate the candidate to check. If blank method will return 
{@code false}.
@@ -287,19 +327,30 @@ public class DocumentName implements 
Comparable<DocumentName> {
 
     @Override
     public int compareTo(final DocumentName other) {
-        return CompareToBuilder.reflectionCompare(this, other);
+        return new CompareToBuilder()
+                .append(this.root, other.root)
+                .append(this.getBaseName(), other.getBaseName())
+                .append(this.getName(), other.getName()).build();
     }
 
     @Override
-    public boolean equals(final Object other) {
-        return EqualsBuilder.reflectionEquals(this, other);
+    public final boolean equals(final Object other) {
+        if (other instanceof DocumentName otherDocumentName) {
+            return compareTo(otherDocumentName) == 0;
+        }
+        return false;
     }
 
     @Override
-    public int hashCode() {
-        return HashCodeBuilder.reflectionHashCode(this);
+    public final int hashCode() {
+        return new 
HashCodeBuilder().append(root).append(getBaseName()).append(getName()).toHashCode();
     }
 
+    /**
+     * The File System Info Data for a DocumentName.
+     * Use to preserve data across DocumentNames without having to
+     * reconstruct the data for each DocumentName.
+     */
     private static final class FSInfoData {
         /** The case sensitivity flag */
         private final boolean isCaseSensitive;
@@ -468,6 +519,14 @@ public class DocumentName implements 
Comparable<DocumentName> {
             return Optional.empty();
         }
 
+        /**
+         * Gets the array of roots for this file system.
+         * @return an array of roots for this file system.
+         */
+        public String[] roots() {
+            return data.roots.toArray(new String[0]);
+        }
+
         /**
          * Tokenizes the string based on the directory separator of this 
DocumentName.
          * @param source the source to tokenize.
@@ -486,7 +545,9 @@ public class DocumentName implements 
Comparable<DocumentName> {
             if (StringUtils.isBlank(pattern)) {
                 return "";
             }
-            List<String> parts = new 
ArrayList<>(Arrays.asList(tokenize(pattern)));
+            String adjustedPattern = dirSeparator().equals("/") ? 
pattern.replace("\\", "/") : pattern.replace("/", "\\");
+
+            List<String> parts = new 
ArrayList<>(Arrays.asList(tokenize(adjustedPattern)));
             for (int i = 0; i < parts.size(); i++) {
                 String part = parts.get(i);
                 if (part.equals("..")) {
@@ -502,6 +563,16 @@ public class DocumentName implements 
Comparable<DocumentName> {
             return 
parts.stream().filter(Objects::nonNull).collect(Collectors.joining(dirSeparator()));
         }
 
+        /**
+         * Creates a path separated by the directory separator.
+         * Starting with an empty string will cause the directory separateor 
to appear at the beginning.
+         * @param segments the segments that make up the path.
+         * @return the path string.
+         */
+        public String mkPath(final String... segments) {
+            return String.join(dirSeparator(), segments);
+        }
+
         @Override
         public int compareTo(final FSInfo other) {
             return CompareToBuilder.reflectionCompare(this, other);
@@ -538,7 +609,7 @@ public class DocumentName implements 
Comparable<DocumentName> {
          */
         private Builder(final FSInfo fsInfo) {
             this.fsInfo = fsInfo;
-            root = "";
+            root = fsInfo.data.roots.get(0);
         }
 
         /**
@@ -625,12 +696,6 @@ public class DocumentName implements 
Comparable<DocumentName> {
                 this.root = pair.getLeft();
             }
             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;
         }
 
@@ -644,16 +709,15 @@ public class DocumentName implements 
Comparable<DocumentName> {
          */
         Pair<String, String> splitRoot(final String name) {
             String workingName = name;
-            Optional<String> maybeRoot = fsInfo.rootFor(name);
-            String root = maybeRoot.orElse("");
+            String root = fsInfo.rootFor(name).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());
-                        }
-                    }
+//                    if (!workingName.startsWith(fsInfo.dirSeparator())) {
+//                        if (root.endsWith(fsInfo.dirSeparator())) {
+//                            root = root.substring(0, root.length() - 
fsInfo.dirSeparator().length());
+//                        }
+//                    }
                 }
             }
             return ImmutablePair.of(root, workingName);
@@ -751,6 +815,26 @@ public class DocumentName implements 
Comparable<DocumentName> {
          */
         public DocumentName build() {
             verify();
+            if (this.baseName != null) {
+                if (!this.name.startsWith(baseName.name)) {
+                    this.name = this.name.isEmpty() ? baseName.name :
+                            baseName.name + fsInfo.dirSeparator() + this.name;
+                }
+                if (!this.baseName.getRoot().equals(root)) {
+                    Builder builder = new Builder(baseName).setRoot(root);
+                    if (baseName.baseName != null && baseName.baseName != 
baseName) {
+                        builder.setBaseName(baseName.baseName);
+                    } else {
+                        builder.baseName = null;
+                        builder.sameNameFlag = true;
+                    }
+                    this.baseName = builder.build();
+                }
+            } else {
+                if (this.name.startsWith(root)) {
+                    this.name = this.name.substring(root.length());
+                }
+            }
             return new DocumentName(this);
         }
     }
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 0e0f0d1f..644fce5a 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
@@ -19,23 +19,38 @@
 package org.apache.rat.document;
 
 import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Stream;
+
+import org.apache.commons.lang3.tuple.Pair;
+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.junit.jupiter.params.provider.FieldSource;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 import static org.apache.rat.document.FSInfoTest.WINDOWS;
 
+/**
+ * Tests the DcoumentName.Builder class
+ */
 public class DocumentNameBuilderTest {
 
-    @ParameterizedTest(name="{0}")
-    @MethodSource("buildTestData")
-    void buildTest(String testName, DocumentName documentName, String name, 
String shortName, String baseName, String root,
+    private static final DocumentName.FSInfo[] TEST_SUITE = 
FSInfoTest.TEST_SUITE;
+
+    /**
+     * Validates the data in a document name matches expected data.
+     * @param documentName the document name to check
+     * @param name the expected fully qualified name.
+     * @param shortName the name for the last segment of the name.
+     * @param baseName the name of the base document.
+     * @param root the root the document is in.
+     * @param directorySeparator the expected directory separator.
+     * @param isCaseSensitive the expected case sensitivity.
+     * @param localized the default localized name (e.g. path and file name 
from base name).
+     * @param localizedArg the localized name with directory separator set to 
'+'
+     */
+    void assertDocumentName(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);
@@ -48,120 +63,189 @@ public class DocumentNameBuilderTest {
             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);
+        assertThat(documentName.localized("+")).as("Invalid 
localized('+')").isEqualTo(localizedArg);
     }
 
-    static Stream<Arguments> buildTestData() {
-        List<Arguments> 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");
+    /**
+     * Verifies tha the baseName is not modified when used in the builder.
+     * Base name is default root + OS name.  For example C:\windows, or /unix
+     * @param fsInfo the file system info for the test.
+     */
+    @ParameterizedTest
+    @FieldSource("TEST_SUITE")
+    void baseNamePreserved(DocumentName.FSInfo fsInfo) {
+        final String root = fsInfo.roots()[0];
+        final String baseNameStr = root + fsInfo;
+        // create a document {os name}/bar.  Used to establish basename in 
builder.
+        final DocumentName siblingName = 
DocumentName.builder(fsInfo).setName("bar").setBaseName(fsInfo.toString()).build();
+
+        // check a relative name does not change base name.
+        String nameStr = fsInfo.mkPath("foo", "baz");
+        DocumentName documentName = 
DocumentName.builder(siblingName).setName(nameStr).build();
+        String expected = root + fsInfo.mkPath(fsInfo.toString(), "foo", 
"baz");
+        assertThat(documentName.getName()).as("relative 
value").isEqualTo(expected);
+        assertDocumentName(documentName, expected, "baz", baseNameStr, root, 
fsInfo.dirSeparator(), fsInfo.isCaseSensitive(),
+                fsInfo.dirSeparator() + nameStr, "+foo+baz");
+
+        // check a FQName results in the base name not being changed.
+        documentName = 
DocumentName.builder(siblingName).setName(expected).build();
+        assertThat(documentName.getName()).as("absolute 
value").isEqualTo(expected);
+        assertDocumentName(documentName, expected, "baz", baseNameStr, root, 
fsInfo.dirSeparator(), fsInfo.isCaseSensitive(),
+                fsInfo.dirSeparator() + nameStr, "+foo+baz");
+
+    }
+
+    @ParameterizedTest
+    @FieldSource("TEST_SUITE")
+    void documentNameFromFQNameWithBaseName(DocumentName.FSInfo fsInfo) {
+        final String root = fsInfo.roots()[0];
+        final String baseNameStr = root + fsInfo;
+        String fqName = root + fsInfo.mkPath(fsInfo.toString(), "foo");
+        DocumentName documentName = 
DocumentName.builder(fsInfo).setName(fqName).setBaseName(baseNameStr).build();
+        assertDocumentName(documentName, fqName, "foo", baseNameStr, root, 
fsInfo.dirSeparator(), fsInfo.isCaseSensitive(),
+                fsInfo.dirSeparator() + "foo", "+foo");
+    }
+
+    @ParameterizedTest
+    @FieldSource("TEST_SUITE")
+    void noBaseNameThowsException(DocumentName.FSInfo fsInfo) {
+        final String root = fsInfo.roots()[0];
+        String fqName = root + fsInfo.mkPath(fsInfo.toString(), "foo");
+        assertThatThrownBy(() -> 
DocumentName.builder(fsInfo).setName(fqName).build())
+                .isInstanceOf(NullPointerException.class)
+                .hasMessage("Basename must not be null");
+    }
+
+    @ParameterizedTest
+    @FieldSource("TEST_SUITE")
+    void noNameThowsException(DocumentName.FSInfo fsInfo) {
+        final String root = fsInfo.roots()[0];
+        String fqName = root + fsInfo.mkPath(fsInfo.toString(), "foo");
+        assertThatThrownBy(() -> 
DocumentName.builder(fsInfo).setBaseName(fqName).build())
+                .isInstanceOf(NullPointerException.class)
+                .hasMessage("Name must not be null");
+    }
+
+
+    @ParameterizedTest
+    @FieldSource("TEST_SUITE")
+    void DocumentNameFromDocumentName(DocumentName.FSInfo fsInfo) {
+        final String root = fsInfo.roots()[0];
+        final String baseNameStr = root + fsInfo;
+        String fqName = root + fsInfo.mkPath(fsInfo.toString(), "foo");
+        DocumentName expected = 
DocumentName.builder(fsInfo).setName(fqName).setBaseName(baseNameStr).build();
+
+        DocumentName actual = DocumentName.builder(expected).build();
+        assertThat(actual).isEqualTo(expected);
+
+        assertDocumentName(actual, fqName, "foo", baseNameStr, root, 
fsInfo.dirSeparator(), fsInfo.isCaseSensitive(),
+                fsInfo.dirSeparator() + "foo", "+foo");
+
+    }
+
+    @ParameterizedTest
+    @FieldSource("TEST_SUITE")
+    void builderOnDocumentNameWithNameSharesBaseName(DocumentName.FSInfo 
fsInfo) {
+        final String root = fsInfo.roots()[0];
+        final String baseNameStr = root + fsInfo;
+
+        String fqName = root + fsInfo.mkPath(fsInfo.toString(), "foo");
+        DocumentName firstName = 
DocumentName.builder(fsInfo).setName(fqName).setBaseName(baseNameStr).build();
+
+        fqName = root + fsInfo.mkPath(fsInfo.toString(), "bar");
+        DocumentName actual = 
DocumentName.builder(firstName).setName(fqName).setBaseName(baseNameStr).build();
+
+        assertDocumentName(actual, fqName, "bar", baseNameStr, root, 
fsInfo.dirSeparator(), fsInfo.isCaseSensitive(),
+                fsInfo.dirSeparator() + "bar", "+bar");
+    }
+
+    @ParameterizedTest
+    @FieldSource("TEST_SUITE")
+    void builderOnFile(DocumentName.FSInfo fsInfo) {
+        final String root = fsInfo.roots()[0];
+        final String baseNameStr = root + fsInfo.mkPath(fsInfo.toString(), 
"foo");
+        final String fqName = root + fsInfo.mkPath(fsInfo.toString(), "foo", 
"bar");
+        File file = mock(File.class);
+        File parent = mock(File.class);
+        when(file.getAbsolutePath()).thenReturn(fqName);
         when(file.getParentFile()).thenReturn(parent);
         when(file.isDirectory()).thenReturn(false);
-        when(parent.getAbsolutePath()).thenReturn("C:\\windows\\foo");
+        when(parent.getAbsolutePath()).thenReturn(baseNameStr);
         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();
+        DocumentName actual = new DocumentName.Builder(fsInfo, file).build();
+
+        assertDocumentName(actual, fqName, "bar", baseNameStr, root, 
fsInfo.dirSeparator(), fsInfo.isCaseSensitive(),
+                fsInfo.dirSeparator() + "bar", "+bar");
+
+    }
+
+    @Test
+    void windowRootDifference() {
+        // verify that setting the root results in the entire DocumentName 
being re-rooted e.g. including the basename(s).
+        DocumentName.FSInfo fsInfo = WINDOWS;
+        String root = fsInfo.roots()[0];
+        String baseNameStr = root + fsInfo.mkPath(fsInfo.toString(), "foo");
+        String fqName = root + fsInfo.mkPath(fsInfo.toString(), "foo", "bar");
+        DocumentName firstName = 
DocumentName.builder(fsInfo).setName(fqName).setBaseName(baseNameStr).build();
+
+        root = "D:\\";
+        DocumentName actual = 
DocumentName.builder(firstName).setRoot(root).build();
+
+        baseNameStr = root + fsInfo.mkPath(fsInfo.toString(), "foo");
+        fqName = root + fsInfo.mkPath(fsInfo.toString(), "foo", "bar");
+
+        assertDocumentName(actual, fqName, "bar", baseNameStr, root, 
fsInfo.dirSeparator(), fsInfo.isCaseSensitive(),
+                fsInfo.dirSeparator() + "bar", "+bar");
+
+    }
+
+    @ParameterizedTest
+    @FieldSource("TEST_SUITE")
+    void setRootNull(DocumentName.FSInfo fsInfo) {
+        String root = fsInfo.roots()[0];
+        String baseNameStr = root + fsInfo.mkPath(fsInfo.toString(), "foo");
+        String fqName = root + fsInfo.mkPath(fsInfo.toString(), "foo", "bar");
+        DocumentName firstName = 
DocumentName.builder(fsInfo).setName(fqName).setBaseName(baseNameStr).build();
+
+        // verify setting the root to null results in relative names with a 
blank root set
+        root = null;
+        DocumentName actual = 
DocumentName.builder(firstName).setRoot(root).build();
+
+        baseNameStr = fsInfo.mkPath(fsInfo.toString(), "foo");
+        fqName = fsInfo.mkPath(fsInfo.toString(), "foo", "bar");
+
+        assertDocumentName(actual, fqName, "bar", baseNameStr, "", 
fsInfo.dirSeparator(), fsInfo.isCaseSensitive(),
+                fsInfo.dirSeparator() + "bar", "+bar");
+
+    }
+
+    @ParameterizedTest
+    @FieldSource("TEST_SUITE")
+    void setRootEmpty(DocumentName.FSInfo fsInfo) {
+        String root = fsInfo.roots()[0];
+        String baseNameStr = root + fsInfo.mkPath(fsInfo.toString(), "foo");
+        String fqName = root + fsInfo.mkPath(fsInfo.toString(), "foo", "bar");
+        DocumentName firstName = 
DocumentName.builder(fsInfo).setName(fqName).setBaseName(baseNameStr).build();
+
+        root = "";
+        DocumentName actual = 
DocumentName.builder(firstName).setRoot(root).build();
+
+        baseNameStr = root + fsInfo.mkPath(fsInfo.toString(), "foo");
+        fqName = root + fsInfo.mkPath(fsInfo.toString(), "foo", "bar");
+
+        assertDocumentName(actual, fqName, "bar", baseNameStr, root, 
fsInfo.dirSeparator(), fsInfo.isCaseSensitive(),
+                fsInfo.dirSeparator() + "bar", "+bar");
+
+    }
+
+    @ParameterizedTest
+    @FieldSource("TEST_SUITE")
+    void splitRootsTest(DocumentName.FSInfo fsInfo) {
+        String root = fsInfo.roots()[0];
+        String path = fsInfo.mkPath("My", "path", "to", "a", "file.txt");
+        Pair<String, String> result = 
DocumentName.builder(fsInfo).splitRoot(root + path);
+        assertThat(result.getLeft()).isEqualTo(root);
+        assertThat(result.getRight()).isEqualTo(path);
     }
 }
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 beeeeca9..f360cc8d 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,79 +18,78 @@
  */
 package org.apache.rat.document;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileFilter;
+import java.io.FileReader;
+import java.io.FileWriter;
 import java.io.FilenameFilter;
 import java.io.IOException;
-import java.nio.file.FileSystems;
+import java.nio.charset.StandardCharsets;
 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.FieldSource;
 import org.junit.jupiter.params.provider.MethodSource;
-import org.mockito.Mockito;
 
 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) {
-        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 final FSInfo[] TEST_SUITE = FSInfoTest.TEST_SUITE;
+
+    /**
+     * Create a list of mocked files from the specified directory.
+     * @param directory the native directory to read.
+     * @param fsInfo the file system to mock the files in.
+     * @return an array of mocked files in the file system.
+     */
+    private static File[] listFiles(File directory, FSInfo fsInfo) {
+        File[] fileList = directory.listFiles();
+        return fileList == null ? null : 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);
+    /**
+     * Create an array of mocked files from the specified directory then apply 
applying a file filter.
+     * @param directory the native directory to read files from.
+     * @param fsInfo the file system to create the mocked files in.
+     * @param filter the filter to apply to the mocked files.
+     * @return the array of mocked files that pass the filter.
+     */
+    private static File[] listFiles(File directory, FSInfo fsInfo, FileFilter 
filter) {
+        File[] fileList = directory.listFiles();
+        return fileList == null ? null : 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);
+    /**
+     * Create an array of mocked files from the specified directory then apply 
applying a file filter.
+     * @param directory the native directory to read files from.
+     * @param fsInfo the file system to create the mocked files in.
+     * @param filter the filter to apply to the mocked files.
+     * @return the array of mocked files that pass the filter.
+     */
+    private static File[] listFiles(File directory, FSInfo fsInfo, 
FilenameFilter filter) {
+        File[] fileList = directory.listFiles();
+        return fileList == null ? null : Arrays.stream(fileList).map(f -> 
mkFile(f, fsInfo)).filter(x -> filter.accept(x, 
x.getName())).toArray(File[]::new);
     }
 
+    /**
+     * Creates a mocked file on the specified file system with the
+     * @param file the name of the native file.
+     * @param fsInfo the file system to mock the file in.
+     * @return the mocked file in the specified file system
+     */
     public static File mkFile(final File file, final FSInfo fsInfo) {
         File mockedFile = mock(File.class);
         when(mockedFile.listFiles()).thenAnswer( env -> listFiles(file, 
fsInfo));
@@ -105,222 +104,131 @@ public class DocumentNameTest {
         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;
-    }
-
+    /**
+     * Verifies that {@code resolve()} works correctly.
+     * @param fsInfo the file system under test.
+     * @param base the DocumentName to resolve from.
+     * @param toResolve the string to resolve.
+     * @param expected the expected DocumentName after resolution.
+     */
     @ParameterizedTest(name = "{index} {0} {2}")
     @MethodSource("resolveTestData")
-    void resolveTest(String testName, DocumentName base, String toResolve, 
DocumentName expected) {
+    void resolveTest(DocumentName.FSInfo fsInfo, DocumentName base, String 
toResolve, DocumentName expected) {
        DocumentName actual = base.resolve(toResolve);
        assertThat(actual).isEqualTo(expected);
     }
 
     private static Stream<Arguments> resolveTestData() {
         List<Arguments> lst = new ArrayList<>();
+        DocumentName base;
+        DocumentName expected;
+        for (DocumentName.FSInfo fsInfo : TEST_SUITE) {
+            String root = fsInfo.roots()[0];
+            for (String baseName : List.of(root, root + fsInfo.mkPath("from", 
"base"))) {
+                String name = fsInfo.mkPath("", "dir", fsInfo.toString());
 
-        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));
+                base = 
DocumentName.builder(fsInfo).setName(name).setBaseName(baseName).build();
 
-        expected = 
DocumentName.builder(UNIX).setName("dir/up/and/down").setBaseName("/").build();
-        lst.add(Arguments.of("unix", base, "../up/and/down", expected));
+                expected = 
DocumentName.builder(fsInfo).setName(fsInfo.mkPath("", "dir", 
fsInfo.toString(), "relative")).setBaseName(baseName).build();
+                lst.add(Arguments.of(fsInfo, base, "relative", expected));
 
-        expected = 
DocumentName.builder(UNIX).setName("/from/root").setBaseName("/").build();
-        lst.add(Arguments.of("unix", base, "\\from\\root", expected));
+                expected = 
DocumentName.builder(fsInfo).setName(fsInfo.mkPath("", "from", 
"root")).setBaseName(baseName).build();
+                lst.add(Arguments.of(fsInfo, base, fsInfo.mkPath("", "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(fsInfo).setName(fsInfo.mkPath("dir", "up", "and", 
"down")).setBaseName(baseName).build();
+                lst.add(Arguments.of(fsInfo, base, fsInfo.mkPath("..", "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));
+                expected = 
DocumentName.builder(fsInfo).setName(fsInfo.mkPath("", "from", 
"root")).setBaseName(baseName).build();
+                String wrongSeparator = fsInfo.dirSeparator().equals("/") ? 
"\\" : "/";
+                lst.add(Arguments.of(fsInfo, base, String.join(wrongSeparator, 
"", "from", "root"), expected));
 
+                expected = 
DocumentName.builder(fsInfo).setName(fsInfo.mkPath("dir", "up", "and", 
"down")).setBaseName(baseName).build();
+                lst.add(Arguments.of(fsInfo, base, String.join(wrongSeparator, 
"..", "up", "and", "down"), expected));
+            }
+        }
         return lst.stream();
     }
 
-    @Test
-    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");
+    @ParameterizedTest
+    @FieldSource("TEST_SUITE")
+    void localizeTest(FSInfo fsInfo) {
+        DocumentName documentName = DocumentName.builder(fsInfo).setName(
+                fsInfo.mkPath("", "a", "b", "c"))
+                .setBaseName(fsInfo.mkPath("", "a")).build();
+        assertThat(documentName.localized()).isEqualTo(fsInfo.mkPath("", "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}")
-    @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);
     }
 
-    private static Stream<Arguments> validBuilderData() {
-        List<Arguments> lst = new ArrayList<>();
-        File f = Files.newTemporaryFile();
-
-        Set<String> roots = new HashSet<>();
-        File[] rootary = File.listRoots();
-        if (rootary != null) {
-            for (File root : rootary) {
-                String name = root.getPath();
-                roots.add(name);
-            }
-        }
-
-        String name = f.getAbsolutePath();
-        String root = "";
-        for (String sysRoot : roots) {
-            if (name.startsWith(sysRoot)) {
-                name = name.substring(sysRoot.length());
-                if (sysRoot.endsWith(File.separator)) {
-                    root = sysRoot.substring(0, sysRoot.length() - 
File.separator.length());
-                }
-                break;
-            }
+    @Test
+    void asFileTest() throws IOException {
+        File expected = File.createTempFile("docNameTest", ".txt");
+        try (FileWriter fw = new FileWriter(expected, StandardCharsets.UTF_8)) 
{
+            fw.write("Hello world");
         }
-
-        File p = f.getParentFile();
-        String baseName = p.getAbsolutePath().substring(root.length());
-        if (baseName.startsWith(File.separator)) {
-            baseName = baseName.substring(File.separator.length());
+        DocumentName underTest = DocumentName.builder(expected).build();
+        File actual = underTest.asFile();
+        try (FileReader fr = new FileReader(actual, StandardCharsets.UTF_8);
+        BufferedReader br = new BufferedReader(fr)) {
+            assertThat(br.readLine()).isEqualTo("Hello world");
         }
-        lst.add(Arguments.of("setName(file)", 
DocumentName.builder().setName(f), root, name, baseName, File.separator));
-        lst.add(Arguments.of("Builder(file)", DocumentName.builder(f), root, 
name, baseName, File.separator));
-
-        lst.add(Arguments.of("setName(dir)", 
DocumentName.builder().setName(p), root, baseName, baseName, File.separator));
-        lst.add(Arguments.of("Builder(dir)", DocumentName.builder(p), root, 
baseName, baseName, File.separator));
-
-        File r = new File(root.isEmpty() ? File.separator : root);
-        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(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", 
"/"));
-
-        return lst.stream();
     }
 
     @Test
-    void splitRootsTest() {
-        Pair<String, String> 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");
+    void asPathTest() throws IOException {
+        File expected = File.createTempFile("docNameTest", ".txt");
+        try (FileWriter fw = new FileWriter(expected, StandardCharsets.UTF_8)) 
{
+            fw.write("Hello world");
+        }
+        DocumentName underTest = DocumentName.builder(expected).build();
+        Path actual = underTest.asPath();
+        Path root = Path.of(underTest.getRoot());
+        File file = root.resolve(actual).toFile();
+        try (FileReader fr = new FileReader(file, StandardCharsets.UTF_8);
+             BufferedReader br = new BufferedReader(fr)) {
+            assertThat(br.readLine()).isEqualTo("Hello world");
+        }
     }
 
-    @Test
-    void archiveEntryNameTest() {
-        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");
+    @ParameterizedTest(name = "{index} {0} {1}")
+    @MethodSource("archiveEntryTestData")
+    void archiveEntryNameTest(String os, String testName, DocumentName 
archiveName, String root, String separator, String baseName,
+                              String localizedName) {
+        assertThat(archiveName.getRoot()).as("root").isEqualTo(root);
+        
assertThat(archiveName.getDirectorySeparator()).as("separator").isEqualTo(separator);
+        
assertThat(archiveName.getBaseName()).as("baseName").isEqualTo(baseName);
+        
assertThat(archiveName.localized()).as("localized").isEqualTo(localizedName);
+        assertThat(archiveName.getName()).as("name").isEqualTo(baseName + 
localizedName);
+        if (!separator.equals(archiveName.fsInfo().dirSeparator()))
+        {
+            String newBaseName = separator.equals("/") ? 
baseName.replace('\\', '/') : baseName.replace('/', '\\');
+            
assertThat(archiveName.localized(separator)).as("localized(x)").isEqualTo(newBaseName
 + localizedName);
+        }
+    }
 
-        // test with directory
-        entryName = "./someDir/anArchiveEntry.txt";
-        archiveEntryName = new ArchiveEntryName(archiveName, entryName);
+    static List<Arguments> archiveEntryTestData() {
+        List<Arguments> lst = new ArrayList<>();
 
-        
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");
+        for (FSInfo fsInfo :  FSInfoTest.TEST_SUITE) {
+            String os = fsInfo.toString();
+            String root = fsInfo.roots()[0];
+            String baseName = String.format(String.format("%sarchives", root));
+            String simpleName = String.format("%sanArchive.zip", 
fsInfo.dirSeparator());
+            String entryName = "./anArchiveEntry.txt";
+            DocumentName archiveName = 
DocumentName.builder(fsInfo).setName(baseName + 
simpleName).setBaseName(baseName).build();
+            lst.add(Arguments.of(os, "archive name", archiveName, root, 
fsInfo.dirSeparator(), baseName, simpleName));
+
+            ArchiveEntryName archiveEntryName = new 
ArchiveEntryName(archiveName, entryName);
+            baseName = archiveName.getName() + "#";
+            root = baseName + "/";
+            lst.add(Arguments.of(os, "archive entry name", archiveEntryName, 
root, "/", baseName, "/anArchiveEntry.txt"));
+
+            // test with directory
+            entryName = "./someDir/anArchiveEntry.txt";
+            archiveEntryName = new ArchiveEntryName(archiveName, entryName);
+
+            lst.add(Arguments.of(os, "archive entry with directory", 
archiveEntryName, root, "/", baseName, "/someDir/anArchiveEntry.txt"));
+        }
+        return lst;
     }
 }

Reply via email to