diff --git a/README.md b/README.md index 7ab2f103ca..0733821415 100644 --- a/README.md +++ b/README.md @@ -444,7 +444,7 @@ I expected subject : () -> kotlin.Nothing (readme.examples.ToThrowExample • java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) • java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) • java.base/java.lang.reflect.Method.invoke(Method.java:566) - » cause : + » cause : java.lang.RuntimeException » message : "a cause" » stacktrace : • readme.examples.ToThrowExamples$ex-notToThrow$1.invoke(ToThrowExamples.kt:42) @@ -1724,7 +1724,7 @@ expect(listOf(1, 2, 3, -1)).toHaveElementsAndAll { } } ``` -↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/ThirdPartyExamples.kt#L24)[Output](#ex-third-party-1) +↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/ThirdPartyExamples.kt#L25)[Output](#ex-third-party-1) ```text I expected subject : [1, 2, 3, -1] (java.util.Arrays.ArrayList <1234789>) @@ -1757,7 +1757,7 @@ fun Expect.notToBeNegative() = expect(-10).notToBeNegative() ``` -↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/ThirdPartyExamples.kt#L34)[Output](#ex-third-party-2) +↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/ThirdPartyExamples.kt#L35)[Output](#ex-third-party-2) ```text I expected subject : -10 @@ -1772,10 +1772,10 @@ I expected subject : -10 """ » stacktrace : - • readme.examples.ThirdPartyExamples$ex-third-party-2$notToBeNegative$1.invoke(ThirdPartyExamples.kt:38) - • readme.examples.ThirdPartyExamples$ex-third-party-2$notToBeNegative$1.invoke(ThirdPartyExamples.kt:36) - • readme.examples.ThirdPartyExamples.ex_third_party_2$notToBeNegative(ThirdPartyExamples.kt:36) - • readme.examples.ThirdPartyExamples.ex-third-party-2(ThirdPartyExamples.kt:48) + • readme.examples.ThirdPartyExamples$ex-third-party-2$notToBeNegative$1.invoke(ThirdPartyExamples.kt:39) + • readme.examples.ThirdPartyExamples$ex-third-party-2$notToBeNegative$1.invoke(ThirdPartyExamples.kt:37) + • readme.examples.ThirdPartyExamples.ex_third_party_2$notToBeNegative(ThirdPartyExamples.kt:37) + • readme.examples.ThirdPartyExamples.ex-third-party-2(ThirdPartyExamples.kt:49) • java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) • java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) • java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) @@ -1793,7 +1793,7 @@ Atrium (and create a PR so that others benefit as well 😉): import ch.tutteli.atrium.logic._logic fun Expect.notToBeNegative() = - _logic.createAndAppend("not to be", Text("negative")) { subject -> + _core.createAndAppend("not to be", Text("negative")) { subject -> when (subject) { is Int -> subject.sign >= 0 is Long -> subject.sign >= 0 @@ -1807,7 +1807,7 @@ fun Expect.notToBeNegative() = expect(-10).notToBeNegative() ``` -↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/ThirdPartyExamples.kt#L52)[Output](#ex-third-party-3) +↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/ThirdPartyExamples.kt#L53)[Output](#ex-third-party-3) ```text I expected subject : -10 @@ -1989,7 +1989,7 @@ my expectations : ✘ calling myFun with -2147483648 : ✘ ▶ I expected subject : null » to contain : - • value : + • value : "min" » but no match was found ✘ calling myFun with 2147483647 : ✘ ▶ I expected subject : "2147483647" @@ -2110,7 +2110,7 @@ I expected subject : () -> kotlin.Nothing (readme.examples.MostExamples$e » ▶ message : • not to equal: null but to be an instance of : String (kotlin.String) -- Class: java.lang.String • to contain : - • value : + • value : "no no no" » but no match was found ℹ️ Properties of the unexpected IllegalArgumentException » message : "no no no..." @@ -2122,7 +2122,7 @@ I expected subject : () -> kotlin.Nothing (readme.examples.MostExamples$e • java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) • java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) • java.base/java.lang.reflect.Method.invoke(Method.java:566) - » cause : + » cause : java.lang.UnsupportedOperationException » message : "not supported" » stacktrace : • readme.examples.MostExamples$ex-add-info-3$1.invoke(MostExamples.kt:115) @@ -2217,7 +2217,7 @@ This is kind of the simplest way of defining expectation functions. Following an import ch.tutteli.atrium.logic._logic fun Expect.toBeAMultipleOf(base: Int) = - _logic.createAndAppend("is multiple of", base) { it % base == 0 } + _core.createAndAppend("is multiple of", base) { it % base == 0 } ``` @@ -2228,7 +2228,7 @@ and its usage: ```kotlin expect(12).toBeAMultipleOf(5) ``` -↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/OwnExpectationFunctions.kt#L33)[Output](#ex-own-boolean-1) +↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/OwnExpectationFunctions.kt#L34)[Output](#ex-own-boolean-1) ```text I expected subject : 12 @@ -2263,7 +2263,7 @@ Consider the following expectation function: import ch.tutteli.atrium.logic._logic fun Expect.toBeEven() = - _logic.createAndAppend("is", Text("an even number")) { it % 2 == 0 } + _core.createAndAppend("is", Text("an even number")) { it % 2 == 0 } ``` @@ -2276,7 +2276,7 @@ Its usage looks then as follows: ```kotlin expect(13).toBeEven() ``` -↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/OwnExpectationFunctions.kt#L48)[Output](#ex-own-boolean-2) +↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/OwnExpectationFunctions.kt#L49)[Output](#ex-own-boolean-2) ```text I expected subject : 13 @@ -2305,7 +2305,7 @@ fun Expect.toComplyValidation() = expect(MyDomainModel(alpha1 = 1204)).toComplyValidation() ``` -↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/ThirdPartyExamples.kt#L79)[Output](#ex-third-party-10) +↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/ThirdPartyExamples.kt#L80)[Output](#ex-third-party-10) ```text I expected subject : MyDomainModel(alpha1=1204) (readme.examples.ThirdPartyExamples.MyDomainModel <1234789>) @@ -2313,11 +2313,11 @@ I expected subject : MyDomainModel(alpha1=1204) (readme.examples.ThirdPar ℹ️ Properties of the unexpected IllegalStateException » message : "threshold value for alpha1 exceeded, expected <= 1000, was 1204" » stacktrace : - • readme.examples.ThirdPartyExamples.validateMaxThreshold(ThirdPartyExamples.kt:75) - • readme.examples.ThirdPartyExamples$ex-third-party-10$toComplyValidation$1.invoke(ThirdPartyExamples.kt:83) - • readme.examples.ThirdPartyExamples$ex-third-party-10$toComplyValidation$1.invoke(ThirdPartyExamples.kt:81) - • readme.examples.ThirdPartyExamples.ex_third_party_10$toComplyValidation(ThirdPartyExamples.kt:81) - • readme.examples.ThirdPartyExamples.ex-third-party-10(ThirdPartyExamples.kt:87) + • readme.examples.ThirdPartyExamples.validateMaxThreshold(ThirdPartyExamples.kt:76) + • readme.examples.ThirdPartyExamples$ex-third-party-10$toComplyValidation$1.invoke(ThirdPartyExamples.kt:84) + • readme.examples.ThirdPartyExamples$ex-third-party-10$toComplyValidation$1.invoke(ThirdPartyExamples.kt:82) + • readme.examples.ThirdPartyExamples.ex_third_party_10$toComplyValidation(ThirdPartyExamples.kt:82) + • readme.examples.ThirdPartyExamples.ex-third-party-10(ThirdPartyExamples.kt:88) • java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) • java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) • java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) @@ -2412,7 +2412,7 @@ Its usage is then as follows: expect(Person("Susanne", "Whitley", 43, emptyList())) .toHaveNumberOfChildren(2) ``` -↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/OwnExpectationFunctions.kt#L67)[Output](#ex-own-compose-3) +↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/OwnExpectationFunctions.kt#L68)[Output](#ex-own-compose-3) ```text I expected subject : Person(firstName=Susanne, lastName=Whitley, age=43, children=[]) (readme.examples.Person <1234789>) @@ -2448,7 +2448,7 @@ I.e. it fails for a `Person` with 0 children, because such a person does not hav expect(Person("Susanne", "Whitley", 43, emptyList())) .toHaveAdultChildren() ``` -↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/OwnExpectationFunctions.kt#L86)[Output](#ex-own-compose-4) +↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/OwnExpectationFunctions.kt#L87)[Output](#ex-own-compose-4) ```text I expected subject : Person(firstName=Susanne, lastName=Whitley, age=43, children=[]) (readme.examples.Person <1234789>) @@ -2494,7 +2494,7 @@ expect(Person("Susanne", "Whitley", 43, listOf(Person("Petra", "Whitley", 12, em feature { f(it::age) }.toBeGreaterThan(18) } ``` -↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/OwnExpectationFunctions.kt#L97)[Output](#ex-own-compose-5) +↑ [Example](https://github.com/robstoll/atrium/tree/main/misc/tools/readme-examples/src/test/kotlin/readme/examples/OwnExpectationFunctions.kt#L98)[Output](#ex-own-compose-5) ```text I expected subject : Person(firstName=Susanne, lastName=Whitley, age=43, children=[Person(firstName=Petra, lastName=Whitley, age=12, children=[])]) (readme.examples.Person <1234789>) @@ -2521,6 +2521,7 @@ because Kotlin cannot infer the types automatically. ```kotlin +import ch.tutteli.atrium._core import ch.tutteli.atrium.logic.utils.mapArguments fun >> Expect.areNamesOf( diff --git a/apis/fluent/atrium-api-fluent/src/commonTest/kotlin/ch/tutteli/atrium/api/fluent/en_GB/FeatureWorstCaseTest.kt b/apis/fluent/atrium-api-fluent/src/commonTest/kotlin/ch/tutteli/atrium/api/fluent/en_GB/FeatureWorstCaseTest.kt index dc54416eb2..d9f17b86a9 100644 --- a/apis/fluent/atrium-api-fluent/src/commonTest/kotlin/ch/tutteli/atrium/api/fluent/en_GB/FeatureWorstCaseTest.kt +++ b/apis/fluent/atrium-api-fluent/src/commonTest/kotlin/ch/tutteli/atrium/api/fluent/en_GB/FeatureWorstCaseTest.kt @@ -1,4 +1,3 @@ -@file:Suppress("UNUSED_PARAMETER", "unused") package ch.tutteli.atrium.api.fluent.en_GB @@ -15,13 +14,12 @@ class WorstCase { fun overloaded(b: Boolean): Int = 1 } - -@Suppress(/* requires new type inference */ "RemoveExplicitTypeArguments") +// we don't run any tests in here but check that the compiler does not report any ambiguities fun testOverloadAmbiguity() { expect(WorstCase()) { - feature { p(it::propAndFun) } - feature { f0(it::propAndFun) } - feature { f0(it::overloaded) } - feature { f1(it::overloaded, true) } + feature { p(it::propAndFun) } + feature { f0(it::propAndFun) } + feature { f0(it::overloaded) } + feature { f1(it::overloaded, true) } } } diff --git a/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/creating/proofs/builders/EntryPointProofBuilder.kt b/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/creating/proofs/builders/EntryPointProofBuilder.kt index ab096fa4f7..be5dedb5c1 100644 --- a/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/creating/proofs/builders/EntryPointProofBuilder.kt +++ b/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/creating/proofs/builders/EntryPointProofBuilder.kt @@ -28,6 +28,12 @@ fun ProofContainer.buildProof(init: EntryPointProofBuilder.() -> Unit) @DslMarker annotation class ProofBuilderMarker +//TODO 1.4.0 also introduce a DslMarker for Atrium as such to prevent scenarios as the following: +// expect{ .. }.toThrow<...> { +// message { message { } } +// } +// makes it look like `message` has again a `message` feature where in reality its the same, +// a DslMarker should prevent this //TODO 1.3.0 remove again? typealias AnyBuilder = BaseGroupBuilder<*, *, *> diff --git a/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/creating/transformers/propertiesOfThrowable.kt b/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/creating/transformers/propertiesOfThrowable.kt index 852ff8df8e..9e9f491fc0 100644 --- a/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/creating/transformers/propertiesOfThrowable.kt +++ b/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/creating/transformers/propertiesOfThrowable.kt @@ -50,7 +50,7 @@ private fun AnyBuilder.addHints( private fun AnyBuilder.addMessageHint(throwable: Throwable) = row { column(OCCURRED_EXCEPTION_MESSAGE) - column(throwable.message?.let { Text(it) } ?: Text.NULL) + column(Reportable.representation(throwable.message)) } private fun AnyBuilder.addStackTraceHint( @@ -64,7 +64,7 @@ private fun AnyBuilder.addStackTraceHint( throwable.stackBacktrace.asSequence() } stackTrace.forEach { - add(Text(it)) + text(it) } } } @@ -89,7 +89,7 @@ fun AnyBuilder.addChildHint( ) { val secondStackTrace = takeIf(throwable.stackBacktrace.size > 1) { throwable.stackBacktrace[1] } - reportableGroup(childDescription, Text.EMPTY) { + reportableGroup(childDescription, child) { addHints(child, secondStackTrace) } } diff --git a/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/reporting/prerendering/text/impl/DefaultFallbackReportableGroupWithDesignationTextPreRenderer.kt b/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/reporting/prerendering/text/impl/DefaultFallbackReportableGroupWithDesignationTextPreRenderer.kt index 08ec109cd5..fbcb3dee9f 100644 --- a/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/reporting/prerendering/text/impl/DefaultFallbackReportableGroupWithDesignationTextPreRenderer.kt +++ b/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/reporting/prerendering/text/impl/DefaultFallbackReportableGroupWithDesignationTextPreRenderer.kt @@ -1,16 +1,16 @@ package ch.tutteli.atrium.reporting.prerendering.text.impl -import ch.tutteli.atrium.creating.proofs.ProofGroupWithDesignation -import ch.tutteli.atrium.reporting.reportables.Icon -import ch.tutteli.atrium.reporting.prerendering.text.TextPreRenderControlObject import ch.tutteli.atrium.reporting.prerendering.text.OutputNode +import ch.tutteli.atrium.reporting.prerendering.text.TextPreRenderControlObject import ch.tutteli.atrium.reporting.prerendering.text.TypedTextPreRenderer import ch.tutteli.atrium.reporting.prerendering.text.transformSubProofGroup +import ch.tutteli.atrium.reporting.reportables.Icon +import ch.tutteli.atrium.reporting.reportables.ReportableGroupWithDesignation internal class DefaultFallbackReportableGroupWithDesignationTextPreRenderer : - TypedTextPreRenderer(ProofGroupWithDesignation::class) { + TypedTextPreRenderer(ReportableGroupWithDesignation::class) { override fun transformIt( - reportable: ProofGroupWithDesignation, + reportable: ReportableGroupWithDesignation, controlObject: TextPreRenderControlObject ): List { val newControlObject = diff --git a/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/reporting/prerendering/text/impl/assertion/DefaultAssertionGroupTextPreRenderer.kt b/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/reporting/prerendering/text/impl/assertion/DefaultAssertionGroupTextPreRenderer.kt index effd1ab8db..80df134b86 100644 --- a/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/reporting/prerendering/text/impl/assertion/DefaultAssertionGroupTextPreRenderer.kt +++ b/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/reporting/prerendering/text/impl/assertion/DefaultAssertionGroupTextPreRenderer.kt @@ -1,9 +1,11 @@ //TODO 2.0.0 remove file @file:Suppress("DEPRECATION") + package ch.tutteli.atrium.reporting.prerendering.text.impl.assertion import ch.tutteli.atrium.assertions.* import ch.tutteli.atrium.creating.proofs.Proof +import ch.tutteli.atrium.reporting.Text import ch.tutteli.atrium.reporting.filters.ReportableFilter import ch.tutteli.atrium.reporting.reportables.Icon import ch.tutteli.atrium.reporting.prerendering.text.TextPreRenderControlObject @@ -62,7 +64,22 @@ class DefaultAssertionGroupTextPreRenderer(private val iconStyler: TextIconStyle } is ListAssertionGroupType -> - controlObject.transformSubProofGroup(reportable, controlObject, Icon.LIST_BULLET_POINT) + if (controlObject.explainsProof && assertionGroup.representation != Text.EMPTY) { + // if we are in an ExplanatoryAssertionGroup, and the listGroup has a representation, + // then we want to show it in reporting (with proofs, a debugGroup never consists of proofs + // and hence this + controlObject.transformSubProofGroup(reportable, controlObject.copy(explainsProof = false)) { child -> + val newControlObject = determineChildControlObject( + controlObject, + child, + Icon.LIST_BULLET_POINT, + additionalIndent = 1 + ) + controlObject.transformChildIncludingIndentationAndPrefix(child, newControlObject) + } + } else { + controlObject.transformSubProofGroup(reportable, controlObject, Icon.LIST_BULLET_POINT) + } is SummaryAssertionGroupType -> controlObject.transformSubProofGroup( reportable, diff --git a/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/reporting/reportables/Reportable.kt b/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/reporting/reportables/Reportable.kt index 39360c4c77..07397d9df7 100644 --- a/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/reporting/reportables/Reportable.kt +++ b/atrium-core/src/commonMain/kotlin/ch/tutteli/atrium/reporting/reportables/Reportable.kt @@ -2,7 +2,6 @@ package ch.tutteli.atrium.reporting.reportables import ch.tutteli.atrium.creating.proofs.InvisibleProofGroup import ch.tutteli.atrium.creating.proofs.Proof -import ch.tutteli.atrium.creating.proofs.unwrapInvisibleGroup import ch.tutteli.atrium.reporting.HorizontalAlignment import ch.tutteli.atrium.reporting.Text import ch.tutteli.atrium.reporting.reportables.impl.* diff --git a/atrium-core/src/commonTest/kotlin/ch/tutteli/atrium/reporting/CreateReportTest.kt b/atrium-core/src/commonTest/kotlin/ch/tutteli/atrium/reporting/CreateReportTest.kt index 97166ad584..454675c509 100644 --- a/atrium-core/src/commonTest/kotlin/ch/tutteli/atrium/reporting/CreateReportTest.kt +++ b/atrium-core/src/commonTest/kotlin/ch/tutteli/atrium/reporting/CreateReportTest.kt @@ -17,8 +17,11 @@ import ch.tutteli.atrium.reporting.prerendering.text.TypedTextPreRenderer import ch.tutteli.atrium.reporting.reportables.Icon import ch.tutteli.atrium.reporting.reportables.InlineElement import ch.tutteli.atrium.reporting.reportables.Reportable +import ch.tutteli.atrium.reporting.reportables.Representation import ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionAnyProof import ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionCharSequenceProof +import ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionThrowableProof +import ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionThrowableProof.OCCURRED_EXCEPTION_STACKTRACE import ch.tutteli.atrium.reporting.reportables.descriptions.ErrorMessages import ch.tutteli.atrium.reporting.text.TextReporter import ch.tutteli.atrium.reporting.theming.text.StyledString @@ -259,7 +262,7 @@ class CreateReportTest { |a verb : /usr/bin/noprogram |(f) to : exist |(d) properties of unexpected exception :${" "} - | • message : oho... + | • message : "oho..." """.trimMargin() ) expectForReporterWithAnsi( @@ -268,7 +271,49 @@ class CreateReportTest { |a verb : /usr/bin/noprogram |$x to : exist |$d properties of unexpected exception :${" "} - | • message : oho... + | • message : "oho..." + """.trimMargin() + ) + } + + @Test + fun debugGroup_withReportableGroup() { + val builder = buildRootGroup(representation = Text("/usr/bin/noprogram")) { + simpleProof(Text("to"), Text("exist")) { false } + debugGroup(Text("properties of unexpected exception")) { + reportableGroup(OCCURRED_EXCEPTION_STACKTRACE, Text.EMPTY) { + text("com.example.MyClass:32:8") + } + reportableGroup(DescriptionThrowableProof.OCCURRED_EXCEPTION_CAUSE, IllegalStateException("oho..")){ + row { + column(Text("message")) + column(Reportable.representation("oho...")) + } + } + } + } + expectForReporterWithoutAnsi( + builder, + """ + |a verb : /usr/bin/noprogram + |(f) to : exist + |(d) properties of unexpected exception :${" "} + | • stacktrace :${" "} + | • com.example.MyClass:32:8 + | • cause : java.lang.IllegalStateException + | • message : "oho..." + """.trimMargin() + ) + expectForReporterWithAnsi( + builder, + """ + |a verb : /usr/bin/noprogram + |$x to : exist + |$d properties of unexpected exception :${" "} + | • stacktrace :${" "} + | • com.example.MyClass:32:8 + | • cause : java.lang.IllegalStateException + | • message : "oho..." """.trimMargin() ) } @@ -801,6 +846,29 @@ class CreateReportTest { BasicExplanatoryAssertion(Text("test")), BasicExplanatoryAssertion(Text("lines")) ) + ), + BasicAssertionGroup( + DefaultListAssertionGroupType, + DescriptionThrowableExpectation.OCCURRED_EXCEPTION_CAUSE, + IllegalStateException("oho.. error occurred"), + listOf( + ExplanatoryAssertionGroup( + DefaultExplanatoryAssertionGroupType, listOf( + BasicDescriptiveAssertion( + DescriptionThrowableExpectation.OCCURRED_EXCEPTION_MESSAGE, + "oho.. error occurred" + ) { true }, + BasicAssertionGroup( + DefaultListAssertionGroupType, + DescriptionThrowableExpectation.OCCURRED_EXCEPTION_STACKTRACE, + Text.EMPTY, + listOf( + BasicExplanatoryAssertion(Text("some other line")) + ) + ), + ), holds = true + ) + ) ) ), holds = true ) @@ -817,6 +885,10 @@ class CreateReportTest { | » stacktrace :${" "} | • test | • lines + | » cause : java.lang.IllegalStateException + | » message : "oho.. error occurred" + | » stacktrace :${" "} + | • some other line """.trimMargin() ) expectForReporterWithAnsi( @@ -828,6 +900,10 @@ class CreateReportTest { | » stacktrace :${" "} | • test | • lines + | » cause : java.lang.IllegalStateException + | » message : "oho.. error occurred" + | » stacktrace :${" "} + | • some other line """.trimMargin() ) } diff --git a/misc/atrium-specs/src/commonMain/kotlin/ch/tutteli/atrium/specs/defaultBulletPoints.kt b/misc/atrium-specs/src/commonMain/kotlin/ch/tutteli/atrium/specs/defaultBulletPoints.kt index e8e80935df..1dac4fd437 100644 --- a/misc/atrium-specs/src/commonMain/kotlin/ch/tutteli/atrium/specs/defaultBulletPoints.kt +++ b/misc/atrium-specs/src/commonMain/kotlin/ch/tutteli/atrium/specs/defaultBulletPoints.kt @@ -6,7 +6,7 @@ package ch.tutteli.atrium.specs import ch.tutteli.atrium.assertions.* const val rootBulletPoint = "◆ " -const val listBulletPoint = "⚬ " +const val listBulletPoint = "• " const val featureArrow = "▶ " const val featureBulletPoint = "◾ " diff --git a/misc/atrium-specs/src/commonMain/kotlin/ch/tutteli/atrium/specs/integration/FeatureExpectationsSpec.kt b/misc/atrium-specs/src/commonMain/kotlin/ch/tutteli/atrium/specs/integration/FeatureExpectationsSpec.kt index fcf657b45d..b529433a46 100644 --- a/misc/atrium-specs/src/commonMain/kotlin/ch/tutteli/atrium/specs/integration/FeatureExpectationsSpec.kt +++ b/misc/atrium-specs/src/commonMain/kotlin/ch/tutteli/atrium/specs/integration/FeatureExpectationsSpec.kt @@ -229,7 +229,10 @@ abstract class FeatureExpectationsSpec( expect { expect(TestData("hello robert and some additional text", 1)).itsLazyWithNestedImmediate() }.toThrow { - messageToContain("$lazyWithNestedImmediateFeatureInfo: 37", "$toEqualDescr: 12") + message { + toContainDescr(lazyWithNestedImmediateFeatureInfo, 37) + toContainToEqualDescr(12) + } } } } @@ -241,7 +244,10 @@ abstract class FeatureExpectationsSpec( expect { expect(TestData("hello robert and some additional text", 1)).itsLazyWithNestedLazy() }.toThrow { - messageToContain("$lazyWithNestedLazyFeatureInfo: 37", "$toEqualDescr: 12") + message { + toContainDescr(lazyWithNestedLazyFeatureInfo, 37) + toContainToEqualDescr(12) + } } } } diff --git a/misc/atrium-specs/src/commonMain/kotlin/ch/tutteli/atrium/specs/integration/FloatingPointWithErrorToleranceExpectationsSpec.kt b/misc/atrium-specs/src/commonMain/kotlin/ch/tutteli/atrium/specs/integration/FloatingPointWithErrorToleranceExpectationsSpec.kt index 4f64275988..f777aa2314 100644 --- a/misc/atrium-specs/src/commonMain/kotlin/ch/tutteli/atrium/specs/integration/FloatingPointWithErrorToleranceExpectationsSpec.kt +++ b/misc/atrium-specs/src/commonMain/kotlin/ch/tutteli/atrium/specs/integration/FloatingPointWithErrorToleranceExpectationsSpec.kt @@ -100,11 +100,9 @@ fun Root.checkFloatingPoint( @Suppress("DEPRECATION") formatFloatingPointNumber(tolerance) ) - toContain( - subject, - "$toEqualInclErrorToleranceDescr: $num", - exactCheck - ) + toContainSubject(subject) + toContainDescr(toEqualInclErrorToleranceDescr, num) + toContain(exactCheck) if (withFailureNotice) { toContain(failureNotice) } else { diff --git a/misc/atrium-specs/src/commonMain/kotlin/ch/tutteli/atrium/specs/integration/Fun0ExpectationsSpec.kt b/misc/atrium-specs/src/commonMain/kotlin/ch/tutteli/atrium/specs/integration/Fun0ExpectationsSpec.kt index b36cb064cf..e6db03f3c1 100644 --- a/misc/atrium-specs/src/commonMain/kotlin/ch/tutteli/atrium/specs/integration/Fun0ExpectationsSpec.kt +++ b/misc/atrium-specs/src/commonMain/kotlin/ch/tutteli/atrium/specs/integration/Fun0ExpectationsSpec.kt @@ -2,13 +2,12 @@ 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.core.polyfills.format import ch.tutteli.atrium.core.polyfills.fullName import ch.tutteli.atrium.creating.Expect +import ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionAnyProof +import ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionFunLikeProof +import ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionThrowableProof import ch.tutteli.atrium.specs.* -import ch.tutteli.atrium.translations.DescriptionFunLikeExpectation -import ch.tutteli.atrium.translations.DescriptionFunLikeExpectation.NO_EXCEPTION_OCCURRED -import ch.tutteli.atrium.translations.DescriptionFunLikeExpectation.THROWN_EXCEPTION_WHEN_CALLED import ch.tutteli.atrium.translations.DescriptionThrowableExpectation import org.spekframework.spek2.Spek import org.spekframework.spek2.style.specification.Suite @@ -55,15 +54,15 @@ abstract class Fun0ExpectationsSpec( fun describeFun(vararg pairs: SpecPair<*>, body: Suite.() -> Unit) = describeFunTemplate(describePrefix, pairs.map { it.name }.toTypedArray(), body = body) - val messageDescr = DescriptionThrowableExpectation.OCCURRED_EXCEPTION_MESSAGE.getDefault() - val stackTraceDescr = DescriptionThrowableExpectation.OCCURRED_EXCEPTION_STACKTRACE.getDefault() - val causeDescr = DescriptionThrowableExpectation.OCCURRED_EXCEPTION_CAUSE.getDefault() + val messageDescr = DescriptionThrowableProof.OCCURRED_EXCEPTION_MESSAGE.string + val stackTraceDescr = DescriptionThrowableProof.OCCURRED_EXCEPTION_STACKTRACE.string + val causeDescr = DescriptionThrowableProof.OCCURRED_EXCEPTION_CAUSE.string val separator = lineSeparator val errMessage = "oho... error occurred" fun messageAndStackTrace(message: String) = - "\\s+\\Q$explanatoryBulletPoint\\E$messageDescr: \"$message\".*$separator" + - "\\s+\\Q$explanatoryBulletPoint\\E$stackTraceDescr: $separator" + + "\\s+\\Q$explanatoryBulletPoint\\E$messageDescr\\s+: \"$message\".*$separator" + + "\\s+\\Q$explanatoryBulletPoint\\E$stackTraceDescr\\s+: $separator" + "\\s+\\Q$listBulletPoint\\E${Fun0ExpectationsSpec::class.fullName}" describeFun(toThrowFeature, toThrow, notToThrowFeature, notToThrow) { @@ -83,12 +82,16 @@ abstract class Fun0ExpectationsSpec( } }.toThrow { message { - toContain.exactly(1).values( - "${THROWN_EXCEPTION_WHEN_CALLED.getDefault()}: " + - NO_EXCEPTION_OCCURRED.getDefault(), - "$toBeAnInstanceOfDescr: ${IllegalArgumentException::class.simpleName}" + toContainSubject("() -> kotlin.Int") + toContainDescr( + DescriptionFunLikeProof.THROWN_EXCEPTION_WHEN_CALLED, + DescriptionFunLikeProof.NO_EXCEPTION_OCCURRED.string ) - if (hasExtraHint) toContain("$toEqualDescr: ${IllegalArgumentException::class.fullName}") + toContainDescr( + DescriptionAnyProof.TO_BE_AN_INSTANCE_OF, + IllegalArgumentException::class.simpleName + ) + if (hasExtraHint) toContainToEqualDescr(IllegalArgumentException::class.fullName) } } } @@ -104,7 +107,7 @@ abstract class Fun0ExpectationsSpec( it("$name - shows return value in case sub-assertion fails") { expect { expect { 123456789 }.notToThrowFun { toEqual(1) } - }.toThrow() { + }.toThrow { messageToContain("123456789") } } @@ -133,11 +136,11 @@ abstract class Fun0ExpectationsSpec( }.toThrow { message { toContainRegex( - "$toBeAnInstanceOfDescr:.+" + IllegalArgumentException::class.fullName, + "$toBeAnInstanceOfDescr\\s+:.+" + IllegalArgumentException::class.fullName, UnsupportedOperationException::class.simpleName + separator + messageAndStackTrace(errMessage) ) - if (hasExtraHint) toContain("$toEqualDescr: \"hello\"") + if (hasExtraHint) toContainToEqualDescr("\"hello\"") } } } @@ -155,14 +158,11 @@ abstract class Fun0ExpectationsSpec( }.toThrow { message { toContainRegex( - "\\Qinvoke()\\E: ${ - DescriptionFunLikeExpectation.THREW.getDefault() - .format(UnsupportedOperationException::class.fullName) - }", + "\\Qinvoke()\\E\\s+: ${DescriptionFunLikeProof.THREW.string} ${UnsupportedOperationException::class.fullName}", UnsupportedOperationException::class.simpleName + separator + messageAndStackTrace(errMessage) ) - if (hasExtraHint) toContain("$toEqualDescr: 2") + if (hasExtraHint) toContainToEqualDescr(2) } } } @@ -178,7 +178,7 @@ abstract class Fun0ExpectationsSpec( toContainRegex( UnsupportedOperationException::class.simpleName + separator + messageAndStackTrace("not supported"), - "\\s+\\Q$explanatoryBulletPoint\\E$causeDescr: ${IllegalStateException::class.fullName}" + + "\\s+\\Q$explanatoryBulletPoint\\E$causeDescr\\s+: ${IllegalStateException::class.fullName}.*" +separator + messageAndStackTrace(errMessage) ) @@ -195,7 +195,7 @@ abstract class Fun0ExpectationsSpec( }.toThrowFun { message.toEqual("hello") } }.toThrow { expectCauseInReporting() - if (hasExtraHint) messageToContain("$toEqualDescr: \"hello\"") + if (hasExtraHint) message { toContainToEqualDescr("\"hello\"") } } } } @@ -208,7 +208,7 @@ abstract class Fun0ExpectationsSpec( }.notToThrowFun { toEqual(2) } }.toThrow { expectCauseInReporting() - if (hasExtraHint) messageToContain("$toEqualDescr: 2") + if (hasExtraHint) message { toContainToEqualDescr(2) } } } } @@ -224,9 +224,9 @@ abstract class Fun0ExpectationsSpec( toContainRegex( UnsupportedOperationException::class.simpleName + separator + messageAndStackTrace("not supported"), - "\\s+\\Q$explanatoryBulletPoint\\E$causeDescr: ${RuntimeException::class.fullName}" + + "\\s+\\Q$explanatoryBulletPoint\\E$causeDescr\\s+: ${RuntimeException::class.fullName}" + separator + messageAndStackTrace("io"), - "\\s+\\Q$explanatoryBulletPoint\\E$causeDescr: ${IllegalStateException::class.fullName}" + + "\\s+\\Q$explanatoryBulletPoint\\E$causeDescr\\s+: ${IllegalStateException::class.fullName}" + messageAndStackTrace(errMessage) ) } @@ -240,7 +240,7 @@ abstract class Fun0ExpectationsSpec( }.toThrowFun { message.toEqual("hello") } }.toThrow { expectCauseAndNestedInReporting() - if (hasExtraHint) messageToContain("$toEqualDescr: \"hello\"") + if (hasExtraHint) message { toContainToEqualDescr("\"hello\"") } } } } @@ -253,7 +253,7 @@ abstract class Fun0ExpectationsSpec( }.notToThrowFun { toEqual(2) } }.toThrow { expectCauseAndNestedInReporting() - if (hasExtraHint) messageToContain("$toEqualDescr: 2") + if (hasExtraHint) message { toContainToEqualDescr(2) } } } } diff --git a/misc/tools/readme-examples/src/test/kotlin/readme/examples/OwnExpectationFunctions.kt b/misc/tools/readme-examples/src/test/kotlin/readme/examples/OwnExpectationFunctions.kt index ba60dd8af0..f77dc5fa47 100644 --- a/misc/tools/readme-examples/src/test/kotlin/readme/examples/OwnExpectationFunctions.kt +++ b/misc/tools/readme-examples/src/test/kotlin/readme/examples/OwnExpectationFunctions.kt @@ -1,5 +1,6 @@ package readme.examples//@formatter:off //snippet-mapArguments-start +import ch.tutteli.atrium._core import ch.tutteli.atrium.logic.utils.mapArguments //snippet-mapArguments-end //snippet-own-boolean-import-start @@ -21,7 +22,7 @@ class OwnExpectationFunctions : ReadmeTest { //snippet-own-boolean-1-start fun Expect.toBeAMultipleOf(base: Int) = - _logic.createAndAppend("is multiple of", base) { it % base == 0 } + _core.createAndAppend("is multiple of", base) { it % base == 0 } //snippet-own-boolean-1-end @Test fun `code-own-boolean-1`() { @@ -36,7 +37,7 @@ class OwnExpectationFunctions : ReadmeTest { //snippet-own-boolean-2-start fun Expect.toBeEven() = - _logic.createAndAppend("is", Text("an even number")) { it % 2 == 0 } + _core.createAndAppend("is", Text("an even number")) { it % 2 == 0 } //snippet-own-boolean-2-end @Test fun `code-own-boolean-2`() { diff --git a/misc/tools/readme-examples/src/test/kotlin/readme/examples/ThirdPartyExamples.kt b/misc/tools/readme-examples/src/test/kotlin/readme/examples/ThirdPartyExamples.kt index a42be431a5..4450a6348f 100644 --- a/misc/tools/readme-examples/src/test/kotlin/readme/examples/ThirdPartyExamples.kt +++ b/misc/tools/readme-examples/src/test/kotlin/readme/examples/ThirdPartyExamples.kt @@ -1,5 +1,6 @@ package readme.examples +import ch.tutteli.atrium._core import ch.tutteli.atrium.api.fluent.en_GB.* import ch.tutteli.atrium.creating.Expect //@formatter:off @@ -53,7 +54,7 @@ class ThirdPartyExamples : ReadmeTest { //snippet-logic-import-insert fun Expect.notToBeNegative() = - _logic.createAndAppend("not to be", Text("negative")) { subject -> + _core.createAndAppend("not to be", Text("negative")) { subject -> when (subject) { is Int -> subject.sign >= 0 is Long -> subject.sign >= 0 diff --git a/translations/atrium-translations-en_GB/src/commonMain/kotlin/ch/tutteli/atrium/translations/DescriptionFunLikeExpectation.kt b/translations/atrium-translations-en_GB/src/commonMain/kotlin/ch/tutteli/atrium/translations/DescriptionFunLikeExpectation.kt index 72cc211765..ba10197a7e 100644 --- a/translations/atrium-translations-en_GB/src/commonMain/kotlin/ch/tutteli/atrium/translations/DescriptionFunLikeExpectation.kt +++ b/translations/atrium-translations-en_GB/src/commonMain/kotlin/ch/tutteli/atrium/translations/DescriptionFunLikeExpectation.kt @@ -9,13 +9,29 @@ import ch.tutteli.atrium.reporting.translating.StringBasedTranslatable /** * Contains the [DescriptiveAssertion.description]s of the assertion functions which are applicable to [Any]. */ +@Deprecated( + "Switch to DescriptionFunLikeProof from core, will be removed with 2.0.0 at the latest", + ReplaceWith("ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionFunLikeProof") +) enum class DescriptionFunLikeExpectation(override val value: String) : StringBasedTranslatable { + @Deprecated( + "will be removed with 2.0.0 at the latest", + ReplaceWith("ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionFunLikeProof.NO_EXCEPTION_OCCURRED") + ) /** @since 0.18.0 */ NO_EXCEPTION_OCCURRED("❗❗ no exception occurred"), + @Deprecated( + "will be removed with 2.0.0 at the latest", + ReplaceWith("ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionFunLikeProof.THROWN_EXCEPTION_WHEN_CALLED") + ) /** @since 0.18.0 */ THROWN_EXCEPTION_WHEN_CALLED("thrown exception when called"), + @Deprecated( + "will be removed with 2.0.0 at the latest", + ReplaceWith("ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionFunLikeProof.THREW") + ) /** @since 0.18.0 */ THREW("❗❗ threw %s") } diff --git a/translations/atrium-translations-en_GB/src/commonMain/kotlin/ch/tutteli/atrium/translations/DescriptionThrowableExpectation.kt b/translations/atrium-translations-en_GB/src/commonMain/kotlin/ch/tutteli/atrium/translations/DescriptionThrowableExpectation.kt index 3fbb34b44f..8a01858289 100644 --- a/translations/atrium-translations-en_GB/src/commonMain/kotlin/ch/tutteli/atrium/translations/DescriptionThrowableExpectation.kt +++ b/translations/atrium-translations-en_GB/src/commonMain/kotlin/ch/tutteli/atrium/translations/DescriptionThrowableExpectation.kt @@ -9,26 +9,57 @@ import ch.tutteli.atrium.reporting.translating.StringBasedTranslatable /** * Contains the [DescriptiveAssertion.description]s of the assertion functions which are applicable to [Throwable]. */ +@Deprecated( + "Switch to DescriptionThrowableProof from core, will be removed with 2.0.0 at the latest", + ReplaceWith("ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionThrowableProof") +) enum class DescriptionThrowableExpectation(override val value: String) : StringBasedTranslatable { - + @Deprecated( + "will be removed with 2.0.0 at the latest", + ReplaceWith("ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionThrowableProof.CAUSE") + ) /** @since 0.18.0 */ CAUSE("cause"), + @Deprecated( + "will be removed with 2.0.0 at the latest", + ReplaceWith("ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionThrowableProof.HAS_NO_CAUSE") + ) /** @since 0.18.0 */ HAS_NO_CAUSE("❗❗ not caused by another exception"), + @Deprecated( + "will be removed with 2.0.0 at the latest", + ReplaceWith("ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionThrowableProof.OCCURRED_EXCEPTION_CAUSE") + ) /** @since 0.18.0 */ OCCURRED_EXCEPTION_CAUSE("cause"), + @Deprecated( + "will be removed with 2.0.0 at the latest", + ReplaceWith("ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionThrowableProof.OCCURRED_EXCEPTION_PROPERTIES") + ) /** @since 0.18.0 */ OCCURRED_EXCEPTION_PROPERTIES("Properties of the unexpected %s"), + @Deprecated( + "will be removed with 2.0.0 at the latest", + ReplaceWith("ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionThrowableProof.OCCURRED_EXCEPTION_MESSAGE") + ) /** @since 0.18.0 */ OCCURRED_EXCEPTION_MESSAGE("message"), + @Deprecated( + "will be removed with 2.0.0 at the latest", + ReplaceWith("ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionThrowableProof.OCCURRED_EXCEPTION_STACKTRACE") + ) /** @since 0.18.0 */ OCCURRED_EXCEPTION_STACKTRACE("stacktrace"), + @Deprecated( + "will be removed with 2.0.0 at the latest", + ReplaceWith("ch.tutteli.atrium.reporting.reportables.descriptions.DescriptionThrowableProof.OCCURRED_EXCEPTION_SUPPRESSED") + ) /** @since 0.18.0 */ OCCURRED_EXCEPTION_SUPPRESSED("suppressed"), }