More consise reporting for contains.atLeast(1) (#934)

This commit is contained in:
Edward Hou
2021-06-10 22:53:05 -07:00
committed by GitHub
parent 9d97be5f3e
commit dac885bc6e
21 changed files with 148 additions and 83 deletions

View File

@@ -999,8 +999,7 @@ expect(listOf(1, 2, 2, 4)).toContain(2, 3)
expected that subject: [1, 2, 2, 4] (java.util.Arrays.ArrayList <1234789>) expected that subject: [1, 2, 2, 4] (java.util.Arrays.ArrayList <1234789>)
contains, in any order: contains, in any order:
⚬ an element which equals: 3 (kotlin.Int <1234789>) ⚬ an element which equals: 3 (kotlin.Int <1234789>)
⚬ ▶number of such entries: 0 » but no such element was found
is at least: 1
``` ```
</ex-collection-short-1> </ex-collection-short-1>
@@ -1039,13 +1038,11 @@ expected that subject: [1, 2, 2, 4] (java.util.Arrays.ArrayList <1234789>
contains, in any order: contains, in any order:
⚬ an element which: ⚬ an element which:
» is less than: 0 (kotlin.Int <1234789>) » is less than: 0 (kotlin.Int <1234789>)
⚬ ▶number of such entries: 0 » but no such element was found
is at least: 1
⚬ an element which: ⚬ an element which:
» is greater than: 2 (kotlin.Int <1234789>) » is greater than: 2 (kotlin.Int <1234789>)
» is less than: 4 (kotlin.Int <1234789>) » is less than: 4 (kotlin.Int <1234789>)
⚬ ▶number of such entries: 0 » but no such element was found
is at least: 1
``` ```
</ex-collection-short-2> </ex-collection-short-2>
@@ -1085,8 +1082,7 @@ expected that subject: [1, 2, 3, 4] (java.util.Arrays.ArrayList <1234789>
contains, in any order: contains, in any order:
⚬ an element which: ⚬ an element which:
» is less than: 0 (kotlin.Int <1234789>) » is less than: 0 (kotlin.Int <1234789>)
⚬ ▶number of such entries: 0 » but no such element was found
is at least: 1
``` ```
</ex-collection-any> </ex-collection-any>
<hr/> <hr/>
@@ -1739,8 +1735,7 @@ expected that subject: "calling myNullableFun with ..." <1234789>
myNullableFun(-2147483648): null myNullableFun(-2147483648): null
» contains: » contains:
⚬ value: "min" <1234789> ⚬ value: "min" <1234789>
⚬ ▶number of matches: » but no match was found
is at least: 1
myNullableFun(2147483647): "2147483647" <1234789> myNullableFun(2147483647): "2147483647" <1234789>
equals: "max" <1234789> equals: "max" <1234789>
``` ```
@@ -1888,8 +1883,7 @@ expected that subject: () -> kotlin.Nothing (readme.examples.MostExamples
is instance of type: String (kotlin.String) -- Class: java.lang.String is instance of type: String (kotlin.String) -- Class: java.lang.String
contains: contains:
⚬ value: "no no no" <1234789> ⚬ value: "no no no" <1234789>
⚬ ▶number of matches: » but no match was found
is at least: 1
Properties of the unexpected IllegalArgumentException Properties of the unexpected IllegalArgumentException
» message: "no no no..." <1234789> » message: "no no no..." <1234789>
» stacktrace: » stacktrace:

View File

@@ -2,11 +2,14 @@ package ch.tutteli.atrium.logic.creating.basic.contains.creators.impl
import ch.tutteli.atrium.assertions.AssertionGroup import ch.tutteli.atrium.assertions.AssertionGroup
import ch.tutteli.atrium.assertions.builders.assertionBuilder import ch.tutteli.atrium.assertions.builders.assertionBuilder
import ch.tutteli.atrium.assertions.builders.withExplanatoryAssertion
import ch.tutteli.atrium.creating.AssertionContainer import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.logic.creating.basic.contains.Contains import ch.tutteli.atrium.logic.creating.basic.contains.Contains
import ch.tutteli.atrium.logic.assertions.impl.LazyThreadUnsafeAssertionGroup import ch.tutteli.atrium.logic.assertions.impl.LazyThreadUnsafeAssertionGroup
import ch.tutteli.atrium.logic.creating.basic.contains.checkers.AtLeastChecker
import ch.tutteli.atrium.reporting.Text import ch.tutteli.atrium.reporting.Text
import ch.tutteli.atrium.reporting.translating.Translatable import ch.tutteli.atrium.reporting.translating.Translatable
import ch.tutteli.atrium.reporting.translating.TranslatableWithArgs
/** /**
* Represents the base class for [Contains.Creator]s, providing a template to fulfill its job. * Represents the base class for [Contains.Creator]s, providing a template to fulfill its job.
@@ -31,6 +34,17 @@ abstract class ContainsAssertionCreator<T : Any, TT : Any, in SC, C : Contains.C
*/ */
protected abstract val descriptionContains: Translatable protected abstract val descriptionContains: Translatable
/**
* Provides the translation for when an item is not found in a `contains.atLeast(1)` check.
*/
protected abstract val descriptionNotFound: Translatable
/**
* Provides the translation for `and N such elements were found` when an item is not found in a
* `contains.atLeast(1)` check.
*/
protected abstract val descriptionNumberOfElementsFound: Translatable
final override fun createAssertionGroup( final override fun createAssertionGroup(
container: AssertionContainer<T>, container: AssertionContainer<T>,
searchCriteria: List<SC> searchCriteria: List<SC>
@@ -83,9 +97,27 @@ abstract class ContainsAssertionCreator<T : Any, TT : Any, in SC, C : Contains.C
private fun featureFactory(count: Int, numberOfOccurrences: Translatable): AssertionGroup { private fun featureFactory(count: Int, numberOfOccurrences: Translatable): AssertionGroup {
val assertions = checkers.map { it.createAssertion(count) } val assertions = checkers.map { it.createAssertion(count) }
return assertionBuilder.feature val checker = checkers.firstOrNull()
.withDescriptionAndRepresentation(numberOfOccurrences, Text(count.toString())) return if (checkers.size == 1 && checker is AtLeastChecker && checker.times == 1) {
.withAssertions(assertions) if (checker.createAssertion(count).holds()) {
.build() assertionBuilder.explanatoryGroup
.withDefaultType
.withExplanatoryAssertion(
TranslatableWithArgs(descriptionNumberOfElementsFound, count.toString())
)
.build()
} else {
assertionBuilder.explanatoryGroup
.withDefaultType
.withExplanatoryAssertion(descriptionNotFound)
.failing
.build()
}
} else {
assertionBuilder.feature
.withDescriptionAndRepresentation(numberOfOccurrences, Text(count.toString()))
.withAssertions(assertions)
.build()
}
} }
} }

View File

@@ -3,8 +3,12 @@ package ch.tutteli.atrium.logic.creating.basic.contains.creators.impl
import ch.tutteli.atrium.assertions.Assertion import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.assertions.AssertionGroup import ch.tutteli.atrium.assertions.AssertionGroup
import ch.tutteli.atrium.assertions.builders.assertionBuilder import ch.tutteli.atrium.assertions.builders.assertionBuilder
import ch.tutteli.atrium.assertions.builders.invisibleGroup
import ch.tutteli.atrium.core.trueProvider
import ch.tutteli.atrium.creating.AssertionContainer import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.logic.creating.basic.contains.Contains import ch.tutteli.atrium.logic.creating.basic.contains.Contains
import ch.tutteli.atrium.logic.creating.iterable.contains.searchbehaviours.NotSearchBehaviour
import ch.tutteli.atrium.logic.impl.createExplanatoryGroupForMismatches
import ch.tutteli.atrium.reporting.translating.Translatable import ch.tutteli.atrium.reporting.translating.Translatable
/** /**
@@ -36,12 +40,24 @@ abstract class ContainsObjectsAssertionCreator<T : Any, TT : Any, in SC, S : Con
searchCriterion: SC, searchCriterion: SC,
featureFactory: (Int, Translatable) -> AssertionGroup featureFactory: (Int, Translatable) -> AssertionGroup
): AssertionGroup { ): AssertionGroup {
val count = search(multiConsumableContainer, searchCriterion) val assertions = mutableListOf<Assertion>()
val featureAssertion = featureFactory(count, descriptionNumberOfOccurrences) if (searchBehaviour is NotSearchBehaviour) {
val mismatches = mismatchesForNotSearchBehaviour(multiConsumableContainer, searchCriterion)
if (mismatches.isNotEmpty()) assertions.add(createExplanatoryGroupForMismatches(mismatches))
} else {
val count = search(multiConsumableContainer, searchCriterion)
val featureAssertion = featureFactory(count, descriptionNumberOfOccurrences)
assertions.add(featureAssertion)
}
return assertionBuilder.list return if (assertions.isEmpty()) {
assertionBuilder.invisibleGroup
.withAssertion(
assertionBuilder.createDescriptive(groupDescription, searchCriterion, trueProvider)
).build()
} else assertionBuilder.list
.withDescriptionAndRepresentation(groupDescription, searchCriterion) .withDescriptionAndRepresentation(groupDescription, searchCriterion)
.withAssertion(featureAssertion) .withAssertions(assertions)
.build() .build()
} }
@@ -67,4 +83,19 @@ abstract class ContainsObjectsAssertionCreator<T : Any, TT : Any, in SC, S : Con
* @return The number of times the [searchCriterion] matched in the subject of this expectation. * @return The number of times the [searchCriterion] matched in the subject of this expectation.
*/ */
protected abstract fun search(multiConsumableContainer: AssertionContainer<TT>, searchCriterion: SC): Int protected abstract fun search(multiConsumableContainer: AssertionContainer<TT>, searchCriterion: SC): Int
/**
* Finds the mismatched indices and values when the [searchBehaviour] is `NotSearchBehaviour` in the subject of the
* given [multiConsumableContainer] and creates a list of assertions about the mismatched indexed values
*
* @param multiConsumableContainer The provider of the subject of this expectation in which we shall look for something
* not matching the given [searchCriterion].
* @param searchCriterion The search criterion used to determine whether something matches or not.
*
* @return A list of [Assertion]s that describe the indexed values that did not match the [searchCriterion]
*/
protected open fun mismatchesForNotSearchBehaviour(
multiConsumableContainer: AssertionContainer<TT>,
searchCriterion: SC
): List<Assertion> = emptyList()
} }

View File

@@ -37,6 +37,8 @@ class CharSequenceContainsAssertionCreator<T : CharSequence, in SC : Any, S : Se
override val descriptionContains: Translatable = DescriptionCharSequenceAssertion.CONTAINS override val descriptionContains: Translatable = DescriptionCharSequenceAssertion.CONTAINS
override val descriptionNumberOfOccurrences: Translatable = DescriptionCharSequenceAssertion.NUMBER_OF_OCCURRENCES override val descriptionNumberOfOccurrences: Translatable = DescriptionCharSequenceAssertion.NUMBER_OF_OCCURRENCES
override val descriptionNotFound: Translatable = DescriptionCharSequenceAssertion.NOT_FOUND
override val descriptionNumberOfElementsFound: Translatable = DescriptionCharSequenceAssertion.NUMBER_OF_MATCHES_FOUND
override fun makeSubjectMultipleTimesConsumable(container: AssertionContainer<T>): AssertionContainer<String> = override fun makeSubjectMultipleTimesConsumable(container: AssertionContainer<T>): AssertionContainer<String> =
container.changeSubject.unreported { it.toString() }.toAssertionContainer() container.changeSubject.unreported { it.toString() }.toAssertionContainer()

View File

@@ -53,6 +53,8 @@ class InAnyOrderEntriesAssertionCreator<E : Any, T : IterableLike>(
IterableLikeContains.Creator<T, (Expect<E>.() -> Unit)?> { IterableLikeContains.Creator<T, (Expect<E>.() -> Unit)?> {
override val descriptionContains: Translatable = DescriptionIterableAssertion.CONTAINS override val descriptionContains: Translatable = DescriptionIterableAssertion.CONTAINS
override val descriptionNotFound: Translatable = DescriptionIterableAssertion.ELEMENT_NOT_FOUND
override val descriptionNumberOfElementsFound: Translatable = DescriptionIterableAssertion.NUMBER_OF_ELEMENTS_FOUND
override fun makeSubjectMultipleTimesConsumable(container: AssertionContainer<T>): AssertionContainer<List<E?>> = override fun makeSubjectMultipleTimesConsumable(container: AssertionContainer<T>): AssertionContainer<List<E?>> =
turnSubjectToList(container, converter) turnSubjectToList(container, converter)

View File

@@ -43,6 +43,8 @@ class InAnyOrderValuesAssertionCreator<SC, T : IterableLike>(
override val descriptionContains: Translatable = DescriptionIterableAssertion.CONTAINS override val descriptionContains: Translatable = DescriptionIterableAssertion.CONTAINS
override val descriptionNumberOfOccurrences: Translatable = DescriptionIterableAssertion.NUMBER_OF_OCCURRENCES override val descriptionNumberOfOccurrences: Translatable = DescriptionIterableAssertion.NUMBER_OF_OCCURRENCES
override val groupDescription: Translatable = DescriptionIterableAssertion.AN_ELEMENT_WHICH_EQUALS override val groupDescription: Translatable = DescriptionIterableAssertion.AN_ELEMENT_WHICH_EQUALS
override val descriptionNotFound: Translatable = DescriptionIterableAssertion.ELEMENT_NOT_FOUND
override val descriptionNumberOfElementsFound: Translatable = DescriptionIterableAssertion.NUMBER_OF_ELEMENTS_FOUND
override fun makeSubjectMultipleTimesConsumable(container: AssertionContainer<T>): AssertionContainer<List<SC>> = override fun makeSubjectMultipleTimesConsumable(container: AssertionContainer<T>): AssertionContainer<List<SC>> =
turnSubjectToList(container, converter) turnSubjectToList(container, converter)
@@ -50,23 +52,16 @@ class InAnyOrderValuesAssertionCreator<SC, T : IterableLike>(
override fun search(multiConsumableContainer: AssertionContainer<List<SC>>, searchCriterion: SC): Int = override fun search(multiConsumableContainer: AssertionContainer<List<SC>>, searchCriterion: SC): Int =
multiConsumableContainer.maybeSubject.fold({ -1 }) { subject -> subject.filter { it == searchCriterion }.size } multiConsumableContainer.maybeSubject.fold({ -1 }) { subject -> subject.filter { it == searchCriterion }.size }
override fun searchAndCreateAssertion( /**
* Override in any subclass that wants to report mismatched elements individually when the [searchBehaviour]
* is [NotSearchBehaviour]
*/
override fun mismatchesForNotSearchBehaviour(
multiConsumableContainer: AssertionContainer<List<SC>>, multiConsumableContainer: AssertionContainer<List<SC>>,
searchCriterion: SC, searchCriterion: SC
featureFactory: (Int, Translatable) -> AssertionGroup ): List<Assertion> {
): AssertionGroup { val list = multiConsumableContainer.maybeSubject.getOrElse { emptyList() }
return if (searchBehaviour is NotSearchBehaviour) { return createIndexAssertions(list) { (_, element) -> element == searchCriterion }
val list = multiConsumableContainer.maybeSubject.getOrElse { emptyList() }
val mismatches = createIndexAssertions(list) { (_, element) -> element == searchCriterion }
val assertions = mutableListOf<Assertion>()
if (mismatches.isNotEmpty()) assertions.add(createExplanatoryGroupForMismatches(mismatches))
assertionBuilder.list
.withDescriptionAndRepresentation(groupDescription, searchCriterion)
.withAssertions(assertions)
.build()
} else {
super.searchAndCreateAssertion(multiConsumableContainer, searchCriterion, featureFactory)
}
} }
/** /**

View File

@@ -142,7 +142,7 @@ abstract class CharSequenceToContainAtLeastExpectationsSpec(
it("${toContainAtLeastPair.first("'h'", "once")} throws AssertionError") { it("${toContainAtLeastPair.first("'h'", "once")} throws AssertionError") {
expect { expect {
fluentHelloWorld.toContainAtLeastFun(1, 'h') fluentHelloWorld.toContainAtLeastFun(1, 'h')
}.toThrow<AssertionError> { messageToContain("$atLeast: 1", "$valueWithIndent: 'h'") } }.toThrow<AssertionError> { messageToContain(noMatchFoundDescr, "$valueWithIndent: 'h'") }
} }
it("${toContainAtLeastIgnoringCasePair.first("'h'", "once")} does not throw") { it("${toContainAtLeastIgnoringCasePair.first("'h'", "once")} does not throw") {
fluentHelloWorld.toContainAtLeastIgnoringCaseFun(1, 'h') fluentHelloWorld.toContainAtLeastIgnoringCaseFun(1, 'h')
@@ -151,7 +151,7 @@ abstract class CharSequenceToContainAtLeastExpectationsSpec(
it("${toContainAtLeastPair.first("'H', 'E'", "once")} throws AssertionError") { it("${toContainAtLeastPair.first("'H', 'E'", "once")} throws AssertionError") {
expect { expect {
fluentHelloWorld.toContainAtLeastFun(1, 'H', 'E') fluentHelloWorld.toContainAtLeastFun(1, 'H', 'E')
}.toThrow<AssertionError> { messageToContain(atLeast, 'E') } }.toThrow<AssertionError> { messageToContain(noMatchFoundDescr, 'E') }
} }
it("${toContainAtLeastIgnoringCasePair.first("'H', 'E'", "once")} does not throw") { it("${toContainAtLeastIgnoringCasePair.first("'H', 'E'", "once")} does not throw") {
fluentHelloWorld.toContainAtLeastIgnoringCaseFun(1, 'H', 'E') fluentHelloWorld.toContainAtLeastIgnoringCaseFun(1, 'H', 'E')
@@ -162,7 +162,7 @@ abstract class CharSequenceToContainAtLeastExpectationsSpec(
fluentHelloWorld.toContainAtLeastFun(1, 'E', 'H') fluentHelloWorld.toContainAtLeastFun(1, 'E', 'H')
}.toThrow<AssertionError> { }.toThrow<AssertionError> {
message { message {
toContain("$atLeast: 1", "$valueWithIndent: 'E'") toContain(noMatchFoundDescr, "$valueWithIndent: 'E'")
notToContain("$valueWithIndent: 'H'") notToContain("$valueWithIndent: 'H'")
} }
} }
@@ -181,7 +181,7 @@ abstract class CharSequenceToContainAtLeastExpectationsSpec(
fluentHelloWorld.toContainAtLeastFun(1, 'H', 'E', 'w', 'r') fluentHelloWorld.toContainAtLeastFun(1, 'H', 'E', 'w', 'r')
}.toThrow<AssertionError> { }.toThrow<AssertionError> {
message { message {
toContain("$atLeast: 1", "$valueWithIndent: 'E'", "$valueWithIndent: 'w'") toContain(noMatchFoundDescr, "$valueWithIndent: 'E'", "$valueWithIndent: 'w'")
notToContain("$valueWithIndent: 'H'", "$valueWithIndent: 'r'") notToContain("$valueWithIndent: 'H'", "$valueWithIndent: 'r'")
} }
} }

View File

@@ -42,8 +42,7 @@ abstract class CharSequenceToContainNotToContainExpectationsSpec(
messageToContain( messageToContain(
"$rootBulletPoint$toContainDescr: $separator" + "$rootBulletPoint$toContainDescr: $separator" +
"$valueWithIndent: \"Hello\"", "$valueWithIndent: \"Hello\"",
"$numberOfOccurrences: 0", noMatchFoundDescr
"$atLeast: 1"
) )
} }
} }
@@ -103,9 +102,8 @@ abstract class CharSequenceToContainNotToContainExpectationsSpec(
fluent.toContainFun("hello", "robert") fluent.toContainFun("hello", "robert")
}.toThrow<AssertionError> { }.toThrow<AssertionError> {
message { message {
this.toContain.exactly(2).values( this.toContain.exactly(2).value(
"$numberOfOccurrences: 0", noMatchFoundDescr
"$atLeast: 1"
) )
this.toContain.exactly(1).values( this.toContain.exactly(1).values(
"$rootBulletPoint$toContainDescr: $separator", "$rootBulletPoint$toContainDescr: $separator",

View File

@@ -134,8 +134,7 @@ abstract class CharSequenceToContainRegexExpectationsSpec(
toContain( toContain(
"$rootBulletPoint$toContainDescr: $separator" + "$rootBulletPoint$toContainDescr: $separator" +
"$regexWithIndent: ${roberto.toLowerCase()}", "$regexWithIndent: ${roberto.toLowerCase()}",
"$numberOfOccurrences: 0", noMatchFoundDescr
"$atLeast: 1"
) )
} }
} }

View File

@@ -20,6 +20,7 @@ abstract class CharSequenceToContainSpecBase(spec: Root.() -> Unit) : Spek(spec)
val numberOfOccurrences = DescriptionCharSequenceAssertion.NUMBER_OF_OCCURRENCES.getDefault() val numberOfOccurrences = DescriptionCharSequenceAssertion.NUMBER_OF_OCCURRENCES.getDefault()
val value = DescriptionCharSequenceAssertion.VALUE.getDefault() val value = DescriptionCharSequenceAssertion.VALUE.getDefault()
val stringMatchingRegex = DescriptionCharSequenceAssertion.STRING_MATCHING_REGEX.getDefault() val stringMatchingRegex = DescriptionCharSequenceAssertion.STRING_MATCHING_REGEX.getDefault()
val noMatchFoundDescr = DescriptionCharSequenceAssertion.NOT_FOUND.getDefault()
val atLeast = DescriptionCharSequenceAssertion.AT_LEAST.getDefault() val atLeast = DescriptionCharSequenceAssertion.AT_LEAST.getDefault()
val atMost = DescriptionCharSequenceAssertion.AT_MOST.getDefault() val atMost = DescriptionCharSequenceAssertion.AT_MOST.getDefault()

View File

@@ -27,6 +27,7 @@ abstract class IterableToContainEntriesSpecBase(
val indexDescr = String.format(DescriptionIterableAssertion.INDEX.getDefault(), index) val indexDescr = String.format(DescriptionIterableAssertion.INDEX.getDefault(), index)
return "$indexDescr: ${value.toString()}" return "$indexDescr: ${value.toString()}"
} }
val noSuchEntryDescr = DescriptionIterableAssertion.ELEMENT_NOT_FOUND.getDefault()
fun index(index: Int) = String.format(DescriptionIterableAssertion.INDEX.getDefault(), index) fun index(index: Int) = String.format(DescriptionIterableAssertion.INDEX.getDefault(), index)

View File

@@ -62,8 +62,7 @@ abstract class IterableToContainInAnyOrderAtLeast1EntriesExpectationsSpec(
"$rootBulletPoint$toContainInAnyOrder: $separator", "$rootBulletPoint$toContainInAnyOrder: $separator",
"$anElementWhich: $separator", "$anElementWhich: $separator",
"$toBeLessThanDescr: 1.0", "$toBeLessThanDescr: 1.0",
"$numberOfOccurrences: 0", noSuchEntryDescr
"$atLeastDescr: 1"
) )
} }
} }
@@ -75,8 +74,7 @@ abstract class IterableToContainInAnyOrderAtLeast1EntriesExpectationsSpec(
message { message {
toContain.exactly(2).values( toContain.exactly(2).values(
"$anElementWhich: $separator", "$anElementWhich: $separator",
"$numberOfOccurrences: 0", noSuchEntryDescr
"$atLeastDescr: 1"
) )
toContain.exactly(1).values( toContain.exactly(1).values(
"$rootBulletPoint$toContainInAnyOrder: $separator", "$rootBulletPoint$toContainInAnyOrder: $separator",
@@ -100,8 +98,7 @@ abstract class IterableToContainInAnyOrderAtLeast1EntriesExpectationsSpec(
"$anElementWhich: $separator", "$anElementWhich: $separator",
"$toBeGreaterThanDescr: 1.0", "$toBeGreaterThanDescr: 1.0",
"$toBeLessThanDescr: 2.0", "$toBeLessThanDescr: 2.0",
"$numberOfOccurrences: 0", noSuchEntryDescr
"$atLeastDescr: 1"
) )
} }
} }
@@ -161,8 +158,7 @@ abstract class IterableToContainInAnyOrderAtLeast1EntriesExpectationsSpec(
"$rootBulletPoint$toContainInAnyOrder: $separator", "$rootBulletPoint$toContainInAnyOrder: $separator",
"$anElementWhich: $separator", "$anElementWhich: $separator",
"$toBeDescr: 2.0", "$toBeDescr: 2.0",
"$numberOfOccurrences: 0", noSuchEntryDescr
"$atLeastDescr: 1"
) )
} }
} }
@@ -177,8 +173,7 @@ abstract class IterableToContainInAnyOrderAtLeast1EntriesExpectationsSpec(
message { message {
toContain.exactly(2).values( toContain.exactly(2).values(
"$anElementWhich: $separator", "$anElementWhich: $separator",
"$numberOfOccurrences: 0", noSuchEntryDescr
"$atLeastDescr: 1"
) )
toContain.exactly(1).values( toContain.exactly(1).values(
"$rootBulletPoint$toContainInAnyOrder: $separator", "$rootBulletPoint$toContainInAnyOrder: $separator",
@@ -200,8 +195,7 @@ abstract class IterableToContainInAnyOrderAtLeast1EntriesExpectationsSpec(
"$rootBulletPoint$toContainInAnyOrder: $separator", "$rootBulletPoint$toContainInAnyOrder: $separator",
"$anElementWhich: $separator", "$anElementWhich: $separator",
"$isDescr: null", "$isDescr: null",
"$numberOfOccurrences: 0", noSuchEntryDescr
"$atLeastDescr: 1"
) )
} }
} }

View File

@@ -41,8 +41,7 @@ abstract class IterableToContainInAnyOrderAtLeast1ValuesExpectationsSpec(
messageToContain( messageToContain(
"$rootBulletPoint$toContainInAnyOrder: $separator", "$rootBulletPoint$toContainInAnyOrder: $separator",
"$anElementWhichIs: 1.0", "$anElementWhichIs: 1.0",
"$numberOfOccurrences: 0", noSuchValueDescr
"$atLeastDescr: 1"
) )
} }
} }
@@ -73,8 +72,7 @@ abstract class IterableToContainInAnyOrderAtLeast1ValuesExpectationsSpec(
messageToContain( messageToContain(
"$rootBulletPoint$toContainInAnyOrder: $separator", "$rootBulletPoint$toContainInAnyOrder: $separator",
"$anElementWhichIs: 9.5", "$anElementWhichIs: 9.5",
"$numberOfOccurrences: 0", noSuchValueDescr
"$atLeastDescr: 1"
) )
} }
} }
@@ -84,8 +82,7 @@ abstract class IterableToContainInAnyOrderAtLeast1ValuesExpectationsSpec(
}.toThrow<AssertionError> { }.toThrow<AssertionError> {
message { message {
toContain.exactly(2).values( toContain.exactly(2).values(
"$numberOfOccurrences: 0", noSuchValueDescr
"$atLeastDescr: 1"
) )
toContain.exactly(1).values( toContain.exactly(1).values(
"$rootBulletPoint$toContainInAnyOrder: $separator", "$rootBulletPoint$toContainInAnyOrder: $separator",

View File

@@ -90,14 +90,14 @@ abstract class IterableToContainInAnyOrderAtLeastValuesExpectationsSpec(
it("${toContainAtLeastPair.first("1.1", "once")} throws AssertionError") { it("${toContainAtLeastPair.first("1.1", "once")} throws AssertionError") {
expect { expect {
expect(oneToSeven()).toContainAtLeastFun(1, 1.1) expect(oneToSeven()).toContainAtLeastFun(1, 1.1)
}.toThrow<AssertionError> { messageToContain("$atLeastDescr: 1", "$anElementWhichIs: 1.1") } }.toThrow<AssertionError> { messageToContain(noSuchValueDescr, "$anElementWhichIs: 1.1") }
} }
it("${toContainAtLeastPair.first("1.0, 2.3", "once")} throws AssertionError mentioning only 2.3") { it("${toContainAtLeastPair.first("1.0, 2.3", "once")} throws AssertionError mentioning only 2.3") {
expect { expect {
expect(oneToSeven()).toContainAtLeastFun(1, 1.0, 2.3) expect(oneToSeven()).toContainAtLeastFun(1, 1.0, 2.3)
}.toThrow<AssertionError> { }.toThrow<AssertionError> {
message { message {
toContain("$atLeastDescr: 1", "$anElementWhichIs: 2.3") toContain(noSuchValueDescr, "$anElementWhichIs: 2.3")
notToContain("$anElementWhichIs: 1.0") notToContain("$anElementWhichIs: 1.0")
} }
} }
@@ -107,7 +107,7 @@ abstract class IterableToContainInAnyOrderAtLeastValuesExpectationsSpec(
expect(oneToSeven()).toContainAtLeastFun(1, 2.3, 1.0) expect(oneToSeven()).toContainAtLeastFun(1, 2.3, 1.0)
}.toThrow<AssertionError> { }.toThrow<AssertionError> {
message { message {
toContain("$atLeastDescr: 1", "$anElementWhichIs: 2.3") toContain(noSuchValueDescr, "$anElementWhichIs: 2.3")
notToContain("$anElementWhichIs: 1.0") notToContain("$anElementWhichIs: 1.0")
} }
} }
@@ -118,8 +118,7 @@ abstract class IterableToContainInAnyOrderAtLeastValuesExpectationsSpec(
}.toThrow<AssertionError> { }.toThrow<AssertionError> {
message { message {
toContain.exactly(2).values( toContain.exactly(2).values(
"$numberOfOccurrences: 0", noSuchValueDescr
"$atLeastDescr: 1"
) )
toContain.exactly(1).values( toContain.exactly(1).values(
"$rootBulletPoint$toContainInAnyOrder: $separator", "$rootBulletPoint$toContainInAnyOrder: $separator",

View File

@@ -47,6 +47,7 @@ abstract class IterableToContainSpecBase(spec: Root.() -> Unit) : Spek(spec) {
val hasDescriptionBasic = DescriptionBasic.HAS.getDefault() val hasDescriptionBasic = DescriptionBasic.HAS.getDefault()
val nextElement = DescriptionIterableAssertion.NEXT_ELEMENT.getDefault() val nextElement = DescriptionIterableAssertion.NEXT_ELEMENT.getDefault()
val notToContainDescr = DescriptionIterableAssertion.CONTAINS_NOT.getDefault() val notToContainDescr = DescriptionIterableAssertion.CONTAINS_NOT.getDefault()
val noSuchValueDescr = DescriptionIterableAssertion.ELEMENT_NOT_FOUND.getDefault()
val sizeDescr = DescriptionCollectionAssertion.SIZE.getDefault() val sizeDescr = DescriptionCollectionAssertion.SIZE.getDefault()
val atLeastDescr = DescriptionIterableAssertion.AT_LEAST.getDefault() val atLeastDescr = DescriptionIterableAssertion.AT_LEAST.getDefault()

View File

@@ -46,8 +46,7 @@ abstract class IterableToHaveElementsAndAnyExpectationsSpec(
"$rootBulletPoint$toContainInAnyOrder: $separator", "$rootBulletPoint$toContainInAnyOrder: $separator",
"$anElementWhich: $separator", "$anElementWhich: $separator",
"$toBeLessThanDescr: 1.0", "$toBeLessThanDescr: 1.0",
"$numberOfOccurrences: 0", noSuchEntryDescr
"$atLeastDescr: 1"
) )
} }
@@ -65,8 +64,7 @@ abstract class IterableToHaveElementsAndAnyExpectationsSpec(
"$anElementWhich: $separator", "$anElementWhich: $separator",
"$isGreaterThanDescr: 1.0", "$isGreaterThanDescr: 1.0",
"$toBeLessThanDescr: 2.0", "$toBeLessThanDescr: 2.0",
"$numberOfOccurrences: 0", noSuchEntryDescr
"$atLeastDescr: 1"
) )
} }
} }
@@ -105,8 +103,7 @@ abstract class IterableToHaveElementsAndAnyExpectationsSpec(
"$rootBulletPoint$toContainInAnyOrder: $separator", "$rootBulletPoint$toContainInAnyOrder: $separator",
"$anElementWhich: $separator", "$anElementWhich: $separator",
"$toBeDescr: 2.0", "$toBeDescr: 2.0",
"$numberOfOccurrences: 0", noSuchEntryDescr
"$atLeastDescr: 1"
) )
} }
} }
@@ -124,8 +121,7 @@ abstract class IterableToHaveElementsAndAnyExpectationsSpec(
"$rootBulletPoint$toContainInAnyOrder: $separator", "$rootBulletPoint$toContainInAnyOrder: $separator",
"$anElementWhich: $separator", "$anElementWhich: $separator",
"$isDescr: null", "$isDescr: null",
"$numberOfOccurrences: 0", noSuchEntryDescr
"$atLeastDescr: 1"
) )
} }
} }

View File

@@ -35,7 +35,12 @@ buildscript {
"IterableContains.*Spec.*points to containsNot", "IterableContains.*Spec.*points to containsNot",
// we improved reporting for notToContain with 0.17.0 // we improved reporting for notToContain with 0.17.0
"IterableContainsNot(Entries|Values)AssertionsSpec.*`containsNot( nullable)?`.*throws AssertionError", "IterableContainsNot(Entries|Values)AssertionsSpec.*`containsNot( nullable)?`.*throws AssertionError",
"IterableNoneAssertionsSpec.*`(none|containsNot)( nullable)?`.*throws AssertionError" "IterableNoneAssertionsSpec.*`(none|containsNot)( nullable)?`.*throws AssertionError",
// changed reporting for contains.atLeast(1) with 0.17.0
or(
"(CharSequence|Iterable)Contains.*Spec",
"IterableAnyAssertionsSpec"
) + ".*`.*(any|contains).*`.*(throws.*AssertionError|failing cases)"
) + ".*)", ) + ".*)",
// we don't use asci bullet points in reporting since 0.17.0 // we don't use asci bullet points in reporting since 0.17.0
// but have own tests to assure that changing bullet points work // but have own tests to assure that changing bullet points work
@@ -98,7 +103,12 @@ buildscript {
"IterableContains.*Spec.*points to containsNot", "IterableContains.*Spec.*points to containsNot",
// we improved reporting for notToContain with 0.17.0 // we improved reporting for notToContain with 0.17.0
"IterableContainsNot(Entries|Values)AssertionsSpec.*`containsNot.*`.*throws AssertionError", "IterableContainsNot(Entries|Values)AssertionsSpec.*`containsNot.*`.*throws AssertionError",
"IterableNoneAssertionsSpec.*`(none|containsNot).*`.*throws AssertionError" "IterableNoneAssertionsSpec.*`(none|containsNot).*`.*throws AssertionError",
// changed reporting for contains.atLeast(1) with 0.17.0
or(
"(CharSequence|Iterable)Contains.*Spec",
"IterableAnyAssertionsSpec"
) + ".*`.*(any|contains).*`.*(throws.*AssertionError|failing cases)"
) + ".*)", ) + ".*)",
// we don't use asci bullet points in reporting since 0.17.0 // we don't use asci bullet points in reporting since 0.17.0
// but have own tests to assure that changing bullet points work // but have own tests to assure that changing bullet points work
@@ -162,7 +172,12 @@ buildscript {
"IterableExpectationsSpec.*`(containsNoDuplicates|contains noDuplicates)`", "IterableExpectationsSpec.*`(containsNoDuplicates|contains noDuplicates)`",
// we improved reporting for notToContain with 0.17.0 // we improved reporting for notToContain with 0.17.0
"IterableContainsNot(Entries|Values)ExpectationsSpec.*`containsNot.*`.*throws AssertionError", "IterableContainsNot(Entries|Values)ExpectationsSpec.*`containsNot.*`.*throws AssertionError",
"IterableNoneExpectationsSpec.*`(none|containsNot).*`.*throws AssertionError" "IterableNoneExpectationsSpec.*`(none|containsNot).*`.*throws AssertionError",
// changed reporting for contains.atLeast(1) with 0.17.0
or(
"(CharSequence|Iterable)Contains.*Spec",
"IterableAnyExpectationsSpec"
) + ".*`.*(any|contains).*`.*(throws.*AssertionError|failing cases)"
) + ".*)").let { commonPatterns -> ) + ".*)").let { commonPatterns ->
Pair( Pair(
// bc // bc

View File

@@ -19,6 +19,8 @@ enum class DescriptionCharSequenceAssertion(override val value: String) : String
IGNORING_CASE("%s, Gross-/Kleinschreibung ignorierend"), IGNORING_CASE("%s, Gross-/Kleinschreibung ignorierend"),
MATCHES("stimmt vollständig überein mit"), MATCHES("stimmt vollständig überein mit"),
MISMATCHES("stimmt nicht vollständig überein mit"), MISMATCHES("stimmt nicht vollständig überein mit"),
NOT_FOUND("aber es wurde kein Treffer gefunden"),
NUMBER_OF_MATCHES_FOUND("und %s Treffer wurden gefunden"),
NUMBER_OF_OCCURRENCES("Anzahl Treffer"), NUMBER_OF_OCCURRENCES("Anzahl Treffer"),
STARTS_WITH("beginnt mit"), STARTS_WITH("beginnt mit"),
STARTS_NOT_WITH("beginnt nicht mit"), STARTS_NOT_WITH("beginnt nicht mit"),

View File

@@ -46,7 +46,9 @@ enum class DescriptionIterableAssertion(override val value: String) : StringBase
NEXT_ELEMENT("ein nächstes Element"), NEXT_ELEMENT("ein nächstes Element"),
NO_ELEMENTS("❗❗ kann nicht eruiert werden, leeres Iterable"), NO_ELEMENTS("❗❗ kann nicht eruiert werden, leeres Iterable"),
DUPLICATE_ELEMENTS("doppelte Elemente"), DUPLICATE_ELEMENTS("doppelte Elemente"),
DUPLICATED_BY("(dupliziert von Index: %s") DUPLICATED_BY("(dupliziert von Index: %s"),
ELEMENT_NOT_FOUND("aber es konnte kein solches Element gefunden werden"),
NUMBER_OF_ELEMENTS_FOUND("und % Elemente wurden gefunden")
} }
internal const val COULD_NOT_EVALUATE_DEFINED_ASSERTIONS = internal const val COULD_NOT_EVALUATE_DEFINED_ASSERTIONS =

View File

@@ -19,6 +19,8 @@ enum class DescriptionCharSequenceAssertion(override val value: String) : String
IGNORING_CASE("%s, ignoring case"), IGNORING_CASE("%s, ignoring case"),
MATCHES("matches entirely"), MATCHES("matches entirely"),
MISMATCHES("does not match entirely"), MISMATCHES("does not match entirely"),
NOT_FOUND("but no match was found"),
NUMBER_OF_MATCHES_FOUND("and %s matches were found"),
NUMBER_OF_OCCURRENCES("number of matches"), NUMBER_OF_OCCURRENCES("number of matches"),
STARTS_WITH("starts with"), STARTS_WITH("starts with"),
STARTS_NOT_WITH("does not start with"), STARTS_NOT_WITH("does not start with"),

View File

@@ -46,7 +46,9 @@ enum class DescriptionIterableAssertion(override val value: String) : StringBase
NEXT_ELEMENT("a next element"), NEXT_ELEMENT("a next element"),
NO_ELEMENTS("❗❗ cannot be determined, empty Iterable"), NO_ELEMENTS("❗❗ cannot be determined, empty Iterable"),
DUPLICATE_ELEMENTS("duplicate elements"), DUPLICATE_ELEMENTS("duplicate elements"),
DUPLICATED_BY("duplicated by index: %s") DUPLICATED_BY("duplicated by index: %s"),
ELEMENT_NOT_FOUND("but no such element was found"),
NUMBER_OF_ELEMENTS_FOUND("and %s such elements were found")
} }
internal const val COULD_NOT_EVALUATE_DEFINED_ASSERTIONS = "Could not evaluate the defined assertion(s)" internal const val COULD_NOT_EVALUATE_DEFINED_ASSERTIONS = "Could not evaluate the defined assertion(s)"