diff --git a/README.md b/README.md
index c5c4639ed..950cded94 100644
--- a/README.md
+++ b/README.md
@@ -319,6 +319,7 @@ expect: 10 (kotlin.Int <1234789>)
◆ is greater than: 10 (kotlin.Int <1234789>)
```
+
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 {
```
↑ [Example](https://github.com/robstoll/atrium/tree/master/samples/readme-examples/src/main/kotlin/readme/examples/ReadmeSpec.kt#L67) ↓ Output
```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)
```
@@ -377,9 +379,10 @@ expect {
```
↑ [Example](https://github.com/robstoll/atrium/tree/master/samples/readme-examples/src/main/kotlin/readme/examples/ReadmeSpec.kt#L74) ↓ Output
```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)
```
@@ -396,10 +399,11 @@ expect {
```
↑ [Example](https://github.com/robstoll/atrium/tree/master/samples/readme-examples/src/main/kotlin/readme/examples/ReadmeSpec.kt#L80) ↓ Output
```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>
```
@@ -418,8 +422,8 @@ expect {
```
↑ [Example](https://github.com/robstoll/atrium/tree/master/samples/readme-examples/src/main/kotlin/readme/examples/ReadmeSpec.kt#L88) ↓ Output
```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 {
```
↑ [Example](https://github.com/robstoll/atrium/tree/master/samples/readme-examples/src/main/kotlin/readme/examples/ReadmeSpec.kt#L404) ↓ Output
```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)
```
diff --git a/apis/fluent-en_GB/atrium-api-fluent-en_GB-common/src/main/kotlin/ch/tutteli/atrium/api/fluent/en_GB/fun0Assertions.kt b/apis/fluent-en_GB/atrium-api-fluent-en_GB-common/src/main/kotlin/ch/tutteli/atrium/api/fluent/en_GB/fun0Assertions.kt
new file mode 100644
index 000000000..cdc5d95b9
--- /dev/null
+++ b/apis/fluent-en_GB/atrium-api-fluent-en_GB-common/src/main/kotlin/ch/tutteli/atrium/api/fluent/en_GB/fun0Assertions.kt
@@ -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>` 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 Expect Any?>.toThrow(): Expect =
+ 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.foo() = "dummy" // limited only to Person, not recommended
+ * fun Expect.bar() = "dummy" // available to Person and all subtypes, the way to go
+ * fun Expect.baz() = "dummy" // specific only for Student, ok since closed class
+ *
+ * val p: Person = Student()
+ * expect(p) // subject of type Person
+ * .isA { ... } // 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>` 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 Expect Any?>.toThrow(
+ noinline assertionCreator: Expect.() -> Unit
+): Expect = 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> Expect.notToThrow(): Expect = ExpectImpl.fun0.isNotThrowing(this).getExpectOfFeature()
diff --git a/bundles/cc-de_CH-robstoll/atrium-cc-de_CH-robstoll-common/src/test/kotlin/SmokeTest.kt b/bundles/cc-de_CH-robstoll/atrium-cc-de_CH-robstoll-common/src/test/kotlin/SmokeTest.kt
index eb46649eb..fa7e4ad2a 100644
--- a/bundles/cc-de_CH-robstoll/atrium-cc-de_CH-robstoll-common/src/test/kotlin/SmokeTest.kt
+++ b/bundles/cc-de_CH-robstoll/atrium-cc-de_CH-robstoll-common/src/test/kotlin/SmokeTest.kt
@@ -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{}
}
@Test
fun assertAnExceptionWithAMessageOccurred() {
- assertThat {
+ expect {
throw IllegalArgumentException("oho... hello btw")
}.wirft {
messageEnthaelt("hello")
@@ -57,7 +56,7 @@ class SmokeTest {
@Test
fun assertNotToThrow() {
- assertThat {
+ expect {
}.wirftNichts()
}
diff --git a/bundles/cc-infix-en_GB-robstoll/atrium-cc-infix-en_GB-robstoll-common/src/test/kotlin/SmokeTest.kt b/bundles/cc-infix-en_GB-robstoll/atrium-cc-infix-en_GB-robstoll-common/src/test/kotlin/SmokeTest.kt
index ab7a89265..0faa40592 100644
--- a/bundles/cc-infix-en_GB-robstoll/atrium-cc-infix-en_GB-robstoll-common/src/test/kotlin/SmokeTest.kt
+++ b/bundles/cc-infix-en_GB-robstoll/atrium-cc-infix-en_GB-robstoll-common/src/test/kotlin/SmokeTest.kt
@@ -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 {}
}
@Test
fun assertAnExceptionWithAMessageOccurred() {
- assertThat {
+ assert {
throw IllegalArgumentException("oho... hello btw")
}.toThrow {
o messageContains "hello"
@@ -44,7 +43,7 @@ class SmokeTest {
@Test
fun assertNotToThrow() {
- assertThat {
+ assert {
}.notToThrow()
}
diff --git a/domain/api/atrium-domain-api-common/src/main/kotlin/ch/tutteli/atrium/domain/creating/Fun0Assertions.kt b/domain/api/atrium-domain-api-common/src/main/kotlin/ch/tutteli/atrium/domain/creating/Fun0Assertions.kt
new file mode 100644
index 000000000..dca6bf4a7
--- /dev/null
+++ b/domain/api/atrium-domain-api-common/src/main/kotlin/ch/tutteli/atrium/domain/creating/Fun0Assertions.kt
@@ -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 isThrowing(
+ assertionContainer: Expect Any?>,
+ expectedType: KClass
+ ): ChangedSubjectPostStep<*, TExpected>
+
+ fun R> isNotThrowing(assertionContainer: Expect): ChangedSubjectPostStep<*, R>
+}
diff --git a/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/ExpectImpl.kt b/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/ExpectImpl.kt
index 5ba290666..b94dce233 100644
--- a/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/ExpectImpl.kt
+++ b/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/ExpectImpl.kt
@@ -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].
diff --git a/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/Fun0AssertionsBuilder.kt b/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/Fun0AssertionsBuilder.kt
new file mode 100644
index 000000000..5b27584e0
--- /dev/null
+++ b/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/Fun0AssertionsBuilder.kt
@@ -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 isThrowing(
+ assertionContainer: Expect Any?>,
+ expectedType: KClass
+ ) = fun0Assertions.isThrowing(assertionContainer, expectedType)
+
+ override inline fun R> isNotThrowing(assertionContainer: Expect) =
+ fun0Assertions.isNotThrowing(assertionContainer)
+}
diff --git a/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/NewFeatureAssertionsBuilder.kt b/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/NewFeatureAssertionsBuilder.kt
index 8f072a849..b76f5eae3 100644
--- a/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/NewFeatureAssertionsBuilder.kt
+++ b/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/NewFeatureAssertionsBuilder.kt
@@ -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 extractor(originalAssertionContainer: Expect) =
+ inline fun extractor(originalAssertionContainer: Expect): FeatureExtractorBuilder.DescriptionStep =
FeatureExtractorBuilder.create(originalAssertionContainer)
@@ -71,16 +71,16 @@ object NewFeatureAssertionsBuilder : NewFeatureAssertions {
fun manualFeature(
assertionContainer: Expect,
- name: String,
+ description: String,
provider: T.() -> R
- ): ExtractedFeaturePostStep = extractFeature(assertionContainer, name, provider)
+ ): ExtractedFeaturePostStep = extractFeature(assertionContainer, description, provider)
fun manualFeature(
assertionContainer: Expect,
- name: Translatable,
+ description: Translatable,
provider: T.() -> R
): ExtractedFeaturePostStep =
- genericFeature(assertionContainer, createMetaFeature(assertionContainer, name, provider))
+ genericFeature(assertionContainer, createMetaFeature(assertionContainer, description, provider))
fun genericSubjectBasedFeature(
assertionContainer: Expect,
@@ -104,31 +104,31 @@ object NewFeatureAssertionsBuilder : NewFeatureAssertions {
private fun extractFeature(
assertionContainer: Expect,
- name: String,
+ description: String,
provider: (T) -> R
): ExtractedFeaturePostStep =
- genericFeature(assertionContainer, createMetaFeature(assertionContainer, name, provider))
+ genericFeature(assertionContainer, createMetaFeature(assertionContainer, description, provider))
private fun createMetaFeature(
assertionContainer: Expect,
- name: String,
+ description: String,
provider: (T) -> R
- ): MetaFeature = createMetaFeature(assertionContainer, Untranslatable(name), provider)
+ ): MetaFeature = createMetaFeature(assertionContainer, Untranslatable(description), provider)
private fun createMetaFeature(
assertionContainer: Expect,
- name: Translatable,
+ description: Translatable,
provider: (T) -> R
): MetaFeature {
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(private val expect: Expect) {
//@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(private val expect: Expect) {
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(private val expect: Expect) {
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(private val expect: Expect) {
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(private val expect: Expect) {
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(private val expect: Expect) {
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, ...)`).
diff --git a/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/changers/FeatureExtractorBuilder.kt b/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/changers/FeatureExtractorBuilder.kt
index 4ae971cfe..37c9dd9f5 100644
--- a/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/changers/FeatureExtractorBuilder.kt
+++ b/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/changers/FeatureExtractorBuilder.kt
@@ -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.
*/
diff --git a/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/changers/SubjectChangerBuilder.kt b/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/changers/SubjectChangerBuilder.kt
index 4652451d1..58fb1e6b8 100644
--- a/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/changers/SubjectChangerBuilder.kt
+++ b/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/changers/SubjectChangerBuilder.kt
@@ -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 downCastTo(subType: KClass): FailureHandlerOption =
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.
*/
diff --git a/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/changers/impl/subjectchanger/defaultImpls.kt b/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/changers/impl/subjectchanger/defaultImpls.kt
index 4be7c79e1..81697ef87 100644
--- a/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/changers/impl/subjectchanger/defaultImpls.kt
+++ b/domain/builders/atrium-domain-builders-common/src/main/kotlin/ch/tutteli/atrium/domain/builders/creating/changers/impl/subjectchanger/defaultImpls.kt
@@ -77,13 +77,13 @@ class FinalStepImpl(
transformAndApply = { assertionCreator -> transformIt(this, Some(assertionCreator)) }
)
- private fun transformIt(expect: Expect, subAssertions: Option.() -> Unit>) =
+ private fun transformIt(expect: Expect, maybeSubAssertions: Option.() -> Unit>) =
subjectChanger.reported(
expect,
transformationStep.description,
transformationStep.representation,
transformation,
failureHandler,
- subAssertions
+ maybeSubAssertions
)
}
diff --git a/domain/builders/atrium-domain-builders-common/src/test/kotlin/ch/tutteli/atrium/domain/builders/creating/EitherSpec.kt b/domain/builders/atrium-domain-builders-common/src/test/kotlin/ch/tutteli/atrium/domain/builders/creating/EitherSpec.kt
index 24c340113..c3a8a4a54 100644
--- a/domain/builders/atrium-domain-builders-common/src/test/kotlin/ch/tutteli/atrium/domain/builders/creating/EitherSpec.kt
+++ b/domain/builders/atrium-domain-builders-common/src/test/kotlin/ch/tutteli/atrium/domain/builders/creating/EitherSpec.kt
@@ -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
diff --git a/domain/robstoll-lib/atrium-domain-robstoll-lib-common/src/main/kotlin/ch/tutteli/atrium/domain/robstoll/lib/creating/fun0Assertions.kt b/domain/robstoll-lib/atrium-domain-robstoll-lib-common/src/main/kotlin/ch/tutteli/atrium/domain/robstoll/lib/creating/fun0Assertions.kt
new file mode 100644
index 000000000..251d3ad34
--- /dev/null
+++ b/domain/robstoll-lib/atrium-domain-robstoll-lib-common/src/main/kotlin/ch/tutteli/atrium/domain/robstoll/lib/creating/fun0Assertions.kt
@@ -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 _isThrowing(
+ assertionContainer: Expect Any?>,
+ expectedType: KClass
+): 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 catchAndAdjustThrowable(act: () -> R): Either =
+ 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 {
+
+ inline fun map(f: (R) -> T): Either = flatMap { Right(f(it)) }
+
+ inline fun flatMap(f: (R) -> Either): Either = fold({ Left(it) }, f)
+
+ inline fun 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()
+private data class Right(val r: R) : Either()
+
+fun R> _isNotThrowing(assertionContainer: Expect): 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, R> {
+ override fun createAssertion(
+ originalAssertionContainer: Expect>,
+ descriptiveAssertion: Assertion,
+ maybeAssertionCreator: Option.() -> Unit>
+ ): Assertion {
+ return ExpectImpl.changeSubject(originalAssertionContainer).unreported { (it as Left).l }
+ .let {
+ val handler = ThrowableThrownFailureHandler(maxStackTrace = 15)
+ handler.createAssertion(it, descriptiveAssertion, maybeAssertionCreator)
+ }
+ }
+ })
+ .build()
+ }
+}
+
+
diff --git a/domain/robstoll/atrium-domain-robstoll-common/src/main/kotlin/ch/tutteli/atrium/domain/robstoll/creating/Fun0AssertionsImpl.kt b/domain/robstoll/atrium-domain-robstoll-common/src/main/kotlin/ch/tutteli/atrium/domain/robstoll/creating/Fun0AssertionsImpl.kt
new file mode 100644
index 000000000..8501ae0ec
--- /dev/null
+++ b/domain/robstoll/atrium-domain-robstoll-common/src/main/kotlin/ch/tutteli/atrium/domain/robstoll/creating/Fun0AssertionsImpl.kt
@@ -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 isThrowing(
+ assertionContainer: Expect Any?>,
+ expectedType: KClass
+ ) = _isThrowing(assertionContainer, expectedType)
+
+ override fun R> isNotThrowing(assertionContainer: Expect) = _isNotThrowing(assertionContainer)
+}
diff --git a/domain/robstoll/atrium-domain-robstoll-js/src/main/kotlin/ch/tutteli/atrium/domain/robstoll/registerServices.kt b/domain/robstoll/atrium-domain-robstoll-js/src/main/kotlin/ch/tutteli/atrium/domain/robstoll/registerServices.kt
index 3473df665..fb0414237 100644
--- a/domain/robstoll/atrium-domain-robstoll-js/src/main/kotlin/ch/tutteli/atrium/domain/robstoll/registerServices.kt
+++ b/domain/robstoll/atrium-domain-robstoll-js/src/main/kotlin/ch/tutteli/atrium/domain/robstoll/registerServices.kt
@@ -14,6 +14,7 @@ private val register = run {
registerService { ch.tutteli.atrium.domain.robstoll.creating.ComparableAssertionsImpl() }
registerService { ch.tutteli.atrium.domain.robstoll.creating.FeatureAssertionsImpl() }
registerService { ch.tutteli.atrium.domain.robstoll.creating.FloatingPointAssertionsImpl() }
+ registerService { ch.tutteli.atrium.domain.robstoll.creating.Fun0AssertionsImpl() }
registerService { ch.tutteli.atrium.domain.robstoll.creating.IterableAssertionsImpl() }
registerService { ch.tutteli.atrium.domain.robstoll.creating.ListAssertionsImpl() }
registerService { ch.tutteli.atrium.domain.robstoll.creating.MapAssertionsImpl() }
diff --git a/domain/robstoll/atrium-domain-robstoll-jvm/src/main/resources/META-INF/services/ch.tutteli.atrium.domain.creating.Fun0Assertions b/domain/robstoll/atrium-domain-robstoll-jvm/src/main/resources/META-INF/services/ch.tutteli.atrium.domain.creating.Fun0Assertions
new file mode 100644
index 000000000..827dc57b2
--- /dev/null
+++ b/domain/robstoll/atrium-domain-robstoll-jvm/src/main/resources/META-INF/services/ch.tutteli.atrium.domain.creating.Fun0Assertions
@@ -0,0 +1 @@
+ch.tutteli.atrium.domain.robstoll.creating.Fun0AssertionsImpl
diff --git a/domain/robstoll/atrium-domain-robstoll-jvm/src/module/module-info.java b/domain/robstoll/atrium-domain-robstoll-jvm/src/module/module-info.java
index 8a1f66a41..8eb9431c2 100644
--- a/domain/robstoll/atrium-domain-robstoll-jvm/src/module/module-info.java
+++ b/domain/robstoll/atrium-domain-robstoll-jvm/src/module/module-info.java
@@ -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;
diff --git a/misc/specs/atrium-specs-common/src/main/kotlin/ch/tutteli/atrium/specs/creating/ReportingAssertionContainerSpec.kt b/misc/specs/atrium-specs-common/src/main/kotlin/ch/tutteli/atrium/specs/creating/ReportingAssertionContainerSpec.kt
index a73bc8cd5..403187795 100644
--- a/misc/specs/atrium-specs-common/src/main/kotlin/ch/tutteli/atrium/specs/creating/ReportingAssertionContainerSpec.kt
+++ b/misc/specs/atrium-specs-common/src/main/kotlin/ch/tutteli/atrium/specs/creating/ReportingAssertionContainerSpec.kt
@@ -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()
diff --git a/misc/specs/atrium-specs-common/src/main/kotlin/ch/tutteli/atrium/specs/integration/ThrowableAssertionsSpec.kt b/misc/specs/atrium-specs-common/src/main/kotlin/ch/tutteli/atrium/specs/integration/ThrowableAssertionsSpec.kt
index 929b14b28..507a5e5bb 100644
--- a/misc/specs/atrium-specs-common/src/main/kotlin/ch/tutteli/atrium/specs/integration/ThrowableAssertionsSpec.kt
+++ b/misc/specs/atrium-specs-common/src/main/kotlin/ch/tutteli/atrium/specs/integration/ThrowableAssertionsSpec.kt
@@ -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 {
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 {
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 {
@@ -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") {
diff --git a/misc/specs/atrium-specs-common/src/main/kotlin/ch/tutteli/atrium/specs/verbs/VerbSpec.kt b/misc/specs/atrium-specs-common/src/main/kotlin/ch/tutteli/atrium/specs/verbs/VerbSpec.kt
index 52e45a5cd..339de8e67 100644
--- a/misc/specs/atrium-specs-common/src/main/kotlin/ch/tutteli/atrium/specs/verbs/VerbSpec.kt
+++ b/misc/specs/atrium-specs-common/src/main/kotlin/ch/tutteli/atrium/specs/verbs/VerbSpec.kt
@@ -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 Expect>,
forNonNullableCreator: Pair.() -> Unit) -> Expect>,
forNullable: Pair Expect>,
- forThrowable: Pair Unit) -> ThrowableThrown.Builder>,
+ forThrowable: Pair 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
}
})
diff --git a/misc/specs/atrium-specs-jvm/src/main/kotlin/ch/tutteli/atrium/specs/integration/ThrowableAssertionsJvmSpec.kt b/misc/specs/atrium-specs-jvm/src/main/kotlin/ch/tutteli/atrium/specs/integration/ThrowableAssertionsJvmSpec.kt
index 34a7e3476..117a86da3 100644
--- a/misc/specs/atrium-specs-jvm/src/main/kotlin/ch/tutteli/atrium/specs/integration/ThrowableAssertionsJvmSpec.kt
+++ b/misc/specs/atrium-specs-jvm/src/main/kotlin/ch/tutteli/atrium/specs/integration/ThrowableAssertionsJvmSpec.kt
@@ -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 {
message {
containsRegex(pattern, *otherPatterns)
diff --git a/misc/verbs-internal/atrium-verbs-internal-common/src/main/kotlin/ch.tutteli.atrium.api.verbs.internal/atriumVerbs.kt b/misc/verbs-internal/atrium-verbs-internal-common/src/main/kotlin/ch.tutteli.atrium.api.verbs.internal/atriumVerbs.kt
index bf87ac04d..a4a060a2b 100644
--- a/misc/verbs-internal/atrium-verbs-internal-common/src/main/kotlin/ch.tutteli.atrium.api.verbs.internal/atriumVerbs.kt
+++ b/misc/verbs-internal/atrium-verbs-internal-common/src/main/kotlin/ch.tutteli.atrium.api.verbs.internal/atriumVerbs.kt
@@ -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 expect(subject: T, representation: String? = null, options: ExpectOptions = ExpectOptions()): Expect =
+fun expect(subject: T, representation: String? = null, options: ExpectOptions? = null): Expect =
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 expect(
subject: T,
representation: String? = null,
- options: ExpectOptions = ExpectOptions(),
+ options: ExpectOptions? = null,
assertionCreator: Expect.() -> Unit
): Expect = expect(subject, representation, options).addAssertionsCreatedBy(assertionCreator)
@@ -46,7 +56,40 @@ fun 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 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 ExpectBuilder.OptionsStep.withMaybeRepresentationAndMaybeOptions(
+ representation: String?, options: ExpectOptions?
+): ExpectBuilder.FinalStep =
+ 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"),
diff --git a/misc/verbs-internal/atrium-verbs-internal-common/src/test/kotlin/ch/tutteli/atrium/api/verbs/internal/VerbSpec.kt b/misc/verbs-internal/atrium-verbs-internal-common/src/test/kotlin/ch/tutteli/atrium/api/verbs/internal/VerbSpec.kt
index f4278d9c8..5ec55814b 100644
--- a/misc/verbs-internal/atrium-verbs-internal-common/src/test/kotlin/ch/tutteli/atrium/api/verbs/internal/VerbSpec.kt
+++ b/misc/verbs-internal/atrium-verbs-internal-common/src/test/kotlin/ch/tutteli/atrium/api/verbs/internal/VerbSpec.kt
@@ -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() }) }
)
diff --git a/misc/verbs/atrium-verbs-common/src/main/kotlin/ch/tutteli/atrium/api.verbs/AssertionVerb.kt b/misc/verbs/atrium-verbs-common/src/main/kotlin/ch/tutteli/atrium/api.verbs/AssertionVerb.kt
index efbccfe86..61429f0a0 100644
--- a/misc/verbs/atrium-verbs-common/src/main/kotlin/ch/tutteli/atrium/api.verbs/AssertionVerb.kt
+++ b/misc/verbs/atrium-verbs-common/src/main/kotlin/ch/tutteli/atrium/api.verbs/AssertionVerb.kt
@@ -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"),
}
diff --git a/misc/verbs/atrium-verbs-common/src/main/kotlin/ch/tutteli/atrium/api.verbs/assert.kt b/misc/verbs/atrium-verbs-common/src/main/kotlin/ch/tutteli/atrium/api.verbs/assert.kt
index 8919ad2f2..af1e18514 100644
--- a/misc/verbs/atrium-verbs-common/src/main/kotlin/ch/tutteli/atrium/api.verbs/assert.kt
+++ b/misc/verbs/atrium-verbs-common/src/main/kotlin/ch/tutteli/atrium/api.verbs/assert.kt
@@ -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 assert(subject: T, representation: String? = null, options: ExpectOptions? = null): Expect =
ExpectBuilder.forSubject(subject)
@@ -32,9 +30,10 @@ fun 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 assert(
subject: T,
@@ -44,12 +43,20 @@ fun assert(
): Expect = 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 assert(
+ options: ExpectOptions? = null,
+ representation: String? = null,
+ act: () -> R
+): Expect<() -> R> = assert(act, representation, options)
@Deprecated(
"`assert` should not be nested, use `feature` instead.",
diff --git a/misc/verbs/atrium-verbs-common/src/main/kotlin/ch/tutteli/atrium/api.verbs/assertThat.kt b/misc/verbs/atrium-verbs-common/src/main/kotlin/ch/tutteli/atrium/api.verbs/assertThat.kt
index 5e5601eca..9b56135e9 100644
--- a/misc/verbs/atrium-verbs-common/src/main/kotlin/ch/tutteli/atrium/api.verbs/assertThat.kt
+++ b/misc/verbs/atrium-verbs-common/src/main/kotlin/ch/tutteli/atrium/api.verbs/assertThat.kt
@@ -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 assertThat(subject: T, representation: String? = null, options: ExpectOptions? = null): Expect =
ExpectBuilder.forSubject(subject)
@@ -32,9 +30,10 @@ fun 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 assertThat(
subject: T,
@@ -44,13 +43,20 @@ fun assertThat(
): Expect = 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 assertThat(
+ options: ExpectOptions? = null,
+ representation: String? = null,
+ act: () -> R
+): Expect<() -> R> = assertThat(act, representation, options)
@Deprecated(
"`assertThat` should not be nested, use `feature` instead.",
diff --git a/misc/verbs/atrium-verbs-common/src/main/kotlin/ch/tutteli/atrium/api.verbs/expect.kt b/misc/verbs/atrium-verbs-common/src/main/kotlin/ch/tutteli/atrium/api.verbs/expect.kt
index bbff8327c..6877a7c85 100644
--- a/misc/verbs/atrium-verbs-common/src/main/kotlin/ch/tutteli/atrium/api.verbs/expect.kt
+++ b/misc/verbs/atrium-verbs-common/src/main/kotlin/ch/tutteli/atrium/api.verbs/expect.kt
@@ -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 expect(subject: T, representation: String? = null, options: ExpectOptions? = null): Expect =
ExpectBuilder.forSubject(subject)
@@ -32,9 +30,10 @@ fun 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 expect(
subject: T,
@@ -44,22 +43,21 @@ fun expect(
): Expect = 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 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 expect(
+ options: ExpectOptions? = null,
+ representation: String? = null,
+ act: () -> R
+): Expect<() -> R> = expect(act, representation, options)
@Deprecated(
"`expect` should not be nested, use `feature` instead.",
diff --git a/misc/verbs/atrium-verbs-common/src/test/kotlin/ch/tutteli/atrium/api/verbs/VerbSpec.kt b/misc/verbs/atrium-verbs-common/src/test/kotlin/ch/tutteli/atrium/api/verbs/VerbSpec.kt
index 7ba4c7394..a4157d056 100644
--- a/misc/verbs/atrium-verbs-common/src/test/kotlin/ch/tutteli/atrium/api/verbs/VerbSpec.kt
+++ b/misc/verbs/atrium-verbs-common/src/test/kotlin/ch/tutteli/atrium/api/verbs/VerbSpec.kt
@@ -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() }) }
+)
diff --git a/translations/de_CH/atrium-translations-de_CH-common/src/main/kotlin/ch/tutteli/atrium/translations/DescriptionFunLikeAssertion.kt b/translations/de_CH/atrium-translations-de_CH-common/src/main/kotlin/ch/tutteli/atrium/translations/DescriptionFunLikeAssertion.kt
new file mode 100644
index 000000000..38061b7ed
--- /dev/null
+++ b/translations/de_CH/atrium-translations-de_CH-common/src/main/kotlin/ch/tutteli/atrium/translations/DescriptionFunLikeAssertion.kt
@@ -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"),
+}
diff --git a/translations/en_GB/atrium-translations-en_GB-common/src/main/kotlin/ch/tutteli/atrium/translations/DescriptionFunLikeAssertion.kt b/translations/en_GB/atrium-translations-en_GB-common/src/main/kotlin/ch/tutteli/atrium/translations/DescriptionFunLikeAssertion.kt
new file mode 100644
index 000000000..a65bdbdef
--- /dev/null
+++ b/translations/en_GB/atrium-translations-en_GB-common/src/main/kotlin/ch/tutteli/atrium/translations/DescriptionFunLikeAssertion.kt
@@ -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"),
+}