commonMain.ch.tutteli.atrium.creating.Expect.kt Maven / Gradle / Ivy
package ch.tutteli.atrium.creating
import ch.tutteli.atrium.assertions.Assertion
/**
* The internal type which we work with which combines [Expect], [AssertionContainer] and [ExpectGrouping].
*
* In theory, [Expect] should extend [ExpectGrouping] but due to Kotlin type inference/overload resolution bugs, we have
* to split it. One benefit of it, we can define extensions for [ExpectGrouping] which are not visible for [Expect].
*
* Similarly, we separate [Expect] from [AssertionContainer] so that we can provide extension functions for
* [AssertionContainer] which are more or less identical to the ones defined for api-fluent but don't return an [Expect]
* but [Assertion] etc.
*
* Also, we separate [Expect] form [AssertionContainer] since a lot of functionality defined for AssertionContainer is
* not relevant for newcomers to Atrium (see [https://github.com/robstoll/atrium-roadmap/wiki/Requirements#personas](https://github.com/robstoll/atrium-roadmap/wiki/Requirements#personas)
* for more information about the personas).
*/
interface ExpectInternal : Expect, AssertionContainer, ExpectGrouping
/**
* Represents the extension point for expectation functions and sophisticated builders for subjects of type [T].
*
* Following a simple example, see [Write own Expectation Functions](https://github.com/robstoll/atrium?tab=readme-ov-file#write-own-expectation-functions)
* for more help:
* ```kotlin
* val Expect.errorCode: FeatureExpect
* get() = feature(SQLException::getErrorCode)
* ```
*
* Note, that we have used a type parameter and not `Expect`. This is due to the fact that `Expect`
* is [invariant](https://kotlinlang.org/docs/reference/generics.html#variance) which means without type parameter
* something like the following would result in a compile error
* ```kotlin
* expect {
* ...
* }.toThrow {
* errorCode.toEqual(23000)
* // compile error: None of the following candidates is applicable because of receiver type mismatch:
* }
* ```
* Besides, we would need to return a `FeatureExpect` and would therefore lose the information
* that the thrown Exception was a `BatchUpdateException` and would first need to use `toBeAnInstanceOf`
* if we want to assert something which is specific to `BatchUpdateException`. With the type parameter we don't and
* could therefore then also write something like the following within the `toThrow` block:
* ```kotlin
* feature(BatchUpdateException::getUpdateCounts).toEqual(intArrayOf(3, 2))
* ```
*
* In general, you should always use the type parameter approach, the only exception is if you deal with final classes
* (e.g. data classes) which don't have a type parameter itself. In such a case there is no benefit to have a type
* parameter but on the other hand, it also doesn't hurt -- less to think about
* (your IDE might warn you that it is not necessary though).
*
* As a side notice, we have not defined `Expect` as covariant on purpose (switched to invariant in v0.9.0),
* because if we did, then things like `expect(1).toEqual(1.0)` would no longer be a compile error.
* And Atrium's goal is exactly to prevent users from pitfalls like that.
*
* @param T The type of the subject of `this` expectation.
*/
interface Expect
typealias ExpectationCreator = Expect.() -> Unit
/**
* Represents a group of expectations including nested groups of expectations (nested [ExpectGrouping]).
*
* It's the extension point for groups of expectations with unrelated subjects.
*
* @since 1.1.0
*/
interface ExpectGrouping
© 2015 - 2024 Weber Informatics LLC | Privacy Policy