Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 42 additions & 8 deletions src/main/java/com/github/fge/filesystem/path/GenericPath.java
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ public int getNameCount()
@Override
public Path getName(final int index)
{
if (elements.root != null && elements.root.isEmpty() && elements.names.length == 0) {
return new GenericPath(fs, factory, PathElements.EMPTY);
}

final String name;

//noinspection ProhibitedExceptionCaught
Expand Down Expand Up @@ -191,23 +195,53 @@ public boolean endsWith(final Path other)
if (!fs.equals(other.getFileSystem()))
return false;

final String separator = getFileSystem().getSeparator();

final PathElements otherElements = ((GenericPath) other).elements;

//noinspection VariableNotUsedInsideIf
if (otherElements.root != null)
return false;
/* If the path of comparison starts with a separator, then we can
* do a simple String.endsWith() to come to the correct value.
*/
if (other.toString().startsWith(separator)) {
return toString().equals(other.toString());
}

final String[] otherNames = otherElements.rootAndNames();
final String[] rootAndNames = elements.rootAndNames();

// We make a copy of the array because we are modifying its values
final String[] names = Arrays.copyOf(rootAndNames, rootAndNames.length);

if (names.length == 1 && names[0].equals(separator)) {
// Do nothing - just preserve our single separator as root

/* Remove separator from the start of the first element, so that
* everything will match seamlessly. */
} else if (names.length > 0 && names[0].startsWith(separator)) {
names[0] = names[0].substring(separator.length());
}

final String[] names = elements.names;
final int length = names.length;
final String[] otherNames = otherElements.names;
final int otherLength = otherNames.length;

// If searching for an ending larger than our elements, it's false
if (length < otherLength)
return false;

for (int i = 0; i < otherLength; i++)
if (!names[length - i].equals(otherNames[otherLength - i]))
// If both element's length is the same, just do an equals test
if (length == otherLength)
return Arrays.equals(names, otherNames);

// Otherwise, we need to move through the last elements one by one
for (int i = 1; i <= otherLength; i++) {
final int nameIdx = length - i;
final String name = names[nameIdx];
final int otherNameIdx = otherLength - i;
final String otherName = otherNames[otherNameIdx];

if (!name.equals(otherName))
return false;
}

return true;
}
Expand Down Expand Up @@ -236,7 +270,7 @@ public Path resolve(final Path other)
final GenericPath otherPath = (GenericPath) other;

final PathElements newNames
= factory.resolve(elements, otherPath.elements);
= factory.resolve(elements, otherPath.elements);

/*
* See PathElementsFactory's .resolve()
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/com/github/fge/filesystem/path/PathElements.java
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,33 @@ PathElements lastName()
return length == 0 ? null : singleton(names[length - 1]);
}

/**
* Return an array of strings starting with the root and then all of the
* names.
*
* @return null if there is no root and no names, otherwise as description
*/
@Nonnull
String[] rootAndNames()
{
if (root != null && names.length == 0) {
return new String[] { root };
} else if (root == null && names.length > 0) {
return names;
} else if (root != null && names.length > 0) {
final String[] elements = new String[names.length + 1];
elements[0] = root;
int i = 1;
for (String name : names) {
elements[i++] = name;
}

return elements;
} else {
return new String[] { root == null ? "" : root };
}
}

/**
* Returns an iterator over a set of elements of type T.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,8 @@ protected final String toString(final PathElements elements)
{
final StringBuilder sb = new StringBuilder();

final boolean hasRoot = elements.root != null;
final String root = elements.root;
final boolean hasRoot = root != null;
final String[] names = elements.names;
final int len = names.length;

Expand All @@ -445,10 +446,18 @@ protected final String toString(final PathElements elements)
if (len == 0)
return sb.toString();

if (hasRoot)
if (hasRoot) {
sb.append(rootSeparator);
}

final String firstName = names[0];

if (hasRoot && !firstName.startsWith(separator) &&
!root.endsWith(separator)) {
sb.append(separator);
}

sb.append(names[0]);
sb.append(firstName);

for (int i = 1; i < len; i++)
sb.append(separator).append(names[i]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ public final OutputStream newOutputStream(final Path path,
if (optionSet.contains(StandardOpenOption.CREATE_NEW))
throw new FileAlreadyExistsException(path.toString());
} catch (NoSuchFileException e) {
if (!optionSet.contains(StandardOpenOption.CREATE))
if (!(optionSet.contains(StandardOpenOption.CREATE) || optionSet.contains(StandardOpenOption.CREATE_NEW)))
throw e;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
import static org.mockito.Mockito.mock;
import static org.testng.Assert.assertTrue;

public final class FileAttributesFactoryTest
{
Expand Down Expand Up @@ -67,7 +66,7 @@ public void registeringNewProviderWorksWhenClassIsCorrect()
}
};

assertTrue(true);
assertThat(true).isTrue();
}

@Test
Expand Down Expand Up @@ -207,4 +206,4 @@ public void attributeProviderExtendingBasicReportsBasicViewSupported()
.as("attribute provider extending basic supports basic")
.isTrue();
}
}
}
113 changes: 106 additions & 7 deletions src/test/java/com/github/fge/filesystem/path/GenericPathTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
package com.github.fge.filesystem.path;

import com.github.fge.filesystem.CustomSoftAssertions;
import com.github.fge.filesystem.provider.FileSystemFactoryProvider;
import com.github.fge.filesystem.driver.FileSystemDriver;
import com.github.fge.filesystem.fs.GenericFileSystem;
import com.github.fge.filesystem.provider.FileSystemFactoryProvider;
import com.github.fge.filesystem.provider.FileSystemRepository;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
Expand Down Expand Up @@ -60,26 +60,28 @@ public void initMocks()
repository = mock(FileSystemRepository.class);
when(repository.getFactoryProvider()).thenReturn(factoryProvider);
driver = mock(FileSystemDriver.class);
factory = mock(PathElementsFactory.class);
factory = factoryProvider.getPathElementsFactory();
fs = new GenericFileSystem(uri, repository, driver, provider);
}

@Test
public void isAbsoluteDelegatesToPathElementsFactory()
{
final PathElementsFactory mockFactory = mock(PathElementsFactory.class);

final PathElements elements1 = new PathElements("/", NO_NAMES);
final PathElements elements2 = PathElements.EMPTY;

when(factory.isAbsolute(elements1)).thenReturn(false);
when(factory.isAbsolute(elements2)).thenReturn(true);
when(mockFactory.isAbsolute(elements1)).thenReturn(false);
when(mockFactory.isAbsolute(elements2)).thenReturn(true);

Path path;

path = new GenericPath(fs, factory, elements1);
path = new GenericPath(fs, mockFactory, elements1);

assertThat(path.isAbsolute()).isFalse();

path = new GenericPath(fs, factory, elements2);
path = new GenericPath(fs, mockFactory, elements2);

assertThat(path.isAbsolute()).isTrue();
}
Expand Down Expand Up @@ -120,6 +122,103 @@ public void getFileNameWithNameElementsDoesNotReturnNull()
assertPath(path.getFileName()).isNotNull();
}

/* The typical behavior of a Unix path is to return a path with an
* empty root and no names when element 0 is requested from a path
* with an empty root and no names.
*/
@Test
public void getEmptyFileNameReturnsEmptyFirstName() {
final PathElements elements = new PathElements("", new String[] {});
final Path path = new GenericPath(fs, factory, elements);

assertThat(path.getName(0).toString()).isEqualTo("");
}

@Test
public void pathToStringWithRootDirectoryAsName() {
final PathElements elements
= new PathElements("", new String[] { "/" });
final Path path = new GenericPath(fs, factory, elements);
assertThat(path.toString()).isEqualTo("/");
}

@Test
public void pathToStringWithRootDirectoryAndSingleName() {
final PathElements elements
= new PathElements("/", new String[] { "tmp" });
final Path path = new GenericPath(fs, factory, elements);
assertThat(path.toString()).isEqualTo("/tmp");
}

@Test
public void pathToStringFromDirectoryRoot() {
final PathElements elements
= new PathElements("/tmp", PathElements.NO_NAMES);
final Path path = new GenericPath(fs, factory, elements);
assertThat(path.toString()).isEqualTo("/tmp");
}

@Test
public void pathToStringFromDirectoryRootWithSubdir() {
final PathElements elements
= new PathElements("/tmp", new String[] { "foo.txt" });
final Path path = new GenericPath(fs, factory, elements);
assertThat(path.toString()).isEqualTo("/tmp/foo.txt");
}

@Test
public void pathToStringFromDirectoryRootWithNoSubdir() {
final PathElements elements
= new PathElements("/tmp/foo.txt", PathElements.NO_NAMES);
FileSystemFactoryProvider provider = repository.getFactoryProvider();
final Path path = new GenericPath(fs, provider.getPathElementsFactory(),
elements);
assertThat(path.toString()).isEqualTo("/tmp/foo.txt");
}

@Test
public void endsWithMatchesLastName() {
final PathElements elements
= new PathElements("/tmp/", new String[] { "foo.txt" });
final Path path = new GenericPath(fs, factory, elements);
assertThat(path.endsWith("foo.txt")).isTrue();
assertThat(path.endsWith("/tmp/foo.txt")).isTrue();
}

@Test
public void endsWithMatchesLastDirectoryAndName() {
final PathElements elements = new PathElements("/tmp",
new String[] { "bar", "foo.txt" });
final Path path = new GenericPath(fs, factory, elements);
assertThat(path.endsWith("bar/foo.txt")).isTrue();
assertThat(path.endsWith("/tmp/bar/foo.txt")).isTrue();
}

@Test
public void endsWithMatchesRoot() {
final PathElements elements
= new PathElements("/tmp", PathElements.NO_NAMES);
final Path path = new GenericPath(fs, factory, elements);
assertThat(path.endsWith("tmp")).isTrue();
assertThat(path.endsWith("/tmp")).isTrue();
}

@Test
public void endsWithRootDoesntMatchEmpty() {
final PathElements elements
= new PathElements("/", PathElements.NO_NAMES);
final Path path = new GenericPath(fs, factory, elements);
assertThat(path.endsWith("")).isFalse();
}

@Test
public void endsWithEmptyPathsMatch() {
final PathElements elements
= new PathElements("", PathElements.NO_NAMES);
final Path path = new GenericPath(fs, factory, elements);
assertThat(path.endsWith("")).isTrue();
}

/*
* This test this part of the Path's .relativize() method:
*
Expand Down Expand Up @@ -240,4 +339,4 @@ public void toUriPathReturnsCorrectURI(final String s, final String path,
assertThat(p.toUri().toString()).as("generated URI is correct")
.isEqualTo(expected);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
import static org.testng.Assert.assertTrue;

public final class PathElementsFactoryTest
{
Expand Down Expand Up @@ -229,14 +228,14 @@ public void relativizingWithDifferentRootsThrowsIAE()
factory.relativize(elements1, elements2);
fail("No exception thrown!");
} catch (IllegalArgumentException ignored) {
assertTrue(true);
assertThat(true).isTrue();
}

try {
factory.relativize(elements2, elements1);
fail("No exception thrown!");
} catch (IllegalArgumentException ignored) {
assertTrue(true);
assertThat(true).isTrue();
}
}

Expand Down Expand Up @@ -370,4 +369,4 @@ private static String[] stringArray(final String first,
System.arraycopy(other, 0, ret, 1, other.length);
return ret;
}
}
}