FileMatcher.java
/**
* Copyright (C) 2022 Christopher J. Stehno
*
* Licensed 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 io.github.cjstehno.testthings.match;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import static io.github.cjstehno.testthings.match.PredicateMatcher.matchesPredicate;
import static java.lang.String.join;
import static java.nio.file.Files.readAllLines;
import static lombok.AccessLevel.PRIVATE;
import static org.hamcrest.CoreMatchers.equalTo;
/**
* Matchers useful for matching File information.
*/
public abstract class FileMatcher extends BaseMatcher<File> {
/**
* Creates a file matcher for matching the file name.
*
* @param nameMatcher the name string matcher
* @return the file matcher
*/
public static Matcher<File> nameMatches(final Matcher<String> nameMatcher) {
return new FileNameMatcher(nameMatcher);
}
/**
* Creates a file matcher for matching the file name.
*
* @param name expected name
* @return the file matcher
*/
public static Matcher<File> nameEqualTo(final String name) {
return nameMatches(equalTo(name));
}
/**
* Creates a file matcher for matching the file extension (not including the dot).
*
* @param extensionMatcher the extension string matcher
* @return the file matcher
*/
public static Matcher<File> extensionMatches(final Matcher<String> extensionMatcher) {
return new FileExtensionMatcher(extensionMatcher);
}
/**
* Creates a file matcher for matching the file extension (not including the dot).
*
* @param extension the file extension
* @return the file matcher
*/
public static Matcher<File> extensionEqualTo(final String extension) {
return extensionMatches(equalTo(extension));
}
/**
* Creates a file matcher for matching whether a file exists.
*
* @return the file matcher
*/
public static Matcher<File> fileExists() {
return matchesPredicate(File::exists, "a file that exists");
}
/**
* Creates a file matcher for matching whether is readable.
*
* @return the file matcher
*/
public static Matcher<File> isReadable() {
return matchesPredicate(File::canRead, "a file that is readable");
}
/**
* /**
* Creates a file matcher for matching whether a file is writable.
*
* @return the file matcher
*/
public static Matcher<File> isWritable() {
return matchesPredicate(File::canRead, "a file that is writable");
}
/**
* Creates a file matcher for matching whether a file is a file (not a directory).
*
* @return the file matcher
*/
public static Matcher<File> isFile() {
return matchesPredicate(File::isFile, "a file that is a normal file");
}
/**
* Creates a file matcher for matching whether a file is a directory.
*
* @return the file matcher
*/
public static Matcher<File> isDirectory() {
return matchesPredicate(File::isDirectory, "a file that is a directory");
}
/**
* Creates a file matcher for matching the content bytes.
*
* @param arrayMatcher the byte array matcher
* @return the file matcher
*/
public static Matcher<File> fileBytesMatch(final Matcher<byte[]> arrayMatcher) {
return new FileBytesMatcher(arrayMatcher);
}
/**
* Creates a file matcher for matching the content as a string. Multiline content will be joined with line breaks
* (i.e. "\n").
*
* @param stringMatcher the string text matcher
* @return the file matcher
*/
public static Matcher<File> fileTextMatches(final Matcher<String> stringMatcher) {
return new FileTextMatcher(stringMatcher);
}
/**
* Creates a file matcher for matching the size of a file.
*
* @param sizeMatcher the matcher for the size of the file
* @return the file matcher
*/
public static Matcher<File> fileSizeMatches(final Matcher<Long> sizeMatcher) {
return new FileSizeMatcher(sizeMatcher);
}
@RequiredArgsConstructor(access = PRIVATE)
private static class FileBytesMatcher extends FileMatcher {
private final Matcher<byte[]> contentMatcher;
@Override public boolean matches(final Object actual) {
try {
return contentMatcher.matches(Files.readAllBytes(((File) actual).toPath()));
} catch (final IOException e) {
return false;
}
}
@Override public void describeTo(final Description description) {
description.appendText("a file with content matching ");
contentMatcher.describeTo(description);
}
}
@RequiredArgsConstructor(access = PRIVATE)
private static class FileTextMatcher extends FileMatcher {
private final Matcher<String> contentMatcher;
@Override public boolean matches(final Object actual) {
try {
return contentMatcher.matches(join("\n", readAllLines(((File) actual).toPath())));
} catch (final IOException e) {
return false;
}
}
@Override public void describeTo(final Description description) {
description.appendText("a file with content matching ");
contentMatcher.describeTo(description);
}
}
@RequiredArgsConstructor(access = PRIVATE)
private static class FileNameMatcher extends FileMatcher {
private final Matcher<String> nameMatcher;
@Override public boolean matches(final Object actual) {
return nameMatcher.matches(((File) actual).getName());
}
@Override public void describeTo(final Description description) {
description.appendText("A file with name matching ");
nameMatcher.describeTo(description);
}
}
@RequiredArgsConstructor(access = PRIVATE)
private static class FileSizeMatcher extends FileMatcher {
private final Matcher<Long> sizeMatcher;
@Override public boolean matches(final Object actual) {
val actualFile = (File) actual;
System.out.println(actualFile.length());
return sizeMatcher.matches(actualFile.length());
}
@Override public void describeTo(final Description description) {
description.appendText("a file with size matching ");
sizeMatcher.describeTo(description);
}
}
@RequiredArgsConstructor(access = PRIVATE)
private static class FileExtensionMatcher extends FileMatcher {
private final Matcher<String> extensionMatcher;
@Override public boolean matches(final Object actual) {
val actualName = ((File) actual).getName();
val actualExt = actualName.substring(actualName.lastIndexOf('.') + 1);
return extensionMatcher.matches(actualExt);
}
@Override public void describeTo(final Description description) {
description.appendText("A file with extension matching ");
extensionMatcher.describeTo(description);
}
}
}