replace SubjectProvider with Expect but do not yet remove

we cannot yet remove it because we still have addAssertion on Expect
and if we remove it, would also have one on AssertionContainer. Two
different definitions which would not work together. This also means:
- deprecate addAssertion/addAssertionsCreatedBy/createAndAddAssertion
  in Expect, add append... to AssertionContainer
This commit is contained in:
Robert Stoll
2021-04-02 23:04:12 +02:00
parent 91a36a93fb
commit 144d35c167
66 changed files with 403 additions and 200 deletions

View File

@@ -20,7 +20,7 @@ jobs:
- name: build
run: ./gradlew build
# TODO 0.17.0 or 0.18.0 re-activate scala API
# TODO 0.18.0 re-activate scala API
# - name: composite build atrium-scala2
# run: ./gradlew build
# working-directory: misc/tools/atrium-scala2-test

View File

@@ -47,7 +47,7 @@ jobs:
run: ATRIUM_ANDROID_JAR="$PWD/android-jar-cache/android.jar" ./gradlew checkDexer
shell: bash
# TODO 0.17.0 or 0.18.0 re-activate scala API
# TODO 0.18.0 re-activate scala API
# - name: composite build atrium-scala2
# run: ./gradlew build
# working-directory: misc\tools\atrium-scala2-test

View File

@@ -2000,8 +2000,10 @@ This is kind of the simplest way of defining assertion functions. Following an e
<code-own-boolean-1>
```kotlin
import ch.tutteli.atrium.logic._logic
fun Expect<Int>.isMultipleOf(base: Int) =
createAndAddAssertion("is multiple of", base) { it % base == 0 }
_logic.createAndAppendAssertion("is multiple of", base) { it % base == 0 }
```
</code-own-boolean-1>
@@ -2012,7 +2014,7 @@ and its usage:
```kotlin
expect(12).isMultipleOf(5)
```
↑ <sub>[Example](https://github.com/robstoll/atrium/tree/master/misc/tools/readme-examples/src/main/kotlin/readme/examples/OwnExpectationFunctionsSpec.kt#L39)</sub> ↓ <sub>[Output](#ex-own-boolean-1)</sub>
↑ <sub>[Example](https://github.com/robstoll/atrium/tree/master/misc/tools/readme-examples/src/main/kotlin/readme/examples/OwnExpectationFunctionsSpec.kt#L44)</sub> ↓ <sub>[Output](#ex-own-boolean-1)</sub>
<a name="ex-own-boolean-1"></a>
```text
expected that subject: 12 (kotlin.Int <1234789>)
@@ -2048,8 +2050,10 @@ Consider the following assertion function:
<code-own-boolean-2>
```kotlin
import ch.tutteli.atrium.logic._logic
fun Expect<Int>.isEven() =
createAndAddAssertion("is", Text("an even number")) { it % 2 == 0 }
_logic.createAndAppendAssertion("is", Text("an even number")) { it % 2 == 0 }
```
</code-own-boolean-2>
@@ -2062,7 +2066,7 @@ Its usage looks then as follows:
```kotlin
expect(13).isEven()
```
↑ <sub>[Example](https://github.com/robstoll/atrium/tree/master/misc/tools/readme-examples/src/main/kotlin/readme/examples/OwnExpectationFunctionsSpec.kt#L50)</sub> ↓ <sub>[Output](#ex-own-boolean-2)</sub>
↑ <sub>[Example](https://github.com/robstoll/atrium/tree/master/misc/tools/readme-examples/src/main/kotlin/readme/examples/OwnExpectationFunctionsSpec.kt#L57)</sub> ↓ <sub>[Output](#ex-own-boolean-2)</sub>
<a name="ex-own-boolean-2"></a>
```text
expected that subject: 13 (kotlin.Int <1234789>)
@@ -2095,8 +2099,10 @@ if you want that both are evaluated:
<code-own-compose-2>
```kotlin
import ch.tutteli.atrium.logic._logic
fun <T : Date> Expect<T>.isBetween(lowerBoundInclusive: T, upperBoundExclusive: T) =
addAssertionsCreatedBy {
_logic.appendAssertionsCreatedBy {
isGreaterThanOrEqual(lowerBoundInclusive)
isLessThan(upperBoundExclusive)
}
@@ -2161,7 +2167,7 @@ Its usage is then as follows:
expect(Person("Susanne", "Whitley", 43, listOf()))
.hasNumberOfChildren(2)
```
↑ <sub>[Example](https://github.com/robstoll/atrium/tree/master/misc/tools/readme-examples/src/main/kotlin/readme/examples/OwnExpectationFunctionsSpec.kt#L67)</sub> ↓ <sub>[Output](#ex-own-compose-3)</sub>
↑ <sub>[Example](https://github.com/robstoll/atrium/tree/master/misc/tools/readme-examples/src/main/kotlin/readme/examples/OwnExpectationFunctionsSpec.kt#L74)</sub> ↓ <sub>[Output](#ex-own-compose-3)</sub>
<a name="ex-own-compose-3"></a>
```text
expected that subject: Person(firstName=Susanne, lastName=Whitley, age=43, children=[]) (readme.examples.Person <1234789>)
@@ -2195,7 +2201,7 @@ but we do not have to, as `all` already checks that there is at least one elemen
expect(Person("Susanne", "Whitley", 43, listOf()))
.hasAdultChildren()
```
↑ <sub>[Example](https://github.com/robstoll/atrium/tree/master/misc/tools/readme-examples/src/main/kotlin/readme/examples/OwnExpectationFunctionsSpec.kt#L82)</sub> ↓ <sub>[Output](#ex-own-compose-4)</sub>
↑ <sub>[Example](https://github.com/robstoll/atrium/tree/master/misc/tools/readme-examples/src/main/kotlin/readme/examples/OwnExpectationFunctionsSpec.kt#L89)</sub> ↓ <sub>[Output](#ex-own-compose-4)</sub>
<a name="ex-own-compose-4"></a>
```text
expected that subject: Person(firstName=Susanne, lastName=Whitley, age=43, children=[]) (readme.examples.Person <1234789>)
@@ -2237,7 +2243,7 @@ expect(Person("Susanne", "Whitley", 43, listOf(Person("Petra", "Whitley", 12, li
.children // using the val -> subsequent assertions are about children and fail fast
.hasSize(2)
```
↑ <sub>[Example](https://github.com/robstoll/atrium/tree/master/misc/tools/readme-examples/src/main/kotlin/readme/examples/OwnExpectationFunctionsSpec.kt#L92)</sub> ↓ <sub>[Output](#ex-own-compose-5)</sub>
↑ <sub>[Example](https://github.com/robstoll/atrium/tree/master/misc/tools/readme-examples/src/main/kotlin/readme/examples/OwnExpectationFunctionsSpec.kt#L99)</sub> ↓ <sub>[Output](#ex-own-compose-5)</sub>
<a name="ex-own-compose-5"></a>
```text
expected that subject: Person(firstName=Susanne, lastName=Whitley, age=43, children=[Person(firstName=Petra, lastName=Whitley, age=12, children=[])]) (readme.examples.Person <1234789>)
@@ -2458,8 +2464,13 @@ we do no longer use a `String` but a proper `Translatable`.
<code-i18n-1>
```kotlin
fun Expect<Int>.isMultipleOf(base: Int): Expect<Int> =
createAndAddAssertion(DescriptionIntAssertion.IS_MULTIPLE_OF, base) { it % base == 0 }
import ch.tutteli.atrium.logic.*
fun Expect<Int>.isMultipleOf(base: Int): Expect<Int> = _logic.run {
appendAssertion(
createDescriptiveAssertion(DescriptionIntAssertion.IS_MULTIPLE_OF, base) { it % base == 0 }
)
}
enum class DescriptionIntAssertion(override val value: String) : StringBasedTranslatable {
IS_MULTIPLE_OF("is multiple of")
@@ -2505,8 +2516,13 @@ as second example:
<code-i18n-2>
```kotlin
fun Expect<Int>.isEven(): Expect<Int> =
createAndAddAssertion(DescriptionBasic.IS, DescriptionIntAssertions.EVEN) { it % 2 == 0 }
import ch.tutteli.atrium.logic.*
fun Expect<Int>.isEven(): Expect<Int> = _logic.run {
appendAssertion(
createDescriptiveAssertion(DescriptionBasic.IS, DescriptionIntAssertions.EVEN) { it % 2 == 0 }
)
}
enum class DescriptionIntAssertions(override val value: String) : StringBasedTranslatable {
EVEN("an even number")

View File

@@ -193,7 +193,7 @@ inline val <T> Expect<T>.and: Expect<T> get() = this
* @sample ch.tutteli.atrium.api.fluent.en_GB.samples.deprecated.AnyAssertionSamples.and
*/
infix fun <T> Expect<T>.and(assertionCreator: Expect<T>.() -> Unit): Expect<T> =
addAssertionsCreatedBy(assertionCreator)
_logic.appendAssertionsCreatedBy(assertionCreator)
/**
* Expects that the subject of `this` expectation is not (equal to) [expected] and [otherValues].

View File

@@ -34,7 +34,7 @@ fun <E> Expect<out Array<out E>>.asList(): Expect<List<E>> =
* @sample ch.tutteli.atrium.api.fluent.en_GB.samples.deprecated.ArrayAssertionSamples.asList
*/
fun <E> Expect<Array<E>>.asList(assertionCreator: Expect<List<E>>.() -> Unit): Expect<Array<E>> =
apply { asList().addAssertionsCreatedBy(assertionCreator) }
apply { asList()._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
* Expects that the subject of `this` expectation holds all assertions the given [assertionCreator] creates for
@@ -51,7 +51,7 @@ fun <E> Expect<Array<E>>.asList(assertionCreator: Expect<List<E>>.() -> Unit): E
*/
@JvmName("asListEOut")
fun <E> Expect<Array<out E>>.asList(assertionCreator: Expect<List<E>>.() -> Unit): Expect<Array<out E>> =
apply { asList().addAssertionsCreatedBy(assertionCreator) }
apply { asList()._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
* Turns `Expect<CharArray>` into `Expect<List<Byte>>`.
@@ -84,7 +84,7 @@ fun Expect<ByteArray>.asList(): Expect<List<Byte>> =
*/
@JvmName("byteArrAsList")
fun Expect<ByteArray>.asList(assertionCreator: Expect<List<Byte>>.() -> Unit): Expect<ByteArray> =
apply { asList().addAssertionsCreatedBy(assertionCreator) }
apply { asList()._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
@@ -118,7 +118,7 @@ fun Expect<CharArray>.asList(): Expect<List<Char>> =
*/
@JvmName("charArrAsList")
fun Expect<CharArray>.asList(assertionCreator: Expect<List<Char>>.() -> Unit): Expect<CharArray> =
apply { asList().addAssertionsCreatedBy(assertionCreator) }
apply { asList()._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
@@ -152,7 +152,7 @@ fun Expect<ShortArray>.asList(): Expect<List<Short>> =
*/
@JvmName("shortArrAsList")
fun Expect<ShortArray>.asList(assertionCreator: Expect<List<Short>>.() -> Unit): Expect<ShortArray> =
apply { asList().addAssertionsCreatedBy(assertionCreator) }
apply { asList()._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
@@ -186,7 +186,7 @@ fun Expect<IntArray>.asList(): Expect<List<Int>> =
*/
@JvmName("intArrAsList")
fun Expect<IntArray>.asList(assertionCreator: Expect<List<Int>>.() -> Unit): Expect<IntArray> =
apply { asList().addAssertionsCreatedBy(assertionCreator) }
apply { asList()._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
@@ -220,7 +220,7 @@ fun Expect<LongArray>.asList(): Expect<List<Long>> =
*/
@JvmName("longArrAsList")
fun Expect<LongArray>.asList(assertionCreator: Expect<List<Long>>.() -> Unit): Expect<LongArray> =
apply { asList().addAssertionsCreatedBy(assertionCreator) }
apply { asList()._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
@@ -254,7 +254,7 @@ fun Expect<FloatArray>.asList(): Expect<List<Float>> =
*/
@JvmName("floatArrAsList")
fun Expect<FloatArray>.asList(assertionCreator: Expect<List<Float>>.() -> Unit): Expect<FloatArray> =
apply { asList().addAssertionsCreatedBy(assertionCreator) }
apply { asList()._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
@@ -288,7 +288,7 @@ fun Expect<DoubleArray>.asList(): Expect<List<Double>> =
*/
@JvmName("doubleArrAsList")
fun Expect<DoubleArray>.asList(assertionCreator: Expect<List<Double>>.() -> Unit): Expect<DoubleArray> =
apply { asList().addAssertionsCreatedBy(assertionCreator) }
apply { asList()._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
@@ -321,4 +321,4 @@ fun Expect<BooleanArray>.asList(): Expect<List<Boolean>> =
*/
@JvmName("boolArrAsList")
fun Expect<BooleanArray>.asList(assertionCreator: Expect<List<Boolean>>.() -> Unit): Expect<BooleanArray> =
apply { asList().addAssertionsCreatedBy(assertionCreator) }
apply { asList()._logic.appendAssertionsCreatedBy(assertionCreator) }

View File

@@ -337,4 +337,4 @@ fun <E, T : Iterable<E>> Expect<T>.asList(): Expect<List<E>> = _logic.changeSubj
* @since 0.14.0
*/
fun <E, T : Iterable<E>> Expect<T>.asList(assertionCreator: Expect<List<E>>.() -> Unit): Expect<T> =
apply { asList().addAssertionsCreatedBy(assertionCreator) }
apply { asList()._logic.appendAssertionsCreatedBy(assertionCreator) }

View File

@@ -236,7 +236,7 @@ fun <K, V, T : Map<out K, V>> Expect<T>.asEntries(): Expect<Set<Map.Entry<K, V>>
*/
fun <K, V, T : Map<out K, V>> Expect<T>.asEntries(
assertionCreator: Expect<Set<Map.Entry<K, V>>>.() -> Unit
): Expect<T> = apply { asEntries().addAssertionsCreatedBy(assertionCreator) }
): Expect<T> = apply { asEntries()._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
* Expects that the subject of `this` expectation (a [Map]) is an empty [Map].

View File

@@ -25,7 +25,7 @@ fun <E, T : Sequence<E>> Expect<T>.asIterable(): Expect<Iterable<E>> =
* @return an [Expect] for the subject of `this` expectation.
*/
fun <E, T : Sequence<E>> Expect<T>.asIterable(assertionCreator: Expect<Iterable<E>>.() -> Unit): Expect<T> =
apply { asIterable().addAssertionsCreatedBy(assertionCreator) }
apply { asIterable()._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
* Turns `Expect<E, T : Sequence<E>>` into `Expect<List<E>`.
@@ -51,4 +51,4 @@ fun <E, T : Sequence<E>> Expect<T>.asList(): Expect<List<E>> = _logic.changeSubj
* @since 0.14.0
*/
fun <E, T : Sequence<E>> Expect<T>.asList(assertionCreator: Expect<List<E>>.() -> Unit): Expect<T> =
apply { asList().addAssertionsCreatedBy(assertionCreator) }
apply { asList()._logic.appendAssertionsCreatedBy(assertionCreator) }

View File

@@ -27,7 +27,7 @@ class IterableAnyExpectationsSpec : Spek({
"[Atrium][Builder] "
)
// TODO 0.17.0 #722 this will differ once we don't implement the same behaviour for contains and none
// TODO 0.19.0 #722 this will differ once we don't implement the same behaviour for contains and none
// that's fine and we can simply remove this test here
object ShortcutSpec : ch.tutteli.atrium.specs.integration.IterableAnyExpectationsSpec(
shortcutDescription to C::containsEntryShortcut,

View File

@@ -17,7 +17,7 @@ class IterableNoneExpectationsSpec : Spek({
"[Atrium][Predicate] "
)
// TODO 0.17.0 #722 this will differ once we don't implement the same behaviour for contains and none
// TODO 0.19.0 #722 this will differ once we don't implement the same behaviour for contains and none
// that's fine and we can simply remove this test here
object BuilderSpec : ch.tutteli.atrium.specs.integration.IterableNoneExpectationsSpec(
functionDescription to C::containsNotFun,

View File

@@ -36,4 +36,4 @@ fun <T : File> Expect<T>.asPath(): Expect<Path> =
* @since 0.9.0
*/
fun <T : File> Expect<T>.asPath(assertionCreator: Expect<Path>.() -> Unit): Expect<T> =
apply { asPath().addAssertionsCreatedBy(assertionCreator) }
apply { asPath()._logic.appendAssertionsCreatedBy(assertionCreator) }

View File

@@ -194,7 +194,7 @@ inline infix fun <T> Expect<T>.and(@Suppress("UNUSED_PARAMETER") o: o): Expect<T
* @return an [Expect] for the subject of `this` expectation.
*/
infix fun <T> Expect<T>.and(assertionCreator: Expect<T>.() -> Unit): Expect<T> =
addAssertionsCreatedBy(assertionCreator)
_logic.appendAssertionsCreatedBy(assertionCreator)
/**
* Inline property referring actually to `this` and allows to write infix assertions within an assertion group block

View File

@@ -34,7 +34,7 @@ infix fun <E> Expect<out Array<out E>>.asList(@Suppress("UNUSED_PARAMETER") o: o
* @since 0.12.0
*/
infix fun <E> Expect<Array<E>>.asList(assertionCreator: Expect<List<E>>.() -> Unit): Expect<Array<E>> =
apply { asList(o).addAssertionsCreatedBy(assertionCreator) }
apply { asList(o)._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
* Expects that the subject of `this` expectation holds all assertions the given [assertionCreator] creates for
@@ -51,7 +51,7 @@ infix fun <E> Expect<Array<E>>.asList(assertionCreator: Expect<List<E>>.() -> Un
*/
@JvmName("asListEOut")
infix fun <E> Expect<Array<out E>>.asList(assertionCreator: Expect<List<E>>.() -> Unit): Expect<Array<out E>> =
apply { asList(o).addAssertionsCreatedBy(assertionCreator) }
apply { asList(o)._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
* Turns `Expect<CharArray>` into `Expect<List<Byte>>`.
@@ -84,7 +84,7 @@ infix fun Expect<ByteArray>.asList(@Suppress("UNUSED_PARAMETER") o: o): Expect<L
*/
@JvmName("byteArrAsList")
infix fun Expect<ByteArray>.asList(assertionCreator: Expect<List<Byte>>.() -> Unit): Expect<ByteArray> =
apply { asList(o).addAssertionsCreatedBy(assertionCreator) }
apply { asList(o)._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
@@ -118,7 +118,7 @@ infix fun Expect<CharArray>.asList(@Suppress("UNUSED_PARAMETER") o: o): Expect<L
*/
@JvmName("charArrAsList")
infix fun Expect<CharArray>.asList(assertionCreator: Expect<List<Char>>.() -> Unit): Expect<CharArray> =
apply { asList(o).addAssertionsCreatedBy(assertionCreator) }
apply { asList(o)._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
@@ -152,7 +152,7 @@ infix fun Expect<ShortArray>.asList(@Suppress("UNUSED_PARAMETER") o: o): Expect<
*/
@JvmName("shortArrAsList")
infix fun Expect<ShortArray>.asList(assertionCreator: Expect<List<Short>>.() -> Unit): Expect<ShortArray> =
apply { asList(o).addAssertionsCreatedBy(assertionCreator) }
apply { asList(o)._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
@@ -186,7 +186,7 @@ infix fun Expect<IntArray>.asList(@Suppress("UNUSED_PARAMETER") o: o): Expect<Li
*/
@JvmName("intArrAsList")
infix fun Expect<IntArray>.asList(assertionCreator: Expect<List<Int>>.() -> Unit): Expect<IntArray> =
apply { asList(o).addAssertionsCreatedBy(assertionCreator) }
apply { asList(o)._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
@@ -220,7 +220,7 @@ infix fun Expect<LongArray>.asList(@Suppress("UNUSED_PARAMETER") o: o): Expect<L
*/
@JvmName("longArrAsList")
infix fun Expect<LongArray>.asList(assertionCreator: Expect<List<Long>>.() -> Unit): Expect<LongArray> =
apply { asList(o).addAssertionsCreatedBy(assertionCreator) }
apply { asList(o)._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
@@ -254,7 +254,7 @@ infix fun Expect<FloatArray>.asList(@Suppress("UNUSED_PARAMETER") o: o): Expect<
*/
@JvmName("floatArrAsList")
infix fun Expect<FloatArray>.asList(assertionCreator: Expect<List<Float>>.() -> Unit): Expect<FloatArray> =
apply { asList(o).addAssertionsCreatedBy(assertionCreator) }
apply { asList(o)._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
@@ -288,7 +288,7 @@ infix fun Expect<DoubleArray>.asList(@Suppress("UNUSED_PARAMETER") o: o): Expect
*/
@JvmName("doubleArrAsList")
infix fun Expect<DoubleArray>.asList(assertionCreator: Expect<List<Double>>.() -> Unit): Expect<DoubleArray> =
apply { asList(o).addAssertionsCreatedBy(assertionCreator) }
apply { asList(o)._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
@@ -322,4 +322,4 @@ infix fun Expect<BooleanArray>.asList(@Suppress("UNUSED_PARAMETER") o: o): Expec
*/
@JvmName("boolArrAsList")
infix fun Expect<BooleanArray>.asList(assertionCreator: Expect<List<Boolean>>.() -> Unit): Expect<BooleanArray> =
apply { asList(o).addAssertionsCreatedBy(assertionCreator) }
apply { asList(o)._logic.appendAssertionsCreatedBy(assertionCreator) }

View File

@@ -385,4 +385,4 @@ infix fun <E, T : Iterable<E>> Expect<T>.asList(
* @since 0.14.0
*/
infix fun <E, T : Iterable<E>> Expect<T>.asList(assertionCreator: Expect<List<E>>.() -> Unit): Expect<T> =
apply { asList(o).addAssertionsCreatedBy(assertionCreator) }
apply { asList(o)._logic.appendAssertionsCreatedBy(assertionCreator) }

View File

@@ -292,7 +292,7 @@ infix fun <K, V, T : Map<out K, V>> Expect<T>.asEntries(
*/
infix fun <K, V, T : Map<out K, V>> Expect<T>.asEntries(
assertionCreator: Expect<Set<Map.Entry<K, V>>>.() -> Unit
): Expect<T> = apply { asEntries(o).addAssertionsCreatedBy(assertionCreator) }
): Expect<T> = apply { asEntries(o)._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
* Expects that the subject of `this` expectation (a [Map]) is an empty [Map].

View File

@@ -26,7 +26,7 @@ infix fun <E, T : Sequence<E>> Expect<T>.asIterable(
* @return an [Expect] for the subject of `this` expectation.
*/
infix fun <E, T : Sequence<E>> Expect<T>.asIterable(assertionCreator: Expect<Iterable<E>>.() -> Unit): Expect<T> =
apply { asIterable(o).addAssertionsCreatedBy(assertionCreator) }
apply { asIterable(o)._logic.appendAssertionsCreatedBy(assertionCreator) }
/**
* Turns `Expect<E, T : Sequence<E>>` into `Expect<List<E>`.
@@ -54,4 +54,4 @@ infix fun <E, T : Sequence<E>> Expect<T>.asList(
* @since 0.14.0
*/
infix fun <E, T : Sequence<E>> Expect<T>.asList(assertionCreator: Expect<List<E>>.() -> Unit): Expect<T> =
apply { asList(o).addAssertionsCreatedBy(assertionCreator) }
apply { asList(o)._logic.appendAssertionsCreatedBy(assertionCreator) }

View File

@@ -36,4 +36,4 @@ infix fun <T : File> Expect<T>.asPath(@Suppress("UNUSED_PARAMETER") o: o): Expec
* @since 0.12.0
*/
infix fun <T : File> Expect<T>.asPath(assertionCreator: Expect<Path>.() -> Unit): Expect<T> =
apply { asPath(o).addAssertionsCreatedBy(assertionCreator) }
apply { asPath(o)._logic.appendAssertionsCreatedBy(assertionCreator) }

View File

@@ -334,7 +334,7 @@ def createJsTestTask(String... subprojectNames) {
from compileKotlin2Js.destinationDir
prefixedProject('verbs-internal-js').afterEvaluate {
// TODO 0.17.0 or 0.18.0, check if still required with the new Kotlin MPP plugin
// TODO 0.18.0, check if still required with the new Kotlin MPP plugin
configurations.testRuntimeClasspath.allDependencies.withType(ProjectDependency).each {
dependsOn(it.dependencyProject.assemble)
}

View File

@@ -9,6 +9,7 @@ import ch.tutteli.atrium.api.verbs.expect
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.logic._logic
import ch.tutteli.atrium.logic._logicAppend
import ch.tutteli.atrium.logic.createDescriptiveAssertion
import ch.tutteli.atrium.reporting.Text
@@ -26,6 +27,7 @@ class SmokeTest {
@Test
fun assertionFunctionWithoutI18nCanBeUsed() {
assertThat(2).isEven()
assertThat(1).isOdd()
}
@Test
@@ -106,8 +108,11 @@ class SmokeTest {
}
}
//TODO 0.17.0 also add test case for using the string overload once we have createAndAppend
fun Expect<Int>.isEven() = createAndAddAssertion(IS, Text("an even number")) { it % 2 == 0 }
fun Expect<Int>.isEven() =
_logic.createAndAppendAssertion("is", Text("an even number")) { it % 2 == 0 }
fun Expect<Int>.isOdd() =
_logic.appendAssertion(_logic.createDescriptiveAssertion(IS, Text("an odd number")) { it % 2 == 1 })
fun Expect<Int>.isMultipleOf(base: Int): Expect<Int> = _logicAppend { isMultipleOf(base) }

View File

@@ -7,6 +7,7 @@ import ch.tutteli.atrium.api.verbs.assertThat
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.logic._logic
import ch.tutteli.atrium.logic._logicAppend
import ch.tutteli.atrium.logic.createDescriptiveAssertion
import ch.tutteli.atrium.reporting.Text
@@ -26,6 +27,7 @@ object SmokeSpec : Spek({
test("see if own assertion function without i18n can be used") {
assertThat(2).isEven()
assertThat(1).isOdd()
}
test("see if own assertion function with i18n can be used") {
@@ -34,7 +36,10 @@ object SmokeSpec : Spek({
})
fun Expect<Int>.isEven() =
createAndAddAssertion(DescriptionBasic.IS, Text("an even number")) { it % 2 == 0 }
_logic.createAndAppendAssertion("is", Text("an even number")) { it % 2 == 0 }
fun Expect<Int>.isOdd() =
_logic.appendAssertion(_logic.createDescriptiveAssertion(DescriptionBasic.IS, Text("an odd number")) { it % 2 == 1 })
fun Expect<Int>.isMultipleOf(base: Int) = _logicAppend { isMultipleOf(base) }

View File

@@ -11,6 +11,7 @@ import ch.tutteli.atrium.api.verbs.expect
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.logic._logic
import ch.tutteli.atrium.logic._logicAppend
import ch.tutteli.atrium.logic.createDescriptiveAssertion
import ch.tutteli.atrium.reporting.Text
@@ -29,6 +30,7 @@ object SmokeSpec : Spek({
test("see if own assertion function without i18n can be used") {
expect(2).isEven()
expect(1).isOdd()
}
test("see if own assertion function with i18n can be used") {
@@ -36,8 +38,11 @@ object SmokeSpec : Spek({
}
})
fun Expect<Int>.isEven(): Expect<Int> =
createAndAddAssertion(DescriptionBasic.IS, Text("an even number")) { it % 2 == 0 }
fun Expect<Int>.isEven() =
_logic.createAndAppendAssertion("is", Text("an even number")) { it % 2 == 0 }
fun Expect<Int>.isOdd() =
_logic.appendAssertion(_logic.createDescriptiveAssertion(DescriptionBasic.IS, Text("an odd number")) { it % 2 == 1 })
fun Expect<Int>.isMultipleOf(base: Int): Expect<Int> = _logicAppend { isMultipleOf(base) }

View File

@@ -3,6 +3,7 @@ import ch.tutteli.atrium.api.verbs.assertThat
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.logic._logic
import ch.tutteli.atrium.logic._logicAppend
import ch.tutteli.atrium.logic.createDescriptiveAssertion
import ch.tutteli.atrium.reporting.Text
@@ -20,6 +21,7 @@ class SmokeTest {
@Test
fun assertionFunctionWithoutI18nCanBeUsed() {
assertThat(2) tobe even
assertThat(1) tobe odd
}
@Test
@@ -53,10 +55,14 @@ class SmokeTest {
@Suppress("ClassName")
object even
@Suppress("ClassName")
object odd
//TODO 0.17.0 also add test case for using the string overload once we have createAndAppend
infix fun Expect<Int>.tobe(@Suppress("UNUSED_PARAMETER") even: even) =
createAndAddAssertion(IS, Text("an even number")) { it % 2 == 0 }
_logic.appendAssertion(_logic.createDescriptiveAssertion(IS, Text("an even number")) { it % 2 == 0 })
infix fun Expect<Int>.tobe(@Suppress("UNUSED_PARAMETER") odd: odd) =
_logic.appendAssertion(_logic.createDescriptiveAssertion(IS, Text("an odd number")) { it % 2 == 1})
infix fun Expect<Int>.isMultipleOf(base: Int): Expect<Int> = _logicAppend { isMultipleOf(base) }

View File

@@ -5,6 +5,7 @@ import ch.tutteli.atrium.api.verbs.assertThat
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.logic._logic
import ch.tutteli.atrium.logic._logicAppend
import ch.tutteli.atrium.logic.createDescriptiveAssertion
import ch.tutteli.atrium.reporting.Text
@@ -19,6 +20,7 @@ object SmokeSpec : Spek({
test("see if own assertion function without i18n can be used") {
assertThat(2) tobe even
assertThat(1) tobe odd
}
test("see if own assertion function with i18n can be used") {
@@ -28,9 +30,14 @@ object SmokeSpec : Spek({
@Suppress("ClassName")
object even
@Suppress("ClassName")
object odd
infix fun Expect<Int>.tobe(@Suppress("UNUSED_PARAMETER") even: even) =
createAndAddAssertion(DescriptionBasic.IS, Text("an even number")) { it % 2 == 0 }
_logic.appendAssertion(_logic.createDescriptiveAssertion(DescriptionBasic.IS, Text("an even number")) { it % 2 == 0 })
infix fun Expect<Int>.tobe(@Suppress("UNUSED_PARAMETER") odd: odd) =
_logic.appendAssertion(_logic.createDescriptiveAssertion(DescriptionBasic.IS, Text("an odd number")) { it % 2 == 1 })
infix fun Expect<Int>.isMultipleOf(base: Int): Expect<Int> = _logicAppend { isMultipleOf(base) }

View File

@@ -12,6 +12,7 @@ import ch.tutteli.atrium.api.verbs.expect
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.logic._logic
import ch.tutteli.atrium.logic._logicAppend
import ch.tutteli.atrium.logic.createDescriptiveAssertion
import ch.tutteli.atrium.reporting.Text
@@ -30,6 +31,7 @@ object SmokeSpec : Spek({
test("see if own assertion function without i18n can be used") {
expect(2) tobe even
expect(1) tobe odd
}
test("see if own assertion function with i18n can be used") {
@@ -39,9 +41,14 @@ object SmokeSpec : Spek({
@Suppress("ClassName")
object even
@Suppress("ClassName")
object odd
infix fun Expect<Int>.tobe(@Suppress("UNUSED_PARAMETER") even: even) =
createAndAddAssertion(DescriptionBasic.IS, Text("an even number")) { it % 2 == 0 }
_logic.appendAssertion(_logic.createDescriptiveAssertion(DescriptionBasic.IS, Text("an even number")) { it % 2 == 0 })
infix fun Expect<Int>.tobe(@Suppress("UNUSED_PARAMETER") odd: odd) =
_logic.appendAssertion(_logic.createDescriptiveAssertion(DescriptionBasic.IS, Text("an odd number")) { it % 2 == 1 })
infix fun Expect<Int>.isMultipleOf(base: Int): Expect<Int> = _logicAppend { isMultipleOf(base) }

View File

@@ -163,22 +163,22 @@ interface AssertionBuilder {
* @param representation The representation of the expected outcome.
* @param test The test which checks whether the assertion holds.
*/
//TODO remove with 0.17.0
//TODO remove with 0.18.0
@Suppress("DEPRECATION")
@Deprecated(
"Use _logic.createDescriptive instead; will be removed with 0.17.0",
"Use _logic.createDescriptive instead; will be removed with 0.18.0",
ReplaceWith(
"container.createDescriptiveAssertion",
"container.createDescriptiveAssertion(expect, description, represetnation, test)",
"ch.tutteli.atrium.logic._logic",
"ch.tutteli.atrium.logic.createDescriptiveAssertion"
)
)
fun <T> createDescriptive(
subjectProvider: ch.tutteli.atrium.creating.SubjectProvider<T>,
expect: Expect<T>,
description: String,
representation: Any?,
test: (T) -> Boolean
): DescriptiveAssertion = createDescriptive(subjectProvider, Untranslatable(description), representation, test)
): DescriptiveAssertion = createDescriptive(expect, Untranslatable(description), representation, test)
/**
* Creates a [DescriptiveAssertion] based on the [description], [representation] and [test] as well as the
@@ -201,23 +201,23 @@ interface AssertionBuilder {
* @param representation The representation of the expected outcome.
* @param test The test which checks whether the assertion holds.
*/
//TODO remove with 0.17.0
//TODO remove with 0.18.0
@Deprecated(
"Use extension AssertionContainer.createDescriptiveAssertion instead - e.g. _logic.createDescriptiveAssertion; will be removed with 0.17.0",
"Use extension AssertionContainer.createDescriptiveAssertion instead - e.g. _logic.createDescriptiveAssertion; will be removed with 0.18.0",
ReplaceWith(
"container.createDescriptiveAssertion",
"container.createDescriptiveAssertion(expect, description, represetantion, test)",
"ch.tutteli.atrium.logic._logic",
"ch.tutteli.atrium.logic.createDescriptiveAssertion"
)
)
fun <T> createDescriptive(
@Suppress("DEPRECATION") subjectProvider: ch.tutteli.atrium.creating.SubjectProvider<T>,
expect: Expect<T>,
description: Translatable,
representation: Any?,
test: (T) -> Boolean
): DescriptiveAssertion =
descriptive
.withTest(subjectProvider, test)
.withTest(expect, test)
.withDescriptionAndRepresentation(description, representation)
.build()
}

View File

@@ -1,5 +1,8 @@
package ch.tutteli.atrium.assertions.builders
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.creating.Expect
/**
* Contract for sub option steps which are based on a defined or absent subject of the expectation.
*/
@@ -40,12 +43,13 @@ interface SubjectBasedOption {
companion object {
@Suppress("DEPRECATION")
operator fun <T, R, PO : DefinedOption<T, R, *>> invoke(
subjectProvider: ch.tutteli.atrium.creating.SubjectProvider<T>,
expect: Expect<T>,
subStep: PO.() -> Pair<() -> R, (T) -> R>,
presentOptionFactory: () -> PO
): R {
val (ifAbsent, ifPresent) = presentOptionFactory().subStep()
return subjectProvider.maybeSubject.fold(ifAbsent, ifPresent)
@Suppress("UNCHECKED_CAST")
return (expect as AssertionContainer<T>).maybeSubject.fold(ifAbsent, ifPresent)
}
}
}

View File

@@ -2,6 +2,7 @@ package ch.tutteli.atrium.assertions.builders.common
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.assertions.RepresentationOnlyAssertion
import ch.tutteli.atrium.creating.Expect
/**
* Step which allows to specify [RepresentationOnlyAssertion.holds].
@@ -34,9 +35,9 @@ interface HoldsStep<R> {
* @return `true` in case [SubjectProvider.maybeSubject] is None or the result of [test] passing the subject.
*/
//TODO if we introduce Record or something else as replacement for Assertion then not but if we keep Assertion
// then move to logic and expect AssertionContainer with 0.16.0
// then move to logic and expect ProofContainer with 0.18.0
fun <T> withTest(
@Suppress("DEPRECATION") subjectProvider: ch.tutteli.atrium.creating.SubjectProvider<T>,
expect: Expect<T>,
test: (T) -> Boolean
): R
}

View File

@@ -2,6 +2,8 @@ package ch.tutteli.atrium.assertions.builders.common.impl
import ch.tutteli.atrium.assertions.builders.common.HoldsStep
import ch.tutteli.atrium.core.falseProvider
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.creating.Expect
internal abstract class HoldsStepImpl<R> : HoldsStep<R> {
//TODO use falseProvider https://youtrack.jetbrains.com/issue/KT-27736
@@ -9,8 +11,9 @@ internal abstract class HoldsStepImpl<R> : HoldsStep<R> {
//TODO use trueProvider https://youtrack.jetbrains.com/issue/KT-27736
override val holding: R = withTest { true }
override fun <T> withTest(@Suppress("DEPRECATION") subjectProvider: ch.tutteli.atrium.creating.SubjectProvider<T>, test: (T) -> Boolean): R = withTest {
subjectProvider.maybeSubject.fold(falseProvider, test)
override fun <T> withTest(expect: Expect<T>, test: (T) -> Boolean): R = withTest {
@Suppress("UNCHECKED_CAST")
(expect as AssertionContainer<T>).maybeSubject.fold(falseProvider, test)
}
final override fun withTest(test: () -> Boolean): R = createNextStep(test)

View File

@@ -5,6 +5,7 @@ import ch.tutteli.atrium.assertions.DescriptiveAssertion
import ch.tutteli.atrium.assertions.builders.impl.descriptive.DescriptionOptionImpl
import ch.tutteli.atrium.assertions.builders.impl.descriptive.FinalStepImpl
import ch.tutteli.atrium.assertions.builders.impl.descriptive.HoldsOptionImpl
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.reporting.Text
import ch.tutteli.atrium.reporting.translating.Translatable
import ch.tutteli.atrium.reporting.translating.Untranslatable
@@ -34,16 +35,15 @@ interface Descriptive {
fun withTest(test: () -> Boolean): DescriptionOption<FinalStep>
/**
* Uses the given [test] as [DescriptiveAssertion.holds] based on the subject provided by [subjectProvider].
* Uses the given [test] as [DescriptiveAssertion.holds] based on the subject provided by [expect].
*
* Notice, this function might change its signature with 1.0.0 to something like
* ```
* fun <T> withTest(expect: Expect, test: (T) -> Boolean): DescriptionOption<FinalStep>
* ```
*/
//TODO 0.18.0: don't use SubjectProvider in the new ProofBuilder but ProofContainer instead
fun <T> withTest(
@Suppress("DEPRECATION") subjectProvider: ch.tutteli.atrium.creating.SubjectProvider<T>,
expect: Expect<T>,
test: (T) -> Boolean
): DescriptionOption<FinalStep>

View File

@@ -4,6 +4,8 @@ import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.assertions.AssertionGroup
import ch.tutteli.atrium.assertions.DescriptiveAssertion
import ch.tutteli.atrium.assertions.builders.impl.descriptiveWithFailureHint.*
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.reporting.SHOULD_NOT_BE_SHOWN_TO_THE_USER_BUG
import ch.tutteli.atrium.reporting.Text
import ch.tutteli.atrium.reporting.translating.Translatable
@@ -33,12 +35,12 @@ fun Descriptive.DescriptionOption<Descriptive.FinalStep>.withFailureHint(
* on the subject of the expectation.
*/
//TODO if we introduce Record or something else as replacement for Assertion then not but if we keep Assertion
// then move to logic and expect AssertionContainer with 0.16.0
// then move to logic and expect ProofContainer with 0.18.0
fun <T> Descriptive.DescriptionOption<Descriptive.FinalStep>.withFailureHintBasedOnDefinedSubject(
@Suppress("DEPRECATION") subjectProvider: ch.tutteli.atrium.creating.SubjectProvider<T>,
expect: Expect<T>,
failureHintFactory: (T) -> Assertion
): Descriptive.DescriptionOption<DescriptiveAssertionWithFailureHint.FinalStep> {
return withFailureHintBasedOnSubject(subjectProvider) {
return withFailureHintBasedOnSubject(expect) {
ifDefined(failureHintFactory)
.ifAbsent {
assertionBuilder.explanatoryGroup
@@ -46,7 +48,7 @@ fun <T> Descriptive.DescriptionOption<Descriptive.FinalStep>.withFailureHintBase
.withExplanatoryAssertion(Text(SHOULD_NOT_BE_SHOWN_TO_THE_USER_BUG))
.build()
}
}.showOnlyIfSubjectDefined(subjectProvider)
}.showOnlyIfSubjectDefined(expect)
}
/**
@@ -54,15 +56,15 @@ fun <T> Descriptive.DescriptionOption<Descriptive.FinalStep>.withFailureHintBase
* (which is based on the subject of the expectation)
* which might be shown if the [Descriptive.DescriptionOption.test] fails.
*
* You can use [withFailureHint] which does not expect a [subjectProvider] in case your [DescriptiveAssertion] is not based
* You can use [withFailureHint] which does not expect a [expect] in case your [DescriptiveAssertion] is not based
* on the subject of the expectation.
*/
fun <T> Descriptive.DescriptionOption<Descriptive.FinalStep>.withFailureHintBasedOnSubject(
@Suppress("DEPRECATION") subjectProvider: ch.tutteli.atrium.creating.SubjectProvider<T>,
expect: Expect<T>,
failureHintSubStep: DescriptiveAssertionWithFailureHint.FailureHintSubjectDefinedOption<T>.() -> Pair<() -> Assertion, (T) -> Assertion>
): DescriptiveAssertionWithFailureHint.ShowOption = withFailureHint {
SubjectBasedOption(
subjectProvider,
expect,
failureHintSubStep,
DescriptiveAssertionWithFailureHint.FailureHintSubjectDefinedOption.Companion::create
)
@@ -117,31 +119,31 @@ interface DescriptiveAssertionWithFailureHint {
* Defines that the failure hint shall be shown in any case as long as the subject is defined
*/
fun <T> showOnlyIfSubjectDefined(
@Suppress("DEPRECATION") subjectProvider: ch.tutteli.atrium.creating.SubjectProvider<T>
expect: Expect<T>
): Descriptive.DescriptionOption<FinalStep> =
showOnlyIf { subjectProvider.maybeSubject.isDefined() }
showOnlyIf { (expect as AssertionContainer<*>).maybeSubject.isDefined() }
/**
* Defines that the failure hint shall be shown if the subject is defined and the given [predicate] holds for it
*/
fun <T> showBasedOnDefinedSubjectOnlyIf(
@Suppress("DEPRECATION") subjectProvider: ch.tutteli.atrium.creating.SubjectProvider<T>,
expect: Expect<T>,
predicate: (T) -> Boolean
): Descriptive.DescriptionOption<FinalStep> =
showBasedOnSubjectOnlyIf(subjectProvider) { ifDefined { predicate(it) } ifAbsent { false } }
showBasedOnSubjectOnlyIf(expect) { ifDefined { predicate(it) } ifAbsent { false } }
/**
* Defines that the failure hint shall only be shown based on a predicate influenced by the
* subject of the expectation.
*
* You can use the other overload without [subjectProvider] in case the predicate is not based on the subject
* You can use the other overload without [expect] in case the predicate is not based on the subject
* of the assertion.
*/
fun <T> showBasedOnSubjectOnlyIf(
@Suppress("DEPRECATION") subjectProvider: ch.tutteli.atrium.creating.SubjectProvider<T>,
expect: Expect<T>,
showSubStep: ShowSubjectDefinedOption<T>.() -> Pair<() -> Boolean, (T) -> Boolean>
): Descriptive.DescriptionOption<FinalStep> = showOnlyIf {
SubjectBasedOption(subjectProvider, showSubStep, ShowSubjectDefinedOption.Companion::create)
SubjectBasedOption(expect, showSubStep, ShowSubjectDefinedOption.Companion::create)
}
companion object {

View File

@@ -3,6 +3,8 @@ package ch.tutteli.atrium.assertions.builders.impl.descriptive
import ch.tutteli.atrium.assertions.DescriptiveAssertion
import ch.tutteli.atrium.assertions.builders.Descriptive
import ch.tutteli.atrium.core.falseProvider
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.reporting.Text
import ch.tutteli.atrium.reporting.translating.Translatable
@@ -21,10 +23,11 @@ internal object HoldsOptionImpl : Descriptive.HoldsOption {
Descriptive.DescriptionOption.create(test, Descriptive.FinalStep.Companion::create)
override fun <T> withTest(
@Suppress("DEPRECATION") subjectProvider: ch.tutteli.atrium.creating.SubjectProvider<T>,
expect: Expect<T>,
test: (T) -> Boolean
): Descriptive.DescriptionOption<Descriptive.FinalStep> = withTest {
subjectProvider.maybeSubject.fold(falseProvider, test)
@Suppress("UNCHECKED_CAST")
(expect as AssertionContainer<T>).maybeSubject.fold(falseProvider, test)
}
}

View File

@@ -1,10 +1,13 @@
package ch.tutteli.atrium.creating
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.assertions.DescriptiveAssertion
import ch.tutteli.atrium.assertions.builders.assertionBuilder
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
import ch.tutteli.atrium.core.None
import ch.tutteli.atrium.core.Option
import ch.tutteli.atrium.core.Some
import ch.tutteli.atrium.reporting.translating.Untranslatable
import kotlin.reflect.KClass
/**
@@ -13,16 +16,15 @@ import kotlin.reflect.KClass
* In contrast to expectation functions defined for [Expect] which usually return [Expect], functions defined for
* [AssertionContainer] return [Assertion] so that they can be appended to whatever we want.
*
* Note, do not use [SubjectProvider] as this interface will be removed with 0.17.0.
*
* @param T The type of the subject of `this` expectation.
*/
//TODO 0.17.0 introduce ProofContainer
//TODO 0.18.0 introduce ProofContainer
interface AssertionContainer<T> : @kotlin.Suppress("DEPRECATION") SubjectProvider<T> {
/**
* Either [Some] wrapping the subject of an [Assertion] or [None] in case a previous subject transformation
* could not be carried out.
*/
//TODO 0.18.0 remove override once we no longer extend SubjectProvider
override val maybeSubject: Option<T>
/**
@@ -40,18 +42,49 @@ interface AssertionContainer<T> : @kotlin.Suppress("DEPRECATION") SubjectProvide
@ExperimentalComponentFactoryContainer
val components: ComponentFactoryContainer
// /**
// * Appends the given [assertion] to this container and returns an [Expect] which includes it.
// *
// * Whether the returned [Expect] is the same as the initial one is up to the implementation (i.e. if a mutable
// * structure is used or an immutable). Atrium strives for an immutable data structure in the long run and will
// * little by little refactor the code accordingly.
// *
// * @param assertion The assertion which will be appended to this container.
// *
// * @return an [Expect] for the subject of `this` expectation.
// *
// * @throws AssertionError Might throw an [AssertionError] in case [Assertion]s are immediately evaluated.
// */
// fun append(assertion: Assertion): Expect<T>
/**
* Appends the given [assertion] to this container and returns an [Expect] which includes it.
*
* Whether the returned [Expect] is the same as the initial one is up to the implementation (i.e. if a mutable
* structure is used or an immutable). Atrium strives for an immutable data structure in the long run and will
* little by little refactor the code accordingly.
*
* @param assertion The assertion which will be appended to this container.
*
* @return an [Expect] for the subject of `this` expectation.
*
* @throws AssertionError Might throw an [AssertionError] in case [Assertion]s are immediately evaluated.
*/
fun appendAssertion(assertion: Assertion): Expect<T>
/**
* Appends the [Assertion]s the given [assertionCreator] creates to this container and
* returns an [Expect] which includes them.
*
* Whether the returned [Expect] is the same as the initial one is up to the implementation (i.e. if a mutable
* structure is used or an immutable). Atrium strives for an immutable data structure in the long run and will
* little by little refactor the code accordingly.
*
* @param assertionCreator The lambda which will create assertions.
*
* @return an [Expect] for the subject of `this` expectation.
*
* @throws AssertionError Might throw an [AssertionError] in case [Assertion]s are immediately evaluated.
*/
fun appendAssertionsCreatedBy(assertionCreator: Expect<T>.() -> Unit): Expect<T>
/**
* Creates a [DescriptiveAssertion] based on the given [description], [expected] and [test]
* and [appends][appendAssertion] it to the container.
*
* @param description The description of the assertion, e.g., `is less than`.
* @param expected The expected value, e.g., `5`
* @param test Indicates whether the assertion holds or fails.
*
* @return an [Expect] for the subject of `this` expectation.
*/
//TODO remove SUPPRESS with 0.18.0
@Suppress("UNCHECKED_CAST", "DEPRECATION")
fun createAndAppendAssertion(description: String, expected: Any?, test: (T) -> Boolean): Expect<T> =
appendAssertion(assertionBuilder.createDescriptive(this as Expect<T>, Untranslatable(description),expected, test))
}

View File

@@ -21,8 +21,28 @@ interface CollectingExpect<T> : Expect<T> {
*/
fun getAssertions(): List<Assertion>
@Deprecated(
"use appendAssertionsCreatedBy; will be removed with 0.18.0",
ReplaceWith("this.appendAssertionsCreatedBy(assertionCreator)")
)
override fun addAssertionsCreatedBy(assertionCreator: Expect<T>.() -> Unit): CollectingExpect<T>
/**
* Appends the [Assertion]s the given [assertionCreator] creates to this container and
* returns an [Expect] which includes them.
*
* Whether the returned [Expect] is the same as the initial one is up to the implementation (i.e. if a mutable
* structure is used or an immutable). Atrium strives for an immutable data structure in the long run and will
* little by little refactor the code accordingly.
*
* @param assertionCreator The lambda which will create assertions.
*
* @return an [Expect] for the subject of `this` expectation.
*
* @throws AssertionError Might throw an [AssertionError] in case [Assertion]s are immediately evaluated.
*/
fun appendAssertionsCreatedBy(assertionCreator: Expect<T>.() -> Unit): CollectingExpect<T>
companion object {
@Suppress(
"DEPRECATION",

View File

@@ -25,8 +25,8 @@ annotation class ExpectMarker
*
* See https://github.com/robstoll/atrium-roadmap/wiki/Requirements#personas for more information about the personas.
*/
interface ExpectInternal<T> : Expect<T>, AssertionContainer<T>{
//TODO remove with 0.17.0 no longer necessary once it only exist in AssertionContainer
interface ExpectInternal<T> : Expect<T>, AssertionContainer<T> {
//TODO remove with 0.18.0 no longer necessary once it only exist in AssertionContainer
/**
* Either [Some] wrapping the subject of an [Assertion] or [None] in case a previous subject change could not be
* carried out.
@@ -38,8 +38,6 @@ interface ExpectInternal<T> : Expect<T>, AssertionContainer<T>{
/**
* Represents the extension point for [Assertion] functions and sophisticated builders for subjects of type [T].
*
* Note, do not use [SubjectProvider] as this interface is only temporary and will be removed with 0.17.0.
*
* @param T The type of the subject of `this` expectation.
*/
@Suppress("DEPRECATION")
@@ -47,7 +45,7 @@ interface ExpectInternal<T> : Expect<T>, AssertionContainer<T>{
interface Expect<T> : @kotlin.Suppress("DEPRECATION") SubjectProvider<T> {
@Deprecated(
"use _logic.maybeSubject will be removed with 0.17.0",
"use _logic.maybeSubject; will be removed with 0.18.0",
ReplaceWith("this._logic.maybeSubject", "ch.tutteli.atrium.logic._logic")
)
override val maybeSubject: Option<T>
@@ -64,7 +62,10 @@ interface Expect<T> : @kotlin.Suppress("DEPRECATION") SubjectProvider<T> {
*
* @return an [Expect] for the subject of `this` expectation.
*/
//TODO 0.17.0 move to ProofContainer and deprecate
@Deprecated(
"use _logic.appendAssertionsCreatedBy; will be removed with 0.18.0",
ReplaceWith("this._logic.appendAssertionsCreatedBy(assertionCreator)", "ch.tutteli.atrium.logic._logic")
)
fun addAssertionsCreatedBy(assertionCreator: Expect<T>.() -> Unit): Expect<T>
/**
@@ -74,10 +75,12 @@ interface Expect<T> : @kotlin.Suppress("DEPRECATION") SubjectProvider<T> {
*
* @return an [Expect] for the subject of `this` expectation.
*/
//TODO 0.17.0 move to ProofContainer and deprecate
@Deprecated(
"use _logic.appendAssertion; will be removed with 0.18.0",
ReplaceWith("this._logic.appendAssertion(assertion)", "ch.tutteli.atrium.logic._logic")
)
override fun addAssertion(assertion: Assertion): Expect<T>
/**
* Creates a [DescriptiveAssertion] based on the given [description], [expected] and [test]
* and [adds][addAssertion] it to the container.
@@ -88,7 +91,13 @@ interface Expect<T> : @kotlin.Suppress("DEPRECATION") SubjectProvider<T> {
*
* @return an [Expect] for the subject of `this` expectation.
*/
//TODO 0.17.0 move to ProofContainer and deprecate
@Deprecated(
"use _logic.createAndAppendAssertion; will be removed with 0.18.0",
ReplaceWith(
"this._logic.createAndAppendAssertion(description, expected, test)",
"ch.tutteli.atrium.logic._logic"
)
)
fun createAndAddAssertion(description: String, expected: Any?, test: (T) -> Boolean): Expect<T> =
createAndAddAssertion(Untranslatable(description), expected, test)
@@ -102,7 +111,14 @@ interface Expect<T> : @kotlin.Suppress("DEPRECATION") SubjectProvider<T> {
*
* @return an [Expect] for the subject of `this` expectation.
*/
//TODO 0.17.0 move to ProofContainer and deprecate
@Deprecated(
"use _logic.createAndAppendAssertion; will be removed with 0.18.0",
ReplaceWith(
"this._logic.appendAssertion(this._logic.createDescriptiveAssertion(description, expected, test))",
"ch.tutteli.atrium.logic._logic",
"ch.tutteli.atrium.logic.createDescriptiveAssertion"
)
)
fun createAndAddAssertion(description: Translatable, expected: Any?, test: (T) -> Boolean): Expect<T> =
addAssertion(assertionBuilder.createDescriptive(this, description, expected, test))
}

View File

@@ -5,7 +5,7 @@ import ch.tutteli.atrium.core.None
import ch.tutteli.atrium.core.Option
import ch.tutteli.atrium.core.Some
//TODO remove with 0.17.0
//TODO remove with 0.18.0
/**
* Provides the subject of an [Assertion].
*
@@ -13,7 +13,7 @@ import ch.tutteli.atrium.core.Some
* removed in 0.16.0 and thus this interface will be removed with 0.17.0.
*/
@Suppress("DEPRECATION")
@Deprecated("Will be removed with 0.17.0 without replacement, switch to Expect or AssertionContainer")
@Deprecated("Will be removed with 0.18.0 without replacement, switch to Expect or AssertionContainer")
interface SubjectProvider<out T> {

View File

@@ -18,7 +18,7 @@ abstract class BaseExpectImpl<T>(
) : ExpectInternal<T> {
// TODO 0.17.0 not every expect should have an own implFactories but only the root,
// TODO 0.18.0 not every expect should have an own implFactories but only the root,
// maybe also FeatureExpect but surely not DelegatingExpect or CollectingExpect
private val implFactories: MutableMap<KClass<*>, (() -> Nothing) -> () -> Any> = mutableMapOf()
@@ -36,23 +36,28 @@ abstract class BaseExpectImpl<T>(
implFactories[kClass] = implFactory
}
//TODO 0.17.0 move to RootExpectOptions?
//TODO 0.18.0 move to RootExpectOptions?
inline fun <reified I : Any> withImplFactory(noinline implFactory: (oldFactory: () -> I) -> () -> I) {
registerImpl(I::class, implFactory)
}
override fun addAssertionsCreatedBy(assertionCreator: Expect<T>.() -> Unit): Expect<T> {
//TODO remove with 0.18.0
override fun addAssertionsCreatedBy(assertionCreator: Expect<T>.() -> Unit): Expect<T> =
appendAssertionsCreatedBy(assertionCreator)
override fun appendAssertionsCreatedBy(assertionCreator: Expect<T>.() -> Unit): Expect<T> {
val assertions = CollectingExpect(maybeSubject, components)
.addAssertionsCreatedBy(assertionCreator)
.appendAssertionsCreatedBy(assertionCreator)
.getAssertions()
return addAssertions(assertions)
}
protected fun addAssertions(assertions: List<Assertion>): Expect<T> {
return when (assertions.size) {
0 -> this
1 -> addAssertion(assertions.first())
else -> addAssertion(assertionBuilder.invisibleGroup.withAssertions(assertions).build())
1 -> appendAssertion(assertions.first())
else -> appendAssertion(assertionBuilder.invisibleGroup.withAssertions(assertions).build())
}
}

View File

@@ -16,10 +16,15 @@ internal class CollectingExpectImpl<T>(
override fun getAssertions(): List<Assertion> = assertions.toList()
override fun addAssertion(assertion: Assertion): Expect<T> =
override fun addAssertion(assertion: Assertion): Expect<T> = appendAssertion(assertion)
override fun appendAssertion(assertion: Assertion): Expect<T> =
apply { assertions.add(assertion) }
override fun addAssertionsCreatedBy(assertionCreator: Expect<T>.() -> Unit): CollectingExpect<T> {
override fun addAssertionsCreatedBy(assertionCreator: Expect<T>.() -> Unit): CollectingExpect<T> =
appendAssertionsCreatedBy(assertionCreator)
override fun appendAssertionsCreatedBy(assertionCreator: Expect<T>.() -> Unit): CollectingExpect<T> {
// in case we run into performance problems, the code below is certainly not ideal
val allAssertions = mutableListOf<Assertion>()
allAssertions.addAll(getAssertions())
@@ -51,7 +56,8 @@ internal class CollectingExpectImpl<T>(
.build()
)
}
allAssertions.forEach { addAssertion(it) }
allAssertions.forEach { appendAssertion(it) }
return this
}
}

View File

@@ -14,5 +14,8 @@ internal class DelegatingExpectImpl<T>(private val container: AssertionContainer
get() = container.components
override fun addAssertion(assertion: Assertion): Expect<T> =
appendAssertion(assertion)
override fun appendAssertion(assertion: Assertion): Expect<T> =
apply { container.addAssertion(assertion) }
}

View File

@@ -57,7 +57,10 @@ internal class FeatureExpectImpl<T, R>(
get() = (previousExpect as AssertionContainer<*>).components
override fun addAssertion(assertion: Assertion): Expect<R> {
override fun addAssertion(assertion: Assertion): Expect<R> =
appendAssertion(assertion)
override fun appendAssertion(assertion: Assertion): Expect<R> {
assertions.add(assertion)
//Would be nice if we don't have to add it immediately to the previousExpect but only:
//if (!assertion.holds()) {
@@ -73,7 +76,7 @@ internal class FeatureExpectImpl<T, R>(
//
//However, for this to work we would need to know when no more assertion is defined. This would be possible
//for CollectingExpectImpl
previousExpect.addAssertion(
(previousExpect as AssertionContainer<*>).appendAssertion(
assertionBuilder.feature
.withDescriptionAndRepresentation(description, representation)
.withAssertions(ArrayList(assertions))

View File

@@ -54,7 +54,10 @@ internal class RootExpectImpl<T>(
*/
private val assertions: MutableList<Assertion> = mutableListOf()
override fun addAssertion(assertion: Assertion): Expect<T> {
override fun addAssertion(assertion: Assertion): Expect<T> =
appendAssertion(assertion)
override fun appendAssertion(assertion: Assertion): Expect<T> {
assertions.add(assertion)
if (!assertion.holds()) {
val assertionGroup = assertionBuilder.root
@@ -71,4 +74,5 @@ internal class RootExpectImpl<T>(
return this
}
}

View File

@@ -3,6 +3,7 @@ package ch.tutteli.atrium.assertions.builders
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.core.falseProvider
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.logic._logic
import ch.tutteli.atrium.logic.utils.expectLambda
import ch.tutteli.atrium.specs.SubjectLessSpec
import org.spekframework.spek2.Spek
@@ -10,7 +11,7 @@ import org.spekframework.spek2.Spek
class DescriptiveWithBasedOnSubjectSpec : Spek({
fun addDescriptive(f: (Expect<Int>, Descriptive.HoldsOption) -> Assertion) = expectLambda<Int> {
addAssertion(f(this, assertionBuilder.descriptive))
_logic.appendAssertion(f(this, assertionBuilder.descriptive))
}
include(object : SubjectLessSpec<Int>("",

View File

@@ -33,13 +33,13 @@ class BulletPointProviderSpec : Spek({
expectWitNewBulletPoint(p, "a") toBe "b"
}),
ListAssertionGroupType::class to ("- " to { p ->
expectWitNewBulletPoint(p, "a").addAssertionsCreatedBy {
addAssertion(
expectWitNewBulletPoint(p, "a")._logic.appendAssertionsCreatedBy(fun Expect<String>.() {
_logic.appendAssertion(
assertionBuilder.list
.withDescriptionAndEmptyRepresentation("hello")
.withAssertion(_logic.toBe("b")).build()
)
}
})
}),
FeatureAssertionGroupType::class to (">> " to { p ->
expectWitNewBulletPoint(p, "a") feature { f("m", it.length) } toBe 2
@@ -54,37 +54,37 @@ class BulletPointProviderSpec : Spek({
expectWitNewBulletPoint(p, listOf(1)) containsExactly 2
}),
ExplanatoryAssertionGroupType::class to (">> " to { p ->
expectWitNewBulletPoint(p, "a").addAssertionsCreatedBy {
addAssertion(
expectWitNewBulletPoint(p, "a")._logic.appendAssertionsCreatedBy(fun Expect<String>.() {
_logic.appendAssertion(
assertionBuilder.explanatoryGroup
.withDefaultType
.withAssertion(_logic.toBe("b"))
.failing
.build()
)
}
})
}),
WarningAssertionGroupType::class to ("(!) " to { p ->
expectWitNewBulletPoint(p, "a").addAssertionsCreatedBy {
addAssertion(
expectWitNewBulletPoint(p, "a")._logic.appendAssertionsCreatedBy(fun Expect<String>.() {
_logic.appendAssertion(
assertionBuilder.explanatoryGroup
.withWarningType
.withAssertion(_logic.toBe("b"))
.failing
.build()
)
}
})
}),
InformationAssertionGroupType::class to ("(i) " to { p ->
expectWitNewBulletPoint(p, "a").addAssertionsCreatedBy {
addAssertion(
expectWitNewBulletPoint(p, "a")._logic.appendAssertionsCreatedBy(fun Expect<String>.() {
_logic.appendAssertion(
assertionBuilder.explanatoryGroup
.withInformationType(false)
.withAssertion(_logic.toBe("b"))
.failing
.build()
)
}
})
})
)

View File

@@ -46,7 +46,14 @@ abstract class InOrderOnlyBaseAssertionCreator<E, T : IterableLike, SC>(
{ emptyList() }
)
if (list.size > index) {
addAssertion(createAdditionalElementsAssertion(container, index, list, remainingList.iterator()))
_logic.appendAssertion(
createAdditionalElementsAssertion(
container,
index,
list,
remainingList.iterator()
)
)
}
}
val description = searchBehaviour.decorateDescription(DescriptionIterableAssertion.CONTAINS)
@@ -74,7 +81,7 @@ abstract class InOrderOnlyBaseAssertionCreator<E, T : IterableLike, SC>(
itr: Iterator<E?>
): Assertion {
return container.collectBasedOnSubject(Some(iterableAsList)) {
addAssertion(LazyThreadUnsafeAssertionGroup {
_logic.appendAssertion(LazyThreadUnsafeAssertionGroup {
val additionalEntries = itr.mapRemainingWithCounter { counter, it ->
val description = TranslatableWithArgs(
DescriptionIterableAssertion.ELEMENT_WITH_INDEX,

View File

@@ -37,7 +37,7 @@ abstract class BaseTransformationExecutionStep<T, R, E : Expect<R>>(
* @return an [Expect] for the subject of this expectation.
*/
final override fun collectAndAppend(assertionCreator: Expect<R>.() -> Unit): Expect<T> =
container.toExpect().addAssertion(collect(assertionCreator))
container.appendAssertion(collect(assertionCreator))
/**
* Finishes the transformation process by collecting the assertions the given [assertionCreator] creates

View File

@@ -46,15 +46,14 @@ class DefaultSubjectChanger : SubjectChanger {
.withDescriptionAndRepresentation(description, representation)
.build()
if (shallTransform) {
expect.addAssertion(descriptiveAssertion)
maybeSubAssertions.fold({ /* nothing to do */ }) { assertionCreator ->
expect.addAssertionsCreatedBy(assertionCreator)
return if (shallTransform) {
val e = expect._logic.appendAssertion(descriptiveAssertion)
maybeSubAssertions.fold({ e }) { assertionCreator ->
expect._logic.appendAssertionsCreatedBy(assertionCreator)
}
} else {
val assertion = failureHandler.createAssertion(container, descriptiveAssertion, maybeSubAssertions)
expect.addAssertion(assertion)
expect._logic.appendAssertion(assertion)
}
return expect
}
}

View File

@@ -36,7 +36,7 @@ class DefaultAnyAssertions : AnyAssertions {
} else {
val collectSubject = container.maybeSubject.flatMap { if (it != null) Some(it) else None }
val assertion = container.collectBasedOnSubject(collectSubject) {
addAssertionsCreatedBy(assertionCreatorOrNull)
_logic.appendAssertionsCreatedBy(assertionCreatorOrNull)
}
//TODO 0.17.0 this is a pattern which occurs over and over again, maybe incorporate into collect?
container.maybeSubject.fold(
@@ -74,7 +74,7 @@ class DefaultAnyAssertions : AnyAssertions {
override fun <T> isNotIn(container: AssertionContainer<T>, expected: Iterable<T>): Assertion {
val assertions = expected.map { value ->
assertionBuilder.representationOnly
.withTest(container) { it != value }
.withTest(container.toExpect()) { it != value }
.withRepresentation(value)
.build()
}

View File

@@ -8,6 +8,8 @@ import ch.tutteli.atrium.core.polyfills.formatFloatingPointNumber
import ch.tutteli.atrium.core.polyfills.fullName
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.logic.FloatingPointAssertions
import ch.tutteli.atrium.logic.createDescriptiveAssertion
import ch.tutteli.atrium.logic.toExpect
import ch.tutteli.atrium.reporting.translating.TranslatableWithArgs
import ch.tutteli.atrium.translations.DescriptionFloatingPointAssertion.*
import kotlin.math.absoluteValue
@@ -69,10 +71,11 @@ internal fun <T : Comparable<T>> toBeWithErrorTolerance(
tolerance: T,
absDiff: (T) -> T,
explanatoryAssertionCreator: (T) -> List<Assertion>
): Assertion = assertionBuilder.descriptive
.withTest(container) { absDiff(it) <= tolerance }
.withFailureHintBasedOnDefinedSubject(container) { subject ->
//TODO that's not nice in case we use it in an Iterable contains assertion, for instance contains...entry { toBeWithErrorTolerance(x, 0.01) }
): Assertion =
assertionBuilder.descriptive
.withTest(container.toExpect()) { absDiff(it) <= tolerance }
.withFailureHintBasedOnDefinedSubject(container.toExpect()) { subject ->
//TODO 0.18.0 that's not nice in case we use it in an Iterable contains assertion, for instance contains...entry { toBeWithErrorTolerance(x, 0.01) }
//we do not want to see the failure nor the exact check in the 'an entry which...' part
//same problematic applies to feature assertions within an identification lambda
// => yet explanatory assertion should always hold

View File

@@ -12,7 +12,7 @@ import ch.tutteli.atrium.creating.Expect
* Use [_logic] for more sophisticated scenarios, like feature extraction.
*/
inline fun <T> Expect<T>._logicAppend(assertionCreator: AssertionContainer<T>.() -> Assertion): Expect<T> =
addAssertion(_logic.assertionCreator())
_logic.run { appendAssertion(assertionCreator()) }
/**
* Entry point to the logic level of Atrium -- which is one level deeper than the API --

View File

@@ -40,7 +40,7 @@ inline val <T : CharSequence, S : CharSequenceContains.SearchBehaviour>
inline fun <T : CharSequence, S : CharSequenceContains.SearchBehaviour>
CharSequenceContains.CheckerStep<T, S>._logicAppend(
factory: CharSequenceContains.CheckerStepLogic<T, S>.() -> Assertion
): Expect<T> = _logic.let { l -> l.entryPointStepLogic.container.toExpect().addAssertion(l.factory()) }
): Expect<T> = _logic.let { l -> l.entryPointStepLogic.container.appendAssertion(l.factory()) }
/**
* Entry point to the logic level of Atrium -- which is one level deeper than the API --

View File

@@ -18,7 +18,7 @@ import ch.tutteli.atrium.reporting.BUG_REPORT_URL
inline fun <E, T : Any, S : IterableLikeContains.SearchBehaviour>
IterableLikeContains.EntryPointStep<E, T, S>._logicAppend(
factory: IterableLikeContains.EntryPointStepLogic<E, T, S>.() -> Assertion
): Expect<T> = _logic.let { l -> l.container.toExpect().addAssertion(l.factory()) }
): Expect<T> = _logic.let { l -> l.container.appendAssertion(l.factory()) }
/**
* Entry point to the logic level of Atrium -- which is one level deeper than the API --
@@ -52,7 +52,7 @@ inline val <E, T : Any, S : IterableLikeContains.SearchBehaviour>
inline fun <E, T : Any, S : IterableLikeContains.SearchBehaviour>
IterableLikeContains.CheckerStep<E, T, S>._logicAppend(
factory: IterableLikeContains.CheckerStepLogic<E, T, S>.() -> Assertion
): Expect<T> = _logic.let { l -> l.entryPointStepLogic.container.toExpect().addAssertion(l.factory()) }
): Expect<T> = _logic.let { l -> l.entryPointStepLogic.container.appendAssertion(l.factory()) }
/**
* Entry point to the logic level of Atrium -- which is one level deeper than the API --

View File

@@ -15,7 +15,7 @@ import ch.tutteli.atrium.reporting.BUG_REPORT_URL
inline fun <K, V, T : Any, S : MapLikeContains.SearchBehaviour>
MapLikeContains.EntryPointStep<K, V, T, S>._logicAppend(
factory: MapLikeContains.EntryPointStepLogic<K, V, T, S>.() -> Assertion
): Expect<T> = _logic.let { l -> l.container.toExpect().addAssertion(l.factory()) }
): Expect<T> = _logic.let { l -> l.container.appendAssertion(l.factory()) }
/**
* Entry point to the logic level of Atrium -- which is one level deeper than the API --

View File

@@ -10,7 +10,6 @@ import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.creating.ExpectInternal
import ch.tutteli.atrium.logic.creating.transformers.FeatureExtractorBuilder
import ch.tutteli.atrium.logic.creating.transformers.SubjectChangerBuilder
import ch.tutteli.atrium.logic.creating.transformers.TransformationExecutionStep
import ch.tutteli.atrium.reporting.BUG_REPORT_URL
import ch.tutteli.atrium.reporting.Text
import ch.tutteli.atrium.reporting.translating.Translatable
@@ -25,24 +24,27 @@ import ch.tutteli.atrium.reporting.translating.Translatable
* @param representation The representation of the expected outcome
* @param test The test which checks whether the assertion holds
*/
//TODO deprecate with 0.18.0
fun <T> AssertionContainer<T>.createDescriptiveAssertion(
description: Translatable,
representation: Any?,
test: (T) -> Boolean
): Assertion = assertionBuilder.descriptive
.withTest(this, test)
.withTest(this.toExpect(), test)
.withDescriptionAndRepresentation(description, representation)
.build()
/**
* Entry point to use the [SubjectChangerBuilder] based on this [AssertionContainer].
*/
//TODO deprecate with 0.18.0
val <T> AssertionContainer<T>.changeSubject: SubjectChangerBuilder.KindStep<T>
get() = SubjectChangerBuilder(this)
/**
* Entry point to use the [FeatureExtractorBuilder] based on this [AssertionContainer].
*/
//TODO deprecate with 0.18.0
val <T> AssertionContainer<T>.extractFeature: FeatureExtractorBuilder.DescriptionStep<T>
get() = FeatureExtractorBuilder(this)
@@ -52,6 +54,7 @@ val <T> AssertionContainer<T>.extractFeature: FeatureExtractorBuilder.Descriptio
* logic level.
*/
//is not internal as it is used by extensions, however it is not made visible via module-info.java
//TODO deprecate with 0.18.0 and move toProofContainer to core
fun <T> Expect<T>.toAssertionContainer(): AssertionContainer<T> =
when (this) {
is ExpectInternal<T> -> this
@@ -61,6 +64,7 @@ fun <T> Expect<T>.toAssertionContainer(): AssertionContainer<T> =
/**
* Casts this [AssertionContainer] back to an [Expect] so that you can use it in places where an [Expect] is used.
*/
//TODO deprecate with 0.18.0 and move ProofContainer.toExpect to core
fun <T> AssertionContainer<T>.toExpect(): Expect<T> =
when (this) {
is ExpectInternal<T> -> this

View File

@@ -97,6 +97,8 @@ inline fun <T> AssertionContainer<*>.collectForDifferentSubject(
*
* @return The collected assertions.
*/
//TODO check if it makes more sense to stay on the logic level for assertionCreator
//TODO 0.18.0 deprecate and move to ProofContainer
inline fun <T> AssertionContainer<*>.collectBasedOnSubject(
maybeSubject: Option<T>,
noinline assertionCreator: Expect<T>.() -> Unit

View File

@@ -12,6 +12,7 @@ import ch.tutteli.atrium.assertions.builders.withFailureHint
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.logic.BigDecimalAssertions
import ch.tutteli.atrium.logic.createDescriptiveAssertion
import ch.tutteli.atrium.logic.toExpect
import ch.tutteli.atrium.translations.DescriptionBigDecimalAssertion.*
import java.math.BigDecimal
@@ -35,7 +36,7 @@ class DefaultBigDecimalAssertions : BigDecimalAssertions {
nameOfIsNumericallyEqualTo: String
): Assertion =
assertionBuilder.descriptive
.withTest(container) { it == expected }
.withTest(container.toExpect()) { it == expected }
.withFailureHint {
assertionBuilder.explanatoryGroup
.withInformationType(withIndent = true)
@@ -45,7 +46,7 @@ class DefaultBigDecimalAssertions : BigDecimalAssertions {
)
.build()
}
.showBasedOnDefinedSubjectOnlyIf(container) {
.showBasedOnDefinedSubjectOnlyIf(container.toExpect()) {
isNumericallyEqualTo(it, expected)
}
.withDescriptionAndRepresentation(IS_EQUAL_INCLUDING_SCALE, expected)

View File

@@ -22,7 +22,6 @@ import ch.tutteli.atrium.reporting.Text
import ch.tutteli.atrium.reporting.translating.Translatable
import ch.tutteli.atrium.reporting.translating.TranslatableWithArgs
import ch.tutteli.atrium.translations.DescriptionBasic
import ch.tutteli.atrium.translations.DescriptionMapLikeAssertion
import ch.tutteli.atrium.translations.DescriptionPathAssertion.*
import ch.tutteli.niok.*
import java.nio.charset.Charset

View File

@@ -39,7 +39,7 @@ abstract class SubjectLessSpec<T>(
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
@UseExperimental(ExperimentalNewExpectTypes::class, ExperimentalComponentFactoryContainer::class)
val container = RootExpectBuilder.forSubject(1.0)
val expect = RootExpectBuilder.forSubject(1.0)
.withVerb("custom assertion verb")
.withOptions {
withComponent(AtriumErrorAdjuster::class) { _ -> NoOpAtriumErrorAdjuster }
@@ -50,7 +50,7 @@ abstract class SubjectLessSpec<T>(
.withDefaultType
.withAssertions(assertions)
.build()
container.addAssertion(explanatoryGroup)
expect._logic.appendAssertion(explanatoryGroup)
}
}
}

View File

@@ -3,6 +3,7 @@ package ch.tutteli.atrium.specs.integration
import ch.tutteli.atrium.api.fluent.en_GB.*
import ch.tutteli.atrium.api.verbs.internal.expect
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.logic._logic
import ch.tutteli.atrium.specs.*
import ch.tutteli.atrium.translations.DescriptionCharSequenceAssertion.CONTAINS_NOT
import org.spekframework.spek2.style.specification.Suite
@@ -165,18 +166,18 @@ abstract class CharSequenceContainsContainsNotExpectationsSpec(
val nameWithArrow = "${featureArrow}name"
it("${contains.name} 'treboR' and 'llotS' - error message contains '$nameWithArrow' exactly once") {
expect {
expect(person).addAssertionsCreatedBy {
expect(person)._logic.appendAssertionsCreatedBy(fun Expect<Person>.() {
feature(Person::name).containsFun("treboR", "llotS")
}
})
}.toThrow<AssertionError> {
message { this.contains.exactly(1).value(nameWithArrow) }
}
}
it("${containsNot.name} 'Robert' and 'Stoll' - error message contains '$nameWithArrow' exactly once") {
expect {
expect(person).addAssertionsCreatedBy {
expect(person)._logic.appendAssertionsCreatedBy(fun Expect<Person>.() {
feature(Person::name).containsNotFun("Robert", "Stoll")
}
})
}.toThrow<AssertionError> {
message { this.contains.exactly(1).value(nameWithArrow) }
}

View File

@@ -4,6 +4,8 @@ import ch.tutteli.atrium.api.fluent.en_GB.*
import ch.tutteli.atrium.api.verbs.internal.expect
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
import ch.tutteli.atrium.creating.ExperimentalComponentFactoryContainer
import ch.tutteli.atrium.logic._logic
import ch.tutteli.atrium.logic.createDescriptiveAssertion
import ch.tutteli.atrium.logic.creating.RootExpectBuilder
import ch.tutteli.atrium.reporting.translating.Locale
import ch.tutteli.atrium.reporting.translating.StringBasedTranslatable
@@ -188,13 +190,14 @@ abstract class TranslatorIntSpec(
describe("translation for $testTranslatable.${TestTranslatable.DATE_KNOWN} (with a date as parameter) is provided for 'fr' and 'it'") {
it("uses the translation form 'fr' but the primary Locale to format the date") {
expect {
assertWithDeCh_Fr(1).createAndAddAssertion(
val assertwithdechFr = assertWithDeCh_Fr(1)
assertwithdechFr._logic.appendAssertion(assertwithdechFr._logic.createDescriptiveAssertion(
TranslatableWithArgs(
TestTranslatable.DATE_KNOWN,
firstOfFeb2017,
firstOfFeb2017
), 1
) { false }
) { false })
}.toThrow<AssertionError> { messageContains("02/01/17 était Mittwoch!!") }
}
}
@@ -202,12 +205,13 @@ abstract class TranslatorIntSpec(
describe("translation for $testTranslatable.${TestTranslatable.DATE_UNKNOWN} (with a date as parameter) is provided for 'it' but not for 'fr'") {
it("uses default translation but the primary Locale to format the date") {
expect {
assertWithDeCh_Fr(1).createAndAddAssertion(
val assertwithdechFr = assertWithDeCh_Fr(1)
assertwithdechFr._logic.appendAssertion(assertwithdechFr._logic.createDescriptiveAssertion(
TranslatableWithArgs(
TestTranslatable.DATE_UNKNOWN,
firstOfFeb2017
), 1
) { false }
) { false })
}.toThrow<AssertionError> { messageContains("only Mittwoch") }
}
}
@@ -221,12 +225,13 @@ abstract class TranslatorIntSpec(
+ "and the translation from 'ch' for $descriptionAnyAssertion.$toBe"
) {
expect {
assertWithDeCh_Fr(1).createAndAddAssertion(
val assertwithdechFr = assertWithDeCh_Fr(1)
assertwithdechFr._logic.appendAssertion(assertwithdechFr._logic.createDescriptiveAssertion(
TranslatableWithArgs(
TestTranslatable.PLACEHOLDER,
toBe
), 1
) { false }
) { false })
}.toThrow<AssertionError> { messageContains("Caractère de remplacement ist") }
}
}
@@ -245,13 +250,14 @@ abstract class TranslatorIntSpec(
describe("translation for $testTranslatable.${TestTranslatable.DATE_KNOWN} (with a date as parameter) is provided for 'fr' and 'it'") {
it("uses the translation form 'fr' but the primary Locale to format the date") {
expect {
assertWithDeCh_FrCh_ItCh(1).createAndAddAssertion(
val assertwithdechFrchItch = assertWithDeCh_FrCh_ItCh(1)
assertwithdechFrchItch._logic.appendAssertion(assertwithdechFrchItch._logic.createDescriptiveAssertion(
TranslatableWithArgs(
TestTranslatable.DATE_KNOWN,
firstOfFeb2017,
firstOfFeb2017
), 1
) { false }
) { false })
}.toThrow<AssertionError> { messageContains("02/01/17 était Mittwoch!!") }
}
}
@@ -259,12 +265,13 @@ abstract class TranslatorIntSpec(
describe("translation for $testTranslatable.${TestTranslatable.DATE_UNKNOWN} (with a date as parameter) is provided for 'it' but not for 'fr'") {
it("uses 'it' but the primary Locale to format the date") {
expect {
assertWithDeCh_FrCh_ItCh(1).createAndAddAssertion(
val assertwithdechFrchItch = assertWithDeCh_FrCh_ItCh(1)
assertwithdechFrchItch._logic.appendAssertion(assertwithdechFrchItch._logic.createDescriptiveAssertion(
TranslatableWithArgs(
TestTranslatable.DATE_UNKNOWN,
firstOfFeb2017
), 1
) { false }
) { false })
}.toThrow<AssertionError> { messageContains("solo Mittwoch!!") }
}
}

View File

@@ -6,6 +6,10 @@ import ch.tutteli.atrium.creating.Expect
import org.spekframework.spek2.Spek
import java.util.*
//snippet-own-compose-import-start
import ch.tutteli.atrium.logic._logic
//snippet-own-compose-import-end
/**
* The tests and error message are written here and automatically placed into the README via generation.
* The generation is done during the project built. To trigger it manually, you have to run:
@@ -23,8 +27,10 @@ import java.util.*
object Between2Spec : Spek({
test("code-own-compose-2") {
//snippet-own-compose-import-insert
fun <T : Date> Expect<T>.isBetween(lowerBoundInclusive: T, upperBoundExclusive: T) =
addAssertionsCreatedBy {
_logic.appendAssertionsCreatedBy {
isGreaterThanOrEqual(lowerBoundInclusive)
isLessThan(upperBoundExclusive)
}

View File

@@ -35,15 +35,25 @@ import org.spekframework.spek2.Spek
object I18nSpec : Spek({
test("code-i18n-1") {
fun Expect<Int>.isMultipleOf(base: Int): Expect<Int> =
createAndAddAssertion(DescriptionIntAssertion.IS_MULTIPLE_OF, base) { it % base == 0 }
//snippet-import-logic-insert
fun Expect<Int>.isMultipleOf(base: Int): Expect<Int> = _logic.run {
appendAssertion(
createDescriptiveAssertion(DescriptionIntAssertion.IS_MULTIPLE_OF, base) { it % base == 0 }
)
}
//snippet-DescriptionIntAssertion-insert
}
test("code-i18n-2") {
fun Expect<Int>.isEven(): Expect<Int> =
createAndAddAssertion(DescriptionBasic.IS, DescriptionIntAssertions.EVEN) { it % 2 == 0 }
//snippet-import-logic-insert
fun Expect<Int>.isEven(): Expect<Int> = _logic.run {
appendAssertion(
createDescriptiveAssertion(DescriptionBasic.IS, DescriptionIntAssertions.EVEN) { it % 2 == 0 }
)
}
//snippet-DescriptionIntAssertions-insert
}

View File

@@ -4,6 +4,9 @@ package readme.examples
//snippet-mapArguments-start
import ch.tutteli.atrium.logic.utils.mapArguments
//snippet-mapArguments-end
//snippet-own-boolean-import-start
import ch.tutteli.atrium.logic._logic
//snippet-own-boolean-import-end
//@formatter:on
import ch.tutteli.atrium.api.fluent.en_GB.*
@@ -31,9 +34,11 @@ object OwnExpectationFunctionsSpec : Spek({
//snippet-own-boolean-1-start
fun Expect<Int>.isMultipleOf(base: Int) =
createAndAddAssertion("is multiple of", base) { it % base == 0 }
_logic.createAndAppendAssertion("is multiple of", base) { it % base == 0 }
//snippet-own-boolean-1-end
test("code-own-boolean-1") {
//snippet-own-boolean-import-insert
//snippet-own-boolean-1-insert
}
test("ex-own-boolean-1") {
@@ -42,9 +47,11 @@ object OwnExpectationFunctionsSpec : Spek({
//snippet-own-boolean-2-start
fun Expect<Int>.isEven() =
createAndAddAssertion("is", Text("an even number")) { it % 2 == 0 }
_logic.createAndAppendAssertion("is", Text("an even number")) { it % 2 == 0 }
//snippet-own-boolean-2-end
test("code-own-boolean-2") {
//snippet-own-boolean-import-insert
//snippet-own-boolean-2-insert
}
test("ex-own-boolean-2") {

View File

@@ -5,6 +5,7 @@ import ch.tutteli.atrium.api.fluent.en_GB.withOptions
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.creating.ExperimentalComponentFactoryContainer
import ch.tutteli.atrium.creating.build
import ch.tutteli.atrium.logic._logic
import ch.tutteli.atrium.reporting.text.TextObjectFormatter
import ch.tutteli.atrium.reporting.text.impl.AbstractTextObjectFormatter
import ch.tutteli.atrium.reporting.translating.Translator
@@ -16,7 +17,7 @@ fun <T> expect(t: T): Expect<T> =
}
fun <T> expect(t: T, assertionCreator: Expect<T>.() -> Unit): Expect<T> =
expect(t).addAssertionsCreatedBy(assertionCreator)
expect(t)._logic.appendAssertionsCreatedBy(assertionCreator)
class ReadmeObjectFormatter(translator: Translator) : AbstractTextObjectFormatter(translator) {

View File

@@ -6,6 +6,7 @@ import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.creating.ExperimentalComponentFactoryContainer
import ch.tutteli.atrium.creating.RootExpect
import ch.tutteli.atrium.logic._logic
import ch.tutteli.atrium.logic.creating.RootExpectBuilder
import ch.tutteli.atrium.reporting.AtriumErrorAdjuster
import ch.tutteli.atrium.reporting.erroradjusters.NoOpAtriumErrorAdjuster
@@ -40,7 +41,7 @@ fun <T> expect(subject: T): RootExpect<T> =
* @throws AssertionError in case an assertion does not hold.
*/
fun <T> expect(subject: T, assertionCreator: Expect<T>.() -> Unit): Expect<T> =
expect(subject).addAssertionsCreatedBy(assertionCreator)
expect(subject)._logic.appendAssertionsCreatedBy(assertionCreator)
/**
* Defines the translation used for the assertion verbs used for internal purposes.

View File

@@ -33,7 +33,7 @@ fun <T> assert(subject: T): RootExpect<T> =
* @throws AssertionError in case an assertion does not hold.
*/
fun <T> assert(subject: T, assertionCreator: Expect<T>.() -> Unit): Expect<T> =
assert(subject).addAssertionsCreatedBy(assertionCreator)
assert(subject)._logic.appendAssertionsCreatedBy(assertionCreator)
@Deprecated(
"`assert` should not be nested, use `feature` instead.",

View File

@@ -33,7 +33,7 @@ fun <T> assertThat(subject: T): RootExpect<T> =
* @throws AssertionError in case an assertion does not hold.
*/
fun <T> assertThat(subject: T, assertionCreator: Expect<T>.() -> Unit): Expect<T> =
assertThat(subject).addAssertionsCreatedBy(assertionCreator)
assertThat(subject)._logic.appendAssertionsCreatedBy(assertionCreator)
@Deprecated(
"`assertThat` should not be nested, use `feature` instead.",

View File

@@ -33,7 +33,7 @@ fun <T> expect(subject: T): RootExpect<T> =
* @throws AssertionError in case an assertion does not hold.
*/
fun <T> expect(subject: T, assertionCreator: Expect<T>.() -> Unit): Expect<T> =
expect(subject).addAssertionsCreatedBy(assertionCreator)
expect(subject)._logic.appendAssertionsCreatedBy(assertionCreator)
@Deprecated(
"`expect` should not be nested, use `feature` instead.",