Make notToContain less verbose and show mismatched indices (#931)

This commit is contained in:
Edward Hou
2021-06-09 00:16:57 -07:00
committed by GitHub
parent 4d3acdbc9b
commit 91fad2624c
13 changed files with 218 additions and 174 deletions

View File

@@ -42,12 +42,21 @@ abstract class ContainsAssertionCreator<T : Any, TT : Any, in SC, C : Contains.C
}
}
val description = searchBehaviour.decorateDescription(descriptionContains)
return assertionBuilder.list
val inAnyOrderAssertion = assertionBuilder.list
.withDescriptionAndEmptyRepresentation(description)
.withAssertions(assertions)
.build()
return decorateInAnyOrderAssertion(inAnyOrderAssertion, multiConsumableContainer)
}
/**
* Override in a subclass if you want to decorate the assertion.
*/
protected open fun decorateInAnyOrderAssertion(
inAnyOrderAssertion: AssertionGroup,
multiConsumableContainer: AssertionContainer<TT>
): AssertionGroup = inAnyOrderAssertion
/**
* Make the underlying subject multiple times consumable.
*/

View File

@@ -2,7 +2,6 @@ package ch.tutteli.atrium.logic.creating.basic.contains.creators.impl
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.assertions.AssertionGroup
import ch.tutteli.atrium.assertions.AssertionGroupType
import ch.tutteli.atrium.assertions.builders.assertionBuilder
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.logic.creating.basic.contains.Contains
@@ -32,7 +31,7 @@ abstract class ContainsObjectsAssertionCreator<T : Any, TT : Any, in SC, S : Con
checkers: List<C>
) : ContainsAssertionCreator<T, TT, SC, C>(searchBehaviour, checkers) {
final override fun searchAndCreateAssertion(
override fun searchAndCreateAssertion(
multiConsumableContainer: AssertionContainer<TT>,
searchCriterion: SC,
featureFactory: (Int, Translatable) -> AssertionGroup
@@ -40,9 +39,9 @@ abstract class ContainsObjectsAssertionCreator<T : Any, TT : Any, in SC, S : Con
val count = search(multiConsumableContainer, searchCriterion)
val featureAssertion = featureFactory(count, descriptionNumberOfOccurrences)
return assertionBuilder.customType(getAssertionGroupType())
return assertionBuilder.list
.withDescriptionAndRepresentation(groupDescription, searchCriterion)
.withAssertions(decorateAssertion(multiConsumableContainer, featureAssertion))
.withAssertion(featureAssertion)
.build()
}
@@ -56,11 +55,6 @@ abstract class ContainsObjectsAssertionCreator<T : Any, TT : Any, in SC, S : Con
*/
protected abstract val groupDescription: Translatable
/**
* Provides the [AssertionGroupType] for the resulting [AssertionGroup].
*/
protected abstract fun getAssertionGroupType(): AssertionGroupType
/**
* Searches for something matching the given [searchCriterion] in the subject of the given
@@ -73,9 +67,4 @@ 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.
*/
protected abstract fun search(multiConsumableContainer: AssertionContainer<TT>, searchCriterion: SC): Int
/**
* Either return the given [featureAssertion] as [List] or add further assertions.
*/
abstract fun decorateAssertion(container: AssertionContainer<TT>, featureAssertion: Assertion): List<Assertion>
}

View File

@@ -2,8 +2,6 @@ package ch.tutteli.atrium.logic.creating.charsequence.contains.creators.impl
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.assertions.AssertionGroup
import ch.tutteli.atrium.assertions.AssertionGroupType
import ch.tutteli.atrium.assertions.DefaultListAssertionGroupType
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.logic.changeSubject
import ch.tutteli.atrium.logic.creating.charsequence.contains.CharSequenceContains.*
@@ -40,8 +38,6 @@ class CharSequenceContainsAssertionCreator<T : CharSequence, in SC : Any, S : Se
override val descriptionContains: Translatable = DescriptionCharSequenceAssertion.CONTAINS
override val descriptionNumberOfOccurrences: Translatable = DescriptionCharSequenceAssertion.NUMBER_OF_OCCURRENCES
override fun getAssertionGroupType(): AssertionGroupType = DefaultListAssertionGroupType
override fun makeSubjectMultipleTimesConsumable(container: AssertionContainer<T>): AssertionContainer<String> =
container.changeSubject.unreported { it.toString() }.toAssertionContainer()
@@ -49,9 +45,4 @@ class CharSequenceContainsAssertionCreator<T : CharSequence, in SC : Any, S : Se
// if the maybeSubject is None it means we are in an explanation like context in which
// it should not matter what this number is. Moreover, we check in the atMostChecker that times is >= 0
multiConsumableContainer.maybeSubject.fold({ -1 }) { searcher.search(it, searchCriterion) }
override fun decorateAssertion(
container: AssertionContainer<String>,
featureAssertion: Assertion
): List<Assertion> = listOf(featureAssertion)
}

View File

@@ -2,9 +2,8 @@ package ch.tutteli.atrium.logic.creating.iterable.contains.creators.impl
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.assertions.AssertionGroup
import ch.tutteli.atrium.assertions.DefaultListAssertionGroupType
import ch.tutteli.atrium.assertions.DefaultSummaryAssertionGroupType
import ch.tutteli.atrium.assertions.builders.assertionBuilder
import ch.tutteli.atrium.assertions.builders.invisibleGroup
import ch.tutteli.atrium.core.None
import ch.tutteli.atrium.core.getOrElse
import ch.tutteli.atrium.creating.AssertionContainer
@@ -17,12 +16,15 @@ import ch.tutteli.atrium.logic.creating.iterable.contains.IterableLikeContains
import ch.tutteli.atrium.logic.creating.iterable.contains.searchbehaviours.InAnyOrderSearchBehaviour
import ch.tutteli.atrium.logic.creating.iterable.contains.searchbehaviours.NotSearchBehaviour
import ch.tutteli.atrium.logic.creating.typeutils.IterableLike
import ch.tutteli.atrium.logic.hasNext
import ch.tutteli.atrium.logic.impl.allCreatedAssertionsHold
import ch.tutteli.atrium.logic.impl.createExplanatoryAssertionGroup
import ch.tutteli.atrium.logic.impl.createHasElementAssertion
import ch.tutteli.atrium.logic.impl.createExplanatoryGroupForMismatches
import ch.tutteli.atrium.logic.impl.createIndexAssertions
import ch.tutteli.atrium.reporting.translating.Translatable
import ch.tutteli.atrium.translations.DescriptionIterableAssertion
import ch.tutteli.atrium.translations.DescriptionIterableAssertion.AN_ELEMENT_WHICH
import ch.tutteli.kbox.identity
/**
* Represents a creator of a sophisticated `contains` assertions for [Iterable] where an expected entry can appear
@@ -55,6 +57,26 @@ class InAnyOrderEntriesAssertionCreator<E : Any, T : IterableLike>(
override fun makeSubjectMultipleTimesConsumable(container: AssertionContainer<T>): AssertionContainer<List<E?>> =
turnSubjectToList(container, converter)
override fun decorateInAnyOrderAssertion(
inAnyOrderAssertion: AssertionGroup,
multiConsumableContainer: AssertionContainer<List<E?>>
): AssertionGroup {
val hasNext = multiConsumableContainer.hasNext(::identity)
return if (searchBehaviour is NotSearchBehaviour && !hasNext.holds()) {
assertionBuilder.invisibleGroup
.withAssertions(
hasNext,
assertionBuilder.explanatoryGroup
.withDefaultType
.withAssertion(inAnyOrderAssertion)
.build()
)
.build()
} else {
inAnyOrderAssertion
}
}
override fun searchAndCreateAssertion(
multiConsumableContainer: AssertionContainer<List<E?>>,
searchCriterion: (Expect<E>.() -> Unit)?,
@@ -68,15 +90,18 @@ class InAnyOrderEntriesAssertionCreator<E : Any, T : IterableLike>(
)
val featureAssertion = featureFactory(count, DescriptionIterableAssertion.NUMBER_OF_OCCURRENCES)
val assertions = mutableListOf<Assertion>(explanatoryGroup, featureAssertion)
val groupType = if (searchBehaviour is NotSearchBehaviour) {
assertions.add(createHasElementAssertion(list))
addEmptyAssertionCreatorLambdaIfNecessary(multiConsumableContainer, assertions, searchCriterion, count)
DefaultSummaryAssertionGroupType
val assertions = mutableListOf<Assertion>(explanatoryGroup)
if (searchBehaviour is NotSearchBehaviour) {
createEmptyAssertionHintIfNecessary(multiConsumableContainer, searchCriterion, count)
?.let { assertions.add(it) }
val mismatches = createIndexAssertions(list) { (_, element) ->
allCreatedAssertionsHold(multiConsumableContainer, element, searchCriterion)
}
if (mismatches.isNotEmpty()) assertions.add(createExplanatoryGroupForMismatches(mismatches))
} else {
DefaultListAssertionGroupType
assertions.add(featureAssertion)
}
return assertionBuilder.customType(groupType)
return assertionBuilder.list
.withDescriptionAndEmptyRepresentation(AN_ELEMENT_WHICH)
.withAssertions(assertions)
.build()
@@ -97,21 +122,21 @@ class InAnyOrderEntriesAssertionCreator<E : Any, T : IterableLike>(
// maybe it would be enough to collect
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
@UseExperimental(ExperimentalComponentFactoryContainer::class)
private fun addEmptyAssertionCreatorLambdaIfNecessary(
private fun createEmptyAssertionHintIfNecessary(
container: AssertionContainer<*>,
assertions: MutableList<Assertion>,
searchCriterion: (Expect<E>.() -> Unit)?,
count: Int
) {
): Assertion? {
if (searchCriterion != null && count == 0) {
val collectingExpect = CollectingExpect<E>(None, container.components)
// not using addAssertionsCreatedBy on purpose so that we don't append a failing assertion
collectingExpect.searchCriterion()
val collectedAssertions = collectingExpect.getAssertions()
if (collectedAssertions.isEmpty()) {
// no assertion created in the lambda, so lets add the failing assertion containing the hint
assertions.add(container.collectBasedOnSubject(None, searchCriterion))
// no assertion created in the lambda, so return the failing assertion containing the hint
return container.collectBasedOnSubject(None, searchCriterion)
}
}
return null
}
}

View File

@@ -1,6 +1,9 @@
package ch.tutteli.atrium.logic.creating.iterable.contains.creators.impl
import ch.tutteli.atrium.assertions.*
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.assertions.AssertionGroup
import ch.tutteli.atrium.assertions.builders.assertionBuilder
import ch.tutteli.atrium.assertions.builders.invisibleGroup
import ch.tutteli.atrium.core.getOrElse
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.logic.creating.basic.contains.creators.impl.ContainsObjectsAssertionCreator
@@ -8,9 +11,12 @@ import ch.tutteli.atrium.logic.creating.iterable.contains.IterableLikeContains
import ch.tutteli.atrium.logic.creating.iterable.contains.searchbehaviours.InAnyOrderSearchBehaviour
import ch.tutteli.atrium.logic.creating.iterable.contains.searchbehaviours.NotSearchBehaviour
import ch.tutteli.atrium.logic.creating.typeutils.IterableLike
import ch.tutteli.atrium.logic.impl.createHasElementAssertion
import ch.tutteli.atrium.logic.hasNext
import ch.tutteli.atrium.logic.impl.createExplanatoryGroupForMismatches
import ch.tutteli.atrium.logic.impl.createIndexAssertions
import ch.tutteli.atrium.reporting.translating.Translatable
import ch.tutteli.atrium.translations.DescriptionIterableAssertion
import ch.tutteli.kbox.identity
/**
* Represents a creator of a sophisticated `contains` assertions for [Iterable] where an expected entry can appear
@@ -38,31 +44,49 @@ class InAnyOrderValuesAssertionCreator<SC, T : IterableLike>(
override val descriptionNumberOfOccurrences: Translatable = DescriptionIterableAssertion.NUMBER_OF_OCCURRENCES
override val groupDescription: Translatable = DescriptionIterableAssertion.AN_ELEMENT_WHICH_EQUALS
override fun getAssertionGroupType(): AssertionGroupType {
return if (searchBehaviour is NotSearchBehaviour) {
DefaultSummaryAssertionGroupType
} else {
DefaultListAssertionGroupType
}
}
override fun makeSubjectMultipleTimesConsumable(container: AssertionContainer<T>): AssertionContainer<List<SC>> =
turnSubjectToList(container, converter)
override fun search(multiConsumableContainer: AssertionContainer<List<SC>>, searchCriterion: SC): Int =
multiConsumableContainer.maybeSubject.fold({ -1 }) { subject -> subject.filter { it == searchCriterion }.size }
override fun decorateAssertion(
container: AssertionContainer<List<SC>>,
featureAssertion: Assertion
): List<Assertion> {
override fun searchAndCreateAssertion(
multiConsumableContainer: AssertionContainer<List<SC>>,
searchCriterion: SC,
featureFactory: (Int, Translatable) -> AssertionGroup
): AssertionGroup {
return if (searchBehaviour is NotSearchBehaviour) {
listOf(
featureAssertion,
createHasElementAssertion(container.maybeSubject.getOrElse { emptyList() })
)
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 {
listOf(featureAssertion)
super.searchAndCreateAssertion(multiConsumableContainer, searchCriterion, featureFactory)
}
}
/**
* Override in a subclass if you want to decorate the assertion.
*/
override fun decorateInAnyOrderAssertion(
inAnyOrderAssertion: AssertionGroup,
multiConsumableContainer: AssertionContainer<List<SC>>
): AssertionGroup {
val hasNext = multiConsumableContainer.hasNext(::identity)
return if (searchBehaviour is NotSearchBehaviour && !hasNext.holds()) {
assertionBuilder.invisibleGroup.withAssertions(
hasNext,
assertionBuilder.explanatoryGroup
.withDefaultType
.withAssertion(inAnyOrderAssertion)
.build()
).build()
} else {
inAnyOrderAssertion
}
}
}

View File

@@ -3,7 +3,6 @@ package ch.tutteli.atrium.logic.impl
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.assertions.builders.*
import ch.tutteli.atrium.core.Option
import ch.tutteli.atrium.core.falseProvider
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.logic.IterableLikeAssertions
@@ -27,7 +26,6 @@ import ch.tutteli.atrium.reporting.translating.TranslatableWithArgs
import ch.tutteli.atrium.translations.DescriptionBasic
import ch.tutteli.atrium.translations.DescriptionIterableAssertion
import ch.tutteli.atrium.translations.DescriptionIterableAssertion.NEXT_ELEMENT
import ch.tutteli.kbox.WithIndex
import ch.tutteli.kbox.mapWithIndex
class DefaultIterableLikeAssertions : IterableLikeAssertions {
@@ -101,17 +99,7 @@ class DefaultIterableLikeAssertions : IterableLikeAssertions {
val mismatches = createIndexAssertions(list) { (_, element) ->
!allCreatedAssertionsHold(container, element, assertionCreatorOrNull)
}
assertions.add(
assertionBuilder.explanatoryGroup
.withWarningType
.withAssertion(
assertionBuilder.list
.withDescriptionAndEmptyRepresentation(DescriptionIterableAssertion.WARNING_MISMATCHES)
.withAssertions(mismatches)
.build()
)
.build()
)
assertions.add(createExplanatoryGroupForMismatches(mismatches))
createHasElementPlusFixedClaimGroup(
list,
@@ -134,22 +122,6 @@ class DefaultIterableLikeAssertions : IterableLikeAssertions {
}
}
private fun <E> createIndexAssertions(
list: List<E>,
predicate: (WithIndex<E>) -> Boolean
) = list
.asSequence()
.mapWithIndex()
.filter { predicate(it) }
.map { (index, element) ->
assertionBuilder.createDescriptive(
TranslatableWithArgs(DescriptionIterableAssertion.INDEX, index),
element,
falseProvider
)
}
.toList()
private fun <E> createHasElementPlusFixedClaimGroup(
list: List<E>,
description: Translatable,

View File

@@ -5,14 +5,18 @@ import ch.tutteli.atrium.assertions.AssertionGroup
import ch.tutteli.atrium.assertions.builders.assertionBuilder
import ch.tutteli.atrium.core.None
import ch.tutteli.atrium.core.Some
import ch.tutteli.atrium.core.falseProvider
import ch.tutteli.atrium.core.trueProvider
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.logic.collectBasedOnSubject
import ch.tutteli.atrium.logic.creating.collectors.collectAssertions
import ch.tutteli.atrium.reporting.Text
import ch.tutteli.atrium.reporting.translating.TranslatableWithArgs
import ch.tutteli.atrium.translations.DescriptionBasic
import ch.tutteli.atrium.translations.DescriptionIterableAssertion
import ch.tutteli.kbox.WithIndex
import ch.tutteli.kbox.mapWithIndex
internal fun createHasElementAssertion(list: List<*>): Assertion {
return assertionBuilder.feature
@@ -53,3 +57,34 @@ internal fun <E : Any> createExplanatoryAssertionGroup(
}
.build()
}
internal fun <E> createIndexAssertions(
list: List<E>,
predicate: (WithIndex<E>) -> Boolean
) = list
.asSequence()
.mapWithIndex()
.filter { predicate(it) }
.map { (index, element) ->
assertionBuilder.createDescriptive(
TranslatableWithArgs(DescriptionIterableAssertion.INDEX, index),
element,
falseProvider
)
}
.toList()
internal fun createExplanatoryGroupForMismatches(
mismatches: List<Assertion>
) : AssertionGroup {
return assertionBuilder.explanatoryGroup
.withWarningType
.withAssertion(
assertionBuilder.list
.withDescriptionAndEmptyRepresentation(DescriptionIterableAssertion.WARNING_MISMATCHES)
.withAssertions(mismatches)
.build()
)
.failing
.build()
}

View File

@@ -45,7 +45,6 @@ abstract class IterableNotToContainEntriesExpectationsSpec(
) = notToContainNullableEntries(this, a, aX)
val notToContainDescr = DescriptionIterableAssertion.CONTAINS_NOT.getDefault()
val hasElement = DescriptionIterableAssertion.HAS_ELEMENT.getDefault()
nonNullableCases(
describePrefix,
@@ -67,13 +66,10 @@ abstract class IterableNotToContainEntriesExpectationsSpec(
}.toThrow<AssertionError> {
message {
toContainRegex(
"\\Q$rootBulletPoint\\E$notToContainDescr: $separator" +
"$indentRootBulletPoint\\Q$listBulletPoint\\E$anElementWhich: $separator" +
"$afterExplanatory$toBeDescr: 4.0.*$separator" +
"$featureSuccess$numberOfOccurrences: 0$separator" +
"$isAfterSuccess: 0.*$separator" +
"$featureFailing$hasElement: false$separator" +
"$isAfterFailing: true"
"$hasANextElement$separator" +
"$indentRootBulletPoint\\Q$explanatoryBulletPoint\\E$notToContainDescr: $separator" +
"$indentRootBulletPoint$indentListBulletPoint\\Q$listBulletPoint\\E$anElementWhich: $separator" +
"$indentListBulletPoint$afterExplanatory$toBeDescr: 4.0.*"
)
}
}
@@ -104,10 +100,10 @@ abstract class IterableNotToContainEntriesExpectationsSpec(
"\\Q$rootBulletPoint\\E$notToContainDescr: $separator" +
"$indentRootBulletPoint\\Q$listBulletPoint\\E$anElementWhich: $separator" +
"$afterExplanatory$toBeLessThanDescr: 4.0.*$separator" +
"$featureFailing$numberOfOccurrences: 3$separator" +
"$isAfterFailing: 0.*$separator" +
"$featureSuccess$hasElement: true$separator" +
"$isAfterSuccess: true"
"$afterExplanatoryIndent\\Q$warningBulletPoint$mismatches:\\E $separator" +
"$afterMismatchedWarning${mismatchedIndex(0, "1.0")}.*$separator" +
"$afterMismatchedWarning${mismatchedIndex(1, "2.0")}.*$separator" +
"$afterMismatchedWarning${mismatchedIndex(5, "3.0")}.*"
)
}
}
@@ -121,16 +117,14 @@ abstract class IterableNotToContainEntriesExpectationsSpec(
"\\Q$rootBulletPoint\\E$notToContainDescr: $separator" +
"$indentRootBulletPoint\\Q$listBulletPoint\\E$anElementWhich: $separator" +
"$afterExplanatory$toBeDescr: 1.0.*$separator" +
"$featureFailing$numberOfOccurrences: 1$separator" +
"$isAfterFailing: 0.*$separator" +
"$featureSuccess$hasElement: true$separator" +
"$isAfterSuccess: true$separator" +
"$afterExplanatoryIndent\\Q$warningBulletPoint$mismatches:\\E $separator" +
"$afterMismatchedWarning${mismatchedIndex(0, "1.0")}.*$separator" +
"$indentRootBulletPoint\\Q$listBulletPoint\\E$anElementWhich: $separator" +
"$afterExplanatory$toBeDescr: 4.0.*$separator" +
"$featureFailing$numberOfOccurrences: 3$separator" +
"$isAfterFailing: 0.*$separator" +
"$featureSuccess$hasElement: true$separator" +
"$isAfterSuccess: true"
"$afterExplanatoryIndent\\Q$warningBulletPoint$mismatches:\\E $separator" +
"$afterMismatchedWarning${mismatchedIndex(2, "4.0")}.*$separator" +
"$afterMismatchedWarning${mismatchedIndex(3, "4.0")}.*$separator" +
"$afterMismatchedWarning${mismatchedIndex(8, "4.0")}.*"
)
}
}
@@ -167,10 +161,9 @@ abstract class IterableNotToContainEntriesExpectationsSpec(
"\\Q$rootBulletPoint\\E$notToContainDescr: $separator" +
"$indentRootBulletPoint\\Q$listBulletPoint\\E$anElementWhich: $separator" +
"$afterExplanatory$isDescr: null$separator" +
"$featureFailing$numberOfOccurrences: 2$separator" +
"$isAfterFailing: 0.*$separator" +
"$featureSuccess$hasElement: true$separator" +
"$isAfterSuccess: true"
"$afterExplanatoryIndent\\Q$warningBulletPoint$mismatches:\\E $separator" +
"$afterMismatchedWarning${mismatchedIndex(1, "null")}.*$separator" +
"$afterMismatchedWarning${mismatchedIndex(5, "null")}.*"
)
}
}
@@ -185,10 +178,9 @@ abstract class IterableNotToContainEntriesExpectationsSpec(
"\\Q$rootBulletPoint\\E$notToContainDescr: $separator" +
"$indentRootBulletPoint\\Q$listBulletPoint\\E$anElementWhich: $separator" +
"$afterExplanatory$isDescr: null$separator" +
"$featureFailing$numberOfOccurrences: 2$separator" +
"$isAfterFailing: 0.*$separator" +
"$featureSuccess$hasElement: true$separator" +
"$isAfterSuccess: true"
"$afterExplanatoryIndent\\Q$warningBulletPoint$mismatches:\\E $separator" +
"$afterMismatchedWarning${index(1)}: null.*$separator" +
"$afterMismatchedWarning${index(5)}: null.*"
)
this.notToContain("$notToContainDescr: 1.1")
}

View File

@@ -4,7 +4,6 @@ import ch.tutteli.atrium.api.fluent.en_GB.*
import ch.tutteli.atrium.api.verbs.internal.expect
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.specs.*
import ch.tutteli.atrium.translations.DescriptionIterableAssertion
abstract class IterableNotToContainValuesExpectationsSpec(
notToContainValues: Fun2<Iterable<Double>, Double, Array<out Double>>,
@@ -24,9 +23,6 @@ abstract class IterableNotToContainValuesExpectationsSpec(
fun Expect<Iterable<Double?>>.notToContainNullableFun(a: Double?, vararg aX: Double?) =
notToContainNullableValues(this, a, aX)
val notToContainDescr = DescriptionIterableAssertion.CONTAINS_NOT.getDefault()
val hasElement = DescriptionIterableAssertion.HAS_ELEMENT.getDefault()
val anElementWhichIsWithIndent = "$indentRootBulletPoint$listBulletPoint$anElementWhichIs"
nonNullableCases(
@@ -46,12 +42,9 @@ abstract class IterableNotToContainValuesExpectationsSpec(
}.toThrow<AssertionError> {
message {
toContainRegex(
"\\Q$rootBulletPoint\\E$notToContainDescr: $separator" +
"$anElementWhichIsWithIndent: 4.0.*$separator" +
"$featureSuccess$numberOfOccurrences: 0$separator" +
"$isAfterSuccess: 0.*$separator" +
"$featureFailing$hasElement: false$separator" +
"$isAfterFailing: true"
"$hasANextElement$separator" +
"$indentRootBulletPoint\\Q$explanatoryBulletPoint\\E$notToContainDescr: $separator" +
"$indentListBulletPoint$anElementWhichIsWithIndent: 4.0.*"
)
}
}
@@ -81,10 +74,10 @@ abstract class IterableNotToContainValuesExpectationsSpec(
toContainRegex(
"\\Q$rootBulletPoint\\E$notToContainDescr: $separator" +
"$anElementWhichIsWithIndent: 4.0.*$separator" +
"$featureFailing$numberOfOccurrences: 3$separator" +
"$isAfterFailing: 0.*$separator" +
"$featureSuccess$hasElement: true$separator" +
"$isAfterSuccess: true"
"$afterExplanatoryIndent\\Q$warningBulletPoint$mismatches:\\E $separator" +
"$afterMismatchedWarning${mismatchedIndex(2, "4.0")}.*$separator" +
"$afterMismatchedWarning${mismatchedIndex(3, "4.0")}.*$separator" +
"$afterMismatchedWarning${mismatchedIndex(8, "4.0")}.*"
)
}
}
@@ -97,15 +90,13 @@ abstract class IterableNotToContainValuesExpectationsSpec(
toContainRegex(
"\\Q$rootBulletPoint\\E$notToContainDescr: $separator" +
"$anElementWhichIsWithIndent: 1.0.*$separator" +
"$featureFailing$numberOfOccurrences: 1$separator" +
"$isAfterFailing: 0.*$separator" +
"$featureSuccess$hasElement: true$separator" +
"$isAfterSuccess: true$separator" +
"$afterExplanatoryIndent\\Q$warningBulletPoint$mismatches:\\E $separator" +
"$afterMismatchedWarning${mismatchedIndex(0, "1.0")}.*$separator" +
"$anElementWhichIsWithIndent: 4.0.*$separator" +
"$featureFailing$numberOfOccurrences: 3$separator" +
"$isAfterFailing: 0.*$separator" +
"$featureSuccess$hasElement: true$separator" +
"$isAfterSuccess: true"
"$afterExplanatoryIndent\\Q$warningBulletPoint$mismatches:\\E $separator" +
"$afterMismatchedWarning${mismatchedIndex(2, "4.0")}.*$separator" +
"$afterMismatchedWarning${mismatchedIndex(3, "4.0")}.*$separator" +
"$afterMismatchedWarning${mismatchedIndex(8, "4.0")}.*"
)
}
}
@@ -118,15 +109,13 @@ abstract class IterableNotToContainValuesExpectationsSpec(
toContainRegex(
"\\Q$rootBulletPoint\\E$notToContainDescr: $separator" +
"$anElementWhichIsWithIndent: 4.0.*$separator" +
"$featureFailing$numberOfOccurrences: 3$separator" +
"$isAfterFailing: 0.*$separator" +
"$featureSuccess$hasElement: true$separator" +
"$isAfterSuccess: true$separator" +
"$afterExplanatoryIndent\\Q$warningBulletPoint$mismatches:\\E $separator" +
"$afterMismatchedWarning${mismatchedIndex(2, "4.0")}.*$separator" +
"$afterMismatchedWarning${mismatchedIndex(3, "4.0")}.*$separator" +
"$afterMismatchedWarning${mismatchedIndex(8, "4.0")}.*$separator" +
"$anElementWhichIsWithIndent: 1.0.*$separator" +
"$featureFailing$numberOfOccurrences: 1$separator" +
"$isAfterFailing: 0.*$separator" +
"$featureSuccess$hasElement: true$separator" +
"$isAfterSuccess: true"
"$afterExplanatoryIndent\\Q$warningBulletPoint$mismatches:\\E $separator" +
"$afterMismatchedWarning${mismatchedIndex(0, "1.0")}.*"
)
}
}
@@ -152,10 +141,9 @@ abstract class IterableNotToContainValuesExpectationsSpec(
toContainRegex(
"\\Q$rootBulletPoint\\E$notToContainDescr: $separator" +
"$anElementWhichIsWithIndent: null$separator" +
"$featureFailing$numberOfOccurrences: 2$separator" +
"$isAfterFailing: 0.*$separator" +
"$featureSuccess$hasElement: true$separator" +
"$isAfterSuccess: true"
"$afterExplanatoryIndent\\Q$warningBulletPoint$mismatches:\\E $separator" +
"$afterMismatchedWarning${mismatchedIndex(1, "null")}.*$separator" +
"$afterMismatchedWarning${mismatchedIndex(5, "null")}.*"
)
}
}
@@ -169,10 +157,9 @@ abstract class IterableNotToContainValuesExpectationsSpec(
toContainRegex(
"\\Q$rootBulletPoint\\E$notToContainDescr: $separator" +
"$anElementWhichIsWithIndent: null$separator" +
"$featureFailing$numberOfOccurrences: 2$separator" +
"$isAfterFailing: 0.*$separator" +
"$featureSuccess$hasElement: true$separator" +
"$isAfterSuccess: true"
"$afterExplanatoryIndent\\Q$warningBulletPoint$mismatches:\\E $separator" +
"$afterMismatchedWarning${mismatchedIndex(1, "null")}.*$separator" +
"$afterMismatchedWarning${mismatchedIndex(5, "null")}.*"
)
notToContain("$notToContainDescr: 1.1")
}

View File

@@ -23,14 +23,18 @@ abstract class IterableToContainEntriesSpecBase(
val anElementWhich = DescriptionIterableAssertion.AN_ELEMENT_WHICH.getDefault()
val toBeLessThanDescr = DescriptionComparableAssertion.IS_LESS_THAN.getDefault()
val toBeGreaterThanDescr = DescriptionComparableAssertion.IS_GREATER_THAN.getDefault()
fun <T> mismatchedIndex(index: Int, value: T) : String {
val indexDescr = String.format(DescriptionIterableAssertion.INDEX.getDefault(), index)
return "$indexDescr: ${value.toString()}"
}
fun index(index: Int) = String.format(DescriptionIterableAssertion.INDEX.getDefault(), index)
//@formatter:off
val featureSuccess = "$indentRootBulletPoint$indentListBulletPoint\\Q$successfulBulletPoint$featureArrow\\E"
val featureFailing = "$indentRootBulletPoint$indentListBulletPoint\\Q$failingBulletPoint$featureArrow\\E"
val isAfterFailing = "$indentRootBulletPoint$indentListBulletPoint$indentFailingBulletPoint$indentFeatureArrow\\Q$featureBulletPoint\\E$isDescr"
val isAfterSuccess = "$indentRootBulletPoint$indentListBulletPoint$indentSuccessfulBulletPoint$indentFeatureArrow\\Q$featureBulletPoint\\E$isDescr"
val afterExplanatory = "$indentRootBulletPoint$indentListBulletPoint$indentSuccessfulBulletPoint\\Q$explanatoryBulletPoint\\E"
val afterExplanatoryIndent = "$indentRootBulletPoint$indentListBulletPoint$indentSuccessfulBulletPoint"
val afterMismatchedWarning = "$afterExplanatoryIndent$indentWarningBulletPoint\\Q$listBulletPoint\\E"
val hasANextElement = "\\Q$rootBulletPoint\\E$hasDescriptionBasic: $nextElement"
//@formatter:on
}

View File

@@ -6,6 +6,7 @@ import ch.tutteli.atrium.api.fluent.en_GB.toContain
import ch.tutteli.atrium.core.polyfills.format
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.specs.*
import ch.tutteli.atrium.translations.DescriptionBasic
import ch.tutteli.atrium.translations.DescriptionCollectionAssertion
import ch.tutteli.atrium.translations.DescriptionIterableAssertion
import org.spekframework.spek2.Spek
@@ -43,6 +44,9 @@ abstract class IterableToContainSpecBase(spec: Root.() -> Unit) : Spek(spec) {
val mismatchesAdditionalElements = DescriptionIterableAssertion.WARNING_MISMATCHES_ADDITIONAL_ELEMENTS.getDefault()
val sizeExceeded = DescriptionIterableAssertion.SIZE_EXCEEDED.getDefault()
val anElementWhichIs = DescriptionIterableAssertion.AN_ELEMENT_WHICH_EQUALS.getDefault()
val hasDescriptionBasic = DescriptionBasic.HAS.getDefault()
val nextElement = DescriptionIterableAssertion.NEXT_ELEMENT.getDefault()
val notToContainDescr = DescriptionIterableAssertion.CONTAINS_NOT.getDefault()
val sizeDescr = DescriptionCollectionAssertion.SIZE.getDefault()
val atLeastDescr = DescriptionIterableAssertion.AT_LEAST.getDefault()

View File

@@ -29,7 +29,6 @@ abstract class IterableToHaveElementsAndNoneExpectationsSpec(
) {})
val containsNotDescr = DescriptionIterableAssertion.CONTAINS_NOT.getDefault()
val hasElement = DescriptionIterableAssertion.HAS_ELEMENT.getDefault()
nonNullableCases(
describePrefix,
@@ -42,7 +41,14 @@ abstract class IterableToHaveElementsAndNoneExpectationsSpec(
expect {
expect(fluentEmpty()).toHaveElementsAndNoneFun { toBeLessThan(1.0) }
}.toThrow<AssertionError> {
messageToContain("$featureArrow$hasElement: false")
message {
toContainRegex(
"$hasANextElement$separator" +
"$indentRootBulletPoint\\Q$explanatoryBulletPoint\\E$containsNotDescr: $separator" +
"$indentRootBulletPoint$indentListBulletPoint\\Q$listBulletPoint\\E$anElementWhich: $separator" +
"$indentListBulletPoint$afterExplanatory$toBeLessThanDescr: 1.0.*"
)
}
}
}
}
@@ -66,10 +72,10 @@ abstract class IterableToHaveElementsAndNoneExpectationsSpec(
"\\Q$rootBulletPoint\\E$containsNotDescr: $separator" +
"$indentRootBulletPoint\\Q$listBulletPoint\\E$anElementWhich: $separator" +
"$afterExplanatory$toBeDescr: 4.0.*$separator" +
"$featureFailing$numberOfOccurrences: 3$separator" +
"$isAfterFailing: 0.*$separator" +
"$featureSuccess$hasElement: true$separator" +
"$isAfterSuccess: true"
"$afterExplanatoryIndent\\Q$warningBulletPoint$mismatches:\\E $separator" +
"$afterMismatchedWarning${mismatchedIndex(2, "4.0")}.*$separator" +
"$afterMismatchedWarning${mismatchedIndex(3, "4.0")}.*$separator" +
"$afterMismatchedWarning${mismatchedIndex(8, "4.0")}.*"
)
}
}
@@ -96,10 +102,9 @@ abstract class IterableToHaveElementsAndNoneExpectationsSpec(
"\\Q$rootBulletPoint\\E$containsNotDescr: $separator" +
"$indentRootBulletPoint\\Q$listBulletPoint\\E$anElementWhich: $separator" +
"$afterExplanatory$isDescr: null$separator" +
"$featureFailing$numberOfOccurrences: 2$separator" +
"$isAfterFailing: 0.*$separator" +
"$featureSuccess$hasElement: true$separator" +
"$isAfterSuccess: true"
"$afterExplanatoryIndent\\Q$warningBulletPoint$mismatches:\\E $separator" +
"$afterMismatchedWarning${mismatchedIndex(1, "null")}.*$separator" +
"$afterMismatchedWarning${mismatchedIndex(5, "null")}.*"
)
}
}
@@ -114,10 +119,8 @@ abstract class IterableToHaveElementsAndNoneExpectationsSpec(
"\\Q$rootBulletPoint\\E$containsNotDescr: $separator" +
"$indentRootBulletPoint\\Q$listBulletPoint\\E$anElementWhich: $separator" +
"$afterExplanatory$toBeDescr: 1.0.*$separator" +
"$featureFailing$numberOfOccurrences: 1$separator" +
"$isAfterFailing: 0.*$separator" +
"$featureSuccess$hasElement: true$separator" +
"$isAfterSuccess: true"
"$afterExplanatoryIndent\\Q$warningBulletPoint$mismatches:\\E $separator" +
"$afterMismatchedWarning${mismatchedIndex(0, "1.0")}.*"
)
}
}

View File

@@ -32,7 +32,10 @@ buildscript {
"BigDecimalAssertionsSpec.*overload throws PleaseUseReplacementException",
// we renamed containsNot to notToContain with 0.17.0
"CharSequenceContains.*Spec.*points to containsNot",
"IterableContains.*Spec.*points to containsNot"
"IterableContains.*Spec.*points to containsNot",
// we improved reporting for notToContain with 0.17.0
"IterableContainsNot(Entries|Values)AssertionsSpec.*`containsNot( nullable)?`.*throws AssertionError",
"IterableNoneAssertionsSpec.*`(none|containsNot)( nullable)?`.*throws AssertionError"
) + ".*)",
// we don't use asci bullet points in reporting since 0.17.0
// but have own tests to assure that changing bullet points work
@@ -92,7 +95,10 @@ buildscript {
"BigDecimalAssertionsSpec.*overload throws PleaseUseReplacementException.*",
// we renamed containsNot to notToContain with 0.17.0
"CharSequenceContains.*Spec.*points to containsNot",
"IterableContains.*Spec.*points to containsNot"
"IterableContains.*Spec.*points to containsNot",
// we improved reporting for notToContain with 0.17.0
"IterableContainsNot(Entries|Values)AssertionsSpec.*`containsNot.*`.*throws AssertionError",
"IterableNoneAssertionsSpec.*`(none|containsNot).*`.*throws AssertionError"
) + ".*)",
// we don't use asci bullet points in reporting since 0.17.0
// but have own tests to assure that changing bullet points work
@@ -153,7 +159,10 @@ buildscript {
"CharSequenceContains.*Spec.*points to containsNot",
"IterableContains.*Spec.*points to containsNot",
// we improved reporting for containsNoDuplicates
"IterableExpectationsSpec.*`(containsNoDuplicates|contains noDuplicates)`"
"IterableExpectationsSpec.*`(containsNoDuplicates|contains noDuplicates)`",
// we improved reporting for notToContain with 0.17.0
"IterableContainsNot(Entries|Values)ExpectationsSpec.*`containsNot.*`.*throws AssertionError",
"IterableNoneExpectationsSpec.*`(none|containsNot).*`.*throws AssertionError"
) + ".*)").let { commonPatterns ->
Pair(
// bc