diff --git a/hamcrest/src/main/java/org/hamcrest/FeatureMatcher.java b/hamcrest/src/main/java/org/hamcrest/FeatureMatcher.java index 5c7511ce..e7c5439d 100644 --- a/hamcrest/src/main/java/org/hamcrest/FeatureMatcher.java +++ b/hamcrest/src/main/java/org/hamcrest/FeatureMatcher.java @@ -1,5 +1,7 @@ package org.hamcrest; +import java.util.function.Function; + import org.hamcrest.internal.ReflectiveTypeFinder; /** @@ -29,6 +31,20 @@ public FeatureMatcher(Matcher subMatcher, String featureDescription, this.featureName = featureName; } + /** + * Constructor + * @param subMatcher The matcher to apply to the feature + * @param featureDescription Descriptive text to use in describeTo + * @param featureName Identifying text for mismatch message + * @param expectedType expected type of the feature value + */ +private FeatureMatcher(Matcher subMatcher, String featureDescription, String featureName, Class expectedType) { + super(expectedType); + this.subMatcher = subMatcher; + this.featureDescription = featureDescription; + this.featureName = featureName; + } + /** * Implement this to extract the interesting feature. * @param actual the target object @@ -53,4 +69,20 @@ public final void describeTo(Description description) { .appendDescriptionOf(subMatcher); } + /** + * Create a matcher that matches a feature of an object. + * + * @param expected the matcher for the expected feature value + * @param extractor function to extract the feature from the object + * @param featureDescription descriptive text to use in describeTo + * @param featureName identifying text for mismatch message + * @param expectedType expected type to match against + * @return a matcher that matches the feature of the object + */ + public static Matcher matcher(final Matcher expected, final Function extractor, String featureDescription, String featureName, Class expectedType) { + return new FeatureMatcher(expected, featureDescription, featureName, expectedType) { + @Override protected F featureValueOf(T actual) { return extractor.apply(actual); } + }; + } + } diff --git a/hamcrest/src/main/java/org/hamcrest/TypeSafeDiagnosingMatcher.java b/hamcrest/src/main/java/org/hamcrest/TypeSafeDiagnosingMatcher.java index 4bcf871b..0ad76c4c 100644 --- a/hamcrest/src/main/java/org/hamcrest/TypeSafeDiagnosingMatcher.java +++ b/hamcrest/src/main/java/org/hamcrest/TypeSafeDiagnosingMatcher.java @@ -1,5 +1,7 @@ package org.hamcrest; +import java.util.function.Predicate; + import org.hamcrest.internal.ReflectiveTypeFinder; /** @@ -82,4 +84,31 @@ public final void describeMismatch(Object item, Description mismatchDescription) } } + /** + * Creates a TypeSafeDiagnosingMatcher that matches an item based on a predicate. + * + * @param Type of the item to match + * @param predicate Predicate to test the item + * @param successDescription Description to use when the predicate matches + * @param failureDescription Description to use when the predicate does not match + * @param expectedType Expected type of the item to match + * @return Matcher that matches the item based on the predicate + */ + public static Matcher matcher(Predicate predicate, final String successDescription, final String failureDescription, Class expectedType) { + return new TypeSafeDiagnosingMatcher(expectedType) { + public boolean matchesSafely(T actual, Description mismatchDescription) { + final boolean result = predicate.test(actual); + if (!result) { + mismatchDescription.appendText(String.format("'%s' %s", actual, failureDescription)); + } + return result; + } + + public void describeTo(Description description) { + description.appendText(successDescription); + } + }; + } + + } diff --git a/hamcrest/src/main/java/org/hamcrest/io/PathMatchers.java b/hamcrest/src/main/java/org/hamcrest/io/PathMatchers.java new file mode 100644 index 00000000..39c4d894 --- /dev/null +++ b/hamcrest/src/main/java/org/hamcrest/io/PathMatchers.java @@ -0,0 +1,260 @@ +package org.hamcrest.io; + +import org.hamcrest.FeatureMatcher; +import org.hamcrest.Matcher; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.function.Predicate; + +import static org.hamcrest.TypeSafeDiagnosingMatcher.matcher; +import static org.hamcrest.core.IsEqual.equalTo; + +/** + * Matchers for properties of files. + */ +public final class PathMatchers { + + private PathMatchers() { + } + + /** + * A matcher that checks if a directory exists. + * @return the file matcher + */ + public static Matcher anExistingDirectory() { + return matcher(Files::isDirectory, "an existing directory", "is not a directory", Path.class); + } + + /** + * A matcher that checks if a file or directory exists. + * @return the file matcher + */ + public static Matcher anExistingFileOrDirectory() { + return matcher(Files::exists, "an existing file or directory", "does not exist", Path.class); + } + + /** + * A matcher that checks if a file exists. + * @return the file matcher + */ + public static Matcher anExistingFile() { + return matcher(Files::isRegularFile, "an existing file", "is not a file", Path.class); + } + + /** + * A matcher that checks if a file or directory is readable. + * @return the file matcher + */ + public static Matcher isReadable() { + return matcher(Files::isReadable, "a readable file or directory", "cannot be read", Path.class); + } + + /** + * A matcher that checks if a file/directory is writable. + * @return the file matcher + */ + public static Matcher isWritable() { + return matcher(Files::isWritable, "a writable file or directory", "cannot be written to", Path.class); + } + + /** + * A matcher that checks if a file/directory is executable. + * @return the file matcher + */ + public static Matcher isExecutable() { + return matcher(Files::isExecutable, "an executable file or directory", "is not executable", Path.class); + } + + /** + * A matcher that checks if a file/directory is executable. + * @return the file matcher + */ + public static Matcher isSameFile(Path target) { + return matcher(toUncheckedEx(p->Files.isSameFile(target, p)), "the same file or directory", "is not the same file or directory", Path.class); + } + + /** + * A matcher that checks if a file/directory is a symbolic link. + * @return the file matcher + */ + public static Matcher isSymbolicLink() { + return matcher(Files::isSymbolicLink, "a file or directory is a symbolic link", "is not a symbolic link", Path.class); + } + + /** + * A matcher that checks if a file/directory is executable. + * @return the file matcher + */ + public static Matcher isHidden() { + return matcher(toUncheckedEx(p->PathMatchers.isHidden(p)), "a hidden file or directory", "is not hidden", Path.class); + } + + /** + * A matcher that checks if a file has a specific size. + * @param size the expected size + * @return the file matcher + */ + public static Matcher hasSizeEqualTo(long size) { + return hasSize(equalTo(size)); + } + + /** + * A matcher that checks if a file size matches an expected size. + * @param expected matcher for the expected size + * @return the file matcher + */ + public static Matcher hasSize(final Matcher expected) { + return FeatureMatcher.matcher(expected, p->toUncheckedEx(()->Files.size(p)), "A file with size", "size", Path.class); +// return new FeatureMatcher(expected, "A file with size", "size") { +// @Override protected Long featureValueOf(Path actual) { return toUncheckedEx(()->Files.size(actual)); } +// }; + } + + /** + * A matcher that checks if a file name matches an expected name. + * @param expected the expected name + * @return the file matcher + */ + public static Matcher hasFileName(final Matcher expected) { + return new FeatureMatcher(expected, "A file with name", "name") { + @Override protected Path featureValueOf(Path actual) { return actual.getFileName(); } + }; + } + + /** + * A matcher that checks if a file name matches an expected name. + * @param expected the expected name + * @return the file matcher + */ + public static Matcher hasFileNameString(final Matcher expected) { + return new FeatureMatcher(expected, "A file with name", "name") { + @Override protected String featureValueOf(Path actual) { return actual.getFileName().toString(); } + }; + } + + /** + * A matcher that checks if a file real path matches an expected path. + * @param expected the expected path + * @return the file matcher + */ + public static Matcher hasRealPath(final Matcher expected) { + return new FeatureMatcher(expected, "A file with real path", "path") { + @Override protected Path featureValueOf(Path actual) { return toUncheckedEx(()->actual.toRealPath()); } + }; + } + + /** + * A matcher that checks if a file real path matches an expected path. + * @param expected the expected path + * @return the file matcher + */ + public static Matcher hasRealPathString(final Matcher expected) { + return new FeatureMatcher(expected, "A file with real path", "path") { + @Override protected String featureValueOf(Path actual) { return toUncheckedEx(()->actual.toRealPath().toString()); } + }; + } + + /** + * A matcher that checks if a file canonical path matches an expected path. + * @deprecated Use {@link #hasRealPath(Matcher)} instead. Provided for backward compatibility with FileMatchers. + * + * @param expected the expected path + * @return the file matcher + */ + public static Matcher hasCanonicalPathString(final Matcher expected) { + return hasRealPathString(expected); // + } + + /** + * A matcher that checks if a file absolute path matches an expected path. + * @param expected the expected path + * @return the file matcher + */ + public static Matcher hasAbsolutePath(final Matcher expected) { + return new FeatureMatcher(expected, "A file with absolute path", "path") { + @Override protected Path featureValueOf(Path actual) { return actual.toAbsolutePath(); } + }; + } + /** + * A matcher that checks if a file absolute path matches an expected path. + * @param expected the expected path + * @return the file matcher + */ + public static Matcher hasAbsolutePathString(final Matcher expected) { + return new FeatureMatcher(expected, "A file with absolute path", "path") { + @Override protected String featureValueOf(Path actual) { return actual.toAbsolutePath().toString(); } + }; + } + + /** + * A matcher that checks if a file's FileSystem matches an expected FileSystem. + * @param expected + * @return + */ + public static Matcher hasFileSystem(final Matcher expected) { + return new FeatureMatcher(expected, "A file with file system", "file system") { + @Override protected java.nio.file.FileSystem featureValueOf(Path actual) { return actual.getFileSystem(); } + }; + } + + + // Possible additions: + // - hasParent(Matcher) + // - hasRoot(Matcher) + // - hasAttributes(Matcher>...) + // - hasLastModifiedTime(Matcher) + // - hasOwner(Matcher) + // - hasPosixPermissions(Matcher>) + + // - hasCreationTime(Matcher) + // - hasGroup(Matcher) + // - hasFileKey(Matcher) + // - hasFileAttribute(String, Matcher) + // - hasProvider(Matcher) + + // - hasContent(Matcher) + // - containsStrings(String...) + + // Workaround for JDK 8 not supporting Files.isHidden(Path) for directories (JDK-8215467). Fixed in Java 13. + private static boolean isHidden(Path path) throws IOException { + if (path.getFileSystem().provider().getClass().getName().contains("WindowsFileSystemProvider")) { + // WindowsFileSystemProvider does not support isHidden(Path) for directories + return Files.readAttributes(path, "dos:hidden", java.nio.file.LinkOption.NOFOLLOW_LINKS) + .get("hidden").equals(Boolean.TRUE); + } else { + return Files.isHidden(path); + } + } + + @FunctionalInterface + private interface Predicate_WithExceptions { + boolean test(T t) throws E; + } + + private static Predicate toUncheckedEx(Predicate_WithExceptions predicate) { + return value -> { + try { + return predicate.test(value); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }; + } + + @FunctionalInterface + private interface Supplier_WithExceptions { + T get() throws E; + } + + private static T toUncheckedEx(Supplier_WithExceptions supplier) { + try { + return supplier.get(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} diff --git a/hamcrest/src/test/java/org/hamcrest/FeatureMatcherTest.java b/hamcrest/src/test/java/org/hamcrest/FeatureMatcherTest.java index 82e89aa2..ee020957 100644 --- a/hamcrest/src/test/java/org/hamcrest/FeatureMatcherTest.java +++ b/hamcrest/src/test/java/org/hamcrest/FeatureMatcherTest.java @@ -9,6 +9,8 @@ public final class FeatureMatcherTest { private final FeatureMatcher resultMatcher = resultMatcher(); + private final Matcher resultMatcherStaticCtr = + FeatureMatcher.matcher(new Match("bar"), t->t.getResult(), "Thingy with result", "result", Thingy.class); @Test public void matchesPartOfAnObject() { @@ -16,16 +18,32 @@ public final class FeatureMatcherTest { assertDescription("Thingy with result \"bar\"", resultMatcher); } + @Test public void + matchesPartOfAnObject_staticConstructor() { + assertMatches("feature", resultMatcherStaticCtr, new Thingy("bar")); + assertDescription("Thingy with result \"bar\"", resultMatcherStaticCtr); + } + @Test public void mismatchesPartOfAnObject() { assertMismatchDescription("result mismatch-description", resultMatcher, new Thingy("foo")); } + @Test public void + mismatchesPartOfAnObject_staticConstructor() { + assertMismatchDescription("result mismatch-description", resultMatcherStaticCtr, new Thingy("foo")); + } + @Test public void doesNotThrowNullPointerException() { assertMismatchDescription("was null", resultMatcher, null); } + @Test public void + doesNotThrowNullPointerException_staticConstructor() { + assertMismatchDescription("was null", resultMatcherStaticCtr, null); + } + @Test public void doesNotThrowClassCastException() { resultMatcher.matches(new ShouldNotMatch()); @@ -34,6 +52,14 @@ public final class FeatureMatcherTest { assertEquals("was ShouldNotMatch ", mismatchDescription.toString()); } + @Test public void + doesNotThrowClassCastException_staticConstructor() { + resultMatcherStaticCtr.matches(new ShouldNotMatch()); + StringDescription mismatchDescription = new StringDescription(); + resultMatcherStaticCtr.describeMismatch(new ShouldNotMatch(), mismatchDescription); + assertEquals("was ShouldNotMatch ", mismatchDescription.toString()); + } + public static class Match extends IsEqual { public Match(String equalArg) { super(equalArg); } @Override public void describeMismatch(Object item, Description description) { diff --git a/hamcrest/src/test/java/org/hamcrest/TypeSafeDiagnosingMatcherTest.java b/hamcrest/src/test/java/org/hamcrest/TypeSafeDiagnosingMatcherTest.java index 61062074..c6df85f1 100644 --- a/hamcrest/src/test/java/org/hamcrest/TypeSafeDiagnosingMatcherTest.java +++ b/hamcrest/src/test/java/org/hamcrest/TypeSafeDiagnosingMatcherTest.java @@ -17,6 +17,15 @@ public class TypeSafeDiagnosingMatcherTest { assertMismatchDescription("mismatching", STRING_MATCHER, "other"); } + @Test public void + describesMismatches_staticConstructor() { + Matcher stringMatcher = + TypeSafeDiagnosingMatcher.matcher(item->false,"matches","mismatching",String.class); + assertMismatchDescription("was null", STRING_MATCHER, null); + assertMismatchDescription("was Character \"c\"", STRING_MATCHER, 'c'); + assertMismatchDescription("mismatching", STRING_MATCHER, "other"); + } + @Test public void detects_non_builtin_types() { final Matcher matcher = new TypeSafeDiagnosingMatcher() { @@ -32,13 +41,30 @@ protected boolean matchesSafely(NotBuiltIn item, Description mismatchDescription assertDoesNotMatch("other not built in", (Matcher)matcher, new OtherNotBuiltIn()); } + @Test public void + detects_non_builtin_types_static_constructor() { + final Matcher matcher = + TypeSafeDiagnosingMatcher.matcher(item->true,"a builtin","a not builtin",NotBuiltIn.class); + + assertMatches("not built in", matcher, new NotBuiltIn()); + assertDoesNotMatch("other not built in", (Matcher)matcher, new OtherNotBuiltIn()); + } + @Test public void filters_type_for_subclassed_matcher_when_expected_type_passed_in() { final Matcher matcher = new SubMatcher<>(new NotBuiltIn()); assertMatches("not built in", matcher, new NotBuiltIn()); assertDoesNotMatch("other not built in", (Matcher)matcher, new OtherNotBuiltIn()); - } + } + + @Test public void + filters_type_for_subclassed_matcher_when_expected_type_passed_in_staticConstructor() { + final Matcher matcher = SubMatcher.matcher(new NotBuiltIn()); + + assertMatches("not built in", matcher, new NotBuiltIn()); + assertDoesNotMatch("other not built in", (Matcher)matcher, new OtherNotBuiltIn()); + } @Test public void but_cannot_detect_generic_type_in_subclassed_matcher_using_reflection() { @@ -59,6 +85,7 @@ protected boolean matchesSafely(String item, Description mismatchDescription) { public void describeTo(Description description) { } }; + public static class SubMatcher extends TypeSafeDiagnosingMatcher { public SubMatcher() { super(); @@ -68,6 +95,12 @@ public SubMatcher(T expectedObject) { } @Override protected boolean matchesSafely(T item, Description mismatchDescription) { return true; } @Override public void describeTo(Description description) { description.appendText("sub type"); } + + static Matcher matcher(T expectedObject) { + return new SubMatcher(expectedObject) { + + }; + } } public static class NotBuiltIn { diff --git a/hamcrest/src/test/java/org/hamcrest/io/PathMatchersTest.java b/hamcrest/src/test/java/org/hamcrest/io/PathMatchersTest.java new file mode 100644 index 00000000..e830a8cd --- /dev/null +++ b/hamcrest/src/test/java/org/hamcrest/io/PathMatchersTest.java @@ -0,0 +1,202 @@ +package org.hamcrest.io; + +import org.hamcrest.test.AbstractMatcherTest; +import org.hamcrest.Matcher; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; +import org.junit.jupiter.api.io.CleanupMode; +import org.junit.jupiter.api.io.TempDir; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.DosFileAttributes; + +import static org.hamcrest.test.MatcherAssertions.*; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@SuppressWarnings("ResultOfMethodCallIgnored") +public class PathMatchersTest extends AbstractMatcherTest { + + @TempDir Path tempDir; + private Path directory; + private Path file; + private Path symbolicLink; + + @BeforeEach + protected void setUp() throws IOException { + directory = Files.createDirectory(tempDir.resolve("myDir")); + file = directory.resolve("myFile"); + Files.createFile(file); + Files.createFile(directory.resolve("mydirFile")); // Makes sure myDir is not empty. + if (!OS.WINDOWS.isCurrentOs()) { // Can't do symbolic links on Windows unless admin privileges are available. + Files.createSymbolicLink(tempDir.resolve("mySymbolicLink"), file); + } + } + + @Test + public void testAnExistingDirectory() { + assertMatches("matches existing directory", PathMatchers.anExistingDirectory(), directory); + assertDoesNotMatch("doesn't match existing file", PathMatchers.anExistingDirectory(), file); + assertMismatchDescription("'foo' is not a directory", PathMatchers.anExistingDirectory(), Paths.get("foo")); + } + + @Test + public void testAnExistingFileOrDirectory() { + assertMatches("matches existing file", PathMatchers.anExistingFileOrDirectory(), file); + assertMatches("matches existing directory", PathMatchers.anExistingFileOrDirectory(), directory); + assertMismatchDescription("'foo' does not exist", PathMatchers.anExistingFileOrDirectory(), Paths.get("foo")); + } + + @Test + public void testAnExistingFile() { + assertMatches("matches existing file", PathMatchers.anExistingFile(), file); + assertDoesNotMatch("doesn't match existing directory", PathMatchers.anExistingFile(), directory); + assertMismatchDescription("'foo' is not a file", PathMatchers.anExistingFile(), Paths.get("foo")); + } + + @Test + public void testIsReadable() { // Not all OSes will allow setting readability so have to be forgiving here. + file.toFile().setReadable(true); + assertMatches("matches readable file", PathMatchers.isReadable(), file); + + if (file.toFile().setReadable(false)) { + assertDoesNotMatch("doesn't match unreadable file", PathMatchers.isReadable(), file); + } + } + + @Test + public void testIsWritable() { + assertMatches("matches writable file", PathMatchers.isWritable(), file); + + assertTrue(file.toFile().setWritable(false), "set writable off " + file); + assertDoesNotMatch("doesn't match unwritable file", PathMatchers.isWritable(), file); + + assertMatches("matches writable directory", PathMatchers.isWritable(), directory); + + // Directories cannot be set to read-only on Windows. + if (!OS.WINDOWS.isCurrentOs()) { + assertTrue(directory.toFile().setWritable(false), "set writable off " + file); + assertDoesNotMatch("doesn't match unwritable file", PathMatchers.isWritable(), directory); + } + } + + @Test + public void testIsHidden() throws Exception { + Path hiddenFile = tempDir.resolve(Paths.get(".hidden_file")); + Path hiddenDir = tempDir.resolve(Paths.get(".hidden_dir")); + Files.createFile(hiddenFile); + Files.createDirectory(hiddenDir); + + // Set the hidden attribute for the file and directory on Windows. + if (OS.WINDOWS.isCurrentOs()) { + Files.setAttribute(hiddenFile, "dos:hidden", true); + Files.setAttribute(hiddenDir, "dos:hidden", true); + } + + assertMatches("matches hidden file", PathMatchers.isHidden(), tempDir.resolve(hiddenFile)); + assertMatches("matches hidden directory", PathMatchers.isHidden(), hiddenDir); + + assertDoesNotMatch("doesn't match unhidden (i.e. visible) file", PathMatchers.isHidden(), file); + assertDoesNotMatch("doesn't match unhidden (i.e. visible) directory", PathMatchers.isHidden(), directory); + } + + @Test + public void testIsSameFile() { + // TODO: Needs work + assertMatches("matches same file", PathMatchers.isSameFile(file.toAbsolutePath()), file); + assertDoesNotMatch("doesn't match different file", PathMatchers.isSameFile(file), directory); + assertMismatchDescription("'" + directory.toString() + "' is not the same file or directory", PathMatchers.isSameFile(file), directory); + if (!OS.WINDOWS.isCurrentOs()) { // Windows does not support symbolic links without administrator privileges. + assertMatches("matches same file through symbolic link", PathMatchers.isSameFile(file), + symbolicLink); + assertDoesNotMatch("doesn't match different file through symbolic link", PathMatchers.isSameFile(directory), + symbolicLink); + } + } + + @DisabledOnOs(OS.WINDOWS) // Windows does not support creating symbolic links without administrator privileges. + @Test + public void testisSymbolicLink() { + assertMatches("matches synbolic link", PathMatchers.isSymbolicLink(), symbolicLink); + assertDoesNotMatch("doesn't match a file", PathMatchers.isSymbolicLink(), file); + assertMismatchDescription("'foo' is not a symbolic link", PathMatchers.isSymbolicLink(), Paths.get("foo")); + } + + @Test + public void testHasSizeEqualToLong() { + assertMatches("matches file size", PathMatchers.hasSizeEqualTo(0L), file); + assertDoesNotMatch("doesn't match incorrect file size", PathMatchers.hasSizeEqualTo(34L), file); + + assertMatches("matches file size", PathMatchers.hasSizeEqualTo(0L), directory); + assertDoesNotMatch("doesn't match incorrect file size", PathMatchers.hasSizeEqualTo(34L), directory); + } + + @Test + public void testHasSizeMatcherOfLong() { + assertMatches("matches file size", PathMatchers.hasSize(equalTo(0L)), file); + assertDoesNotMatch("doesn't match incorrect file size", PathMatchers.hasSize(equalTo(23L)), file); + } + + @Test + public void testHasFileName_Path() { + assertMatches("matches file name", PathMatchers.hasFileName(equalTo(file.getFileName())), file); + assertDoesNotMatch("doesn't match incorrect file name", PathMatchers.hasFileName(equalTo(Paths.get("foo"))), file); + } + + @Test + public void testHasFileNameString_String() { + assertMatches("matches file name", PathMatchers.hasFileNameString(equalTo(file.getFileName().toString())), file); + assertDoesNotMatch("doesn't match incorrect file name", PathMatchers.hasFileNameString(equalTo("foo")), file); + } + + @Test + public void testHasRealPath() throws Exception { + assertMatches("matches file canonical path", PathMatchers.hasRealPath(equalTo(file.toRealPath())), file); + assertDoesNotMatch("doesn't match incorrect canonical path", PathMatchers.hasRealPath(equalTo(Paths.get("foo"))), file); + } + + @Test + public void testHasRealPathString() throws Exception { + assertMatches("matches file canonical path", PathMatchers.hasRealPathString(equalTo(file.toRealPath().toString())), file); + assertDoesNotMatch("doesn't match incorrect canonical path", PathMatchers.hasRealPathString(equalTo("foo")), file); + } + + @Test + public void testHasCanonicalPathString() throws Exception { + assertMatches("matches file canonical path", PathMatchers.hasCanonicalPathString(equalTo(file.toRealPath().toString())), file); + assertDoesNotMatch("doesn't match incorrect canonical path", PathMatchers.hasCanonicalPathString(equalTo("foo")), file); + } + + @Test + public void testHasAbsolutePath() { + assertMatches("matches file absolute path", PathMatchers.hasAbsolutePath(equalTo(file.toAbsolutePath())), file); + assertDoesNotMatch("doesn't match incorrect absolute path", PathMatchers.hasAbsolutePath(equalTo(Paths.get("foo"))), file); + } + + @Test + public void testHasAbsolutePathString() { + assertMatches("matches file absolute path", PathMatchers.hasAbsolutePathString(equalTo(file.toAbsolutePath().toString())), file); + assertDoesNotMatch("doesn't match incorrect absolute path", PathMatchers.hasAbsolutePathString(equalTo("foo")), file); + } + + @Test + public void testHasFileSystem() { + assertMatches("matches file system", PathMatchers.hasFileSystem(equalTo(file.getFileSystem())), file); + // TODO: Maybe use JimFS to create a different FileSystem for this test? +// assertDoesNotMatch("doesn't match incorrect file system",PathMatchers.hasFileSystem(equalTo(Paths.get("foo").getFileSystem())), file); + } + + @Override + protected Matcher createMatcher() { + return PathMatchers.hasSizeEqualTo(1L); +// return PathMatchers.isSymbolicLink(); + } + +}