aboutsummaryrefslogtreecommitdiff
path: root/jimfs/src/test/java/com/google/common/jimfs/PathSubject.java
diff options
context:
space:
mode:
Diffstat (limited to 'jimfs/src/test/java/com/google/common/jimfs/PathSubject.java')
-rw-r--r--jimfs/src/test/java/com/google/common/jimfs/PathSubject.java406
1 files changed, 406 insertions, 0 deletions
diff --git a/jimfs/src/test/java/com/google/common/jimfs/PathSubject.java b/jimfs/src/test/java/com/google/common/jimfs/PathSubject.java
new file mode 100644
index 0000000..f6927a5
--- /dev/null
+++ b/jimfs/src/test/java/com/google/common/jimfs/PathSubject.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * 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 com.google.common.jimfs;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.truth.Fact.fact;
+import static com.google.common.truth.Fact.simpleFact;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Arrays.asList;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.io.BaseEncoding;
+import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.Subject;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.checkerframework.checker.nullness.compatqual.NullableDecl;
+
+/**
+ * Subject for doing assertions on file system paths.
+ *
+ * @author Colin Decker
+ */
+public final class PathSubject extends Subject {
+
+ /** Returns the subject factory for doing assertions on paths. */
+ public static Subject.Factory<PathSubject, Path> paths() {
+ return new PathSubjectFactory();
+ }
+
+ private static final LinkOption[] FOLLOW_LINKS = new LinkOption[0];
+ private static final LinkOption[] NOFOLLOW_LINKS = {LinkOption.NOFOLLOW_LINKS};
+
+ private final Path actual;
+ protected LinkOption[] linkOptions = FOLLOW_LINKS;
+ private Charset charset = UTF_8;
+
+ private PathSubject(FailureMetadata failureMetadata, Path subject) {
+ super(failureMetadata, subject);
+ this.actual = subject;
+ }
+
+ private Path toPath(String path) {
+ return actual.getFileSystem().getPath(path);
+ }
+
+ /** Returns this, for readability of chained assertions. */
+ public PathSubject and() {
+ return this;
+ }
+
+ /** Do not follow links when looking up the path. */
+ public PathSubject noFollowLinks() {
+ this.linkOptions = NOFOLLOW_LINKS;
+ return this;
+ }
+
+ /**
+ * Set the given charset to be used when reading the file at this path as text. Default charset if
+ * not set is UTF-8.
+ */
+ public PathSubject withCharset(Charset charset) {
+ this.charset = checkNotNull(charset);
+ return this;
+ }
+
+ /** Asserts that the path is absolute (it has a root component). */
+ public PathSubject isAbsolute() {
+ if (!actual.isAbsolute()) {
+ failWithActual(simpleFact("expected to be absolute"));
+ }
+ return this;
+ }
+
+ /** Asserts that the path is relative (it has no root component). */
+ public PathSubject isRelative() {
+ if (actual.isAbsolute()) {
+ failWithActual(simpleFact("expected to be relative"));
+ }
+ return this;
+ }
+
+ /** Asserts that the path has the given root component. */
+ public PathSubject hasRootComponent(@NullableDecl String root) {
+ Path rootComponent = actual.getRoot();
+ if (root == null && rootComponent != null) {
+ failWithActual("expected to have root component", root);
+ } else if (root != null && !root.equals(rootComponent.toString())) {
+ failWithActual("expected to have root component", root);
+ }
+ return this;
+ }
+
+ /** Asserts that the path has no name components. */
+ public PathSubject hasNoNameComponents() {
+ check("getNameCount()").that(actual.getNameCount()).isEqualTo(0);
+ return this;
+ }
+
+ /** Asserts that the path has the given name components. */
+ public PathSubject hasNameComponents(String... names) {
+ ImmutableList.Builder<String> builder = ImmutableList.builder();
+ for (Path name : actual) {
+ builder.add(name.toString());
+ }
+
+ if (!builder.build().equals(ImmutableList.copyOf(names))) {
+ failWithActual("expected components", asList(names));
+ }
+ return this;
+ }
+
+ /** Asserts that the path matches the given syntax and pattern. */
+ public PathSubject matches(String syntaxAndPattern) {
+ PathMatcher matcher = actual.getFileSystem().getPathMatcher(syntaxAndPattern);
+ if (!matcher.matches(actual)) {
+ failWithActual("expected to match ", syntaxAndPattern);
+ }
+ return this;
+ }
+
+ /** Asserts that the path does not match the given syntax and pattern. */
+ public PathSubject doesNotMatch(String syntaxAndPattern) {
+ PathMatcher matcher = actual.getFileSystem().getPathMatcher(syntaxAndPattern);
+ if (matcher.matches(actual)) {
+ failWithActual("expected not to match", syntaxAndPattern);
+ }
+ return this;
+ }
+
+ /** Asserts that the path exists. */
+ public PathSubject exists() {
+ if (!Files.exists(actual, linkOptions)) {
+ failWithActual(simpleFact("expected to exist"));
+ }
+ if (Files.notExists(actual, linkOptions)) {
+ failWithActual(simpleFact("expected to exist"));
+ }
+ return this;
+ }
+
+ /** Asserts that the path does not exist. */
+ public PathSubject doesNotExist() {
+ if (!Files.notExists(actual, linkOptions)) {
+ failWithActual(simpleFact("expected not to exist"));
+ }
+ if (Files.exists(actual, linkOptions)) {
+ failWithActual(simpleFact("expected not to exist"));
+ }
+ return this;
+ }
+
+ /** Asserts that the path is a directory. */
+ public PathSubject isDirectory() {
+ exists(); // check for directoryness should imply check for existence
+
+ if (!Files.isDirectory(actual, linkOptions)) {
+ failWithActual(simpleFact("expected to be directory"));
+ }
+ return this;
+ }
+
+ /** Asserts that the path is a regular file. */
+ public PathSubject isRegularFile() {
+ exists(); // check for regular fileness should imply check for existence
+
+ if (!Files.isRegularFile(actual, linkOptions)) {
+ failWithActual(simpleFact("expected to be regular file"));
+ }
+ return this;
+ }
+
+ /** Asserts that the path is a symbolic link. */
+ public PathSubject isSymbolicLink() {
+ exists(); // check for symbolic linkness should imply check for existence
+
+ if (!Files.isSymbolicLink(actual)) {
+ failWithActual(simpleFact("expected to be symbolic link"));
+ }
+ return this;
+ }
+
+ /** Asserts that the path, which is a symbolic link, has the given path as a target. */
+ public PathSubject withTarget(String targetPath) throws IOException {
+ Path actualTarget = Files.readSymbolicLink(actual);
+ if (!actualTarget.equals(toPath(targetPath))) {
+ failWithoutActual(
+ fact("expected link target", targetPath),
+ fact("but target was", actualTarget),
+ fact("for path", actual));
+ }
+ return this;
+ }
+
+ /**
+ * Asserts that the file the path points to exists and has the given number of links to it. Fails
+ * on a file system that does not support the "unix" view.
+ */
+ public PathSubject hasLinkCount(int count) throws IOException {
+ exists();
+
+ int linkCount = (int) Files.getAttribute(actual, "unix:nlink", linkOptions);
+ if (linkCount != count) {
+ failWithActual("expected to have link count", count);
+ }
+ return this;
+ }
+
+ /** Asserts that the path resolves to the same file as the given path. */
+ public PathSubject isSameFileAs(String path) throws IOException {
+ return isSameFileAs(toPath(path));
+ }
+
+ /** Asserts that the path resolves to the same file as the given path. */
+ public PathSubject isSameFileAs(Path path) throws IOException {
+ if (!Files.isSameFile(actual, path)) {
+ failWithActual("expected to be same file as", path);
+ }
+ return this;
+ }
+
+ /** Asserts that the path does not resolve to the same file as the given path. */
+ public PathSubject isNotSameFileAs(String path) throws IOException {
+ if (Files.isSameFile(actual, toPath(path))) {
+ failWithActual("expected not to be same file as", path);
+ }
+ return this;
+ }
+
+ /** Asserts that the directory has no children. */
+ public PathSubject hasNoChildren() throws IOException {
+ isDirectory();
+
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(actual)) {
+ if (stream.iterator().hasNext()) {
+ failWithActual(simpleFact("expected to have no children"));
+ }
+ }
+ return this;
+ }
+
+ /** Asserts that the directory has children with the given names, in the given order. */
+ public PathSubject hasChildren(String... children) throws IOException {
+ isDirectory();
+
+ List<Path> expectedNames = new ArrayList<>();
+ for (String child : children) {
+ expectedNames.add(actual.getFileSystem().getPath(child));
+ }
+
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(actual)) {
+ List<Path> actualNames = new ArrayList<>();
+ for (Path path : stream) {
+ actualNames.add(path.getFileName());
+ }
+
+ if (!actualNames.equals(expectedNames)) {
+ failWithoutActual(
+ fact("expected to have children", expectedNames),
+ fact("but had children", actualNames),
+ fact("for path", actual));
+ }
+ }
+ return this;
+ }
+
+ /** Asserts that the file has the given size. */
+ public PathSubject hasSize(long size) throws IOException {
+ if (Files.size(actual) != size) {
+ failWithActual("expected to have size", size);
+ }
+ return this;
+ }
+
+ /** Asserts that the file is a regular file containing no bytes. */
+ public PathSubject containsNoBytes() throws IOException {
+ return containsBytes(new byte[0]);
+ }
+
+ /**
+ * Asserts that the file is a regular file containing exactly the byte values of the given ints.
+ */
+ public PathSubject containsBytes(int... bytes) throws IOException {
+ byte[] realBytes = new byte[bytes.length];
+ for (int i = 0; i < bytes.length; i++) {
+ realBytes[i] = (byte) bytes[i];
+ }
+ return containsBytes(realBytes);
+ }
+
+ /** Asserts that the file is a regular file containing exactly the given bytes. */
+ public PathSubject containsBytes(byte[] bytes) throws IOException {
+ isRegularFile();
+ hasSize(bytes.length);
+
+ byte[] actual = Files.readAllBytes(this.actual);
+ if (!Arrays.equals(bytes, actual)) {
+ System.out.println(BaseEncoding.base16().encode(actual));
+ System.out.println(BaseEncoding.base16().encode(bytes));
+ failWithActual("expected to contain bytes", BaseEncoding.base16().encode(bytes));
+ }
+ return this;
+ }
+
+ /**
+ * Asserts that the file is a regular file containing the same bytes as the regular file at the
+ * given path.
+ */
+ public PathSubject containsSameBytesAs(String path) throws IOException {
+ isRegularFile();
+
+ byte[] expectedBytes = Files.readAllBytes(toPath(path));
+ if (!Arrays.equals(expectedBytes, Files.readAllBytes(actual))) {
+ failWithActual("expected to contain same bytes as", path);
+ }
+ return this;
+ }
+
+ /**
+ * Asserts that the file is a regular file containing the given lines of text. By default, the
+ * bytes are decoded as UTF-8; for a different charset, use {@link #withCharset(Charset)}.
+ */
+ public PathSubject containsLines(String... lines) throws IOException {
+ return containsLines(Arrays.asList(lines));
+ }
+
+ /**
+ * Asserts that the file is a regular file containing the given lines of text. By default, the
+ * bytes are decoded as UTF-8; for a different charset, use {@link #withCharset(Charset)}.
+ */
+ public PathSubject containsLines(Iterable<String> lines) throws IOException {
+ isRegularFile();
+
+ List<String> expected = ImmutableList.copyOf(lines);
+ List<String> actual = Files.readAllLines(this.actual, charset);
+ check("lines()").that(actual).isEqualTo(expected);
+ return this;
+ }
+
+ /** Returns an object for making assertions about the given attribute. */
+ public Attribute attribute(final String attribute) {
+ return new Attribute() {
+ @Override
+ public Attribute is(Object value) throws IOException {
+ Object actualValue = Files.getAttribute(actual, attribute, linkOptions);
+ check("attribute(%s)", attribute).that(actualValue).isEqualTo(value);
+ return this;
+ }
+
+ @Override
+ public Attribute isNot(Object value) throws IOException {
+ Object actualValue = Files.getAttribute(actual, attribute, linkOptions);
+ check("attribute(%s)", attribute).that(actualValue).isNotEqualTo(value);
+ return this;
+ }
+
+ @Override
+ public PathSubject and() {
+ return PathSubject.this;
+ }
+ };
+ }
+
+ private static class PathSubjectFactory implements Subject.Factory<PathSubject, Path> {
+
+ @Override
+ public PathSubject createSubject(FailureMetadata failureMetadata, Path that) {
+ return new PathSubject(failureMetadata, that);
+ }
+ }
+
+ /** Interface for assertions about a file attribute. */
+ public interface Attribute {
+
+ /** Asserts that the value of this attribute is equal to the given value. */
+ Attribute is(Object value) throws IOException;
+
+ /** Asserts that the value of this attribute is not equal to the given value. */
+ Attribute isNot(Object value) throws IOException;
+
+ /** Returns the path subject for further chaining. */
+ PathSubject and();
+ }
+}