mirror of
https://github.com/jlengrand/atrium.git
synced 2026-03-10 08:01:19 +00:00
add feature assertions to the new infix API
This commit is contained in:
@@ -42,7 +42,8 @@ fun <T, R> Expect<T>.feature(
|
||||
* creates a new [Expect] for it and
|
||||
* returns it so that subsequent calls are based on the feature.
|
||||
*
|
||||
* @return The newly created [Expect] for the return value of calling [f] on the current subject of the assertion.
|
||||
* @return The newly created [Expect] for the return value of calling the method [f]
|
||||
* on the current subject of the assertion.
|
||||
*
|
||||
* @since 0.9.0
|
||||
*/
|
||||
@@ -72,7 +73,8 @@ fun <T, R> Expect<T>.feature(
|
||||
* creates a new [Expect] for it and
|
||||
* returns it so that subsequent calls are based on the feature.
|
||||
*
|
||||
* @return The newly created [Expect] for the return value of calling [f] on the current subject of the assertion.
|
||||
* @return The newly created [Expect] for the return value of calling the method [f]
|
||||
* on the current subject of the assertion.
|
||||
*
|
||||
* @since 0.9.0
|
||||
*/
|
||||
@@ -106,7 +108,8 @@ fun <T, A1, R> Expect<T>.feature(
|
||||
* creates a new [Expect] for it and
|
||||
* returns it so that subsequent calls are based on the feature.
|
||||
*
|
||||
* @return The newly created [Expect] for the return value of calling [f] on the current subject of the assertion.
|
||||
* @return The newly created [Expect] for the return value of calling the method [f]
|
||||
* on the current subject of the assertion.
|
||||
*
|
||||
* @since 0.9.0
|
||||
*/
|
||||
@@ -140,7 +143,8 @@ fun <T, A1, A2, R> Expect<T>.feature(
|
||||
* creates a new [Expect] for it and
|
||||
* returns it so that subsequent calls are based on the feature.
|
||||
*
|
||||
* @return The newly created [Expect] for the return value of calling [f] on the current subject of the assertion.
|
||||
* @return The newly created [Expect] for the return value of calling the method [f]
|
||||
* on the current subject of the assertion.
|
||||
*
|
||||
* @since 0.9.0
|
||||
*/
|
||||
@@ -174,7 +178,8 @@ fun <T, A1, A2, A3, R> Expect<T>.feature(
|
||||
* creates a new [Expect] for it and
|
||||
* returns it so that subsequent calls are based on the feature.
|
||||
*
|
||||
* @return The newly created [Expect] for the return value of calling [f] on the current subject of the assertion.
|
||||
* @return The newly created [Expect] for the return value of calling the method [f]
|
||||
* on the current subject of the assertion.
|
||||
*
|
||||
* @since 0.9.0
|
||||
*/
|
||||
|
||||
@@ -171,10 +171,11 @@ inline infix fun <T> Expect<T>.and(@Suppress("UNUSED_PARAMETER") o: o): Expect<T
|
||||
*
|
||||
* @return An [Expect] for the current subject of the assertion.
|
||||
*/
|
||||
infix fun <T> Expect<T>.and(assertionCreator: Expect<T>.() -> Unit) = addAssertionsCreatedBy(assertionCreator)
|
||||
infix fun <T> Expect<T>.and(assertionCreator: Expect<T>.() -> Unit): Expect<T> =
|
||||
addAssertionsCreatedBy(assertionCreator)
|
||||
|
||||
/**
|
||||
* Inline property referring actually to `this` and allows to write nicer sub-assertions.
|
||||
* Inline property referring actually to `this` and allows to write infix assertions within an assertion group block
|
||||
*
|
||||
* For instance, instead of:
|
||||
* ```
|
||||
|
||||
@@ -23,7 +23,7 @@ interface ListGetStep<E, T : List<E>> {
|
||||
|
||||
/**
|
||||
* Makes the assertion that the given [index] is within the bounds of [Expect.subject] and that
|
||||
* the corresponding entry holds all assertions the given [assertionCreator] might create for it.
|
||||
* the corresponding entry holds all assertions the given [assertionCreator] creates for it.
|
||||
*
|
||||
* @return An [Expect] for the current subject of the assertion.
|
||||
* @throws AssertionError Might throw an [AssertionError] if a created [Expect]s (by calling [assertionCreator])
|
||||
|
||||
@@ -4,11 +4,11 @@ import ch.tutteli.atrium.api.infix.en_GB.creating.list.get.builders.ListGetStep
|
||||
import ch.tutteli.atrium.creating.Expect
|
||||
import ch.tutteli.atrium.domain.builders.ExpectImpl
|
||||
|
||||
internal class ListGetStepImpl<E, T: List<E>>(
|
||||
internal class ListGetStepImpl<E, T : List<E>>(
|
||||
override val expect: Expect<T>,
|
||||
override val index: Int
|
||||
) : ListGetStep<E, T> {
|
||||
|
||||
override infix fun assertIt(assertionCreator: Expect<E>.() -> Unit): Expect<T>
|
||||
= expect.addAssertion(ExpectImpl.list.get(expect, index).collect(assertionCreator))
|
||||
override infix fun assertIt(assertionCreator: Expect<E>.() -> Unit): Expect<T> =
|
||||
ExpectImpl.list.get(expect, index).addToInitial(assertionCreator)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
package ch.tutteli.atrium.api.infix.en_GB
|
||||
|
||||
import ch.tutteli.atrium.assertions.AssertionGroup
|
||||
import ch.tutteli.atrium.creating.Expect
|
||||
import ch.tutteli.atrium.creating.FeatureExpect
|
||||
import ch.tutteli.atrium.domain.builders.ExpectImpl
|
||||
import ch.tutteli.atrium.domain.builders.creating.MetaFeatureOption
|
||||
import ch.tutteli.atrium.domain.creating.MetaFeature
|
||||
import kotlin.reflect.*
|
||||
|
||||
/**
|
||||
* Extracts the [property] out of the current subject of the assertion,
|
||||
* creates a new [Expect] for it and
|
||||
* returns it so that subsequent calls are based on the feature.
|
||||
*
|
||||
* @return The newly created [Expect] for the given [property].
|
||||
*
|
||||
* @since 0.10.0
|
||||
*/
|
||||
infix fun <T, R> Expect<T>.feature(property: KProperty1<T, R>): FeatureExpect<T, R> =
|
||||
ExpectImpl.feature.property(this, property).getExpectOfFeature()
|
||||
|
||||
/**
|
||||
* Extracts the value which is returned when calling the method [f] on the current subject of the assertion,
|
||||
* creates a new [Expect] for it and
|
||||
* returns it so that subsequent calls are based on the feature.
|
||||
*
|
||||
* Use `feature of(...)` in case the method requires parameters or in case you want to define
|
||||
* an assertion group block for it.
|
||||
*
|
||||
* @return The newly created [Expect] for the return value of calling the method [f]
|
||||
* on the current subject of the assertion.
|
||||
*
|
||||
* @since 0.10.0
|
||||
*/
|
||||
infix fun <T, R> Expect<T>.feature(f: KFunction1<T, R>): FeatureExpect<T, R> =
|
||||
ExpectImpl.feature.f0(this, f).getExpectOfFeature()
|
||||
|
||||
/**
|
||||
* Extracts a feature out of the current subject of the assertion using the given [Feature.extractor],
|
||||
* creates a new [Expect] for it and
|
||||
* returns it so that subsequent calls are based on the feature.
|
||||
*
|
||||
* Use `of(K..., ...)` to create this representation where the first argument is the extractor in form of a
|
||||
* [KProperty1] or a `KFunctionX` and potentially the required arguments for a `KFunctionX` where `X` > 1.
|
||||
*
|
||||
* @return The newly created [Expect] for the extracted feature.
|
||||
*
|
||||
* @since 0.10.0
|
||||
*/
|
||||
infix fun <T, R> Expect<T>.feature(of: Feature<T, R>): FeatureExpect<T, R> =
|
||||
ExpectImpl.feature.manualFeature(this, of.description, of.extractor).getExpectOfFeature()
|
||||
|
||||
/**
|
||||
* Extracts a feature out of the current subject of the assertion using the given [FeatureWithCreator.extractor],
|
||||
* creates a new [Expect] for it,
|
||||
* applies an assertion group based on the given [FeatureWithCreator.assertionCreator] for the feature and
|
||||
* returns the initial [Expect] with the current subject.
|
||||
*
|
||||
* Use `of(K..., ...) { ... }` to create this representation where the first argument is the extractor in form of a
|
||||
* [KProperty1] or a `KFunctionX`, the last an `assertionCreator`-lambda and the remaining arguments in-between the
|
||||
* required arguments in case of a `KFunctionX` where `X` > 1.
|
||||
*
|
||||
* @return An [Expect] for the current subject of the assertion.
|
||||
* @throws AssertionError Might throw an [AssertionError] in case the created [AssertionGroup] does not hold.
|
||||
*
|
||||
* @since 0.10.0
|
||||
*/
|
||||
infix fun <T, R> Expect<T>.feature(of: FeatureWithCreator<T, R>): Expect<T> =
|
||||
ExpectImpl.feature.manualFeature(this, of.description, of.extractor).addToInitial(of.assertionCreator)
|
||||
|
||||
|
||||
/**
|
||||
* Extracts a feature out of the current subject of the assertion,
|
||||
* based on the given [provider],
|
||||
* creates a new [Expect] for it and
|
||||
* returns it so that subsequent calls are based on the feature.
|
||||
*
|
||||
* @param provider Creates a [MetaFeature] where the subject of the assertion is available via
|
||||
* implicit parameter `it`. Usually you use [f][MetaFeatureOption.f] to create a [MetaFeature],
|
||||
* e.g. `feature { f(it::size) }`
|
||||
*
|
||||
* @return The newly created [Expect] for the extracted feature.
|
||||
*
|
||||
* @since 0.10.0
|
||||
*/
|
||||
infix fun <T, R> Expect<T>.feature(provider: MetaFeatureOption<T>.(T) -> MetaFeature<R>): FeatureExpect<T, R> =
|
||||
ExpectImpl.feature.genericSubjectBasedFeature(this) { MetaFeatureOption(this).provider(it) }.getExpectOfFeature()
|
||||
|
||||
/**
|
||||
* Extracts a feature out of the current subject of the assertion,
|
||||
* based on the given [MetaFeatureOptionWithCreator]
|
||||
* creates a new [Expect] for it,
|
||||
* applies an assertion group based on the given [MetaFeatureOptionWithCreator.assertionCreator] for the feature and
|
||||
* returns the initial [Expect] with the current subject.
|
||||
*
|
||||
* Note that you need to enable the new type inference of Kotlin (or use Kotlin 1.4 and above) in order that Kotlin
|
||||
* is able to infer the types.
|
||||
* As workaround you can use the overload which expects `MetaFeatureOption<T>.(T) -> MetaFeature<R>`
|
||||
* and use `it` after the call (import from the package workaround). For instance:
|
||||
*
|
||||
* ```
|
||||
* // use
|
||||
* expect(person) feature { f(it::age) } it { o toBe 20 }
|
||||
*
|
||||
* // instead of (which causes problems with Kotlin < 1.4)
|
||||
* expect(person) feature of({ f(it::age) }) { o toBe 20 }
|
||||
* ```
|
||||
*
|
||||
* @param of Use the function `of({ ... }) { ... }` to create the [MetaFeatureOptionWithCreator] where the first
|
||||
* argument is a lambda with a [MetaFeatureOption] as receiver which has to create a [MetaFeature]
|
||||
* where the subject of the assertion is available via implicit parameter `it`.
|
||||
* Usually you use [f][MetaFeatureOption.f] to create a [MetaFeature],
|
||||
* e.g. `feature of({ f(it::size) }) { o toBe 3 }`
|
||||
*
|
||||
* @return An [Expect] for the current subject of the assertion.
|
||||
* @since 0.10.0
|
||||
*/
|
||||
infix fun <T, R> Expect<T>.feature(of: MetaFeatureOptionWithCreator<T, R>): Expect<T> =
|
||||
ExpectImpl.feature.genericSubjectBasedFeature(this) {
|
||||
MetaFeatureOption(this).(of.provider)(it)
|
||||
}.addToInitial(of.assertionCreator)
|
||||
|
||||
/**
|
||||
* Creates a [MetaFeature] using the given [provider] and [description].
|
||||
*
|
||||
* This can be used to create complex features with a custom description or as workaround where Kotlin is not able to
|
||||
* infer the types properly.
|
||||
*
|
||||
* For instance:
|
||||
* ```
|
||||
* expect(person) feature { f("first underage child", it.children.first { it < 18 }) }
|
||||
* ```
|
||||
*
|
||||
* @return The newly created [MetaFeature].
|
||||
*/
|
||||
@Suppress("unused" /* unused receiver, but that's fine */)
|
||||
fun <T, R> MetaFeatureOption<T>.f(description: String, provider: R): MetaFeature<R> =
|
||||
MetaFeature(description, provider)
|
||||
|
||||
/**
|
||||
* Parameter object which contains a [description] of a feature along with an [extractor]
|
||||
* which actually extracts the feature out of a subject of an assertion.
|
||||
*
|
||||
* Use `of(K..., ...) { ... }` to create this representation where the first argument is the extractor in form of a
|
||||
* [KProperty1] or a `KFunctionX` and the remaining arguments are the required arguments in case of a `KFunctionX`
|
||||
* where `X` > 1.
|
||||
*
|
||||
* @property description The description of the feature.
|
||||
* @property extractor The extractor which extracts the feature out of the subject of the assertion.
|
||||
|
||||
* @since 0.10.0
|
||||
*/
|
||||
data class Feature<T, R>(val description: String, val extractor: (T) -> R)
|
||||
|
||||
/**
|
||||
* Parameter object which contains a [description] of a feature along with an [extractor]
|
||||
* which actually extracts the feature out of a subject of an assertion + an [assertionCreator]
|
||||
* which defines assertions for the feature.
|
||||
*
|
||||
* Use `of(K..., ...) { ... }` to create this representation where the first argument is the extractor in form of a
|
||||
* [KProperty1] or a `KFunctionX`, the last an [assertionCreator]-lambda and the remaining arguments in-between the
|
||||
* required arguments in case of a `KFunctionX` where `X` > 1.
|
||||
*
|
||||
* @property description The description of the feature.
|
||||
* @property extractor The extractor which extracts the feature out of the subject of the assertion.
|
||||
* @property assertionCreator The `assertionCreator`-lambda which defines assertions for the feature.
|
||||
*
|
||||
* @since 0.10.0
|
||||
*/
|
||||
data class FeatureWithCreator<T, R>(
|
||||
val description: String,
|
||||
val extractor: (T) -> R,
|
||||
val assertionCreator: Expect<R>.() -> Unit
|
||||
)
|
||||
|
||||
|
||||
//@formatter:off
|
||||
/**
|
||||
* Helper function to create a [Feature] based on a [KFunction2] + arguments.
|
||||
*/
|
||||
fun <T, A1, R> of(f: KFunction2<T, A1, R>, a1: A1): Feature<T, R> =
|
||||
Feature(f.name) { f.invoke(it, a1) }
|
||||
|
||||
/**
|
||||
* Helper function to create a [Feature] based on a [KFunction3] + arguments.
|
||||
*/
|
||||
fun <T, A1, A2, R > of(f: KFunction3<T, A1, A2, R>, a1: A1, a2: A2): Feature<T, R> =
|
||||
Feature(f.name) { f.invoke(it, a1, a2) }
|
||||
|
||||
/**
|
||||
* Helper function to create a [Feature] based on a [KFunction4] + arguments.
|
||||
*/
|
||||
fun <T, A1, A2, A3, R> of(f: KFunction4<T, A1, A2, A3, R>, a1: A1, a2: A2, a3: A3): Feature<T, R> =
|
||||
Feature(f.name) { f.invoke(it, a1, a2, a3) }
|
||||
|
||||
/**
|
||||
* Helper function to create a [Feature] based on a [KFunction5] + arguments.
|
||||
*/
|
||||
fun <T, A1, A2, A3, A4, R> of(f: KFunction5<T, A1, A2, A3, A4, R>, a1: A1, a2: A2, a3: A3, a4: A4): Feature<T, R> =
|
||||
Feature(f.name) { f.invoke(it, a1, a2, a3, a4) }
|
||||
|
||||
/**
|
||||
* Helper function to create a [Feature] based on a [KFunction5] + arguments.
|
||||
*/
|
||||
fun <T, A1, A2, A3, A4, A5, R> of(f: KFunction6<T, A1, A2, A3, A4, A5, R>, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5): Feature<T, R> =
|
||||
Feature(f.name) { f.invoke(it, a1, a2, a3, a4, a5) }
|
||||
|
||||
/**
|
||||
* Helper function to create a [FeatureWithCreator] based on a [KProperty1] + [assertionCreator].
|
||||
*/
|
||||
fun <T, R> of(property: KProperty1<T, R>, assertionCreator: Expect<R>.() -> Unit): FeatureWithCreator<T, R> =
|
||||
FeatureWithCreator(property.name, { property.invoke(it) }, assertionCreator)
|
||||
|
||||
/**
|
||||
* Helper function to create a [FeatureWithCreator] based on a [KFunction1] + [assertionCreator].
|
||||
*/
|
||||
fun <T, R> of(f: KFunction1<T, R>, assertionCreator: Expect<R>.() -> Unit): FeatureWithCreator<T, R> =
|
||||
FeatureWithCreator(f.name, { f.invoke(it) }, assertionCreator)
|
||||
|
||||
/**
|
||||
* Helper function to create a [FeatureWithCreator] based on a [KFunction2] + arguments + [assertionCreator].
|
||||
*/
|
||||
fun <T, A1, R> of(f: KFunction2<T, A1, R>, a1: A1, assertionCreator: Expect<R>.() -> Unit): FeatureWithCreator<T, R> =
|
||||
FeatureWithCreator(f.name, { f.invoke(it, a1) }, assertionCreator)
|
||||
|
||||
/**
|
||||
* Helper function to create a [FeatureWithCreator] based on a [KFunction3] + arguments + [assertionCreator].
|
||||
*/
|
||||
fun <T, A1, A2, R > of(f: KFunction3<T, A1, A2, R>, a1: A1, a2: A2, assertionCreator: Expect<R>.() -> Unit): FeatureWithCreator<T, R> =
|
||||
FeatureWithCreator(f.name, { f.invoke(it, a1, a2) }, assertionCreator)
|
||||
|
||||
/**
|
||||
* Helper function to create a [FeatureWithCreator] based on a [KFunction4] + arguments + [assertionCreator].
|
||||
*/
|
||||
fun <T, A1, A2, A3, R> of(f: KFunction4<T, A1, A2, A3, R>, a1: A1, a2: A2, a3: A3, assertionCreator: Expect<R>.() -> Unit): FeatureWithCreator<T, R> =
|
||||
FeatureWithCreator(f.name, { f.invoke(it, a1, a2, a3) }, assertionCreator)
|
||||
|
||||
/**
|
||||
* Helper function to create a [FeatureWithCreator] based on a [KFunction5] + arguments + [assertionCreator].
|
||||
*/
|
||||
fun <T, A1, A2, A3, A4, R> of(f: KFunction5<T, A1, A2, A3, A4, R>, a1: A1, a2: A2, a3: A3, a4: A4, assertionCreator: Expect<R>.() -> Unit): FeatureWithCreator<T, R> =
|
||||
FeatureWithCreator(f.name, { f.invoke(it, a1, a2, a3, a4) }, assertionCreator)
|
||||
//@formatter:on
|
||||
|
||||
|
||||
/**
|
||||
* Parameter object which combines a lambda with a [MetaFeatureOption] receiver (called [provider])
|
||||
* and an [assertionCreator].
|
||||
*
|
||||
* Use the function `of({ ... }) { ... }` to create this representation where the first
|
||||
* argument is a lambda with a [MetaFeatureOption] as receiver which has to create a [MetaFeature]
|
||||
* where the subject of the assertion is available via implicit parameter `it`.
|
||||
* Usually you use [f][MetaFeatureOption.f] to create a [MetaFeature],
|
||||
* e.g. `feature of({ f(it::size) }) { o toBe 3 }`
|
||||
*
|
||||
* @since 0.10.0
|
||||
*/
|
||||
data class MetaFeatureOptionWithCreator<T, R>(
|
||||
val provider: MetaFeatureOption<T>.(T) -> MetaFeature<R>,
|
||||
val assertionCreator: Expect<R>.() -> Unit
|
||||
)
|
||||
|
||||
/**
|
||||
* Helper function to create a [MetaFeatureOptionWithCreator] based on a lambda with
|
||||
* [MetaFeatureOption] receiver (has to return a [MetaFeature]) and an [assertionCreator].
|
||||
*/
|
||||
fun <T, R> of(
|
||||
provider: MetaFeatureOption<T>.(T) -> MetaFeature<R>,
|
||||
assertionCreator: Expect<R>.() -> Unit
|
||||
): MetaFeatureOptionWithCreator<T, R> = MetaFeatureOptionWithCreator(provider, assertionCreator)
|
||||
@@ -27,40 +27,48 @@ object Blank : Keyword
|
||||
|
||||
/**
|
||||
* Represents the pseudo keyword `contain` as in [to] `contain`.
|
||||
* It can be used for a parameter less function so that it has one parameter and thus can be used as infix function.
|
||||
*/
|
||||
object contain : Keyword
|
||||
|
||||
/**
|
||||
* Represents the pseudo keyword `case` as in [ignoring] `case`.
|
||||
* It can be used for a parameter less function so that it has one parameter and thus can be used as infix function.
|
||||
*/
|
||||
object case : Keyword
|
||||
|
||||
/**
|
||||
* Represents the pseudo keyword `entries` as in [grouped] `entries`.
|
||||
* It can be used for a parameter less function so that it has one parameter and thus can be used as infix function.
|
||||
*/
|
||||
object entries : Keyword
|
||||
|
||||
/**
|
||||
* Represents the pseudo keyword `group` as in [within] `group`.
|
||||
* It can be used for a parameter less function so that it has one parameter and thus can be used as infix function.
|
||||
*/
|
||||
object group : Keyword
|
||||
|
||||
/**
|
||||
* Represents a filler, a pseudo keyword where there isn't really a good keyword.
|
||||
* A reader should skip this filler without reading it. For instance, `contains o atleast 1...` should be read as
|
||||
* A reader should skip this filler without reading it. For instance, `contains o atLeast 1...` should be read as
|
||||
* `contains at least once...`
|
||||
*
|
||||
* It can be used for a parameter less function so that it has one parameter and thus can be used as infix function.
|
||||
*
|
||||
* @since 0.10.0
|
||||
*/
|
||||
object o : Keyword
|
||||
|
||||
/**
|
||||
* Represents the pseudo keyword `only` as in [and] `only`.
|
||||
* It can be used for a parameter less function so that it has one parameter and thus can be used as infix function.
|
||||
*/
|
||||
object only : Keyword
|
||||
|
||||
/**
|
||||
* Represents the pseudo keyword `order` as in [inAny] `order`.
|
||||
* It can be used for a parameter less function so that it has one parameter and thus can be used as infix function.
|
||||
*/
|
||||
object order : Keyword
|
||||
|
||||
|
||||
@@ -3,32 +3,34 @@ package ch.tutteli.atrium.api.infix.en_GB
|
||||
import ch.tutteli.atrium.creating.Expect
|
||||
import ch.tutteli.atrium.domain.builders.utils.VarArgHelper
|
||||
|
||||
/**
|
||||
* Parameter object to express `T, vararg T`.
|
||||
*/
|
||||
class All<out T>(override val expected: T, override vararg val otherExpected: T) : VarArgHelper<T>
|
||||
|
||||
/**
|
||||
* Wrapper for a single index -- can be used as distinguishable type for an overload where Int is already in use.
|
||||
*/
|
||||
data class Index(val index: Int)
|
||||
|
||||
data class Key<out K>(val key: K)
|
||||
/**
|
||||
* Parameter object to express `T, vararg T` in the infix-api.
|
||||
*/
|
||||
class All<out T>(override val expected: T, override vararg val otherExpected: T) : VarArgHelper<T>
|
||||
|
||||
/**
|
||||
* Parameter object to express `Pair<K, V>, vararg Pair<K, V>` in the infix-api.
|
||||
*/
|
||||
class Pairs<out K, out V>(
|
||||
override val expected: Pair<K, V>,
|
||||
override vararg val otherExpected: Pair<K, V>
|
||||
) : VarArgHelper<Pair<K, V>>
|
||||
|
||||
|
||||
/**
|
||||
* Parameter object to express a key/value [Pair] whose value type is a lambda with an
|
||||
* [Assert][AssertionPlant] receiver, which means one can either pass a lambda or `null`.
|
||||
* [Expect] receiver, which means one can either pass a lambda or `null`.
|
||||
*/
|
||||
data class KeyValue<out K, V : Any>(val key: K, val valueAssertionCreatorOrNull: (Expect<V>.() -> Unit)?) {
|
||||
fun toPair(): Pair<K, (Expect<V>.() -> Unit)?> = key to valueAssertionCreatorOrNull
|
||||
override fun toString(): String =
|
||||
"KeyValue(key=$key, value=${if (valueAssertionCreatorOrNull == null) "null" else "lambda"})"
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Parameter object to express `Pair<K, V>, vararg Pair<K, V>`.
|
||||
*/
|
||||
class Pairs<out K, out V>(
|
||||
override val expected: Pair<K, V>,
|
||||
override vararg val otherExpected: Pair<K, V>
|
||||
) : VarArgHelper<Pair<K, V>>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
package ch.tutteli.atrium.api.infix.en_GB
|
||||
|
||||
import ch.tutteli.atrium.creating.Expect
|
||||
import ch.tutteli.atrium.domain.builders.ExpectImpl.changeSubject
|
||||
|
||||
@@ -9,8 +11,8 @@ import ch.tutteli.atrium.domain.builders.ExpectImpl.changeSubject
|
||||
*
|
||||
* @return The newly created [Expect] for the transformed subject.
|
||||
*/
|
||||
fun <E, T : Sequence<E>> Expect<T>.asIterable(): Expect<Iterable<E>>
|
||||
= changeSubject(this).unreported { it.asIterable() }
|
||||
fun <E, T : Sequence<E>> Expect<T>.asIterable(): Expect<Iterable<E>> =
|
||||
changeSubject(this).unreported { it.asIterable() }
|
||||
|
||||
/**
|
||||
* Expects that the subject of the assertion holds all assertions the given [assertionCreator] creates for
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package ch.tutteli.atrium.api.infix.en_GB.workaround
|
||||
|
||||
import ch.tutteli.atrium.api.infix.en_GB.and
|
||||
import ch.tutteli.atrium.creating.Expect
|
||||
|
||||
/**
|
||||
* Can be used to create a group of sub assertions when using the fluent API.
|
||||
*
|
||||
* Intended to be used in combination with feature assertions where Kotlin < 1.4 is not able to infer the correct type.
|
||||
* For instance:
|
||||
* ```
|
||||
* // use
|
||||
* expect(person) feature { f(it::age) } it { o toBe 20 }
|
||||
*
|
||||
* // instead of (which causes problems with Kotlin < 1.4)
|
||||
* expect(person) feature of({ f(it::age) }) { o toBe 20 }
|
||||
* ```
|
||||
*
|
||||
* Note that this workaround will be removed in some minor version after a major version with Kotlin 1.4 support
|
||||
* (most likely with Atrium v1.1.0 where Atrium v1.0.0 requires Kotlin 1.4)
|
||||
*
|
||||
* @return An [Expect] for the current subject of the assertion.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE" /* inline so that one does not actually call `it` on binary level */)
|
||||
inline infix fun <T> Expect<T>.it(noinline assertionCreator: Expect<T>.() -> Unit): Expect<T> = and(assertionCreator)
|
||||
@@ -80,23 +80,16 @@ object NewFeatureAssertionsBuilder : NewFeatureAssertions {
|
||||
description: Translatable,
|
||||
provider: T.() -> R
|
||||
): ExtractedFeaturePostStep<T, R> =
|
||||
genericFeature(expect, createMetaFeature(expect, description, provider))
|
||||
genericFeature(expect, ExpectImpl.feature.meta.create(expect, description, provider))
|
||||
|
||||
fun <T, R> genericSubjectBasedFeature(
|
||||
expect: Expect<T>,
|
||||
provider: (T) -> MetaFeature<R>
|
||||
): ExtractedFeaturePostStep<T, R> = ExpectImpl.feature.genericFeature(
|
||||
expect,
|
||||
expect.maybeSubject.fold(this::createFeatureSubjectNotDefined) { provider(it) }
|
||||
ExpectImpl.feature.meta.createSubjectBased(expect, provider)
|
||||
)
|
||||
|
||||
private fun <R> createFeatureSubjectNotDefined(): MetaFeature<R> =
|
||||
MetaFeature(
|
||||
ErrorMessages.DEDSCRIPTION_BASED_ON_SUBJECT,
|
||||
RawString.create(ErrorMessages.REPRESENTATION_BASED_ON_SUBJECT_NOT_DEFINED),
|
||||
None
|
||||
)
|
||||
|
||||
override inline fun <T, R> genericFeature(
|
||||
expect: Expect<T>,
|
||||
metaFeature: MetaFeature<R>
|
||||
@@ -107,30 +100,7 @@ object NewFeatureAssertionsBuilder : NewFeatureAssertions {
|
||||
description: String,
|
||||
provider: (T) -> R
|
||||
): ExtractedFeaturePostStep<T, R> =
|
||||
genericFeature(expect, createMetaFeature(expect, description, provider))
|
||||
|
||||
private fun <T, R> createMetaFeature(
|
||||
expect: Expect<T>,
|
||||
description: String,
|
||||
provider: (T) -> R
|
||||
): MetaFeature<R> = createMetaFeature(expect, Untranslatable(description), provider)
|
||||
|
||||
private fun <T, R> createMetaFeature(
|
||||
expect: Expect<T>,
|
||||
description: Translatable,
|
||||
provider: (T) -> R
|
||||
): MetaFeature<R> {
|
||||
return expect.maybeSubject.fold({
|
||||
MetaFeature(
|
||||
description,
|
||||
RawString.create(ErrorMessages.REPRESENTATION_BASED_ON_SUBJECT_NOT_DEFINED),
|
||||
None
|
||||
)
|
||||
}) {
|
||||
val prop = provider(it)
|
||||
MetaFeature(description, prop, Some(prop))
|
||||
}
|
||||
}
|
||||
genericFeature(expect, ExpectImpl.feature.meta.create(expect, description, provider))
|
||||
|
||||
/**
|
||||
* Returns [MetaFeatureBuilder] which helps to create a [MetaFeature].
|
||||
@@ -143,6 +113,7 @@ object NewFeatureAssertionsBuilder : NewFeatureAssertions {
|
||||
* into an overload ambiguity, then either [p] (for property) or one of the `fN` functions (e.g. [f2] for
|
||||
* a function which expects 2 arguments).
|
||||
*/
|
||||
//TODO move to API, this could potentially be different per API
|
||||
class MetaFeatureOption<T>(private val expect: Expect<T>) {
|
||||
|
||||
/**
|
||||
@@ -338,4 +309,43 @@ object MetaFeatureBuilder {
|
||||
fun <A1, A2, A3, A4, A5, R> f5(expect: Expect<*>, f: KFunction5<A1, A2, A3, A4, A5, R>, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5) =
|
||||
MetaFeature(coreFactory.newMethodCallFormatter().formatCall(f.name, arrayOf(a1, a2, a3, a4, a5)), f.invoke(a1, a2, a3, a4, a5))
|
||||
//@formatter:on
|
||||
|
||||
/**
|
||||
* creates a [MetaFeature] which is entirely based on the subject (i.e. also the description).
|
||||
*/
|
||||
fun <T, R> createSubjectBased(
|
||||
expect: Expect<T>,
|
||||
provider: (T) -> MetaFeature<R>
|
||||
): MetaFeature<R> = expect.maybeSubject.fold(this::createFeatureSubjectNotDefined) { provider(it) }
|
||||
|
||||
private fun <R> createFeatureSubjectNotDefined(): MetaFeature<R> =
|
||||
MetaFeature(
|
||||
ErrorMessages.DEDSCRIPTION_BASED_ON_SUBJECT,
|
||||
RawString.create(ErrorMessages.REPRESENTATION_BASED_ON_SUBJECT_NOT_DEFINED),
|
||||
None
|
||||
)
|
||||
|
||||
fun <T, R> create(
|
||||
expect: Expect<T>,
|
||||
description: String,
|
||||
provider: (T) -> R
|
||||
): MetaFeature<R> = create(expect, Untranslatable(description), provider)
|
||||
|
||||
fun <T, R> create(
|
||||
expect: Expect<T>,
|
||||
description: Translatable,
|
||||
provider: (T) -> R
|
||||
): MetaFeature<R> {
|
||||
return expect.maybeSubject.fold({
|
||||
MetaFeature(
|
||||
description,
|
||||
RawString.create(ErrorMessages.REPRESENTATION_BASED_ON_SUBJECT_NOT_DEFINED),
|
||||
None
|
||||
)
|
||||
}) {
|
||||
val feature = provider(it)
|
||||
MetaFeature(description, feature, Some(feature))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import ch.tutteli.atrium.core.None
|
||||
import ch.tutteli.atrium.core.Option
|
||||
import ch.tutteli.atrium.core.Some
|
||||
import ch.tutteli.atrium.creating.Expect
|
||||
import ch.tutteli.atrium.creating.FeatureExpect
|
||||
import ch.tutteli.atrium.domain.builders.creating.changers.FeatureExtractorBuilder
|
||||
import ch.tutteli.atrium.domain.builders.creating.changers.FeatureOptions
|
||||
import ch.tutteli.atrium.domain.creating.changers.ExtractedFeaturePostStep
|
||||
@@ -68,13 +69,13 @@ class FinalStepImpl<T, R>(
|
||||
extractAndApply = { assertionCreator -> extractIt(this, Some(assertionCreator)) }
|
||||
)
|
||||
|
||||
private fun extractIt(expect: Expect<T>, subAssertions: Option<Expect<R>.() -> Unit>) =
|
||||
private fun extractIt(expect: Expect<T>, maybeSubAssertions: Option<Expect<R>.() -> Unit>): FeatureExpect<T, R> =
|
||||
featureExtractor.extract(
|
||||
expect,
|
||||
featureOptions?.description ?: featureExtractionStep.description,
|
||||
featureExtractionStep.representationForFailure,
|
||||
featureExtraction,
|
||||
subAssertions,
|
||||
maybeSubAssertions,
|
||||
featureOptions?.representationInsteadOfFeature
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user