Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hint not to contain #1156

Merged
merged 2 commits into from
Jun 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1944,7 +1944,7 @@ expect(BigDecimal.TEN).toEqualIncludingScale(BigDecimal("10.0"))
```text
I expected subject: 10 (java.math.BigDecimal <1234789>)
◆ is equal (including scale): 10.0 (java.math.BigDecimal <1234789>)
notice, if you used toEqualNumerically then the expectation would have been met.
💡 notice, if you used toEqualNumerically then the expectation would have been met.
```
</ex-pitfall-1>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ internal object StaticNames {
val atMost = IterableLikeContains.EntryPointStep<*, *, InAnyOrderSearchBehaviour>::atMost.name
val exactly = IterableLikeContains.EntryPointStep<*, *, InAnyOrderSearchBehaviour>::exactly.name
val notOrAtMost = IterableLikeContains.EntryPointStep<*, *, InAnyOrderSearchBehaviour>::notOrAtMost.name

/** @since 0.19.0 */
val notToHaveElementsOrNone = Expect<List<Int>>::notToHaveElementsOrNone.name
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ch.tutteli.atrium.api.fluent.en_GB

import ch.tutteli.atrium.api.fluent.en_GB.creating.iterable.contains.impl.StaticNames
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.logic._logic
import ch.tutteli.atrium.logic.creating.typeutils.IterableLike
Expand Down Expand Up @@ -52,7 +53,7 @@ fun <E, T: IterableLike> CheckerStep<E, T, InAnyOrderSearchBehaviour>.value(expe
fun <E, T: IterableLike> CheckerStep<E, T, InAnyOrderSearchBehaviour>.values(
expected: E,
vararg otherExpected: E
): Expect<T> = _logicAppend { values(expected glue otherExpected) }
): Expect<T> = _logicAppend { values(expected glue otherExpected, StaticNames.notToHaveElementsOrNone) }

/**
* Finishes the specification of the sophisticated `contains` assertion where the subject (an [IterableLike])
Expand Down Expand Up @@ -93,8 +94,7 @@ fun <E : Any, T: IterableLike> CheckerStep<out E?, T, InAnyOrderSearchBehaviour>
fun <E : Any, T: IterableLike> CheckerStep<out E?, T, InAnyOrderSearchBehaviour>.entries(
assertionCreatorOrNull: (Expect<E>.() -> Unit)?,
vararg otherAssertionCreatorsOrNulls: (Expect<E>.() -> Unit)?
): Expect<T> = _logicAppend { entries(assertionCreatorOrNull glue otherAssertionCreatorsOrNulls) }

): Expect<T> = _logicAppend { entries(assertionCreatorOrNull glue otherAssertionCreatorsOrNulls, StaticNames.notToHaveElementsOrNone) }

/**
* Finishes the specification of the sophisticated `contains` assertion where the subject (an [IterableLike])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class IterableNotToContainEntriesExpectationsSpec :
ch.tutteli.atrium.specs.integration.IterableNotToContainEntriesExpectationsSpec(
functionDescription to Companion::notToContainFun,
(functionDescription to Companion::notToContainNullableFun).withNullableSuffix(),
Expect<List<Int>>::notToHaveElementsOrNone.name,
"[Atrium][Builder] "
) {
companion object : IterableToContainSpecBase() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ class IterableToContainNotValuesExpectationsSpec : Spek({
object BuilderSpec : ch.tutteli.atrium.specs.integration.IterableNotToContainValuesExpectationsSpec(
functionDescription to C::notToContainFun,
(functionDescription to C::notToContainNullableFun).withNullableSuffix(),
Expect<List<Int>>::notToHaveElementsOrNone.name,
"[Atrium][Builder] "
)

object ShortcutSpec : ch.tutteli.atrium.specs.integration.IterableNotToContainValuesExpectationsSpec(
fun2<Iterable<Double>,Double, Array<out Double>>(Expect<Iterable<Double>>::notToContain),
fun2<Iterable<Double?>,Double?, Array<out Double?>>(Expect<Iterable<Double?>>::notToContain).withNullableSuffix(),
Expect<List<Int>>::notToHaveElementsOrNone.name,
"[Atrium][Shortcut] "
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,7 @@ internal object StaticNames {
val atMost = IterableLikeContains.EntryPointStep<*, *, InAnyOrderSearchBehaviour>::atMost.name
val exactly = IterableLikeContains.EntryPointStep<*, *, InAnyOrderSearchBehaviour>::exactly.name
val notOrAtMost = IterableLikeContains.EntryPointStep<*, *, InAnyOrderSearchBehaviour>::notOrAtMost.name

/** @since 0.19.0 */
val notToHaveElementsOrNone = Expect<List<Int>>::notToHaveElementsOrNone.name
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ch.tutteli.atrium.api.infix.en_GB

import ch.tutteli.atrium.api.infix.en_GB.creating.Entries
import ch.tutteli.atrium.api.infix.en_GB.creating.Values
import ch.tutteli.atrium.api.infix.en_GB.creating.iterable.contains.impl.StaticNames
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.logic._logic
import ch.tutteli.atrium.logic._logicAppend
Expand Down Expand Up @@ -51,7 +52,7 @@ infix fun <E, T : IterableLike> CheckerStep<E, T, InAnyOrderSearchBehaviour>.val
* @since 0.14.0 -- API existed for [Iterable] but not for [IterableLike].
*/
infix fun <E, T : IterableLike> CheckerStep<E, T, InAnyOrderSearchBehaviour>.the(values: Values<E>): Expect<T> =
_logicAppend { values(values.toList()) }
_logicAppend { values(values.toList(), StaticNames.notToHaveElementsOrNone) }

/**
* Finishes the specification of the sophisticated `contains` assertion where the subject (an [IterableLike])
Expand Down Expand Up @@ -89,7 +90,7 @@ infix fun <E : Any, T : IterableLike> CheckerStep<out E?, T, InAnyOrderSearchBeh
*/
infix fun <E : Any, T : IterableLike> CheckerStep<out E?, T, InAnyOrderSearchBehaviour>.the(
entries: Entries<E>
): Expect<T> = _logicAppend { entries(entries.toList()) }
): Expect<T> = _logicAppend { entries(entries.toList(), StaticNames.notToHaveElementsOrNone) }

/**
* Finishes the specification of the sophisticated `contains` assertion where the subject (an [IterableLike])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class IterableNotToContainEntriesExpectationsSpec :
ch.tutteli.atrium.specs.integration.IterableNotToContainEntriesExpectationsSpec(
getNotToContainPair(),
getNotToContainNullablePair().withNullableSuffix(),
Expect<List<Int>>::notToHaveElementsOrNone.name,
"[Atrium][Builder] "
) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ class IterableNotToContainValuesExpectationsSpec : Spek({
object BuilderSpecToContain : ch.tutteli.atrium.specs.integration.IterableNotToContainValuesExpectationsSpec(
getNotToContainPair(),
getNotToContainNullablePair(),
Expect<List<Int>>::notToHaveElementsOrNone.name,
"[Atrium][Builder] "
)

object ShortcutSpecToContain : ch.tutteli.atrium.specs.integration.IterableNotToContainValuesExpectationsSpec(
getNotToContainShortcutPair(),
getNotToContainNullablePair(),
Expect<List<Int>>::notToHaveElementsOrNone.name,
"[Atrium][Shortcut] "
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,9 @@ object WarningAssertionGroupType : ExplanatoryAssertionGroupType
* the reason for one or multiple assertions.
*/
data class InformationAssertionGroupType(val withIndent: Boolean) : ExplanatoryAssertionGroupType

/**
* The [AssertionGroupType] for [AssertionGroup]s whose [assertions][AssertionGroup.assertions] are used to document
* a hint about the usage of the chosen function or rules in Atrium
*/
object HintAssertionGroupType : ExplanatoryAssertionGroupType
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ interface ExplanatoryGroup {
fun create(
groupType: ExplanatoryAssertionGroupType,
explanatoryAssertions: List<Assertion>,
holds : Boolean = true
holds: Boolean = true
): FinalStep = FinalStepImpl(groupType, explanatoryAssertions, holds)
}
}
Expand Down Expand Up @@ -176,6 +176,12 @@ interface ExplanatoryAssertionGroupTypeOption {
*/
fun withInformationType(withIndent: Boolean): AssertionsOption<InformationAssertionGroupType, ExplanatoryAssertionGroupFinalStep>

/**
* Builder to create an [AssertionGroup] with a [WarningAssertionGroupType].
* @since 0.19.0
*/
val withHintType: AssertionsOption<HintAssertionGroupType, ExplanatoryGroup.FinalStep>

/**
* Builder to create an [AssertionGroup] with a custom [ExplanatoryAssertionGroupType].
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ internal object GroupTypeOptionImpl : ExplanatoryGroup.GroupTypeOption {
groupType: T
): AssertionsOption<T, ExplanatoryGroup.FinalStep> = createAssertionsOption(groupType)

override val withHintType: AssertionsOption<HintAssertionGroupType, ExplanatoryGroup.FinalStep>
get() = createAssertionsOption(HintAssertionGroupType)

private fun <T : ExplanatoryAssertionGroupType> createAssertionsOption(groupType: T) =
AssertionsOption.withEmptyDescriptionAndRepresentation(
groupType, GroupTypeOptionImpl::createExplanatoryAssertionGroupFinalStep
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class TextExplanatoryAssertionGroupFormatter(
private val explanatoryBulletPoint = bulletPoints[ExplanatoryAssertionGroupType::class] ?: "» "
private val warningBulletPoint = bulletPoints[WarningAssertionGroupType::class] ?: "❗❗ "
private val informationBulletPoint = bulletPoints[InformationAssertionGroupType::class] ?: "ℹ "
private val hintBulletPoint = bulletPoints[HintAssertionGroupType::class] ?: "\uD83D\uDCA1 "

override fun formatGroupHeaderAndGetChildParameterObject(
assertionGroup: AssertionGroup,
Expand All @@ -61,6 +62,7 @@ class TextExplanatoryAssertionGroupFormatter(
assertionGroupType.withIndent
)
WarningAssertionGroupType -> withIndent(warningBulletPoint)
HintAssertionGroupType -> withIndent(hintBulletPoint)
else -> withIndent(explanatoryBulletPoint)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ interface IterableLikeContainsInAnyOrderAssertions {

fun <E, T : IterableLike> values(
checkerStepLogic: IterableLikeContains.CheckerStepLogic<E, T, InAnyOrderSearchBehaviour>,
expected: List<E>
expected: List<E>,
notToHaveNextOrNoneFunName: String
): Assertion

fun <E : Any, T : IterableLike> entries(
checkerStepLogic: IterableLikeContains.CheckerStepLogic<out E?, T, InAnyOrderSearchBehaviour>,
assertionCreators: List<(Expect<E>.() -> Unit)?>
assertionCreators: List<(Expect<E>.() -> Unit)?>,
notToHaveNextOrNoneFunName: String
): Assertion
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,31 @@ import ch.tutteli.atrium.logic.creating.typeutils.IterableLike
class DefaultIterableLikeContainsInAnyOrderAssertions : IterableLikeContainsInAnyOrderAssertions {
override fun <E, T : IterableLike> values(
checkerStepLogic: IterableLikeContains.CheckerStepLogic<E, T, InAnyOrderSearchBehaviour>,
expected: List<E>
): Assertion = createAssertionGroup(checkerStepLogic, expected, ::InAnyOrderValuesAssertionCreator)
expected: List<E>,
notToHaveNextOrNoneFunName: String
): Assertion = createAssertionGroup(
checkerStepLogic, expected, notToHaveNextOrNoneFunName, ::InAnyOrderValuesAssertionCreator
)

override fun <E : Any, T : IterableLike> entries(
checkerStepLogic: IterableLikeContains.CheckerStepLogic<out E?, T, InAnyOrderSearchBehaviour>,
assertionCreators: List<(Expect<E>.() -> Unit)?>
): Assertion = createAssertionGroup(checkerStepLogic, assertionCreators, ::InAnyOrderEntriesAssertionCreator)
assertionCreators: List<(Expect<E>.() -> Unit)?>,
notToHaveNextOrNoneFunName: String
): Assertion = createAssertionGroup(
checkerStepLogic, assertionCreators, notToHaveNextOrNoneFunName, ::InAnyOrderEntriesAssertionCreator
)

private fun <E, T : IterableLike, SC, S : IterableLikeContains.SearchBehaviour> createAssertionGroup(
checkerStepLogic: IterableLikeContains.CheckerStepLogic<E, T, S>,
expected: List<SC>,
factory: ((T) -> Iterable<E>, S, List<IterableLikeContains.Checker>) -> IterableLikeContains.Creator<T, SC>
notToHaveNextOrNoneFunName: String,
factory: ((T) -> Iterable<E>, S, List<IterableLikeContains.Checker>, String) -> IterableLikeContains.Creator<T, SC>
): AssertionGroup {
val creator = factory(
checkerStepLogic.entryPointStepLogic.converter,
checkerStepLogic.entryPointStepLogic.searchBehaviour,
checkerStepLogic.checkers
checkerStepLogic.checkers,
notToHaveNextOrNoneFunName
)
return creator.createAssertionGroup(checkerStepLogic.entryPointStepLogic.container, expected)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,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.builders.assertionBuilder
import ch.tutteli.atrium.assertions.builders.invisibleGroup
import ch.tutteli.atrium.assertions.builders.withExplanatoryAssertion
import ch.tutteli.atrium.core.getOrElse
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.creating.Expect
Expand All @@ -11,11 +13,14 @@ 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.*
import ch.tutteli.atrium.reporting.translating.Translatable
import ch.tutteli.atrium.reporting.translating.TranslatableWithArgs
import ch.tutteli.atrium.translations.DescriptionIterableLikeExpectation
import ch.tutteli.atrium.translations.DescriptionIterableLikeExpectation.AN_ELEMENT_WHICH_NEEDS
import ch.tutteli.atrium.translations.DescriptionIterableLikeExpectation.NUMBER_OF_SUCH_ELEMENTS
import ch.tutteli.kbox.identity

/**
* Represents a creator of a sophisticated `contains` assertions for [Iterable] where an expected entry can appear
Expand All @@ -36,14 +41,16 @@ import ch.tutteli.atrium.translations.DescriptionIterableLikeExpectation.NUMBER_
class InAnyOrderEntriesAssertionCreator<E : Any, T : IterableLike>(
private val converter: (T) -> Iterable<E?>,
searchBehaviour: InAnyOrderSearchBehaviour,
checkers: List<IterableLikeContains.Checker>
checkers: List<IterableLikeContains.Checker>,
private val notToHaveNextOrNoneFunName: String
) : ContainsAssertionCreator<T, List<E?>, (Expect<E>.() -> Unit)?, IterableLikeContains.Checker>(
searchBehaviour,
checkers
),
IterableLikeContains.Creator<T, (Expect<E>.() -> Unit)?> {

override val descriptionToContain: Translatable = DescriptionIterableLikeExpectation.TO_CONTAIN

@Deprecated(
"Use descriptionToContain instead; will be removed with 0.19.0",
replaceWith = ReplaceWith("this.descriptionToContain ")
Expand All @@ -61,9 +68,12 @@ class InAnyOrderEntriesAssertionCreator<E : Any, T : IterableLike>(
inAnyOrderAssertion: AssertionGroup,
multiConsumableContainer: AssertionContainer<List<E?>>
): AssertionGroup {
return if (searchBehaviour is NotSearchBehaviour)
decorateAssertionWithHasNext(inAnyOrderAssertion, multiConsumableContainer)
else inAnyOrderAssertion
return if (searchBehaviour is NotSearchBehaviour) {
val assertion = decorateAssertionWithHasNext(inAnyOrderAssertion, multiConsumableContainer)
decorateWithHintUseNotToHaveElementsOrNone(assertion, multiConsumableContainer, notToHaveNextOrNoneFunName)
} else {
inAnyOrderAssertion
}
}

override fun searchAndCreateAssertion(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import ch.tutteli.atrium.logic.creating.iterable.contains.searchbehaviours.NotSe
import ch.tutteli.atrium.logic.creating.typeutils.IterableLike
import ch.tutteli.atrium.logic.impl.createIndexAssertions
import ch.tutteli.atrium.logic.impl.decorateAssertionWithHasNext
import ch.tutteli.atrium.logic.impl.decorateWithHintUseNotToHaveElementsOrNone
import ch.tutteli.atrium.reporting.translating.Translatable
import ch.tutteli.atrium.translations.DescriptionIterableLikeExpectation

Expand All @@ -30,13 +31,15 @@ import ch.tutteli.atrium.translations.DescriptionIterableLikeExpectation
class InAnyOrderValuesAssertionCreator<SC, T : IterableLike>(
private val converter: (T) -> Iterable<SC>,
searchBehaviour: InAnyOrderSearchBehaviour,
checkers: List<IterableLikeContains.Checker>
checkers: List<IterableLikeContains.Checker>,
private val notToHaveNextOrNoneFunName: String
) : ContainsObjectsAssertionCreator<T, List<SC>, SC, InAnyOrderSearchBehaviour, IterableLikeContains.Checker>(
searchBehaviour,
checkers
), IterableLikeContains.Creator<T, SC> {

override val descriptionToContain: Translatable = DescriptionIterableLikeExpectation.TO_CONTAIN

@Suppress("OverridingDeprecatedMember")
override val descriptionContains: Translatable = descriptionToContain
override val descriptionNumberOfOccurrences: Translatable =
Expand Down Expand Up @@ -71,8 +74,11 @@ class InAnyOrderValuesAssertionCreator<SC, T : IterableLike>(
inAnyOrderAssertion: AssertionGroup,
multiConsumableContainer: AssertionContainer<List<SC>>
): AssertionGroup {
return if (searchBehaviour is NotSearchBehaviour)
decorateAssertionWithHasNext(inAnyOrderAssertion, multiConsumableContainer)
else inAnyOrderAssertion
return if (searchBehaviour is NotSearchBehaviour) {
val assertion = decorateAssertionWithHasNext(inAnyOrderAssertion, multiConsumableContainer)
decorateWithHintUseNotToHaveElementsOrNone(assertion, multiConsumableContainer, notToHaveNextOrNoneFunName)
} else {
inAnyOrderAssertion
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ 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.assertions.builders.withExplanatoryAssertion
import ch.tutteli.atrium.core.None
import ch.tutteli.atrium.core.Some
import ch.tutteli.atrium.core.falseProvider
Expand Down Expand Up @@ -118,3 +119,28 @@ internal fun <E> decorateAssertionWithHasNext(
.build()
}
}
internal fun <E> decorateWithHintUseNotToHaveElementsOrNone(
assertion: AssertionGroup,
listAssertionContainer: AssertionContainer<List<E>>,
notToHaveNextOrNoneFunName: String
): AssertionGroup {
val hasNext = listAssertionContainer.hasNext(::identity)
return if (!hasNext.holds()) {
assertionBuilder.invisibleGroup
.withAssertions(
assertion,
assertionBuilder.explanatoryGroup
.withHintType
.withExplanatoryAssertion(
TranslatableWithArgs(
DescriptionIterableLikeExpectation.USE_NOT_TO_HAVE_ELEMENTS_OR_NONE,
notToHaveNextOrNoneFunName
)
)
.build()
)
.build()
} else {
assertion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
import ch.tutteli.atrium.logic.creating.iterable.contains.creators.impl.DefaultIterableLikeContainsInAnyOrderAssertions


fun <E, T : IterableLike> IterableLikeContains.CheckerStepLogic<E, T, InAnyOrderSearchBehaviour>.values(expected: List<E>): Assertion = impl.values(this, expected)
fun <E, T : IterableLike> IterableLikeContains.CheckerStepLogic<E, T, InAnyOrderSearchBehaviour>.values(expected: List<E>, notToHaveNextOrNoneFunName: String): Assertion =
impl.values(this, expected, notToHaveNextOrNoneFunName)

fun <E : Any, T : IterableLike> IterableLikeContains.CheckerStepLogic<out E?, T, InAnyOrderSearchBehaviour>.entries(assertionCreators: List<(Expect<E>.() -> Unit)?>): Assertion = impl.entries(this, assertionCreators)
fun <E : Any, T : IterableLike> IterableLikeContains.CheckerStepLogic<out E?, T, InAnyOrderSearchBehaviour>.entries(assertionCreators: List<(Expect<E>.() -> Unit)?>, notToHaveNextOrNoneFunName: String): Assertion =
impl.entries(this, assertionCreators, notToHaveNextOrNoneFunName)

@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
@UseExperimental(ExperimentalNewExpectTypes::class)
Expand Down
Loading