From 1d4c19c53e205ac486f4f6386179eabe8318316e Mon Sep 17 00:00:00 2001 From: Joshua Gleitze Date: Fri, 30 Oct 2020 09:13:06 +0100 Subject: [PATCH] add Path.hasDirectoryEntry (#685) --- .../atrium/api/fluent/en_GB/pathAssertions.kt | 34 ++- .../api/fluent/en_GB/PathAssertionsSpec.kt | 7 +- .../en_GB/creating/path/DirectoryEntries.kt | 13 + .../atrium/api/infix/en_GB/pathAssertions.kt | 62 ++++- .../src/module/module-info.java | 1 + .../api/infix/en_GB/PathAssertionsSpec.kt | 14 +- .../kotlin/ch/tutteli/atrium/logic/any.kt | 1 + .../ch/tutteli/atrium/logic/charSequence.kt | 1 + .../ch/tutteli/atrium/logic/collectionLike.kt | 1 + .../ch/tutteli/atrium/logic/comparable.kt | 1 + .../contains/creators/charSequenceContains.kt | 1 + .../contains/creators/iterableLikeContains.kt | 1 + .../iterableLikeContainsInAnyOrder.kt | 1 + .../kotlin/ch/tutteli/atrium/logic/feature.kt | 1 + .../ch/tutteli/atrium/logic/floatingPoint.kt | 1 + .../kotlin/ch/tutteli/atrium/logic/fun0.kt | 1 + .../ch/tutteli/atrium/logic/iterableLike.kt | 1 + .../ch/tutteli/atrium/logic/iterator.kt | 1 + .../kotlin/ch/tutteli/atrium/logic/list.kt | 1 + .../kotlin/ch/tutteli/atrium/logic/map.kt | 1 + .../ch/tutteli/atrium/logic/mapEntry.kt | 1 + .../kotlin/ch/tutteli/atrium/logic/pair.kt | 1 + .../ch/tutteli/atrium/logic/throwable.kt | 1 + .../ch/tutteli/atrium/logic/bigDecimal.kt | 1 + .../tutteli/atrium/logic/chronoLocalDate.kt | 1 + .../atrium/logic/chronoLocalDateTime.kt | 1 + .../atrium/logic/chronoZonedDateTime.kt | 1 + .../tutteli/atrium/logic/floatingPointJvm.kt | 1 + .../ch/tutteli/atrium/logic/localDate.kt | 1 + .../ch/tutteli/atrium/logic/localDateTime.kt | 1 + .../ch/tutteli/atrium/logic/optional.kt | 1 + .../kotlin/ch/tutteli/atrium/logic/path.kt | 8 +- .../ch/tutteli/atrium/logic/zonedDateTime.kt | 1 + .../ch/tutteli/atrium/logic/PathAssertions.kt | 12 +- .../logic/impl/DefaultPathAssertions.kt | 28 ++- .../tutteli/atrium/logic/kotlin_1_3/result.kt | 1 + logic/generateLogic.gradle | 3 +- .../api/fluent/en_GB/jdk8/pathAssertions.kt | 6 +- .../fluent/en_GB/jdk8/PathAssertionsSpec.kt | 9 +- .../specs/integration/PathAssertionsSpec.kt | 222 +++++++++++------- 40 files changed, 306 insertions(+), 140 deletions(-) create mode 100644 apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/infix/en_GB/creating/path/DirectoryEntries.kt diff --git a/apis/fluent-en_GB/atrium-api-fluent-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/fluent/en_GB/pathAssertions.kt b/apis/fluent-en_GB/atrium-api-fluent-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/fluent/en_GB/pathAssertions.kt index 82364dd54..d9cf321fe 100644 --- a/apis/fluent-en_GB/atrium-api-fluent-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/fluent/en_GB/pathAssertions.kt +++ b/apis/fluent-en_GB/atrium-api-fluent-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/fluent/en_GB/pathAssertions.kt @@ -7,7 +7,7 @@ package ch.tutteli.atrium.api.fluent.en_GB import ch.tutteli.atrium.creating.Expect import ch.tutteli.atrium.logic.* -import ch.tutteli.kbox.forElementAndForEachIn +import ch.tutteli.kbox.glue import java.nio.charset.Charset import java.nio.file.Path @@ -196,7 +196,7 @@ fun Expect.resolve(other: String, assertionCreator: Expect.( * Therefore, if a symbolic link exists at the location the subject points to, * search will continue at the location the link points at. * - * This assertion is not atomic with respect to concurrent file system operations on the paths the assertions works on. + * This assertion is not atomic with respect to concurrent file system operations on the paths the assertion works on. * Its result, in particular its extended explanations, may be wrong if such concurrent file system operations * take place. * @@ -255,7 +255,7 @@ fun Expect.isExecutable(): Expect = * Therefore, if a symbolic link exists at the location the subject points to, search will continue * at the location the link points at. * - * This assertion is not atomic with respect to concurrent file system operations on the paths the assertions works on. + * This assertion is not atomic with respect to concurrent file system operations on the paths the assertion works on. * Its result, in particular its extended explanations, may be wrong if such concurrent file system operations * take place. * @@ -275,7 +275,7 @@ fun Expect.isRegularFile(): Expect = * Therefore, if a symbolic link exists at the location the subject points to, search will continue * at the location the link points at. * - * This assertion is not atomic with respect to concurrent file system operations on the paths the assertions works on. + * This assertion is not atomic with respect to concurrent file system operations on the paths the assertion works on. * Its result, in particular its extended explanations, may be wrong if such concurrent file system operations * take place. * @@ -312,17 +312,17 @@ fun Expect.isRelative(): Expect = _logicAppend { isRelative() } /** - * Expects that the subject of the assertion (a [Path]) is a directory; - * meaning that there is a file system entry at the location the [Path] points to and that is a directory. + * Expects that the subject of the assertion (a [Path]) is a directory having the provided entries. + * That means that there is a file system entry at the location the [Path] points to and that it is a directory. + * Furthermore, every argument string resolved against the subject yields an existing file system entry. * - * Every argument string is expected to exist as a child file or child directory for the subject of the assertion. + * This assertion _resolves_ symbolic links for the subject, but not for the entries. + * Therefore, if a symbolic link exists at the location the subject points to, the search will continue at the location + * the link points at. If a symbolic link exists at one of the entries, this will fulfill the respective assertion and + * the entry’s symbolic link will not be followed. * - * This assertion _resolves_ symbolic links. - * Therefore, if a symbolic link exists at the location the subject points to, search will continue - * at the location the link points at. - * - * This assertion is not atomic with respect to concurrent file system operations on the paths the assertions works on. - * Its result, in particular its extended explanations, may be wrong if such concurrent file system operations + * This assertion is not atomic with respect to concurrent file system operations on the paths the assertion works on. + * The result, in particular its extended explanations, may be wrong if such concurrent file system operations * take place. * * @return An [Expect] for the current subject of the assertion. @@ -330,12 +330,8 @@ fun Expect.isRelative(): Expect = * * @since 0.14.0 */ -fun Expect.contains(path: String, vararg otherPaths: String): Expect = - isDirectory() and { - forElementAndForEachIn(path, otherPaths) { p -> - resolve(p) { exists() } - } - } +fun Expect.hasDirectoryEntry(entry: String, vararg otherEntries: String): Expect = + _logicAppend { hasDirectoryEntry(entry glue otherEntries) } /** * Creates an [Expect] for the property [Path.extension][ch.tutteli.niok.extension] diff --git a/apis/fluent-en_GB/atrium-api-fluent-en_GB-jvm/src/test/kotlin/ch/tutteli/atrium/api/fluent/en_GB/PathAssertionsSpec.kt b/apis/fluent-en_GB/atrium-api-fluent-en_GB-jvm/src/test/kotlin/ch/tutteli/atrium/api/fluent/en_GB/PathAssertionsSpec.kt index c5418a5a2..5c2f111af 100644 --- a/apis/fluent-en_GB/atrium-api-fluent-en_GB-jvm/src/test/kotlin/ch/tutteli/atrium/api/fluent/en_GB/PathAssertionsSpec.kt +++ b/apis/fluent-en_GB/atrium-api-fluent-en_GB-jvm/src/test/kotlin/ch/tutteli/atrium/api/fluent/en_GB/PathAssertionsSpec.kt @@ -19,15 +19,18 @@ class PathAssertionsSpec : ch.tutteli.atrium.specs.integration.PathAssertionsSpe fun0(Expect::isDirectory), fun0(Expect::isAbsolute), fun0(Expect::isRelative), - fun2>(Expect::contains), + Expect::hasDirectoryEntry.name to Companion::hasDirectoryEntrySingle, + fun2>(Expect::hasDirectoryEntry), fun1(Expect::hasSameBinaryContentAs), fun3(Expect::hasSameTextualContentAs), - fun1(Companion::hasSameTextualContentAsDefaultArgs) + Expect::hasSameTextualContentAs.name to Companion::hasSameTextualContentAsDefaultArgs ) { companion object { private fun hasSameTextualContentAsDefaultArgs(expect: Expect, targetPath: Path): Expect = expect.hasSameTextualContentAs(targetPath) + + private fun hasDirectoryEntrySingle(expect: Expect, entry: String) = expect.hasDirectoryEntry(entry) } @Suppress("unused", "UNUSED_VALUE") diff --git a/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/infix/en_GB/creating/path/DirectoryEntries.kt b/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/infix/en_GB/creating/path/DirectoryEntries.kt new file mode 100644 index 000000000..380d36ee3 --- /dev/null +++ b/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/infix/en_GB/creating/path/DirectoryEntries.kt @@ -0,0 +1,13 @@ +package ch.tutteli.atrium.api.infix.en_GB.creating.path + +import ch.tutteli.atrium.domain.builders.utils.VarArgHelper + +/** + * Parameter object which collects directory entries (as [String]s). + * Use the function `directoryEntry(String, vararg String)` to create this representation. + * + * @since 0.14.0 + */ +class DirectoryEntries(override val expected: String, override val otherExpected: Array) : + VarArgHelper + diff --git a/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/infix/en_GB/pathAssertions.kt b/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/infix/en_GB/pathAssertions.kt index de1652d53..4a395f79f 100644 --- a/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/infix/en_GB/pathAssertions.kt +++ b/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/infix/en_GB/pathAssertions.kt @@ -5,10 +5,12 @@ package ch.tutteli.atrium.api.infix.en_GB +import ch.tutteli.atrium.api.infix.en_GB.creating.path.DirectoryEntries import ch.tutteli.atrium.api.infix.en_GB.creating.path.PathWithCreator import ch.tutteli.atrium.api.infix.en_GB.creating.path.PathWithEncoding import ch.tutteli.atrium.creating.Expect import ch.tutteli.atrium.logic.* +import ch.tutteli.kbox.glue import java.nio.charset.Charset import java.nio.file.Path @@ -176,6 +178,60 @@ infix fun Expect.parent(assertionCreator: Expect.() -> Unit) infix fun Expect.resolve(other: String): Expect = _logic.resolve(other).transform() +/** + * Expects that the subject of the assertion (a [Path]) is a directory having the provided [entry]. + * That means that there is a file system entry at the location the [Path] points to and that it is a directory. + * Furthermore, the argument string resolved against the subject yields an existing file system entry. + * + * This assertion _resolves_ symbolic links for the subject, but not for the [entry]. + * Therefore, if a symbolic link exists at the location the subject points to, the search will continue at the location + * the link points at. If a symbolic link exists at the [entry], this will fulfill the assertion and the entry’s + * symbolic link will not be followed. + * + * This assertion is not atomic with respect to concurrent file system operations on the paths the assertions work on. + * The result, in particular its extended explanations, may be wrong if such concurrent file system operations + * take place. + * + * @return An [Expect] for the current subject of the assertion. + * @throws AssertionError Might throw an [AssertionError] if the assertion made is not correct. + * @see [has] + * + * @since 0.14.0 + */ +infix fun Expect.hasDirectoryEntry(entry: String) = + _logicAppend { hasDirectoryEntry(listOf(entry)) } + +/** + * Expects that the subject of the assertion (a [Path]) is a directory having the provided entries. + * That means that there is a file system entry at the location the [Path] points to and that it is a directory. + * Furthermore, every argument string resolved against the subject yields an existing file system entry. + * + * This assertion _resolves_ symbolic links for the subject, but not for the entries. + * Therefore, if a symbolic link exists at the location the subject points to, the search will continue at the location + * the link points at. If a symbolic link exists at one of the entries, this will fulfill the respective assertion and + * the entry’s symbolic link will not be followed. + * + * This assertion is not atomic with respect to concurrent file system operations on the paths the assertions work on. + * The result, in particular its extended explanations, may be wrong if such concurrent file system operations + * take place. + * + * @return An [Expect] for the current subject of the assertion. + * @throws AssertionError Might throw an [AssertionError] if the assertion made is not correct. + * @see [directoryEntries] + * @see [hasDirectoryEntry] + * + * @since 0.14.0 + */ +infix fun Expect.has(directoryEntries: DirectoryEntries) = + _logicAppend { hasDirectoryEntry(directoryEntries.toList()) } + +/** + * Helper function for [has] to create [DirectoryEntries] with the provided [entry] and the [otherEntries]. + * + * @since 0.14.0 + */ +fun directoryEntries(entry: String, vararg otherEntries: String) = DirectoryEntries(entry, otherEntries) + /** * Expects that [PathWithCreator.path] resolves against this [Path], that the resolved [Path] holds all assertions the * given [PathWithCreator.assertionCreator] creates for it and @@ -206,7 +262,7 @@ fun path(path: String, assertionCreator: Expect.() -> Unit): PathWithCrea * Therefore, if a symbolic link exists at the location the subject points to, * search will continue at the location the link points at. * - * This assertion is not atomic with respect to concurrent file system operations on the paths the assertions works on. + * This assertion is not atomic with respect to concurrent file system operations on the paths the assertion works on. * Its result, in particular its extended explanations, may be wrong if such concurrent file system operations * take place. * @@ -264,7 +320,7 @@ infix fun Expect.toBe(@Suppress("UNUSED_PARAMETER") executable: ex * Therefore, if a symbolic link exists at the location the subject points to, search will continue * at the location the link points at. * - * This assertion is not atomic with respect to concurrent file system operations on the paths the assertions works on. + * This assertion is not atomic with respect to concurrent file system operations on the paths the assertion works on. * Its result, in particular its extended explanations, may be wrong if such concurrent file system operations * take place. * @@ -284,7 +340,7 @@ infix fun Expect.toBe(@Suppress("UNUSED_PARAMETER") aRegularFile: * Therefore, if a symbolic link exists at the location the subject points to, search will continue * at the location the link points at. * - * This assertion is not atomic with respect to concurrent file system operations on the paths the assertions works on. + * This assertion is not atomic with respect to concurrent file system operations on the paths the assertion9 works on. * Its result, in particular its extended explanations, may be wrong if such concurrent file system operations * take place. * diff --git a/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/module/module-info.java b/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/module/module-info.java index 9edf39358..935139024 100644 --- a/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/module/module-info.java +++ b/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/module/module-info.java @@ -1,6 +1,7 @@ module ch.tutteli.atrium.api.infix.en_GB { requires ch.tutteli.atrium.logic; requires kotlin.stdlib; + requires ch.tutteli.kbox; requires java.base; exports ch.tutteli.atrium.api.infix.en_GB; diff --git a/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/test/kotlin/ch/tutteli/atrium/api/infix/en_GB/PathAssertionsSpec.kt b/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/test/kotlin/ch/tutteli/atrium/api/infix/en_GB/PathAssertionsSpec.kt index 2b6a0b6dd..5877fc770 100644 --- a/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/test/kotlin/ch/tutteli/atrium/api/infix/en_GB/PathAssertionsSpec.kt +++ b/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/test/kotlin/ch/tutteli/atrium/api/infix/en_GB/PathAssertionsSpec.kt @@ -5,7 +5,6 @@ import ch.tutteli.atrium.specs.fun1 import ch.tutteli.atrium.specs.fun3 import ch.tutteli.atrium.specs.notImplemented import ch.tutteli.atrium.specs.testutils.WithAsciiReporter -import ch.tutteli.kbox.forElementAndForEachIn import java.nio.charset.Charset import java.nio.file.Path import java.nio.file.Paths @@ -24,7 +23,8 @@ class PathAssertionsSpec : ch.tutteli.atrium.specs.integration.PathAssertionsSpe "toBe ${aDirectory::class.simpleName}" to Companion::isDirectory, "toBe ${relative::class.simpleName}" to Companion::isAbsolute, "toBe ${relative::class.simpleName}" to Companion::isRelative, - "contains not yet implemented in this API" to Companion::contains, + fun1(Expect::hasDirectoryEntry), + "has ${::directoryEntries.name}" to Companion::hasDirectoryEntryMultiple, fun1(Expect::hasSameBinaryContentAs), fun3(Companion::hasSameTextualContentAs), fun1(Companion::hasSameTextualContentAsDefaultArgs) @@ -40,11 +40,8 @@ class PathAssertionsSpec : ch.tutteli.atrium.specs.integration.PathAssertionsSpe private fun isDirectory(expect: Expect) = expect toBe aDirectory private fun isAbsolute(expect: Expect) = expect toBe absolute private fun isRelative(expect: Expect) = expect toBe relative - private fun contains(expect: Expect, path: String, vararg otherPaths: String) = isDirectory(expect) and { - forElementAndForEachIn(path, otherPaths) { p -> - it resolve path(p) { it toBe existing } - } - } + private fun hasDirectoryEntryMultiple(expect: Expect, entry: String, vararg otherEntries: String) = + expect has directoryEntries(entry, *otherEntries) private fun hasSameTextualContentAs( expect: Expect, @@ -77,6 +74,9 @@ class PathAssertionsSpec : ch.tutteli.atrium.specs.integration.PathAssertionsSpe a1 toBe relative a1 hasSameTextualContentAs withEncoding(Paths.get("a")) a1 hasSameTextualContentAs Paths.get("a") + a1 resolve "a" + a1 hasDirectoryEntry "a" + a1 has directoryEntries("a", "b", "c") } } diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/any.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/any.kt index c3e6706c9..cfbd408d8 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/any.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/any.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/charSequence.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/charSequence.kt index 9c6343b33..96201c21c 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/charSequence.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/charSequence.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/collectionLike.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/collectionLike.kt index d7cf7616a..3af69168d 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/collectionLike.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/collectionLike.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/comparable.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/comparable.kt index 49bde22b3..cef7d5dec 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/comparable.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/comparable.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/creating/charsequence/contains/creators/charSequenceContains.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/creating/charsequence/contains/creators/charSequenceContains.kt index c8b2de545..f7ed374fc 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/creating/charsequence/contains/creators/charSequenceContains.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/creating/charsequence/contains/creators/charSequenceContains.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/creating/iterable/contains/creators/iterableLikeContains.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/creating/iterable/contains/creators/iterableLikeContains.kt index 82c72a1a6..c3eeb059d 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/creating/iterable/contains/creators/iterableLikeContains.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/creating/iterable/contains/creators/iterableLikeContains.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/creating/iterable/contains/creators/iterableLikeContainsInAnyOrder.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/creating/iterable/contains/creators/iterableLikeContainsInAnyOrder.kt index b852d0afc..6343c8003 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/creating/iterable/contains/creators/iterableLikeContainsInAnyOrder.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/creating/iterable/contains/creators/iterableLikeContainsInAnyOrder.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/feature.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/feature.kt index 75e9e98f9..5e66d5d12 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/feature.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/feature.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/floatingPoint.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/floatingPoint.kt index e3756617c..f0e6d16ed 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/floatingPoint.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/floatingPoint.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/fun0.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/fun0.kt index a4f52a942..82fb71ba0 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/fun0.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/fun0.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/iterableLike.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/iterableLike.kt index 8f1957d6e..c02d67c42 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/iterableLike.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/iterableLike.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/iterator.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/iterator.kt index 892e36137..09fe9c392 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/iterator.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/iterator.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/list.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/list.kt index e045a29b9..fbf04d779 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/list.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/list.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/map.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/map.kt index c14e9b871..189c508c7 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/map.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/map.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/mapEntry.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/mapEntry.kt index 272f93dea..9ce3b71e6 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/mapEntry.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/mapEntry.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/pair.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/pair.kt index e3017014d..256075306 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/pair.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/pair.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/throwable.kt b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/throwable.kt index 7fa4b1031..806827c70 100644 --- a/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/throwable.kt +++ b/logic/atrium-logic-common/src/generated/kotlin/ch/tutteli/atrium/logic/throwable.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/bigDecimal.kt b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/bigDecimal.kt index b027fb2b7..cd70efe03 100644 --- a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/bigDecimal.kt +++ b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/bigDecimal.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/chronoLocalDate.kt b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/chronoLocalDate.kt index 488664f79..24651340a 100644 --- a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/chronoLocalDate.kt +++ b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/chronoLocalDate.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/chronoLocalDateTime.kt b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/chronoLocalDateTime.kt index 344f4992f..4204e632a 100644 --- a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/chronoLocalDateTime.kt +++ b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/chronoLocalDateTime.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/chronoZonedDateTime.kt b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/chronoZonedDateTime.kt index 32457f74c..f85d5c3e4 100644 --- a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/chronoZonedDateTime.kt +++ b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/chronoZonedDateTime.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/floatingPointJvm.kt b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/floatingPointJvm.kt index e383990e0..64b6a084a 100644 --- a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/floatingPointJvm.kt +++ b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/floatingPointJvm.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/localDate.kt b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/localDate.kt index 02a1a7aee..c060b9baf 100644 --- a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/localDate.kt +++ b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/localDate.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/localDateTime.kt b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/localDateTime.kt index 1f3efd225..cc3c151a8 100644 --- a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/localDateTime.kt +++ b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/localDateTime.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/optional.kt b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/optional.kt index 452783d61..1588f93a9 100644 --- a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/optional.kt +++ b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/optional.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/path.kt b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/path.kt index 62e87bb4f..32d8c7d90 100644 --- a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/path.kt +++ b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/path.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle @@ -15,6 +16,7 @@ import ch.tutteli.atrium.assertions.Assertion import ch.tutteli.atrium.creating.AssertionContainer import ch.tutteli.atrium.logic.creating.transformers.FeatureExtractorBuilder import java.nio.charset.Charset +import java.nio.file.LinkOption import java.nio.file.Path import ch.tutteli.atrium.core.ExperimentalNewExpectTypes import ch.tutteli.atrium.logic.impl.DefaultPathAssertions @@ -24,8 +26,8 @@ fun AssertionContainer.startsNotWith(expected: Path): Assertion = fun AssertionContainer.endsWith(expected: Path): Assertion = impl.endsWith(this, expected) fun AssertionContainer.endsNotWith(expected: Path): Assertion = impl.endsNotWith(this, expected) -fun AssertionContainer.exists(): Assertion = impl.exists(this) -fun AssertionContainer.existsNot(): Assertion = impl.existsNot(this) +fun AssertionContainer.exists(linkOption: LinkOption? = null): Assertion = impl.exists(this, linkOption) +fun AssertionContainer.existsNot(linkOption: LinkOption? = null): Assertion = impl.existsNot(this, linkOption) fun AssertionContainer.isReadable(): Assertion = impl.isReadable(this) fun AssertionContainer.isWritable(): Assertion = impl.isWritable(this) @@ -46,6 +48,8 @@ fun AssertionContainer.fileNameWithoutExtension(): FeatureExtracto fun AssertionContainer.parent(): FeatureExtractorBuilder.ExecutionStep = impl.parent(this) fun AssertionContainer.resolve(other: String): FeatureExtractorBuilder.ExecutionStep = impl.resolve(this, other) +fun AssertionContainer.hasDirectoryEntry(entries: List): Assertion = impl.hasDirectoryEntry(this, entries) + @Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */) @UseExperimental(ExperimentalNewExpectTypes::class) private inline val AssertionContainer.impl: PathAssertions diff --git a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/zonedDateTime.kt b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/zonedDateTime.kt index af6c6825d..06ece5b31 100644 --- a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/zonedDateTime.kt +++ b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/zonedDateTime.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic/PathAssertions.kt b/logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic/PathAssertions.kt index 58f782381..1e5e77675 100644 --- a/logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic/PathAssertions.kt +++ b/logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic/PathAssertions.kt @@ -9,6 +9,7 @@ import ch.tutteli.atrium.assertions.Assertion import ch.tutteli.atrium.creating.AssertionContainer import ch.tutteli.atrium.logic.creating.transformers.FeatureExtractorBuilder import java.nio.charset.Charset +import java.nio.file.LinkOption import java.nio.file.Path /** @@ -20,8 +21,8 @@ interface PathAssertions { fun endsWith(container: AssertionContainer, expected: Path): Assertion fun endsNotWith(container: AssertionContainer, expected: Path): Assertion - fun exists(container: AssertionContainer): Assertion - fun existsNot(container: AssertionContainer): Assertion + fun exists(container: AssertionContainer, linkOption: LinkOption? = null): Assertion + fun existsNot(container: AssertionContainer, linkOption: LinkOption? = null): Assertion fun isReadable(container: AssertionContainer): Assertion fun isWritable(container: AssertionContainer): Assertion @@ -44,5 +45,10 @@ interface PathAssertions { fun extension(container: AssertionContainer): FeatureExtractorBuilder.ExecutionStep fun fileNameWithoutExtension(container: AssertionContainer): FeatureExtractorBuilder.ExecutionStep fun parent(container: AssertionContainer): FeatureExtractorBuilder.ExecutionStep - fun resolve(container: AssertionContainer, other: String): FeatureExtractorBuilder.ExecutionStep + fun resolve( + container: AssertionContainer, + other: String + ): FeatureExtractorBuilder.ExecutionStep + + fun hasDirectoryEntry(container: AssertionContainer, entries: List): Assertion } diff --git a/logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic/impl/DefaultPathAssertions.kt b/logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic/impl/DefaultPathAssertions.kt index f12ada7a9..10137ccc3 100644 --- a/logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic/impl/DefaultPathAssertions.kt +++ b/logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic/impl/DefaultPathAssertions.kt @@ -7,6 +7,7 @@ package ch.tutteli.atrium.logic.impl import ch.tutteli.atrium.assertions.Assertion import ch.tutteli.atrium.assertions.builders.assertionBuilder +import ch.tutteli.atrium.assertions.builders.invisibleGroup import ch.tutteli.atrium.core.None import ch.tutteli.atrium.core.Some import ch.tutteli.atrium.creating.AssertionContainer @@ -24,10 +25,8 @@ import ch.tutteli.atrium.translations.DescriptionBasic import ch.tutteli.atrium.translations.DescriptionPathAssertion.* import ch.tutteli.niok.* import java.nio.charset.Charset -import java.nio.file.AccessDeniedException -import java.nio.file.AccessMode -import java.nio.file.NoSuchFileException -import java.nio.file.Path +import java.nio.file.* +import java.nio.file.LinkOption.NOFOLLOW_LINKS import java.nio.file.attribute.BasicFileAttributes class DefaultPathAssertions : PathAssertions { @@ -60,8 +59,8 @@ class DefaultPathAssertions : PathAssertions { it.readAllBytes().contentEquals(targetPath.readAllBytes()) } - override fun exists(container: AssertionContainer): Assertion = - changeSubjectToFileAttributes(container) { fileAttributesExpect -> + override fun exists(container: AssertionContainer, linkOption: LinkOption?): Assertion = + changeSubjectToFileAttributes(container, linkOption) { fileAttributesExpect -> assertionBuilder.descriptive .withTest(fileAttributesExpect) { it is Success } .withIOExceptionFailureHint(fileAttributesExpect) { realPath, exception -> @@ -78,8 +77,9 @@ class DefaultPathAssertions : PathAssertions { .build() } - override fun existsNot(container: AssertionContainer): Assertion = - changeSubjectToFileAttributes(container) { fileAttributesExpect -> + + override fun existsNot(container: AssertionContainer, linkOption: LinkOption?): Assertion = + changeSubjectToFileAttributes(container, linkOption) { fileAttributesExpect -> assertionBuilder.descriptive .withTest(fileAttributesExpect) { it is Failure && it.exception is NoSuchFileException } .withFileAttributesFailureHint(fileAttributesExpect) @@ -89,9 +89,12 @@ class DefaultPathAssertions : PathAssertions { private inline fun changeSubjectToFileAttributes( container: AssertionContainer, + linkOption: LinkOption? = null, block: (Expect>) -> R ): R = container.changeSubject.unreported { - it.runCatchingIo { readAttributes() } + it.runCatchingIo { + if (linkOption == null) readAttributes() else readAttributes(linkOption) + } }.let(block) override fun isReadable(container: AssertionContainer): Assertion = @@ -180,4 +183,11 @@ class DefaultPathAssertions : PathAssertions { other: String ): FeatureExtractorBuilder.ExecutionStep = container.f1(Path::resolve, other) + override fun hasDirectoryEntry(container: AssertionContainer, entries: List): Assertion = + assertionBuilder.invisibleGroup.withAssertions( + listOf(container.isDirectory()) + + entries.map { entry -> + container.resolve(entry).collect { _logicAppend { exists(NOFOLLOW_LINKS) } } + } + ).build() } diff --git a/logic/extensions/kotlin_1_3/atrium-logic-kotlin_1_3-common/src/generated/kotlin/ch/tutteli/atrium/logic/kotlin_1_3/result.kt b/logic/extensions/kotlin_1_3/atrium-logic-kotlin_1_3-common/src/generated/kotlin/ch/tutteli/atrium/logic/kotlin_1_3/result.kt index 9bd35e009..1259c4f3b 100644 --- a/logic/extensions/kotlin_1_3/atrium-logic-kotlin_1_3-common/src/generated/kotlin/ch/tutteli/atrium/logic/kotlin_1_3/result.kt +++ b/logic/extensions/kotlin_1_3/atrium-logic-kotlin_1_3-common/src/generated/kotlin/ch/tutteli/atrium/logic/kotlin_1_3/result.kt @@ -1,3 +1,4 @@ +// @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/logic/generateLogic.gradle b/logic/generateLogic.gradle index 75cf06436..3cf1b54f8 100644 --- a/logic/generateLogic.gradle +++ b/logic/generateLogic.gradle @@ -54,7 +54,7 @@ def createGenerateLogicTaskForPackage( String generatedFolder = project.generatedFolder - return task("generateLogic_${relativePackagePath.replaceAll('/', '_')}", description: "generates ext. methods for pacakge $relativePackagePath") { + return task("generateLogic_${relativePackagePath.replaceAll('/', '_')}", description: "generates ext. methods for package $relativePackagePath") { def packagePath = 'ch/tutteli/atrium/logic' + relativePackagePath + (suffix != '' ? "/" + suffix : '') def fullPackage = packagePath.replaceAll('/', '.') def path = "$project.projectDir/src/main/kotlin/$packagePath/" @@ -73,6 +73,7 @@ def createGenerateLogicTaskForPackage( //TODO delete all files in folder first (as we might have removed things) def header = """\ + // @formatter:off //--------------------------------------------------- // Generated content, modify: // logic/generateLogic.gradle diff --git a/misc/deprecated/apis/fluent-en_GB-jdk8/atrium-api-fluent-en_GB-jdk8-jvm/src/main/kotlin/ch/tutteli/atrium/api/fluent/en_GB/jdk8/pathAssertions.kt b/misc/deprecated/apis/fluent-en_GB-jdk8/atrium-api-fluent-en_GB-jdk8-jvm/src/main/kotlin/ch/tutteli/atrium/api/fluent/en_GB/jdk8/pathAssertions.kt index 4d2d198b1..d353fd612 100644 --- a/misc/deprecated/apis/fluent-en_GB-jdk8/atrium-api-fluent-en_GB-jdk8-jvm/src/main/kotlin/ch/tutteli/atrium/api/fluent/en_GB/jdk8/pathAssertions.kt +++ b/misc/deprecated/apis/fluent-en_GB-jdk8/atrium-api-fluent-en_GB-jdk8-jvm/src/main/kotlin/ch/tutteli/atrium/api/fluent/en_GB/jdk8/pathAssertions.kt @@ -254,7 +254,7 @@ fun Expect.resolve(other: String, assertionCreator: Expect.( * Therefore, if a symbolic link exists at the location the subject points to, * search will continue at the location the link points at. * - * This assertion is not atomic with respect to concurrent file system operations on the paths the assertions works on. + * This assertion is not atomic with respect to concurrent file system operations on the paths the assertion works on. * Its result, in particular its extended explanations, may be wrong if such concurrent file system operations * take place. * @@ -297,7 +297,7 @@ fun Expect.isWritable(): Expect = addAssertion(ExpectImpl.path. * Therefore, if a symbolic link exists at the location the subject points to, search will continue * at the location the link points at. * - * This assertion is not atomic with respect to concurrent file system operations on the paths the assertions works on. + * This assertion is not atomic with respect to concurrent file system operations on the paths the assertion works on. * Its result, in particular its extended explanations, may be wrong if such concurrent file system operations * take place. * @@ -320,7 +320,7 @@ fun Expect.isRegularFile(): Expect = addAssertion(ExpectImpl.pa * Therefore, if a symbolic link exists at the location the subject points to, search will continue * at the location the link points at. * - * This assertion is not atomic with respect to concurrent file system operations on the paths the assertions works on. + * This assertion is not atomic with respect to concurrent file system operations on the paths the assertion works on. * Its result, in particular its extended explanations, may be wrong if such concurrent file system operations * take place. * diff --git a/misc/deprecated/apis/fluent-en_GB-jdk8/atrium-api-fluent-en_GB-jdk8-jvm/src/test/kotlin/ch/tutteli/atrium/api/fluent/en_GB/jdk8/PathAssertionsSpec.kt b/misc/deprecated/apis/fluent-en_GB-jdk8/atrium-api-fluent-en_GB-jdk8-jvm/src/test/kotlin/ch/tutteli/atrium/api/fluent/en_GB/jdk8/PathAssertionsSpec.kt index 123a0fbaf..89d4354f1 100644 --- a/misc/deprecated/apis/fluent-en_GB-jdk8/atrium-api-fluent-en_GB-jdk8-jvm/src/test/kotlin/ch/tutteli/atrium/api/fluent/en_GB/jdk8/PathAssertionsSpec.kt +++ b/misc/deprecated/apis/fluent-en_GB-jdk8/atrium-api-fluent-en_GB-jdk8-jvm/src/test/kotlin/ch/tutteli/atrium/api/fluent/en_GB/jdk8/PathAssertionsSpec.kt @@ -3,7 +3,7 @@ package ch.tutteli.atrium.api.fluent.en_GB.jdk8 -import ch.tutteli.atrium.api.fluent.en_GB.contains +import ch.tutteli.atrium.api.fluent.en_GB.hasDirectoryEntry import ch.tutteli.atrium.api.fluent.en_GB.isAbsolute import ch.tutteli.atrium.api.fluent.en_GB.isExecutable import ch.tutteli.atrium.api.fluent.en_GB.isRelative @@ -26,15 +26,18 @@ class PathAssertionsSpec : ch.tutteli.atrium.specs.integration.PathAssertionsSpe fun0(Expect::isDirectory), fun0(Expect::isAbsolute), // checks the new function from fluent-jvm because it is not implemented in fluent-jkd8 fun0(Expect::isRelative), // checks the new function from fluent-jvm because it is not implemented in fluent-jkd8 - fun2>(Expect::contains), // checks the new function from fluent-jvm because it is not implemented in fluent-jkd8 + Expect::hasDirectoryEntry.name to Companion::hasDirectoryEntrySingle, // checks the new function from fluent-jvm because it is not implemented in fluent-jkd8 + fun2>(Expect::hasDirectoryEntry), // checks the new function from fluent-jvm because it is not implemented in fluent-jkd8 fun1(Expect::hasSameBinaryContentAs), fun3(Expect::hasSameTextualContentAs), - fun1(Companion::hasSameTextualContentAsDefaultArgs) + Expect::hasSameTextualContentAs.name to Companion::hasSameTextualContentAsDefaultArgs ) { companion object { private fun hasSameTextualContentAsDefaultArgs(expect: Expect, targetPath: Path): Expect = expect.hasSameTextualContentAs(targetPath) + + private fun hasDirectoryEntrySingle(expect: Expect, entry: String) = expect.hasDirectoryEntry(entry) } @Suppress("unused", "UNUSED_VALUE") diff --git a/misc/specs/atrium-specs-jvm/src/main/kotlin/ch/tutteli/atrium/specs/integration/PathAssertionsSpec.kt b/misc/specs/atrium-specs-jvm/src/main/kotlin/ch/tutteli/atrium/specs/integration/PathAssertionsSpec.kt index 6703234c0..a67bbaa50 100644 --- a/misc/specs/atrium-specs-jvm/src/main/kotlin/ch/tutteli/atrium/specs/integration/PathAssertionsSpec.kt +++ b/misc/specs/atrium-specs-jvm/src/main/kotlin/ch/tutteli/atrium/specs/integration/PathAssertionsSpec.kt @@ -45,7 +45,8 @@ abstract class PathAssertionsSpec( isDirectory: Fun0, isAbsolute: Fun0, isRelative: Fun0, - contains: Fun2>, + hasDirectoryEntrySingle: Fun1, + hasDirectoryEntryMulti: Fun2>, hasSameBinaryContentAs: Fun1, hasSameTextualContentAs: Fun3, hasSameTextualContentAsDefaultArgs: Fun1, @@ -67,7 +68,8 @@ abstract class PathAssertionsSpec( isDirectory.forSubjectLess(), isAbsolute.forSubjectLess(), isRelative.forSubjectLess(), - contains.forSubjectLess("a", arrayOf("b", "c")), + hasDirectoryEntrySingle.forSubjectLess("a"), + hasDirectoryEntryMulti.forSubjectLess("a", arrayOf("b", "c")), hasSameBinaryContentAs.forSubjectLess(Paths.get("a")), hasSameTextualContentAs.forSubjectLess(Paths.get("a"), Charsets.ISO_8859_1, Charsets.ISO_8859_1), hasSameTextualContentAsDefaultArgs.forSubjectLess(Paths.get("a")) @@ -870,100 +872,140 @@ abstract class PathAssertionsSpec( } } - describeFun(contains) { - val containsFun = contains.lambda + val hasDirectoryEntryVariations = listOf( + DirectoryEntryVariation("directory", "directories") { entry -> newDirectory(entry) }, + DirectoryEntryVariation("file", "files") { entry -> newFile(entry) }, + DirectoryEntryVariation("symlink with existing target", "symlinks with existing targets") { entry -> + newFile("$entry-target").createSymbolicLink(resolve(entry)) + }, + DirectoryEntryVariation("symlink with non-existing target", "symlinks with non-existing targets") { entry -> + resolve("$entry-not-existing-target").createSymbolicLink(resolve(entry)) + } + ) - listOf( - ContainsTestData( "directory", "directories") { parent, name -> parent.newDirectory(name) }, - ContainsTestData("file", "files") { parent, name -> parent.newDirectory(name) } - ) .forEach {td -> - it("does not throw if the single parameter is a child ${td.singleName}") withAndWithoutSymlink { maybeLink -> - val folder = maybeLink.create(tempFolder.newDirectory("startDir")) - maybeLink.create(td.factory.invoke(folder, "a")) - expect(folder).containsFun("a", emptyArray()) - } + describeFun(hasDirectoryEntrySingle) { + val hasDirectoryEntryFun = hasDirectoryEntrySingle.lambda - it("does not throw if both parameters are child ${td.multipleName}") withAndWithoutSymlink { maybeLink -> - val folder = maybeLink.create(tempFolder.newDirectory("startDir")) - maybeLink.create(td.factory.invoke(folder, "a")) - maybeLink.create(td.factory.invoke(folder, "b")) - expect(folder).containsFun("a", arrayOf("b")) - } + hasDirectoryEntryVariations.forEach { (singleName, _, createEntry) -> + it("does not throw if the parameter is a child $singleName") withAndWithoutSymlink { maybeLink -> + val folder = maybeLink.create(tempFolder.newDirectory("startDir")) + folder.createEntry("a") + expect(folder).hasDirectoryEntryFun("a") + } + } - it("does not throw if three parameters are child ${td.multipleName}") withAndWithoutSymlink { maybeLink -> - val folder = maybeLink.create(tempFolder.newDirectory("startDir")) - maybeLink.create(td.factory.invoke(folder, "a")) - maybeLink.create(td.factory.invoke(folder, "b")) - maybeLink.create(td.factory.invoke(folder, "c")) - expect(folder).containsFun("a", arrayOf("b", "c")) - } + it("throws if the parameter does not exist") withAndWithoutSymlink { maybeLink -> + val folder = maybeLink.create(tempFolder.newDirectory("startDir")) + expect { + expect(folder).hasDirectoryEntryFun("fileA") + }.toThrow().message { + contains("${TO.getDefault()}: ${EXIST.getDefault()}") + contains("fileA") + } + } + } - it("it throws if the first ${td.singleName} does not exist") withAndWithoutSymlink { maybeLink -> - val folder = maybeLink.create(tempFolder.newDirectory("startDir")) - maybeLink.create(td.factory.invoke(folder, "file2")) - maybeLink.create(td.factory.invoke(folder, "file3")) - expect { - expect(folder).containsFun("file1", arrayOf("file2", "file3")) - }.toThrow().message { - contains("${TO.getDefault()}: ${EXIST.getDefault()}") - contains("file1") - containsNot("file2") - containsNot("file3") - } - } + describeFun(hasDirectoryEntryMulti) { + val hasDirectoryEntryFun = hasDirectoryEntryMulti.lambda - it("it throws if the second ${td.singleName} does not exist") withAndWithoutSymlink { maybeLink -> - val folder = maybeLink.create(tempFolder.newDirectory("startDir")) - maybeLink.create(td.factory.invoke(folder, "file1")) - maybeLink.create(td.factory.invoke(folder, "file3")) - expect { - expect(folder).containsFun("file1", arrayOf("file2", "file3")) - }.toThrow().message { - contains("${TO.getDefault()}: ${EXIST.getDefault()}") - contains("file2") - containsNot("file1") - containsNot("file3") - } - } + hasDirectoryEntryVariations.forEach { (singleName, multiName, createEntry) -> + it("does not throw if the single parameter is a child $singleName") withAndWithoutSymlink { maybeLink -> + val folder = maybeLink.create(tempFolder.newDirectory("startDir")) + folder.createEntry("a") + expect(folder).hasDirectoryEntryFun("a", emptyArray()) + } - it("it throws if third ${td.singleName} does not exist") withAndWithoutSymlink { maybeLink -> - val folder = maybeLink.create(tempFolder.newDirectory("startDir")) - maybeLink.create(td.factory.invoke(folder, "file1")) - maybeLink.create(td.factory.invoke(folder, "file2")) - expect { - expect(folder).containsFun("file1", arrayOf("file2", "file3")) - }.toThrow().message { - contains("${TO.getDefault()}: ${EXIST.getDefault()}") - containsNot("file2") - containsNot("file1") - contains("file3") - } - } + it("does not throw if two parameters are child $multiName") withAndWithoutSymlink { maybeLink -> + val folder = maybeLink.create(tempFolder.newDirectory("startDir")) + folder.createEntry("a") + folder.createEntry("b") + expect(folder).hasDirectoryEntryFun("a", arrayOf("b")) + } - it("it throws if the first and third ${td.singleName} do not exist") withAndWithoutSymlink { maybeLink -> - val folder = maybeLink.create(tempFolder.newDirectory("startDir")) - maybeLink.create(td.factory.invoke(folder, "file2")) - expect { - expect(folder).containsFun("file1", arrayOf("file2", "file3")) - }.toThrow().message { - contains("${TO.getDefault()}: ${EXIST.getDefault()}") - containsNot("file2") - contains("file1") - contains("file3") - } - } + it("does not throw if three parameters are child $multiName") withAndWithoutSymlink { maybeLink -> + val folder = maybeLink.create(tempFolder.newDirectory("startDir")) + folder.createEntry("a") + folder.createEntry("b") + folder.createEntry("c") + expect(folder).hasDirectoryEntryFun("a", arrayOf("b", "c")) + } - it("it throws if the directory does not exist") withAndWithoutSymlink { maybeLink -> - val folder = maybeLink.create(tempFolder.tmpDir.resolve("nonExistent")) - val expectedMessage = "$isDescr: ${A_DIRECTORY.getDefault()}" + it("it throws if the first $singleName does not exist") withAndWithoutSymlink { maybeLink -> + val folder = maybeLink.create(tempFolder.newDirectory("startDir")) + folder.createEntry("file2") + folder.createEntry("file3") + expect { + expect(folder).hasDirectoryEntryFun("file1", arrayOf("file2", "file3")) + }.toThrow().message { + contains("${TO.getDefault()}: ${EXIST.getDefault()}") + contains("file1") + containsNot("file2") + containsNot("file3") + } + } - expect { - expect(folder).containsFun("file1", arrayOf("file2", "file3")) - }.toThrow().message { - contains(expectedMessage, FAILURE_DUE_TO_NO_SUCH_FILE.getDefault()) - containsExplanationFor(maybeLink) - } - } + it("it throws if the second $singleName does not exist") withAndWithoutSymlink { maybeLink -> + val folder = maybeLink.create(tempFolder.newDirectory("startDir")) + folder.createEntry("file1") + folder.createEntry("file3") + expect { + expect(folder).hasDirectoryEntryFun("file1", arrayOf("file2", "file3")) + }.toThrow().message { + contains("${TO.getDefault()}: ${EXIST.getDefault()}") + contains("file2") + containsNot("file1") + containsNot("file3") + } + } + + it("it throws if the third $singleName does not exist") withAndWithoutSymlink { maybeLink -> + val folder = maybeLink.create(tempFolder.newDirectory("startDir")) + folder.createEntry("file1") + folder.createEntry("file2") + expect { + expect(folder).hasDirectoryEntryFun("file1", arrayOf("file2", "file3")) + }.toThrow().message { + contains("${TO.getDefault()}: ${EXIST.getDefault()}") + containsNot("file2") + containsNot("file1") + contains("file3") + } + } + + it("it throws if the first and third $multiName do not exist") withAndWithoutSymlink { maybeLink -> + val folder = maybeLink.create(tempFolder.newDirectory("startDir")) + folder.createEntry("file2") + expect { + expect(folder).hasDirectoryEntryFun("file1", arrayOf("file2", "file3")) + }.toThrow().message { + contains("${TO.getDefault()}: ${EXIST.getDefault()}") + containsNot("file2") + contains("file1") + contains("file3") + } + } + } + + it("does not throw when using all entry types") withAndWithoutSymlink { maybeLink -> + val folder = maybeLink.create(tempFolder.newDirectory("startDir")) + hasDirectoryEntryVariations.first().createEntry(folder, "file1") + hasDirectoryEntryVariations.drop(1).forEachIndexed { index, variation -> + variation.createEntry(folder, "file${index + 2}") + } + val otherEntries = (2..(hasDirectoryEntryVariations.size)).map { "file$it" }.toTypedArray() + expect(folder).hasDirectoryEntryFun("file1", otherEntries) + } + + it("it throws if the directory does not exist") withAndWithoutSymlink { maybeLink -> + val folder = maybeLink.create(tempFolder.tmpDir.resolve("nonExistent")) + val expectedMessage = "$isDescr: ${A_DIRECTORY.getDefault()}" + + expect { + expect(folder).hasDirectoryEntryFun("file1", arrayOf("file2", "file3")) + }.toThrow().message { + contains(expectedMessage, FAILURE_DUE_TO_NO_SUCH_FILE.getDefault()) + containsExplanationFor(maybeLink) + } } } @@ -1339,4 +1381,8 @@ private fun expectedPermissionTypeHintFor(type: Translatable, being: Translatabl being.getDefault() ) -internal data class ContainsTestData(val singleName: String, val multipleName: String, val factory: (f: Path, name: String) -> Path) +internal data class DirectoryEntryVariation( + val singleName: String, + val multipleName: String, + val createEntry: Path.(entry: String) -> Path +)