blob: 5d69f0a15b8f987cc231e464879561d725daaac8 [file] [log] [blame]
/*
* 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.sshd.common.file.util;
import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.attribute.UserPrincipalLookupService;
import java.nio.file.spi.FileSystemProvider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.util.test.BaseTestSupport;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.mockito.Mockito;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class BasePathTest extends BaseTestSupport {
private TestFileSystem fileSystem;
public BasePathTest() {
super();
}
@Before
public void setUp() {
fileSystem = new TestFileSystem(Mockito.mock(FileSystemProvider.class));
}
@Test
public void testBasicPathParsing() {
assertPathEquals("/", "/");
assertPathEquals("/foo", "/foo");
assertPathEquals("/foo", "/", "foo");
assertPathEquals("/foo/bar", "/foo/bar");
assertPathEquals("/foo/bar", "/", "foo", "bar");
assertPathEquals("/foo/bar", "/foo", "bar");
assertPathEquals("/foo/bar", "/", "foo/bar");
assertPathEquals("foo/bar/baz", "foo/bar/baz");
assertPathEquals("foo/bar/baz", "foo", "bar", "baz");
assertPathEquals("foo/bar/baz", "foo/bar", "baz");
assertPathEquals("foo/bar/baz", "foo", "bar/baz");
}
@Test
public void testPathParsingWithExtraSeparators() {
assertPathEquals("/foo/bar", "///foo/bar");
assertPathEquals("/foo/bar", "/foo///bar//");
assertPathEquals("/foo/bar/baz", "/foo", "/bar", "baz/");
//assertPathEquals("/foo/bar/baz", "/foo\\/bar//\\\\/baz\\/");
}
@Test
public void testRootPath() {
new PathTester(fileSystem, "/")
.root("/")
.test("/");
}
@Test
public void testRelativePathSingleName() {
new PathTester(fileSystem, "test")
.names("test")
.test("test");
Path path = parsePath("test");
assertEquals(path, path.getFileName());
}
@Test
public void testRelativePathTwoNames() {
PathTester tester = new PathTester(fileSystem, "foo/bar")
.names("foo", "bar");
tester.test("foo/bar");
}
@Test
public void testRelativePathFourNames() {
new PathTester(fileSystem, "foo/bar/baz/test")
.names("foo", "bar", "baz", "test")
.test("foo/bar/baz/test");
}
@Test
public void testAbsolutePathSingleName() {
new PathTester(fileSystem, "/foo")
.root("/")
.names("foo")
.test("/foo");
}
@Test
public void testAbsolutePathTwoNames() {
new PathTester(fileSystem, "/foo/bar")
.root("/")
.names("foo", "bar")
.test("/foo/bar");
}
@Test
public void testAbsoluteMultiNamePathFourNames() {
new PathTester(fileSystem, "/foo/bar/baz/test")
.root("/")
.names("foo", "bar", "baz", "test")
.test("/foo/bar/baz/test");
}
@Test
public void testResolveFromRoot() {
Path root = parsePath("/");
assertResolvedPathEquals("/foo", root, "foo");
assertResolvedPathEquals("/foo/bar", root, "foo/bar");
assertResolvedPathEquals("/foo/bar", root, "foo", "bar");
assertResolvedPathEquals("/foo/bar/baz/test", root, "foo/bar/baz/test");
assertResolvedPathEquals("/foo/bar/baz/test", root, "foo", "bar/baz", "test");
}
@Test
public void testResolveFromAbsolute() {
Path path = parsePath("/foo");
assertResolvedPathEquals("/foo/bar", path, "bar");
assertResolvedPathEquals("/foo/bar/baz/test", path, "bar/baz/test");
assertResolvedPathEquals("/foo/bar/baz/test", path, "bar/baz", "test");
assertResolvedPathEquals("/foo/bar/baz/test", path, "bar", "baz", "test");
}
@Test
public void testResolveFromRelative() {
Path path = parsePath("foo");
assertResolvedPathEquals("foo/bar", path, "bar");
assertResolvedPathEquals("foo/bar/baz/test", path, "bar/baz/test");
assertResolvedPathEquals("foo/bar/baz/test", path, "bar", "baz", "test");
assertResolvedPathEquals("foo/bar/baz/test", path, "bar/baz", "test");
}
@Test
public void testResolveWithThisAndParentDirNames() {
Path path = parsePath("/foo");
assertResolvedPathEquals("/foo/bar/../baz", path, "bar/../baz");
assertResolvedPathEquals("/foo/bar/../baz", path, "bar", "..", "baz");
assertResolvedPathEquals("/foo/./bar/baz", path, "./bar/baz");
assertResolvedPathEquals("/foo/./bar/baz", path, ".", "bar/baz");
}
@Test
public void testResolveGivenAbsolutePath() {
assertResolvedPathEquals("/test", parsePath("/foo"), "/test");
assertResolvedPathEquals("/test", parsePath("foo"), "/test");
}
@Test
public void testResolveGivenEmptyPath() {
assertResolvedPathEquals("/foo", parsePath("/foo"), "");
assertResolvedPathEquals("foo", parsePath("foo"), "");
}
@Test
public void testResolveAgainstEmptyPath() {
assertResolvedPathEquals("foo/bar", parsePath(""), "foo/bar");
}
@Test
public void testResolveSiblingGivenEmptyPath() {
Path path = parsePath("foo/bar");
Path resolved = path.resolveSibling("");
assertPathEquals("foo", resolved);
path = parsePath("foo");
resolved = path.resolveSibling("");
assertPathEquals("", resolved);
}
@Test
public void testResolveSiblingAgainstEmptyPath() {
Path path = parsePath("");
Path resolved = path.resolveSibling("foo");
assertPathEquals("foo", resolved);
path = parsePath("");
resolved = path.resolveSibling("");
assertPathEquals("", resolved);
}
@Test
public void testRelativizeBothAbsolute() {
assertRelativizedPathEquals("b/c", parsePath("/a"), "/a/b/c");
assertRelativizedPathEquals("c/d", parsePath("/a/b"), "/a/b/c/d");
}
@Test
public void testRelativizeBothRelative() {
assertRelativizedPathEquals("b/c", parsePath("a"), "a/b/c");
assertRelativizedPathEquals("d", parsePath("a/b/c"), "a/b/c/d");
}
@Test
public void testRelativizeAgainstEmptyPath() {
assertRelativizedPathEquals("foo/bar", parsePath(""), "foo/bar");
}
@Test
public void testRelativizeOneAbsoluteOneRelative() {
try {
parsePath("/foo/bar").relativize(parsePath("foo"));
fail();
} catch (IllegalArgumentException expected) {
// ignored
}
try {
parsePath("foo").relativize(parsePath("/foo/bar"));
fail();
} catch (IllegalArgumentException expected) {
// ignored
}
}
@Test
public void testNormalizeWithParentDirName() {
assertNormalizedPathEquals("/foo/baz", "/foo/bar/../baz");
assertNormalizedPathEquals("/foo/baz", "/foo", "bar", "..", "baz");
}
@Test
public void testNormalizeWithThisDirName() {
assertNormalizedPathEquals("/foo/bar/baz", "/foo/bar/./baz");
assertNormalizedPathEquals("/foo/bar/baz", "/foo", "bar", ".", "baz");
}
@Test
public void testNormalizeWithThisAndParentDirNames() {
assertNormalizedPathEquals("foo/test", "foo/./bar/../././baz/../test");
}
@Test
public void testNormalizeWithLeadingParentDirNames() {
assertNormalizedPathEquals("../../foo/baz", "../../foo/bar/../baz");
}
@Test
public void testNormalizeWithLeadingThisAndParentDirNames() {
assertNormalizedPathEquals("../../foo/baz", "./.././.././foo/bar/../baz");
}
@Test
public void testNormalizeWithExtraParentDirNamesAtRoot() {
assertNormalizedPathEquals("/", "/..");
assertNormalizedPathEquals("/", "/../../..");
assertNormalizedPathEquals("/", "/foo/../../..");
assertNormalizedPathEquals("/", "/../foo/../../bar/baz/../../../..");
}
@Test
public void testPathWithExtraSlashes() {
assertPathEquals("/foo/bar/baz", parsePath("/foo/bar/baz/"));
assertPathEquals("/foo/bar/baz", parsePath("/foo//bar///baz"));
assertPathEquals("/foo/bar/baz", parsePath("///foo/bar/baz"));
}
private void assertResolvedPathEquals(
String expected, Path path, String firstResolvePath, String... moreResolvePaths) {
Path resolved = path.resolve(firstResolvePath);
for (String additionalPath : moreResolvePaths) {
resolved = resolved.resolve(additionalPath);
}
assertPathEquals(expected, resolved);
Path relative = parsePath(firstResolvePath, moreResolvePaths);
resolved = path.resolve(relative);
assertPathEquals(expected, resolved);
// assert the invariant that p.relativize(p.resolve(q)).equals(q) when q does not have a root
// p = path, q = relative, p.resolve(q) = resolved
if (relative.getRoot() == null) {
assertEquals(relative, path.relativize(resolved));
}
}
private void assertRelativizedPathEquals(String expected, Path path, String relativizePath) {
Path relativized = path.relativize(parsePath(relativizePath));
assertPathEquals(expected, relativized);
}
private void assertNormalizedPathEquals(String expected, String first, String... more) {
assertPathEquals(expected, parsePath(first, more).normalize());
}
private void assertPathEquals(String expected, String first, String... more) {
assertPathEquals(expected, parsePath(first, more));
}
private void assertPathEquals(String expected, Path path) {
assertEquals(parsePath(expected), path);
}
private Path parsePath(String first, String... more) {
return fileSystem.getPath(first, more);
}
private static class TestFileSystem extends BaseFileSystem<TestPath> {
TestFileSystem(FileSystemProvider fileSystemProvider) {
super(fileSystemProvider);
}
@Override
protected TestPath create(String root, List<String> names) {
return new TestPath(this, root, names);
}
@Override
public void close() throws IOException {
// ignored
}
@Override
public boolean isOpen() {
return false;
}
@Override
public Set<String> supportedFileAttributeViews() {
return null;
}
@Override
public UserPrincipalLookupService getUserPrincipalLookupService() {
return null;
}
}
private static class TestPath extends BasePath<TestPath, TestFileSystem> {
TestPath(TestFileSystem fileSystem, String root, List<String> names) {
super(fileSystem, root, names);
}
@Override
protected TestPath create(String root, List<String> names) {
return new TestPath(getFileSystem(), root, names);
}
@Override
public URI toUri() {
return null;
}
@Override
public Path toRealPath(LinkOption... options) throws IOException {
return null;
}
}
public static class PathTester {
private final FileSystem fileSystem;
private final String string;
private String root;
private List<String> names = Collections.<String>emptyList();
public PathTester(FileSystem fileSystem, String string) {
this.fileSystem = fileSystem;
this.string = string;
}
public PathTester root(String root) {
this.root = root;
return this;
}
public PathTester names(Collection<String> names) {
this.names = GenericUtils.unmodifiableList(names);
return this;
}
public PathTester names(String... names) {
return names(Arrays.asList(names));
}
public void test(String first, String... more) {
Path path = fileSystem.getPath(first, more);
test(path);
}
public void test(Path path) {
assertEquals(string, path.toString());
testRoot(path);
testNames(path);
testParents(path);
testStartsWith(path);
testEndsWith(path);
testSubpaths(path);
}
private void testRoot(Path path) {
if (root != null) {
assertTrue(path + ".isAbsolute() should be true", path.isAbsolute());
assertNotNull(path + ".getRoot() should not be null", path.getRoot());
assertEquals(root, path.getRoot().toString());
} else {
assertFalse(path + ".isAbsolute() should be false", path.isAbsolute());
assertNull(path + ".getRoot() should be null", path.getRoot());
}
}
private void testNames(Path path) {
assertEquals(names.size(), path.getNameCount());
assertEquals(names, names(path));
for (int i = 0; i < names.size(); i++) {
assertEquals(names.get(i), path.getName(i).toString());
// don't test individual names if this is an individual name
if (names.size() > 1) {
new PathTester(fileSystem, names.get(i))
.names(names.get(i))
.test(path.getName(i));
}
}
if (names.size() > 0) {
String fileName = names.get(names.size() - 1);
assertEquals(fileName, path.getFileName().toString());
// don't test individual names if this is an individual name
if (names.size() > 1) {
new PathTester(fileSystem, fileName)
.names(fileName)
.test(path.getFileName());
}
}
}
private void testParents(Path path) {
Path parent = path.getParent();
if (root != null && names.size() >= 1 || names.size() > 1) {
assertNotNull(parent);
}
if (parent != null) {
String parentName = names.size() == 1 ? root : string.substring(0, string.lastIndexOf('/'));
new PathTester(fileSystem, parentName)
.root(root)
.names(names.subList(0, names.size() - 1))
.test(parent);
}
}
private void testSubpaths(Path path) {
if (path.getRoot() == null) {
assertEquals(path, path.subpath(0, path.getNameCount()));
}
if (path.getNameCount() > 1) {
String stringWithoutRoot = root == null ? string : string.substring(root.length());
// test start + 1 to end and start to end - 1 subpaths... this recursively tests all subpaths
// actually tests most possible subpaths multiple times but... eh
Path startSubpath = path.subpath(1, path.getNameCount());
List<String> startNames = split(stringWithoutRoot, "/")
.subList(1, path.getNameCount());
new PathTester(fileSystem, join(startNames, "/"))
.names(startNames)
.test(startSubpath);
Path endSubpath = path.subpath(0, path.getNameCount() - 1);
List<String> endNames = split(stringWithoutRoot, "/")
.subList(0, path.getNameCount() - 1);
new PathTester(fileSystem, join(endNames, "/"))
.names(endNames)
.test(endSubpath);
}
}
private void testStartsWith(Path path) {
// empty path doesn't start with any path
if (root != null || !names.isEmpty()) {
Path other = path;
while (other != null) {
assertTrue(path + ".startsWith(" + other + ") should be true",
path.startsWith(other));
assertTrue(path + ".startsWith(" + other + ") should be true",
path.startsWith(other.toString()));
other = other.getParent();
}
}
}
private void testEndsWith(Path path) {
// empty path doesn't start with any path
if (root != null || !names.isEmpty()) {
Path other = path;
while (other != null) {
assertTrue(path + ".endsWith(" + other + ") should be true",
path.endsWith(other));
assertTrue(path + ".endsWith(" + other + ") should be true",
path.endsWith(other.toString()));
if (other.getRoot() != null && other.getNameCount() > 0) {
other = other.subpath(0, other.getNameCount());
} else if (other.getNameCount() > 1) {
other = other.subpath(1, other.getNameCount());
} else {
other = null;
}
}
}
}
private static List<String> names(Path path) {
List<String> list = new ArrayList<>();
for (Path p : path) {
list.add(p.toString());
}
return list;
}
private List<String> split(String string, String sep) {
return Arrays.asList(string.split(sep));
}
private static String join(Iterable<String> strings, String sep) {
StringBuilder sb = new StringBuilder();
for (String s : strings) {
if (sb.length() > 0) {
sb.append(sep);
}
sb.append(s);
}
return sb.toString();
}
}
}