Skip to content

Commit

Permalink
robstoll#630 add Path.isRelative method
Browse files Browse the repository at this point in the history
  • Loading branch information
Jakub Riegel committed Oct 16, 2020
1 parent 1a10575 commit 1554303
Show file tree
Hide file tree
Showing 13 changed files with 94 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,18 @@ fun <T : Path> Expect<T>.isRegularFile(): Expect<T> =
fun <T : Path> Expect<T>.isDirectory(): Expect<T> =
_logicAppend { isDirectory() }

/**
* Expects that the subject of the assertion (a [Path]) is a relative path;
* meaning that the [Path] specified in this instance does not start at the file system root.
*
* @return An [Expect] for the current subject of the assertion.
* @throws AssertionError Might throw an [AssertionError] if the assertion made is not correct.
*
* @since 0.14.0
*/
fun <T : Path> Expect<T>.isRelative(): Expect<T> =
_logicAppend { isRelative() }

/**
* Creates an [Expect] for the property [Path.extension][ch.tutteli.niok.extension]
* (provided via [niok](https://github.com/robstoll/niok)) of the subject of the assertion,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class PathAssertionsSpec : ch.tutteli.atrium.specs.integration.PathAssertionsSpe
fun0(Expect<Path>::isExecutable),
fun0(Expect<Path>::isRegularFile),
fun0(Expect<Path>::isDirectory),
fun0(Expect<Path>::isRelative),
fun1(Expect<Path>::hasSameBinaryContentAs),
fun3(Expect<Path>::hasSameTextualContentAs),
fun1(Companion::hasSameTextualContentAsDefaultArgs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ object aRegularFile : Keyword
*/
object aDirectory : Keyword

/**
* A helper construct to allow expressing assertions about a path being relative.
* It can be used for a parameterless function so that it has one parameter and thus can be used as infix function.
*
* @since 0.14.0
*/
object relative : Keyword

/**
* Represents a helper construct which allows to express blankness.
* It can be used for a parameterless function so that it has one parameter and thus can be used as infix function.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,19 @@ infix fun <T : Path> Expect<T>.toBe(@Suppress("UNUSED_PARAMETER") aRegularFile:
infix fun <T : Path> Expect<T>.toBe(@Suppress("UNUSED_PARAMETER") aDirectory: aDirectory): Expect<T> =
_logicAppend { isDirectory() }

/**
* Expects that the subject of the assertion (a [Path]) is a relative path;
* meaning that the [Path] specified in this instance does not start at the file system root.
*
* @return An [Expect] for the current subject of the assertion.
* @throws AssertionError Might throw an [AssertionError] if the assertion made is not correct.
*
* @since 0.14.0
*/
infix fun <T : Path> Expect<T>.toBe(@Suppress("UNUSED_PARAMETER") relative: relative): Expect<T> =
_logicAppend { isRelative() }


/**
* Creates an [Expect] for the property [Path.extension][ch.tutteli.niok.extension]
* (provided via [niok](https://github.com/robstoll/niok)) of the subject of the assertion,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class PathAssertionsSpec : ch.tutteli.atrium.specs.integration.PathAssertionsSpe
"toBe ${executable::class.simpleName}" to Companion::isExecutable,
"toBe ${aRegularFile::class.simpleName}" to Companion::isRegularFile,
"toBe ${aDirectory::class.simpleName}" to Companion::isDirectory,
"toBe ${relative::class.simpleName}" to Companion::isRelative,
fun1(Expect<Path>::hasSameBinaryContentAs),
fun3(Companion::hasSameTextualContentAs),
fun1(Companion::hasSameTextualContentAsDefaultArgs)
Expand All @@ -34,6 +35,7 @@ class PathAssertionsSpec : ch.tutteli.atrium.specs.integration.PathAssertionsSpe
private fun isExecutable(expect: Expect<Path>) = expect toBe executable
private fun isRegularFile(expect: Expect<Path>) = expect toBe aRegularFile
private fun isDirectory(expect: Expect<Path>) = expect toBe aDirectory
private fun isRelative(expect: Expect<Path>) = expect toBe relative

private fun hasSameTextualContentAs(
expect: Expect<Path>,
Expand Down Expand Up @@ -62,6 +64,7 @@ class PathAssertionsSpec : ch.tutteli.atrium.specs.integration.PathAssertionsSpe
a1 toBe writable
a1 toBe aRegularFile
a1 toBe aDirectory
a1 toBe relative
a1 hasSameTextualContentAs withEncoding(Paths.get("a"))
a1 hasSameTextualContentAs Paths.get("a")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ fun <T : Path> AssertionContainer<T>.isWritable(): Assertion = impl.isWritable(t
fun <T : Path> AssertionContainer<T>.isExecutable(): Assertion = impl.isExecutable(this)
fun <T : Path> AssertionContainer<T>.isRegularFile(): Assertion = impl.isRegularFile(this)
fun <T : Path> AssertionContainer<T>.isDirectory(): Assertion = impl.isDirectory(this)
fun <T : Path> AssertionContainer<T>.isRelative(): Assertion = impl.isRelative(this)

fun <T : Path> AssertionContainer<T>.hasSameTextualContentAs(targetPath: Path, sourceCharset: Charset, targetCharset: Charset): Assertion =
impl.hasSameTextualContentAs(this, targetPath, sourceCharset, targetCharset)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ interface PathAssertions {
fun <T : Path> isExecutable(container: AssertionContainer<T>): Assertion
fun <T : Path> isRegularFile(container: AssertionContainer<T>): Assertion
fun <T : Path> isDirectory(container: AssertionContainer<T>): Assertion
fun <T : Path> isRelative(container: AssertionContainer<T>): Assertion

fun <T : Path> hasSameTextualContentAs(
container: AssertionContainer<T>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import ch.tutteli.atrium.assertions.AssertionGroup
import ch.tutteli.atrium.assertions.builders.*
import ch.tutteli.atrium.core.polyfills.fullName
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.creating.SubjectProvider
import ch.tutteli.atrium.domain.builders.creating.MapEntryAssertionsBuilder.value
import ch.tutteli.atrium.logic.creating.transformers.impl.ThrowableThrownFailureHandler
import ch.tutteli.atrium.logic.creating.filesystem.Failure
import ch.tutteli.atrium.logic.creating.filesystem.IoResult
import ch.tutteli.atrium.logic.creating.filesystem.Success
import ch.tutteli.atrium.reporting.translating.Translatable
import ch.tutteli.atrium.translations.DescriptionBasic
import ch.tutteli.atrium.translations.DescriptionPathAssertion
import ch.tutteli.atrium.translations.DescriptionPathAssertion.*
import ch.tutteli.niok.followSymbolicLink
import ch.tutteli.niok.getFileAttributeView
Expand Down Expand Up @@ -45,6 +48,21 @@ fun Descriptive.DescriptionOption<Descriptive.FinalStep>.withFileAttributesFailu
}
}

fun Descriptive.DescriptionOption<Descriptive.FinalStep>.withPathAttributesFailureHint(
provider: SubjectProvider<Path>
): Descriptive.DescriptionOption<DescriptiveAssertionWithFailureHint.FinalStep> =
withFailureHintBasedOnDefinedSubject(provider) { path ->
describeWas(path.type)
.let {
assertionBuilder.explanatoryGroup.withDefaultType
.withAssertions(listOf(it))
.build()
}
}

private val Path.type: DescriptionPathAssertion
get() = if (isAbsolute) ABSOLUTE_PATH else RELATIVE_PATH

/**
* Internal for testing purposes only
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ class DefaultPathAssertions : PathAssertions {
override fun <T : Path> isDirectory(container: AssertionContainer<T>): Assertion =
fileTypeAssertion(container, A_DIRECTORY) { it.isDirectory }

override fun <T : Path> isRelative(container: AssertionContainer<T>): Assertion =
assertionBuilder.descriptive
.withTest(container) { !it.isAbsolute }
.withPathAttributesFailureHint(container)
.withDescriptionAndRepresentation(DescriptionBasic.IS, RELATIVE_PATH)
.build()

private fun <T : Path> filePermissionAssertion(
container: AssertionContainer<T>,
permissionName: Translatable,
Expand Down Expand Up @@ -147,7 +154,6 @@ class DefaultPathAssertions : PathAssertions {
.build()
}


override fun <T : Path> fileName(container: AssertionContainer<T>): FeatureExtractorBuilder.ExecutionStep<T, String> =
container.manualFeature(FILE_NAME) { fileName.toString() }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package ch.tutteli.atrium.api.fluent.en_GB.jdk8

import ch.tutteli.atrium.api.fluent.en_GB.isExecutable
import ch.tutteli.atrium.api.fluent.en_GB.isRelative
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.specs.fun0
import ch.tutteli.atrium.specs.fun1
Expand All @@ -24,6 +25,7 @@ class PathAssertionsSpec : ch.tutteli.atrium.specs.integration.PathAssertionsSpe
fun0(Expect<Path>::isExecutable), // checks the new function from fluent-jvm because it is not implemented in fluent-jkd8
fun0(Expect<Path>::isRegularFile),
fun0(Expect<Path>::isDirectory),
fun0(Expect<Path>::isRelative),
fun1(Expect<Path>::hasSameBinaryContentAs),
fun3(Expect<Path>::hasSameTextualContentAs),
fun1(Companion::hasSameTextualContentAsDefaultArgs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import org.spekframework.spek2.dsl.Skip.No
import org.spekframework.spek2.dsl.Skip.Yes
import org.spekframework.spek2.dsl.TestBody
import org.spekframework.spek2.style.specification.Suite
import java.io.File
import java.io.IOException
import java.nio.charset.Charset
import java.nio.file.Files
Expand All @@ -43,6 +44,7 @@ abstract class PathAssertionsSpec(
isExecutable: Fun0<Path>,
isRegularFile: Fun0<Path>,
isDirectory: Fun0<Path>,
isRelative: Fun0<Path>,
hasSameBinaryContentAs: Fun1<Path, Path>,
hasSameTextualContentAs: Fun3<Path, Path, Charset, Charset>,
hasSameTextualContentAsDefaultArgs: Fun1<Path, Path>,
Expand All @@ -62,6 +64,7 @@ abstract class PathAssertionsSpec(
isExecutable.forSubjectLess(),
isRegularFile.forSubjectLess(),
isDirectory.forSubjectLess(),
isRelative.forSubjectLess(),
hasSameBinaryContentAs.forSubjectLess(Paths.get("a")),
hasSameTextualContentAs.forSubjectLess(Paths.get("a"), Charsets.ISO_8859_1, Charsets.ISO_8859_1),
hasSameTextualContentAsDefaultArgs.forSubjectLess(Paths.get("a"))
Expand Down Expand Up @@ -828,6 +831,26 @@ abstract class PathAssertionsSpec(
}
}

describeFun(isRelative) {
val isRelativeFun = isRelative.lambda
val expectedMessage = "$isDescr: ${RELATIVE_PATH.getDefault()}"

it("throws an AssertionError for absolute path") {
val path = tempFolder.newFile("test")

expect {
expect(path).isRelativeFun()
}.toThrow<AssertionError>().message {
contains(expectedMessage, "${WAS.getDefault()}: ${ABSOLUTE_PATH.getDefault()}")
}
}

it("does not throw for relative path") {
val path = Paths.get("test/bla.txt")
expect(path).isRelativeFun()
}
}

describeFun(hasSameBinaryContentAs, hasSameTextualContentAs, hasSameTextualContentAsDefaultArgs) {
val hasSameBinaryContentAsFun = hasSameBinaryContentAs.lambda
val hasSameTextualContentAsFun = hasSameTextualContentAs.lambda
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import java.nio.file.Path
* Contains the [DescriptiveAssertion.description]s of the assertion functions which are applicable to [Path].
*/
enum class DescriptionPathAssertion(override val value: String) : StringBasedTranslatable {
ABSOLUTE_PATH("ein absoluter Pfad"),
DOES_NOT_HAVE_PARENT("!! hat keinen Elternpfad"),
ENDS_NOT_WITH("endet nicht mit"),
ENDS_WITH("endet mit"),
Expand Down Expand Up @@ -44,5 +45,6 @@ enum class DescriptionPathAssertion(override val value: String) : StringBasedTra
HINT_CLOSEST_EXISTING_PARENT_DIRECTORY("das nächste, existierende Elternverzeichnis ist %s"),
HINT_FOLLOWED_SYMBOLIC_LINK("folgte der symbolischen Verknüpfung %s nach %s"),
HAS_SAME_TEXTUAL_CONTENT("hat denselben textlichen Inhalt mit Kodierung %s, %s"),
HAS_SAME_BINARY_CONTENT("hat denselben binären Inhalt")
HAS_SAME_BINARY_CONTENT("hat denselben binären Inhalt"),
RELATIVE_PATH("ein relativer Pfad")
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package ch.tutteli.atrium.translations
import ch.tutteli.atrium.reporting.translating.StringBasedTranslatable

enum class DescriptionPathAssertion(override val value: String) : StringBasedTranslatable {
ABSOLUTE_PATH("an absolute path"),
DOES_NOT_HAVE_PARENT("!! does not have a parent"),
ENDS_NOT_WITH("does not end with"),
ENDS_WITH("ends with"),
Expand Down Expand Up @@ -40,4 +41,5 @@ enum class DescriptionPathAssertion(override val value: String) : StringBasedTra
HINT_FOLLOWED_SYMBOLIC_LINK("followed the symbolic link %s to %s"),
HAS_SAME_TEXTUAL_CONTENT("has same textual content with encoding %s, %s"),
HAS_SAME_BINARY_CONTENT("has same binary content"),
RELATIVE_PATH("a relative path"),
}

0 comments on commit 1554303

Please sign in to comment.