package org.smoothbuild.io.fs.base;
import static java.text.MessageFormat.format;
import static java.util.Arrays.asList;
import static org.quackery.Case.newCase;
import static org.quackery.Suite.suite;
import static org.quackery.report.AssertException.assertEquals;
import static org.quackery.report.AssertException.assertTrue;
import static org.quackery.report.AssertException.fail;
import static org.smoothbuild.io.fs.base.Path.path;
import static org.testory.Testory.thenReturned;
import static org.testory.Testory.thenThrown;
import static org.testory.Testory.when;
import java.nio.file.Paths;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.quackery.Case;
import org.quackery.Quackery;
import org.quackery.Suite;
import org.quackery.junit.QuackeryRunner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.testing.EqualsTester;
@RunWith(QuackeryRunner.class)
public class PathTest {
@Quackery
public static Suite path_value_is_validated() {
return suite("path value is validated")
.add(suite("path can be created for valid name")
.addAll(map(listOfCorrectPaths(), PathTest::pathCanBeCreatedForValidName)))
.add(suite("cannot create path with invalid value")
.addAll(map(listOfInvalidPaths(), PathTest::cannotCreatePathWithInvalidValue)));
}
private static <A, B> List<B> map(List<A> elements, Function<? super A, B> mapper) {
return elements.stream().map(mapper).collect(Collectors.toList());
}
private static Case pathCanBeCreatedForValidName(String path) {
return newCase(format("path [{0}]", path), () -> path(path));
}
private static Case cannotCreatePathWithInvalidValue(String path) {
return newCase(format("path [{0}]", path), () -> {
try {
path(path);
fail();
} catch (IllegalPathException e) {}
});
}
@Test
public void empty_string_path_is_root() {
when(path("").isRoot());
thenReturned(true);
}
@Test
public void simple_path_is_not_root() {
when(path("file.txt").isRoot());
thenReturned(false);
}
@Quackery
public static Suite implements_value() {
return suite("implements value")
.add(testValue("", ""))
.add(testValue("abc", "abc"))
.add(testValue("abc/def", "abc/def"))
.add(testValue("abc/def/ghi", "abc/def/ghi"));
}
private static Case testValue(String path, String value) {
return newCase(format("path [{0}] has value [{1}]", path, value),
() -> assertEquals(path(path).value(), value));
}
@Quackery
public static Suite implements_toJPath() {
return suite("implements toJPath")
.add(testToJPath("", Paths.get(".")))
.add(testToJPath("abc", Paths.get("abc")))
.add(testToJPath("abc/def", Paths.get("abc/def")))
.add(testToJPath("abc/def/ghi", Paths.get("abc/def/ghi")));
}
private static Case testToJPath(String path, java.nio.file.Path jPath) {
return newCase(format("path [{0}] converted to JPath equals [{1}]", path, jPath),
() -> assertEquals(path(path).toJPath(), jPath));
}
@Test
public void parent_of_root_dir_throws_exception() {
when(Path.root()).parent();
thenThrown(IllegalArgumentException.class);
}
@Quackery
public static Suite implements_parent() {
return suite("implements parent")
.add(testParent("abc", ""))
.add(testParent("abc/def", "abc"))
.add(testParent("abc/def/ghi", "abc/def"))
.add(testParent(" ", ""));
}
private static Case testParent(String path, String parent) {
return newCase(format("parent of [{0}] is [{1}]", path, parent),
() -> assertEquals(path(path).parent(), path(parent)));
}
@Quackery
public static Suite implements_appending() {
return suite("implements appending")
.add(testAppending("", "", ""))
.add(testAppending("abc", "", "abc"))
.add(testAppending("abc/def", "", "abc/def"))
.add(testAppending("abc/def/ghi", "", "abc/def/ghi"))
.add(testAppending("", "abc", "abc"))
.add(testAppending("", "abc/def", "abc/def"))
.add(testAppending("", "abc/def/ghi", "abc/def/ghi"))
.add(testAppending("abc", "xyz", "abc/xyz"))
.add(testAppending("abc", "xyz/uvw", "abc/xyz/uvw"))
.add(testAppending("abc", "xyz/uvw/rst", "abc/xyz/uvw/rst"))
.add(testAppending("abc/def", "xyz", "abc/def/xyz"))
.add(testAppending("abc/def", "xyz/uvw", "abc/def/xyz/uvw"))
.add(testAppending("abc/def", "xyz/uvw/rst", "abc/def/xyz/uvw/rst"))
.add(testAppending("abc/def/ghi", "xyz", "abc/def/ghi/xyz"))
.add(testAppending("abc/def/ghi", "xyz/uvw", "abc/def/ghi/xyz/uvw"))
.add(testAppending("abc/def/ghi", "xyz/uvw/rst", "abc/def/ghi/xyz/uvw/rst"))
.add(testAppending(" ", " ", " / "))
.add(testAppending(" ", " / ", " / / "))
.add(testAppending(" / ", " ", " / / "))
.add(testAppending(" / ", " / ", " / / / "));
}
private static Case testAppending(String first, String second, String expected) {
return newCase(format("appending [{0}] to [{1}] returns [{2}]", first, second, expected),
() -> {
String actual = path(first).append(path(second)).value();
assertEquals(actual, expected);
});
}
@Quackery
public static Suite implements_parts() {
return suite("implements parts")
.add(testParts("", asList()))
.add(testParts("abc", asList("abc")))
.add(testParts("abc/def", asList("abc", "def")))
.add(testParts("abc/def/ghi", asList("abc", "def", "ghi")))
.add(testParts(" ", asList(" ")))
.add(testParts(" / ", asList(" ", " ")))
.add(testParts(" / / ", asList(" ", " ", " ")));
}
private static Case testParts(String path, List<String> parts) {
return newCase(format("[{0}] has parts: {1}", path, parts),
() -> {
List<String> actualParts = path(path)
.parts()
.stream()
.map(Path::value)
.collect(Collectors.toList());
assertEquals(actualParts, parts);
});
}
@Test
public void last_part_of_root_dir_throws_exception() {
when(Path.root()).lastPart();
thenThrown(IllegalArgumentException.class);
}
@Quackery
public static Suite implements_last_part() {
return suite("implements lastPart")
.add(testLastPart(" ", " "))
.add(testLastPart(" / ", " "))
.add(testLastPart("abc", "abc"))
.add(testLastPart("abc/def", "def"))
.add(testLastPart("abc/def/ghi", "ghi"));
}
private static Case testLastPart(String path, String lastPart) {
return newCase(format("last part of [{0}] is [{1}]", path, lastPart),
() -> assertEquals(path(path).lastPart(), path(lastPart)));
}
@Test
public void first_part_of_root_dir_throws_exception() {
when(Path.root()).firstPart();
thenThrown(IllegalArgumentException.class);
}
@Quackery
public static Suite implements_first_part() {
return suite("implements firstPart")
.add(testFirstPart(" ", " "))
.add(testFirstPart(" / ", " "))
.add(testFirstPart("abc", "abc"))
.add(testFirstPart("abc/def", "abc"))
.add(testFirstPart("abc/def/ghi", "abc"));
}
private static Case testFirstPart(String path, String firstPart) {
return newCase(format("first part of [{0}] is [{1}]", path, firstPart),
() -> assertEquals(path(path).firstPart(), path(firstPart)));
}
@Quackery
public static Suite implements_start_with() {
return suite("implements startsWith")
.add(testStartsWith(Path.root(), Path.root()))
.add(testStartsWith(Path.path("abc"), Path.root()))
.add(testStartsWith(Path.path("abc/def"), Path.root()))
.add(testStartsWith(Path.path("abc/def/ghi"), Path.root()))
.add(testStartsWith(Path.path("abc/def/ghi"), Path.path("abc")))
.add(testStartsWith(Path.path("abc/def/ghi"), Path.path("abc/def")))
.add(testStartsWith(Path.path("abc/def/ghi"), Path.path("abc/def/ghi")))
.add(testNotStartsWith(Path.path("abc/def/ghi"), Path.path("ab")))
.add(testNotStartsWith(Path.path("abc/def/ghi"), Path.path("abc/d")))
.add(testNotStartsWith(Path.path("abc/def/ghi"), Path.path("def")))
.add(testNotStartsWith(Path.path("abc/def/ghi"), Path.path("ghi")))
.add(testNotStartsWith(Path.root(), Path.path("abc")));
}
private static Case testStartsWith(Path path, Path head) {
return newCase(format("{0} starts with {1}", path, head),
() -> assertTrue(path.startsWith(head)));
}
private static Case testNotStartsWith(Path path, Path notHead) {
return newCase(format("{0} not starts with {1}", path, notHead),
() -> assertTrue(!path.startsWith(notHead)));
}
@Test
public void test_equals_and_hash_code() {
EqualsTester tester = new EqualsTester();
tester.addEqualityGroup(path("equal/path"), path("equal/path"));
for (Path path : listOfCorrectNonEqualPaths()) {
tester.addEqualityGroup(path);
}
tester.testEquals();
}
@Test
public void test_to_string() {
when(path("abc/def").toString());
thenReturned("'abc/def'");
}
public static List<String> listOfCorrectPaths() {
Builder<String> builder = ImmutableList.builder();
builder.add("");
builder.add("abc");
builder.add("abc/def");
builder.add("abc/def/ghi");
builder.add("abc/def/ghi/ijk");
// These paths look really strange but Linux allows creating them.
// I cannot see any good reason for forbidding them.
builder.add("...");
builder.add(".../abc");
builder.add("abc/...");
builder.add("abc/.../def");
return builder.build();
}
public static ImmutableList<String> listOfInvalidPaths() {
Builder<String> builder = ImmutableList.builder();
builder.add("/");
builder.add(".");
builder.add("./");
builder.add("./.");
builder.add("././");
builder.add("abc/");
builder.add("abc/def/");
builder.add("abc/def/ghi/");
builder.add("./abc");
builder.add("./abc/def");
builder.add("./abc/def/ghi");
builder.add("..");
builder.add("../");
builder.add("./../");
builder.add("../abc");
builder.add("abc/..");
builder.add("abc/../def");
builder.add("../..");
builder.add("//");
builder.add("///");
builder.add("/abc");
builder.add("//abc");
builder.add("///abc");
builder.add("abc//");
builder.add("abc///");
builder.add("abc//def");
builder.add("abc///def");
return builder.build();
}
private static List<Path> listOfCorrectNonEqualPaths() {
Builder<Path> builder = ImmutableList.builder();
builder.add(path(""));
builder.add(path("abc"));
builder.add(path("abc/def"));
builder.add(path("abc/def/ghi"));
builder.add(path("abc/def/ghi/ijk"));
// These paths look really strange but Linux allows creating them.
// I cannot see any good reason for forbidding them.
builder.add(path("..."));
builder.add(path(".../abc"));
builder.add(path("abc/..."));
builder.add(path("abc/.../def"));
return builder.build();
}
}