replace ThrowableThrown by normal expect

For this to work we have to:
- introduce Fun0Assertions with the two assertion function
  isThrowing and isNotThrowing
 - rename expect which expects an act to expectOld (remove in
   subsequent commit)
- fix old smoke tests which use wrong assertion verbs
This commit is contained in:
Robert Stoll
2019-11-30 20:10:19 +01:00
parent 3876fc828b
commit 1289e2bce6
30 changed files with 467 additions and 135 deletions

View File

@@ -319,6 +319,7 @@ expect: 10 (kotlin.Int <1234789>)
is greater than: 10 (kotlin.Int <1234789>)
```
</ex-group>
An assertion group throws an `AssertionError` at the end of its block; hence reports that both assertions do not hold.
You can use `and` as filling element between single assertions and assertion group blocks:
@@ -343,15 +344,16 @@ expect {
```
↑ <sub>[Example](https://github.com/robstoll/atrium/tree/master/samples/readme-examples/src/main/kotlin/readme/examples/ReadmeSpec.kt#L67)</sub> ↓ <sub>Output</sub>
```text
expect the thrown exception: java.lang.IllegalArgumentException
◆ is instance of type: IllegalStateException (java.lang.IllegalStateException)
» Properties of the unexpected IllegalArgumentException
» message: "name is empty" <1234789>
» stacktrace:
⚬ readme.examples.ReadmeSpec$1$4$1.invoke(ReadmeSpec.kt:70)
⚬ readme.examples.ReadmeSpec$1$4$1.invoke(ReadmeSpec.kt:45)
⚬ readme.examples.ReadmeSpec$1$4.invoke(ReadmeSpec.kt:627)
⚬ readme.examples.ReadmeSpec$1$4.invoke(ReadmeSpec.kt:45)
expect: () -> kotlin.Nothing (readme.examples.ReadmeSpec$1$4$1 <1234789>)
◆ thrown exception when called: java.lang.IllegalArgumentException
is instance of type: IllegalStateException (java.lang.IllegalStateException)
» Properties of the unexpected IllegalArgumentException
» message: "name is empty" <1234789>
» stacktrace:
⚬ readme.examples.ReadmeSpec$1$4$1.invoke(ReadmeSpec.kt:70)
⚬ readme.examples.ReadmeSpec$1$4$1.invoke(ReadmeSpec.kt:45)
⚬ readme.examples.ReadmeSpec$1$4.invoke(ReadmeSpec.kt:626)
⚬ readme.examples.ReadmeSpec$1$4.invoke(ReadmeSpec.kt:45)
```
</ex-toThrow1>
@@ -377,9 +379,10 @@ expect {
```
↑ <sub>[Example](https://github.com/robstoll/atrium/tree/master/samples/readme-examples/src/main/kotlin/readme/examples/ReadmeSpec.kt#L74)</sub> ↓ <sub>Output</sub>
```text
expect the thrown exception: java.lang.IllegalArgumentException
◆ ▶ message: null
◾ is instance of type: String (kotlin.String) -- Class: String (java.lang.String)
expect: () -> kotlin.Nothing (readme.examples.ReadmeSpec$1$5$1 <1234789>)
◆ ▶ thrown exception when called: java.lang.IllegalArgumentException
◾ message: null
is instance of type: String (kotlin.String) -- Class: String (java.lang.String)
```
</ex-toThrow2>
@@ -396,10 +399,11 @@ expect {
```
↑ <sub>[Example](https://github.com/robstoll/atrium/tree/master/samples/readme-examples/src/main/kotlin/readme/examples/ReadmeSpec.kt#L80)</sub> ↓ <sub>Output</sub>
```text
expect the thrown exception: java.lang.IllegalArgumentException
◆ ▶ message: null
◾ is instance of type: String (kotlin.String) -- Class: String (java.lang.String)
» starts with: "firstName" <1234789>
expect: () -> kotlin.Nothing (readme.examples.ReadmeSpec$1$6$1 <1234789>)
◆ ▶ thrown exception when called: java.lang.IllegalArgumentException
◾ message: null
is instance of type: String (kotlin.String) -- Class: String (java.lang.String)
» starts with: "firstName" <1234789>
```
</ex-toThrow3>
@@ -418,8 +422,8 @@ expect {
```
↑ <sub>[Example](https://github.com/robstoll/atrium/tree/master/samples/readme-examples/src/main/kotlin/readme/examples/ReadmeSpec.kt#L88)</sub> ↓ <sub>Output</sub>
```text
expect the thrown exception: java.lang.IllegalArgumentException
◆ is: not thrown at all
expect: () -> kotlin.Nothing (readme.examples.ReadmeSpec$1$7$1 <1234789>)
◆ does not: throw when called
» Properties of the unexpected IllegalArgumentException
» message: "name is empty" <1234789>
» stacktrace:
@@ -1604,25 +1608,26 @@ expect {
```
↑ <sub>[Example](https://github.com/robstoll/atrium/tree/master/samples/readme-examples/src/main/kotlin/readme/examples/ReadmeSpec.kt#L404)</sub> ↓ <sub>Output</sub>
```text
expect the thrown exception: java.lang.IllegalArgumentException
◆ is instance of type: IllegalStateException (java.lang.IllegalStateException)
» ▶message: CANNOT evaluate representation as it is based on subject which is not defined.
» is instance of type: String (kotlin.String) -- Class: String (java.lang.String)
» contains:
⚬ value: "no no no" <1234789>
⚬ ▶number of occurrences: -1
is at least: 1
» Properties of the unexpected IllegalArgumentException
» message: "no no no..." <1234789>
» stacktrace:
⚬ readme.examples.ReadmeSpec2$1$31$1.invoke(ReadmeSpec.kt:409)
⚬ readme.examples.ReadmeSpec2$1$31$1.invoke(ReadmeSpec.kt:221)
⚬ readme.examples.ReadmeSpec2$1$31.invoke(ReadmeSpec.kt:627)
⚬ readme.examples.ReadmeSpec2$1$31.invoke(ReadmeSpec.kt:221)
» cause: java.lang.UnsupportedOperationException
» message: "not supported" <1234789>
expect: () -> kotlin.Nothing (readme.examples.ReadmeSpec2$1$31$1 <1234789>)
◆ thrown exception when called: java.lang.IllegalArgumentException
is instance of type: IllegalStateException (java.lang.IllegalStateException)
» ▶message: CANNOT evaluate representation as it is based on subject which is not defined.
» is instance of type: String (kotlin.String) -- Class: String (java.lang.String)
» contains:
⚬ value: "no no no" <1234789>
⚬ ▶number of occurrences: -1
is at least: 1
» Properties of the unexpected IllegalArgumentException
» message: "no no no..." <1234789>
» stacktrace:
⚬ readme.examples.ReadmeSpec2$1$31$1.invoke(ReadmeSpec.kt:407)
⚬ readme.examples.ReadmeSpec2$1$31$1.invoke(ReadmeSpec.kt:409)
⚬ readme.examples.ReadmeSpec2$1$31$1.invoke(ReadmeSpec.kt:221)
⚬ readme.examples.ReadmeSpec2$1$31.invoke(ReadmeSpec.kt:626)
⚬ readme.examples.ReadmeSpec2$1$31.invoke(ReadmeSpec.kt:221)
» cause: java.lang.UnsupportedOperationException
» message: "not supported" <1234789>
» stacktrace:
⚬ readme.examples.ReadmeSpec2$1$31$1.invoke(ReadmeSpec.kt:407)
```
</ex-add-info-3>

View File

@@ -0,0 +1,63 @@
package ch.tutteli.atrium.api.fluent.en_GB
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.domain.builders.ExpectImpl
/**
* Expects that the thrown [Throwable] *is a* [TExpected] (the same type or a sub-type).
*
* Notice, that asserting a generic type is [flawed](https://youtrack.jetbrains.com/issue/KT-27826).
* For instance `toThrow<MyException<String>>` would only check if the subject is a `MyException` without checking if
* the element type is actually `String`.
*
* @return An assertion container with the new type [TExpected].
* @throws AssertionError Might throw an [AssertionError] if the assertion made is not correct.
*/
inline fun <reified TExpected : Throwable> Expect<out () -> Any?>.toThrow(): Expect<TExpected> =
ExpectImpl.fun0.isThrowing(this, TExpected::class).getExpectOfFeature()
/**
* Expects that the thrown [Throwable] *is a* [TExpected] (the same type or a sub-type) and
* that it holds all assertions the given [assertionCreator] creates.
*
* Notice, in contrast to other assertion functions which expect an [assertionCreator], this function returns not
* [Expect] of the initial type, which was `Throwable?` but an [Expect] of the specified type [TExpected].
* This has the side effect that a subsequent call has only assertion functions available which are suited
* for [TExpected]. Since [Expect] is invariant it especially means that an assertion function which was not
* written in a generic way will not be available. Fixing such a function is easy (in most cases),
* you need to transform it into a generic from. Following an example:
*
* ```
* interface Person
* class Student: Person
* fun Expect<Person>.foo() = "dummy" // limited only to Person, not recommended
* fun <T: Person> Expect<T>.bar() = "dummy" // available to Person and all subtypes, the way to go
* fun Expect<Student>.baz() = "dummy" // specific only for Student, ok since closed class
*
* val p: Person = Student()
* expect(p) // subject of type Person
* .isA<Student> { ... } // subject now refined to Student
* .baz() // available via Student
* .foo() // not available to Student, only to Person, results in compilation error
* .bar() // available via T : Person
* ```
*
* Notice, that asserting a generic type is [flawed](https://youtrack.jetbrains.com/issue/KT-27826).
* For instance `toThrow<MyException<String>>` would only check if the subject is a `MyException` without checking if
* the element type is actually `String`.
*
* @return An assertion container with the new type [TExpected].
* @throws AssertionError Might throw an [AssertionError] if the assertion made is not correct.
*/
inline fun <reified TExpected : Throwable> Expect<out () -> Any?>.toThrow(
noinline assertionCreator: Expect<TExpected>.() -> Unit
): Expect<TExpected> = ExpectImpl.fun0.isThrowing(this, TExpected::class).addToFeature(assertionCreator)
/**
* Expects that no [Throwable] is thrown at all when calling the subject (a lambda with arity 0, i.e. without argument)
* and changes the subject of the assertion to the return value of type [R].
*
* @throws AssertionError Might throw an [AssertionError] if the assertion made is not correct.
*/
fun <R, T : () -> R> Expect<T>.notToThrow(): Expect<R> = ExpectImpl.fun0.isNotThrowing(this).getExpectOfFeature()

View File

@@ -4,7 +4,6 @@ import ch.tutteli.atrium.api.cc.de_CH.messageEnthaelt
import ch.tutteli.atrium.api.cc.de_CH.wirft
import ch.tutteli.atrium.api.cc.de_CH.wirftNichts
import ch.tutteli.atrium.api.fluent.en_GB.toBe
import ch.tutteli.atrium.api.verbs.assertThat
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.creating.Assert
import ch.tutteli.atrium.creating.AssertionPlant
@@ -41,14 +40,14 @@ class SmokeTest {
@Test
fun assertAnExceptionOccurred() {
assertThat {
expect {
throw IllegalArgumentException()
}.wirft<IllegalArgumentException>{}
}
@Test
fun assertAnExceptionWithAMessageOccurred() {
assertThat {
expect {
throw IllegalArgumentException("oho... hello btw")
}.wirft<IllegalArgumentException> {
messageEnthaelt("hello")
@@ -57,7 +56,7 @@ class SmokeTest {
@Test
fun assertNotToThrow() {
assertThat {
expect {
}.wirftNichts()
}

View File

@@ -1,5 +1,4 @@
import ch.tutteli.atrium.api.cc.infix.en_GB.*
import ch.tutteli.atrium.api.verbs.assertThat
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.creating.Assert
import ch.tutteli.atrium.creating.AssertionPlant
@@ -28,14 +27,14 @@ class SmokeTest {
@Test
fun assertAnExceptionOccurred() {
assertThat {
assert {
throw IllegalArgumentException()
}.toThrow<IllegalArgumentException> {}
}
@Test
fun assertAnExceptionWithAMessageOccurred() {
assertThat {
assert {
throw IllegalArgumentException("oho... hello btw")
}.toThrow<IllegalArgumentException> {
o messageContains "hello"
@@ -44,7 +43,7 @@ class SmokeTest {
@Test
fun assertNotToThrow() {
assertThat {
assert {
}.notToThrow()
}

View File

@@ -0,0 +1,29 @@
package ch.tutteli.atrium.domain.creating
import ch.tutteli.atrium.core.polyfills.loadSingleService
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.domain.creating.changers.ChangedSubjectPostStep
import kotlin.reflect.KClass
/**
* The access point to an implementation of [Fun0Assertions].
*
* It loads the implementation lazily via [loadSingleService].
*/
val fun0Assertions by lazy { loadSingleService(Fun0Assertions::class) }
/**
* Defines the minimum set of assertion functions and builders applicable to lambdas with arity 0
* (i.e. a lambda with 0 arguments or in other words `() -> R`),
* which an implementation of the domain of Atrium has to provide.
*/
interface Fun0Assertions {
fun <TExpected : Throwable> isThrowing(
assertionContainer: Expect<out () -> Any?>,
expectedType: KClass<TExpected>
): ChangedSubjectPostStep<*, TExpected>
fun <R, T : () -> R> isNotThrowing(assertionContainer: Expect<T>): ChangedSubjectPostStep<*, R>
}

View File

@@ -88,6 +88,12 @@ object ExpectImpl {
*/
inline val floatingPoint get() = FloatingPointAssertionsBuilder
/**
* Returns [Fun0AssertionsBuilder] - [Assertion]s applicable to lambdas with arity 0
* which inter alia delegates to the implementation of [FloatingPointAssertions].
*/
inline val fun0 get() = Fun0AssertionsBuilder
/**
* Returns [IterableAssertionsBuilder].
* which inter alia delegates to the implementation of [IterableAssertions].

View File

@@ -0,0 +1,25 @@
@file:Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
package ch.tutteli.atrium.domain.builders.creating
import ch.tutteli.atrium.core.polyfills.loadSingleService
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.domain.creating.Fun0Assertions
import ch.tutteli.atrium.domain.creating.fun0Assertions
import kotlin.reflect.KClass
/**
* Delegates inter alia to the implementation of [Fun0Assertions].
* In detail, it implements [Fun0Assertions] by delegating to [fun0Assertions]
* which in turn delegates to the implementation via [loadSingleService].
*/
object Fun0AssertionsBuilder : Fun0Assertions {
override inline fun <TExpected : Throwable> isThrowing(
assertionContainer: Expect<out () -> Any?>,
expectedType: KClass<TExpected>
) = fun0Assertions.isThrowing(assertionContainer, expectedType)
override inline fun <R, T : () -> R> isNotThrowing(assertionContainer: Expect<T>) =
fun0Assertions.isNotThrowing(assertionContainer)
}

View File

@@ -42,7 +42,7 @@ object NewFeatureAssertionsBuilder : NewFeatureAssertions {
* Also, if the extraction of the feature is always safe, then you can just use one of the fN functions
* (e.g. [f1] for a function expecting 1 argument) or [property].
*/
inline fun <T> extractor(originalAssertionContainer: Expect<T>) =
inline fun <T> extractor(originalAssertionContainer: Expect<T>): FeatureExtractorBuilder.DescriptionStep<T> =
FeatureExtractorBuilder.create(originalAssertionContainer)
@@ -71,16 +71,16 @@ object NewFeatureAssertionsBuilder : NewFeatureAssertions {
fun <T, R> manualFeature(
assertionContainer: Expect<T>,
name: String,
description: String,
provider: T.() -> R
): ExtractedFeaturePostStep<T, R> = extractFeature(assertionContainer, name, provider)
): ExtractedFeaturePostStep<T, R> = extractFeature(assertionContainer, description, provider)
fun <T, R> manualFeature(
assertionContainer: Expect<T>,
name: Translatable,
description: Translatable,
provider: T.() -> R
): ExtractedFeaturePostStep<T, R> =
genericFeature(assertionContainer, createMetaFeature(assertionContainer, name, provider))
genericFeature(assertionContainer, createMetaFeature(assertionContainer, description, provider))
fun <T, R> genericSubjectBasedFeature(
assertionContainer: Expect<T>,
@@ -104,31 +104,31 @@ object NewFeatureAssertionsBuilder : NewFeatureAssertions {
private fun <T, R> extractFeature(
assertionContainer: Expect<T>,
name: String,
description: String,
provider: (T) -> R
): ExtractedFeaturePostStep<T, R> =
genericFeature(assertionContainer, createMetaFeature(assertionContainer, name, provider))
genericFeature(assertionContainer, createMetaFeature(assertionContainer, description, provider))
private fun <T, R> createMetaFeature(
assertionContainer: Expect<T>,
name: String,
description: String,
provider: (T) -> R
): MetaFeature<R> = createMetaFeature(assertionContainer, Untranslatable(name), provider)
): MetaFeature<R> = createMetaFeature(assertionContainer, Untranslatable(description), provider)
private fun <T, R> createMetaFeature(
assertionContainer: Expect<T>,
name: Translatable,
description: Translatable,
provider: (T) -> R
): MetaFeature<R> {
return assertionContainer.maybeSubject.fold({
MetaFeature(
name,
description,
RawString.create(ErrorMessages.REPRESENTATION_BASED_ON_SUBJECT_NOT_DEFINED),
None
)
}) {
val prop = provider(it)
MetaFeature(name, prop, Some(prop))
MetaFeature(description, prop, Some(prop))
}
}
@@ -157,7 +157,8 @@ class MetaFeatureOption<T>(private val expect: Expect<T>) {
//@formatter:off
/**
* Creates a [MetaFeature] for the given function [f] without arguments => use [f0] in case of ambiguity issues.
* Creates a [MetaFeature] for the given function [f] without arguments => use [f0] in case of
* ambiguity issues.
*
* Notice for assertion function writers: you should use [ExpectImpl].[feature][ExpectImpl.feature] and pass a
* class reference instead of using this convenience function (e.g. `ExpectImpl.feature(MyClass::fun)`).
@@ -168,7 +169,8 @@ class MetaFeatureOption<T>(private val expect: Expect<T>) {
f0(f)
/**
* Creates a [MetaFeature] for the given function [f] which expects 1 argument => use [f1] in case of ambiguity issues.
* Creates a [MetaFeature] for the given function [f] which expects 1 argument => use [f1] in case of
* ambiguity issues.
*
* Notice for assertion function writers: you should use [ExpectImpl].[feature][ExpectImpl.feature] and pass a
* class reference instead of using this convenience function (e.g. `ExpectImpl.feature(MyClass::fun, ...)`).
@@ -179,7 +181,8 @@ class MetaFeatureOption<T>(private val expect: Expect<T>) {
f1(f, a1)
/**
* Creates a [MetaFeature] for the given function [f] which expects 2 arguments => use [f2] in case of ambiguity issues.
* Creates a [MetaFeature] for the given function [f] which expects 2 arguments => use [f2] in case of
* ambiguity issues.
*
* Notice for assertion function writers: you should use [ExpectImpl].[feature][ExpectImpl.feature] and pass a
* class reference instead of using this convenience function (e.g. `ExpectImpl.feature(MyClass::fun, ...)`).
@@ -190,7 +193,8 @@ class MetaFeatureOption<T>(private val expect: Expect<T>) {
f2(f, a1, a2)
/**
* Creates a [MetaFeature] for the given function [f] which expects 3 arguments => use [f3] in case of ambiguity issues.
* Creates a [MetaFeature] for the given function [f] which expects 3 arguments => use [f3] in case of
* ambiguity issues.
*
* Notice for assertion function writers: you should use [ExpectImpl].[feature][ExpectImpl.feature] and pass a
* class reference instead of using this convenience function (e.g. `ExpectImpl.feature(MyClass::fun, ...)`).
@@ -201,7 +205,8 @@ class MetaFeatureOption<T>(private val expect: Expect<T>) {
f3(f, a1, a2, a3)
/**
* Creates a [MetaFeature] for the given function [f] which expects 4 arguments => use [f4] in case of ambiguity issues.
* Creates a [MetaFeature] for the given function [f] which expects 4 arguments => use [f4] in case of
* ambiguity issues.
*
* Notice for assertion function writers: you should use [ExpectImpl].[feature][ExpectImpl.feature] and pass a
* class reference instead of using this convenience function (e.g. `ExpectImpl.feature(MyClass::fun, ...)`).
@@ -212,7 +217,8 @@ class MetaFeatureOption<T>(private val expect: Expect<T>) {
f4(f, a1, a2, a3, a4)
/**
* Creates a [MetaFeature] for the given function [f] which expects 5 arguments => use [f5] in case of ambiguity issues.
* Creates a [MetaFeature] for the given function [f] which expects 5 arguments => use [f5] in case of
* ambiguity issues.
*
* Notice for assertion function writers: you should use [ExpectImpl].[feature][ExpectImpl.feature] and pass a
* class reference instead of using this convenience function (e.g. `ExpectImpl.feature(MyClass::fun, ...)`).

View File

@@ -123,8 +123,7 @@ interface FeatureExtractorBuilder {
/**
* Step to define the feature extraction as such where a one can include a check by returning [None] in case the
* extraction should not be carried out
* to see whether the feature extraction is feasible or not.
* extraction should not be carried out.
*
* @param T the type of the current subject.
*/

View File

@@ -3,6 +3,9 @@
package ch.tutteli.atrium.domain.builders.creating.changers
import ch.tutteli.atrium.assertions.DescriptiveAssertion
import ch.tutteli.atrium.core.None
import ch.tutteli.atrium.core.Option
import ch.tutteli.atrium.core.Some
import ch.tutteli.atrium.core.polyfills.cast
import ch.tutteli.atrium.creating.Assert
import ch.tutteli.atrium.creating.AssertionPlantNullable
@@ -17,9 +20,6 @@ import ch.tutteli.atrium.reporting.translating.Translatable
import ch.tutteli.atrium.reporting.translating.Untranslatable
import ch.tutteli.atrium.translations.DescriptionAnyAssertion
import kotlin.reflect.KClass
import ch.tutteli.atrium.core.Some
import ch.tutteli.atrium.core.None
import ch.tutteli.atrium.core.Option
/**
* Defines the contract for sophisticated `change subject` processes.
@@ -117,8 +117,8 @@ interface SubjectChangerBuilder {
fun <TSub : Any> downCastTo(subType: KClass<TSub>): FailureHandlerOption<T, TSub> =
withDescriptionAndRepresentation(DescriptionAnyAssertion.IS_A, subType)
.withTransformation {
Option.someIf( subType.isInstance(it) ){ subType.cast(it) }
}
Option.someIf(subType.isInstance(it)) { subType.cast(it) }
}
/**
* Uses the given [description] and [representation] to represent the change by delegating to the other overload
@@ -152,7 +152,7 @@ interface SubjectChangerBuilder {
/**
* Step to define the transformation which yields the new subject wrapped into a [Some] if the transformation
* as such can be carried out or [None].
* as such can be carried out; otherwise [None].
*
* @param T the type of the current subject.
*/

View File

@@ -77,13 +77,13 @@ class FinalStepImpl<T, R>(
transformAndApply = { assertionCreator -> transformIt(this, Some(assertionCreator)) }
)
private fun transformIt(expect: Expect<T>, subAssertions: Option<Expect<R>.() -> Unit>) =
private fun transformIt(expect: Expect<T>, maybeSubAssertions: Option<Expect<R>.() -> Unit>) =
subjectChanger.reported(
expect,
transformationStep.description,
transformationStep.representation,
transformation,
failureHandler,
subAssertions
maybeSubAssertions
)
}

View File

@@ -6,7 +6,6 @@ import ch.tutteli.atrium.api.fluent.en_GB.startsWith
import ch.tutteli.atrium.api.fluent.en_GB.toThrow
import ch.tutteli.atrium.api.verbs.internal.expect
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.domain.builders.ExpectImpl

View File

@@ -0,0 +1,94 @@
package ch.tutteli.atrium.domain.robstoll.lib.creating
import ch.tutteli.atrium.assertions.Assertion
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.domain.builders.ExpectImpl
import ch.tutteli.atrium.domain.creating.changers.ChangedSubjectPostStep
import ch.tutteli.atrium.domain.creating.changers.SubjectChanger
import ch.tutteli.atrium.domain.robstoll.lib.creating.throwable.thrown.creators.ThrowableThrownFailureHandler
import ch.tutteli.atrium.reporting.RawString
import ch.tutteli.atrium.reporting.reporter
import ch.tutteli.atrium.translations.DescriptionFunLikeAssertion.*
import kotlin.reflect.KClass
fun <TExpected : Throwable> _isThrowing(
assertionContainer: Expect<out () -> Any?>,
expectedType: KClass<TExpected>
): ChangedSubjectPostStep<*, TExpected> =
//TODO allow to pass an ExpectOptions which allows to change the nullRepresentation.
ExpectImpl.feature
.manualFeature(assertionContainer, THROWN_EXCEPTION_WHEN_CALLED) {
catchAndAdjustThrowable(this).fold(
{ it },
{
// use null as subject in case no exception occurred
null
}
)
}
.getExpectOfFeature()
.let {
ExpectImpl.changeSubject(it).reportBuilder()
.downCastTo(expectedType)
.withFailureHandler(ThrowableThrownFailureHandler(maxStackTrace = 7))
.build()
}
private inline fun <R> catchAndAdjustThrowable(act: () -> R): Either<R> =
try {
Right(act())
} catch (throwable: Throwable) {
//TODO should be taken from current assertionContainer once it is configured this way
reporter.atriumErrorAdjuster.adjust(throwable)
Left(throwable)
}
//TODO consider to move to core of Atrium
private sealed class Either<out R> {
inline fun <T> map(f: (R) -> T): Either<T> = flatMap { Right(f(it)) }
inline fun <T> flatMap(f: (R) -> Either<T>): Either<T> = fold({ Left(it) }, f)
inline fun <T> fold(default: (Throwable) -> T, f: (R) -> T): T = when (this) {
is Right -> f(this.r)
is Left -> default(this.l)
}
}
private data class Left(val l: Throwable) : Either<Nothing>()
private data class Right<R>(val r: R) : Either<R>()
fun <R, T : () -> R> _isNotThrowing(assertionContainer: Expect<T>): ChangedSubjectPostStep<*, R> {
return ExpectImpl.changeSubject(assertionContainer)
.unreported {
catchAndAdjustThrowable(it)
}
.let { eitherContainer ->
ExpectImpl.changeSubject(eitherContainer).reportBuilder()
.withDescriptionAndRepresentation(IS_NOT_THROWING_1, RawString.create(IS_NOT_THROWING_2))
.withTransformation {
if (it is Right) Some(it.r) else None
}
//TODO could be extracted into an own pattern/function FailureHandlerAdapter
.withFailureHandler(object : SubjectChanger.FailureHandler<Either<R>, R> {
override fun createAssertion(
originalAssertionContainer: Expect<Either<R>>,
descriptiveAssertion: Assertion,
maybeAssertionCreator: Option<Expect<R>.() -> Unit>
): Assertion {
return ExpectImpl.changeSubject(originalAssertionContainer).unreported { (it as Left).l }
.let {
val handler = ThrowableThrownFailureHandler<Throwable, R>(maxStackTrace = 15)
handler.createAssertion(it, descriptiveAssertion, maybeAssertionCreator)
}
}
})
.build()
}
}

View File

@@ -0,0 +1,18 @@
package ch.tutteli.atrium.domain.robstoll.creating
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.domain.creating.Fun0Assertions
import ch.tutteli.atrium.domain.robstoll.lib.creating._isThrowing
import ch.tutteli.atrium.domain.robstoll.lib.creating._isNotThrowing
import kotlin.reflect.KClass
class Fun0AssertionsImpl : Fun0Assertions {
override fun <TExpected : Throwable> isThrowing(
assertionContainer: Expect<out () -> Any?>,
expectedType: KClass<TExpected>
) = _isThrowing(assertionContainer, expectedType)
override fun <R, T : () -> R> isNotThrowing(assertionContainer: Expect<T>) = _isNotThrowing(assertionContainer)
}

View File

@@ -14,6 +14,7 @@ private val register = run {
registerService<ch.tutteli.atrium.domain.creating.ComparableAssertions> { ch.tutteli.atrium.domain.robstoll.creating.ComparableAssertionsImpl() }
registerService<ch.tutteli.atrium.domain.creating.FeatureAssertions> { ch.tutteli.atrium.domain.robstoll.creating.FeatureAssertionsImpl() }
registerService<ch.tutteli.atrium.domain.creating.FloatingPointAssertions> { ch.tutteli.atrium.domain.robstoll.creating.FloatingPointAssertionsImpl() }
registerService<ch.tutteli.atrium.domain.creating.Fun0Assertions> { ch.tutteli.atrium.domain.robstoll.creating.Fun0AssertionsImpl() }
registerService<ch.tutteli.atrium.domain.creating.IterableAssertions> { ch.tutteli.atrium.domain.robstoll.creating.IterableAssertionsImpl() }
registerService<ch.tutteli.atrium.domain.creating.ListAssertions> { ch.tutteli.atrium.domain.robstoll.creating.ListAssertionsImpl() }
registerService<ch.tutteli.atrium.domain.creating.MapAssertions> { ch.tutteli.atrium.domain.robstoll.creating.MapAssertionsImpl() }

View File

@@ -0,0 +1 @@
ch.tutteli.atrium.domain.robstoll.creating.Fun0AssertionsImpl

View File

@@ -54,6 +54,9 @@ module ch.tutteli.atrium.domain.robstoll {
provides ch.tutteli.atrium.domain.creating.FeatureAssertions
with ch.tutteli.atrium.domain.robstoll.creating.FeatureAssertionsImpl;
provides ch.tutteli.atrium.domain.creating.Fun0Assertions
with ch.tutteli.atrium.domain.robstoll.creating.Fun0AssertionsImpl;
provides ch.tutteli.atrium.domain.creating.feature.extract.creators.FeatureExtractorCreatorFactory
with ch.tutteli.atrium.domain.robstoll.creating.feature.extract.creators.FeatureExtractorCreatorFactoryImpl;

View File

@@ -104,7 +104,7 @@ abstract class ReportingAssertionContainerSpec(
context("in case of assertion which fails") {
context("throws an AssertionError") {
fun expectFun(): ThrowableThrown.Builder {
fun expectFun(): Expect<() -> Any?> {
val testee = createTestee()
return expect {
testee.failingFun()

View File

@@ -4,6 +4,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.api.verbs.internal.expectOld
import ch.tutteli.atrium.core.polyfills.fullName
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.domain.creating.throwable.thrown.ThrowableThrown
@@ -60,7 +61,7 @@ abstract class ThrowableAssertionsSpec(
pattern: String, vararg otherPatterns: String
) {
expect {
expect { ({ throw throwable })() }.toThrowFun()
expectOld { ({ throw throwable })() }.toThrowFun()
}.toThrow<AssertionError> {
message { containsRegex(pattern, *otherPatterns) }
}
@@ -82,7 +83,7 @@ abstract class ThrowableAssertionsSpec(
describeFun(toThrow) {
checkToThrow("it throws an AssertionError when no exception occurs", { doToThrow ->
expect {
expect { ({ /* no exception occurs */ })() }.doToThrow()
expectOld { ({ /* no exception occurs */ })() }.doToThrow()
}.toThrow<AssertionError> {
message {
contains.exactly(1).regex(
@@ -97,7 +98,7 @@ abstract class ThrowableAssertionsSpec(
checkToThrow(
"it allows to define assertions for the Throwable if the correct exception is thrown",
{ toThrowWithCheck ->
expect {
expectOld {
throw IllegalArgumentException("hello")
}.toThrowWithCheck()
},
@@ -146,7 +147,7 @@ abstract class ThrowableAssertionsSpec(
it("throws if no assertion is made") {
expect {
expect {
expectOld {
throw IllegalArgumentException("hello")
}.toThrowFunLazy { }
}.toThrow<AssertionError> {
@@ -163,7 +164,7 @@ abstract class ThrowableAssertionsSpec(
val notToThrowFun = notToThrow.lambda
context("no exception occurs") {
it("does not throw") {
expect {}.notToThrowFun()
expectOld {}.notToThrowFun()
}
}
context("exception is thrown") {

View File

@@ -8,7 +8,6 @@ import ch.tutteli.atrium.domain.builders.AssertImpl
import ch.tutteli.atrium.domain.builders.ExpectImpl
import ch.tutteli.atrium.domain.builders.reporting.ExpectOptions
import ch.tutteli.atrium.domain.builders.reporting.ReporterBuilder
import ch.tutteli.atrium.domain.creating.throwable.thrown.ThrowableThrown
import ch.tutteli.atrium.reporting.RawString
import ch.tutteli.atrium.reporting.Reporter
import ch.tutteli.atrium.reporting.translating.Untranslatable
@@ -25,7 +24,7 @@ abstract class VerbSpec(
forNonNullable: Pair<String, (subject: Int, representation: String?, ExpectOptions) -> Expect<Int>>,
forNonNullableCreator: Pair<String, (subject: Int, representation: String?, ExpectOptions, assertionCreator: Expect<Int>.() -> Unit) -> Expect<Int>>,
forNullable: Pair<String, (subject: Int?, representation: String?, ExpectOptions) -> Expect<Int?>>,
forThrowable: Pair<String, (act: () -> Unit) -> ThrowableThrown.Builder>,
forThrowable: Pair<String, (act: () -> Any?, ExpectOptions, representation: String?) -> Expect<() -> Any?>>,
describePrefix: String = "[Atrium] "
) : Spek({
@@ -178,8 +177,11 @@ abstract class VerbSpec(
}
prefixedDescribe("assertion verb '${forThrowable.first}' which deals with exceptions") {
val (_, assertionVerbFun) = forThrowable
fun assertionVerb(options: ExpectOptions = ExpectOptions(), representation: String? = null, act: () -> Any?) =
assertionVerbFun(act, options, representation)
context("an IllegalArgumentException occurs") {
val (_, assertionVerb) = forThrowable
it("does not throw an exception expecting an IllegalArgumentException") {
assertionVerb {
throw IllegalArgumentException("hello")
@@ -201,6 +203,8 @@ abstract class VerbSpec(
}
}
}
// customisations are not checked as it is assumed that this verb delegates to the verb forNonNullable
}
})

View File

@@ -7,6 +7,7 @@ import ch.tutteli.atrium.api.fluent.en_GB.message
import ch.tutteli.atrium.api.fluent.en_GB.toBe
import ch.tutteli.atrium.api.fluent.en_GB.toThrow
import ch.tutteli.atrium.api.verbs.internal.expect
import ch.tutteli.atrium.api.verbs.internal.expectOld
import ch.tutteli.atrium.core.polyfills.fullName
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.domain.creating.throwable.thrown.ThrowableThrown
@@ -50,7 +51,7 @@ abstract class ThrowableAssertionsJvmSpec(
pattern: String, vararg otherPatterns: String
) {
expect {
expect { ({ throw throwable })() }.toThrowFun()
expectOld { ({ throw throwable })() }.toThrowFun()
}.toThrow<AssertionError> {
message {
containsRegex(pattern, *otherPatterns)

View File

@@ -18,25 +18,35 @@ import ch.tutteli.atrium.reporting.translating.StringBasedTranslatable
/**
* Creates an [Expect] for the given [subject].
*
* @param subject The subject for which we are going to postulate assertions.
* @param representation Optional, use it in case you want to use a custom representation for the subject.
* @param options Optional, use it in case you want to tweak the resulting [Expect], for instance, use another reporter.
*
* @return The newly created assertion container.
* @throws AssertionError in case an assertion does not hold.
*/
fun <T> expect(subject: T, representation: String? = null, options: ExpectOptions = ExpectOptions()): Expect<T> =
fun <T> expect(subject: T, representation: String? = null, options: ExpectOptions? = null): Expect<T> =
ExpectBuilder.forSubject(subject)
.withVerb(EXPECT)
.withOptions(options.merge(ExpectOptions(representation = representation?.let { RawString.create(it) })))
.withMaybeRepresentationAndMaybeOptions(representation, options)
.build()
/**
* Creates an [Expect] for the given [subject] and [Expect.addAssertionsCreatedBy] the
* given [assertionCreator] lambda where the created [Assertion]s are added as a group and usually (depending on
* the configured [Reporter]) reported as a whole.
* given [assertionCreator]-lambda where the created [Assertion]s are added as a group and reported as a whole.
*
* @param subject The subject for which we are going to postulate assertions.
* @param representation Optional, use it in case you want to use a custom representation for the subject.
* @param options Optional, use it in case you want to tweak the resulting [Expect], for instance, use another reporter.
* @param assertionCreator Assertion group block with a non-fail fast behaviour.
*
* @return The newly created assertion container.
* @throws AssertionError in case an assertion does not hold.
*/
fun <T> expect(
subject: T,
representation: String? = null,
options: ExpectOptions = ExpectOptions(),
options: ExpectOptions? = null,
assertionCreator: Expect<T>.() -> Unit
): Expect<T> = expect(subject, representation, options).addAssertionsCreatedBy(assertionCreator)
@@ -46,7 +56,40 @@ fun <T> expect(
*
* @return The newly created [ThrowableThrown.Builder].
*/
fun expect(act: () -> Unit): ThrowableThrown.Builder = ExpectImpl.throwable.thrownBuilder(EXPECT_THROWN, act, reporter)
fun expectOld(act: () -> Unit): ThrowableThrown.Builder =
ExpectImpl.throwable.thrownBuilder(EXPECT_THROWN, act, reporter)
/**
* Creates an [Expect] with the given [act]-lambda as subject.
*
* @param act the subject for which we are going to postulate assertions.
* @param options Optional, use it in case you want to tweak the resulting [Expect], for instance, use another reporter.
* @param representation Optional, use it in case you want to use a custom representation for the subject.
*
* @return The newly created assertion container.
* @throws AssertionError in case an assertion does not hold.
*/
fun <R> expect(
options: ExpectOptions? = null,
representation: String? = null,
act: () -> R
): Expect<() -> R> = expect(act, representation, options)
/**
* Optimised version which only creates ExpectOptions if really required.
*/
fun <T> ExpectBuilder.OptionsStep<T>.withMaybeRepresentationAndMaybeOptions(
representation: String?, options: ExpectOptions?
): ExpectBuilder.FinalStep<T> =
if (representation == null) {
if (options == null) this.withoutOptions()
else this.withOptions(options)
} else {
val representationOption = ExpectOptions(representation = RawString.create(representation))
if (options == null) this.withOptions(representationOption)
else this.withOptions(options.merge(representationOption))
}
enum class AssertionVerb(override val value: String) : StringBasedTranslatable {
EXPECT("expect"),

View File

@@ -8,5 +8,5 @@ object ExpectSpec : VerbSpec(
expect(subject, representation, options, assertionCreator)
},
"expect" to { subject: Int?, representation, options -> expect(subject, representation, options) },
"expect" to { act -> expect { act() } }
"expect" to { act: () -> Any?, options, representation -> expect(options, representation, { act() }) }
)

View File

@@ -8,9 +8,6 @@ import ch.tutteli.atrium.reporting.translating.Translatable
*/
enum class AssertionVerb(override val value: String) : StringBasedTranslatable {
ASSERT("assert"),
ASSERT_THROWN("assert the thrown exception"),
ASSERT_THAT("assert that"),
ASSERT_THAT_THROWN("assert that the thrown exception"),
EXPECT("expect"),
EXPECT_THROWN("expect the thrown exception"),
}

View File

@@ -1,14 +1,11 @@
package ch.tutteli.atrium.api.verbs
import ch.tutteli.atrium.api.verbs.AssertionVerb.ASSERT
import ch.tutteli.atrium.api.verbs.AssertionVerb.ASSERT_THROWN
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.domain.builders.ExpectImpl
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
import ch.tutteli.atrium.domain.builders.reporting.ExpectOptions
import ch.tutteli.atrium.domain.creating.throwable.thrown.ThrowableThrown
import ch.tutteli.atrium.reporting.reporter
/**
* Creates an [Expect] for the given [subject].
@@ -16,8 +13,9 @@ import ch.tutteli.atrium.reporting.reporter
* @param subject The subject for which we are going to postulate assertions.
* @param representation Optional, use it in case you want to use a custom representation for the subject.
* @param options Optional, use it in case you want to tweak the resulting [Expect], for instance, use another reporter.
*
* @return The newly created assertion container.
* @throws AssertionError in case an assertion does not hold
* @throws AssertionError in case an assertion does not hold.
*/
fun <T> assert(subject: T, representation: String? = null, options: ExpectOptions? = null): Expect<T> =
ExpectBuilder.forSubject(subject)
@@ -32,9 +30,10 @@ fun <T> assert(subject: T, representation: String? = null, options: ExpectOption
* @param subject The subject for which we are going to postulate assertions.
* @param representation Optional, use it in case you want to use a custom representation for the subject.
* @param options Optional, use it in case you want to tweak the resulting [Expect], for instance, use another reporter.
*
* @param assertionCreator Assertion group block with a non-fail fast behaviour.
* @return The newly created assertion container.
* @throws AssertionError in case an assertion does not hold
* @throws AssertionError in case an assertion does not hold.
*/
fun <T> assert(
subject: T,
@@ -44,12 +43,20 @@ fun <T> assert(
): Expect<T> = assert(subject, representation, options).addAssertionsCreatedBy(assertionCreator)
/**
* Creates a [ThrowableThrown.Builder] for the given function [act] which catches a potentially thrown [Throwable]
* and allows to define an assertion for it.
* Creates an [Expect] with the given [act]-lambda as subject.
*
* @return The newly created [ThrowableThrown.Builder].
* @param act the subject for which we are going to postulate assertions.
* @param options Optional, use it in case you want to tweak the resulting [Expect], for instance, use another reporter.
*
* @param representation Optional, use it in case you want to use a custom representation for the subject.
* @return The newly created assertion container.
* @throws AssertionError in case an assertion does not hold.
*/
fun assert(act: () -> Unit): ThrowableThrown.Builder = ExpectImpl.throwable.thrownBuilder(ASSERT_THROWN, act, reporter)
fun <R> assert(
options: ExpectOptions? = null,
representation: String? = null,
act: () -> R
): Expect<() -> R> = assert(act, representation, options)
@Deprecated(
"`assert` should not be nested, use `feature` instead.",

View File

@@ -1,14 +1,11 @@
package ch.tutteli.atrium.api.verbs
import ch.tutteli.atrium.api.verbs.AssertionVerb.ASSERT_THAT
import ch.tutteli.atrium.api.verbs.AssertionVerb.ASSERT_THAT_THROWN
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.domain.builders.ExpectImpl
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
import ch.tutteli.atrium.domain.builders.reporting.ExpectOptions
import ch.tutteli.atrium.domain.creating.throwable.thrown.ThrowableThrown
import ch.tutteli.atrium.reporting.reporter
/**
* Creates an [Expect] for the given [subject].
@@ -16,8 +13,9 @@ import ch.tutteli.atrium.reporting.reporter
* @param subject The subject for which we are going to postulate assertions.
* @param representation Optional, use it in case you want to use a custom representation for the subject.
* @param options Optional, use it in case you want to tweak the resulting [Expect], for instance, use another reporter.
*
* @return The newly created assertion container.
* @throws AssertionError in case an assertion does not hold
* @throws AssertionError in case an assertion does not hold.
*/
fun <T> assertThat(subject: T, representation: String? = null, options: ExpectOptions? = null): Expect<T> =
ExpectBuilder.forSubject(subject)
@@ -32,9 +30,10 @@ fun <T> assertThat(subject: T, representation: String? = null, options: ExpectOp
* @param subject The subject for which we are going to postulate assertions.
* @param representation Optional, use it in case you want to use a custom representation for the subject.
* @param options Optional, use it in case you want to tweak the resulting [Expect], for instance, use another reporter.
*
* @param assertionCreator Assertion group block with a non-fail fast behaviour.
* @return The newly created assertion container.
* @throws AssertionError in case an assertion does not hold
* @throws AssertionError in case an assertion does not hold.
*/
fun <T> assertThat(
subject: T,
@@ -44,13 +43,20 @@ fun <T> assertThat(
): Expect<T> = assertThat(subject, representation, options).addAssertionsCreatedBy(assertionCreator)
/**
* Creates a [ThrowableThrown.Builder] for the given function [act] which catches a potentially thrown [Throwable]
* and allows to define an assertion for it.
* Creates an [Expect] with the given [act]-lambda as subject.
*
* @return The newly created [ThrowableThrown.Builder].
* @param act the subject for which we are going to postulate assertions.
* @param options Optional, use it in case you want to tweak the resulting [Expect], for instance, use another reporter.
*
* @param representation Optional, use it in case you want to use a custom representation for the subject.
* @return The newly created assertion container.
* @throws AssertionError in case an assertion does not hold.
*/
fun assertThat(act: () -> Unit): ThrowableThrown.Builder =
ExpectImpl.throwable.thrownBuilder(ASSERT_THAT_THROWN, act, reporter)
fun <R> assertThat(
options: ExpectOptions? = null,
representation: String? = null,
act: () -> R
): Expect<() -> R> = assertThat(act, representation, options)
@Deprecated(
"`assertThat` should not be nested, use `feature` instead.",

View File

@@ -1,14 +1,11 @@
package ch.tutteli.atrium.api.verbs
import ch.tutteli.atrium.api.verbs.AssertionVerb.EXPECT
import ch.tutteli.atrium.api.verbs.AssertionVerb.EXPECT_THROWN
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.domain.builders.ExpectImpl
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
import ch.tutteli.atrium.domain.builders.reporting.ExpectOptions
import ch.tutteli.atrium.domain.creating.throwable.thrown.ThrowableThrown
import ch.tutteli.atrium.reporting.reporter
/**
* Creates an [Expect] for the given [subject].
@@ -16,8 +13,9 @@ import ch.tutteli.atrium.reporting.reporter
* @param subject The subject for which we are going to postulate assertions.
* @param representation Optional, use it in case you want to use a custom representation for the subject.
* @param options Optional, use it in case you want to tweak the resulting [Expect], for instance, use another reporter.
*
* @return The newly created assertion container.
* @throws AssertionError in case an assertion does not hold
* @throws AssertionError in case an assertion does not hold.
*/
fun <T> expect(subject: T, representation: String? = null, options: ExpectOptions? = null): Expect<T> =
ExpectBuilder.forSubject(subject)
@@ -32,9 +30,10 @@ fun <T> expect(subject: T, representation: String? = null, options: ExpectOption
* @param subject The subject for which we are going to postulate assertions.
* @param representation Optional, use it in case you want to use a custom representation for the subject.
* @param options Optional, use it in case you want to tweak the resulting [Expect], for instance, use another reporter.
*
* @param assertionCreator Assertion group block with a non-fail fast behaviour.
* @return The newly created assertion container.
* @throws AssertionError in case an assertion does not hold
* @throws AssertionError in case an assertion does not hold.
*/
fun <T> expect(
subject: T,
@@ -44,22 +43,21 @@ fun <T> expect(
): Expect<T> = expect(subject, representation, options).addAssertionsCreatedBy(assertionCreator)
/**
* Creates a [ThrowableThrown.Builder] for the given function [act] which catches a potentially thrown [Throwable]
* and allows to define an assertion for it.
* Creates an [Expect] with the given [act]-lambda as subject.
*
* @return The newly created [ThrowableThrown.Builder].
* @param act the subject for which we are going to postulate assertions.
* @param options Optional, use it in case you want to tweak the resulting [Expect], for instance, use another reporter.
* @param representation Optional, use it in case you want to use a custom representation for the subject.
*
* @return The newly created assertion container.
* @throws AssertionError in case an assertion does not hold.
*/
fun expect(act: () -> Unit): ThrowableThrown.Builder = ExpectImpl.throwable.thrownBuilder(EXPECT_THROWN, act, reporter)
// TODO #97 now we are almost there to implement expect{}.toThrow in terms of expect
//fun <R> expect(
// representation: String? = null,
// options: ExpectOptions? = null,
// act: () -> R
//): Expect<() -> R> = expect(act, representation, ExpectOptions {
// withVerb(EXPECT_THROWN)
// withNullRepresentation(RawString.create("no exception occurred"))
//}.merge(options))
//note the order of the parameters (options before representation) is this way to disambiguate calls
fun <R> expect(
options: ExpectOptions? = null,
representation: String? = null,
act: () -> R
): Expect<() -> R> = expect(act, representation, options)
@Deprecated(
"`expect` should not be nested, use `feature` instead.",

View File

@@ -8,7 +8,8 @@ object AssertSpec : VerbSpec(
assert(subject, representation, options, assertionCreator)
},
"assert" to { subject: Int?, representation, options -> assert(subject, representation, options) },
"assert" to { act -> assert { act() } })
"assert" to { act: () -> Any?, options, representation -> assert(options, representation, { act() }) }
)
object AssertThatSpec : VerbSpec(
"assertThat" to { subject: Int, representation, options -> assertThat(subject, representation, options) },
@@ -16,7 +17,8 @@ object AssertThatSpec : VerbSpec(
assertThat(subject, representation, options, assertionCreator)
},
"assertThat" to { subject: Int?, representation, options -> assertThat(subject, representation, options) },
"assertThat" to { act -> assertThat { act() } })
"assertThat" to { act: () -> Any?, options, representation -> assertThat(options, representation, { act() }) }
)
object ExpectSpec : VerbSpec(
"expect" to { subject: Int, representation, options -> expect(subject, representation, options) },
@@ -24,5 +26,5 @@ object ExpectSpec : VerbSpec(
expect(subject, representation, options, assertionCreator)
},
"expect" to { subject: Int?, representation, options -> expect(subject, representation, options) },
"expect" to { act -> expect { act() } })
"expect" to { act: () -> Any?, options, representation -> expect(options, representation, { act() }) }
)

View File

@@ -0,0 +1,13 @@
package ch.tutteli.atrium.translations
import ch.tutteli.atrium.assertions.DescriptiveAssertion
import ch.tutteli.atrium.reporting.translating.StringBasedTranslatable
/**
* Contains the [DescriptiveAssertion.description]s of the assertion functions which are applicable to [Any].
*/
enum class DescriptionFunLikeAssertion(override val value: String) : StringBasedTranslatable {
IS_NOT_THROWING_1("wirft"),
IS_NOT_THROWING_2("keine Exception bei Aufruf"),
THROWN_EXCEPTION_WHEN_CALLED("geworfene Exception bei Aufruf"),
}

View File

@@ -0,0 +1,13 @@
package ch.tutteli.atrium.translations
import ch.tutteli.atrium.assertions.DescriptiveAssertion
import ch.tutteli.atrium.reporting.translating.StringBasedTranslatable
/**
* Contains the [DescriptiveAssertion.description]s of the assertion functions which are applicable to [Any].
*/
enum class DescriptionFunLikeAssertion(override val value: String) : StringBasedTranslatable {
IS_NOT_THROWING_1("does not"),
IS_NOT_THROWING_2("throw when called"),
THROWN_EXCEPTION_WHEN_CALLED("thrown exception when called"),
}