All Downloads are FREE. Search and download functionalities are using the official Maven repository.

main.kotlin.ch.tutteli.atrium.logic.impl.DefaultIterableLikeAssertions.kt Maven / Gradle / Ivy

There is a newer version: 1.0.0
Show newest version
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.getOrElse
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.logic.*
import ch.tutteli.atrium.logic.assertions.impl.LazyThreadUnsafeAssertionGroup
import ch.tutteli.atrium.logic.creating.iterable.contains.IterableLikeContains
import ch.tutteli.atrium.logic.creating.iterable.contains.creators.impl.turnSubjectToList
import ch.tutteli.atrium.logic.creating.iterable.contains.searchbehaviours.NoOpSearchBehaviour
import ch.tutteli.atrium.logic.creating.iterable.contains.searchbehaviours.NotSearchBehaviour
import ch.tutteli.atrium.logic.creating.iterable.contains.searchbehaviours.impl.NoOpSearchBehaviourImpl
import ch.tutteli.atrium.logic.creating.iterable.contains.searchbehaviours.impl.NotSearchBehaviourImpl
import ch.tutteli.atrium.logic.creating.iterable.contains.steps.NotCheckerStep
import ch.tutteli.atrium.logic.creating.iterable.contains.steps.impl.EntryPointStepImpl
import ch.tutteli.atrium.logic.creating.iterable.contains.steps.notCheckerStep
import ch.tutteli.atrium.logic.creating.transformers.FeatureExtractorBuilder
import ch.tutteli.atrium.logic.creating.typeutils.IterableLike
import ch.tutteli.atrium.reporting.translating.TranslatableWithArgs
import ch.tutteli.atrium.translations.DescriptionBasic.NOT_TO_HAVE
import ch.tutteli.atrium.translations.DescriptionBasic.TO_HAVE
import ch.tutteli.atrium.translations.DescriptionIterableLikeExpectation
import ch.tutteli.atrium.translations.DescriptionIterableLikeExpectation.ALL_ELEMENTS
import ch.tutteli.atrium.translations.DescriptionIterableLikeExpectation.A_NEXT_ELEMENT
import ch.tutteli.kbox.mapWithIndex

class DefaultIterableLikeAssertions : IterableLikeAssertions {
    override fun  builderContainsInIterableLike(
        container: AssertionContainer,
        converter: (T) -> Iterable
    ): IterableLikeContains.EntryPointStep =
        EntryPointStepImpl(container, converter, NoOpSearchBehaviourImpl())

    override fun  builderContainsNotInIterableLike(
        container: AssertionContainer,
        converter: (T) -> Iterable
    ): NotCheckerStep =
        EntryPointStepImpl(container, converter, NotSearchBehaviourImpl())._logic.notCheckerStep()

    override fun  hasNext(
        container: AssertionContainer,
        converter: (T) -> Iterable
    ): Assertion =
        container.createDescriptiveAssertion(TO_HAVE, A_NEXT_ELEMENT) { hasNext(it, converter) }

    private fun  hasNext(it: T, converter: (T) -> Iterable) =
        converter(it).iterator().hasNext()

    override fun  hasNotNext(
        container: AssertionContainer,
        converter: (T) -> Iterable
    ): Assertion =
        container.createDescriptiveAssertion(NOT_TO_HAVE, A_NEXT_ELEMENT) { !hasNext(it, converter) }

    override fun > min(
        container: AssertionContainer,
        converter: (T) -> Iterable
    ): FeatureExtractorBuilder.ExecutionStep = collect(container, converter, "min", Iterable::min)

    override fun > max(
        container: AssertionContainer,
        converter: (T) -> Iterable
    ): FeatureExtractorBuilder.ExecutionStep = collect(container, converter, "max", Iterable::max)

    private fun > collect(
        container: AssertionContainer,
        converter: (T) -> Iterable,
        method: String,
        collect: Iterable.() -> E?
    ): FeatureExtractorBuilder.ExecutionStep =
        container.extractFeature
            .methodCall(method)
            .withRepresentationForFailure(DescriptionIterableLikeExpectation.NO_ELEMENTS)
            .withFeatureExtraction {
                val iterable = converter(it)
                Option.someIf(iterable.iterator().hasNext()) {
                    iterable.collect() ?: throw IllegalStateException(
                        "Iterable does not hasNext() even though checked before! Concurrent access?"
                    )
                }
            }
            .withoutOptions()
            .build()

    override fun  all(
        container: AssertionContainer,
        converter: (T) -> Iterable,
        assertionCreatorOrNull: (Expect.() -> Unit)?
    ): Assertion = LazyThreadUnsafeAssertionGroup {
        val listAssertionContainer = turnSubjectToList(container, converter)
        val list = listAssertionContainer.maybeSubject.getOrElse { emptyList() }

        val assertions = ArrayList(2)
        assertions.add(createExplanatoryAssertionGroup(container, assertionCreatorOrNull))
        val mismatches = createIndexAssertions(list) { (_, element) ->
            !allCreatedAssertionsHold(container, element, assertionCreatorOrNull)
        }
        if (mismatches.isNotEmpty()) assertions.add(createExplanatoryGroupForMismatches(mismatches))

        decorateAssertionWithHasNext(
            assertionBuilder.list
                .withDescriptionAndEmptyRepresentation(ALL_ELEMENTS)
                .withAssertions(assertions)
                .build(),
            listAssertionContainer
        )
    }

    override fun  containsNoDuplicates(
        container: AssertionContainer,
        converter: (T) -> Iterable
    ): Assertion = LazyThreadUnsafeAssertionGroup {
        val listAssertionContainer = turnSubjectToList(container, converter)
        val list = listAssertionContainer.maybeSubject.getOrElse { emptyList() }

        val lookupHashMap = HashMap()
        val duplicateIndices = HashMap>>()

        list.asSequence()
            .mapWithIndex()
            .forEach { (index, element) ->
                lookupHashMap[element]?.let {
                    duplicateIndices.getOrPut(it) {
                        Pair(element, mutableListOf())
                    }.second.add(index)
                } ?: let {
                    lookupHashMap[element] = index
                }
            }

        val duplicates = duplicateIndices
            .map { (index, pair) ->
                val (element, indices) = pair
                assertionBuilder.descriptive
                    .failing
                    .withHelpOnFailure {
                        assertionBuilder.explanatoryGroup
                            .withDefaultType
                            .withExplanatoryAssertion(
                                TranslatableWithArgs(
                                    DescriptionIterableLikeExpectation.DUPLICATED_BY,
                                    indices.joinToString(", ")
                                )
                            )
                            .build()
                    }
                    .showForAnyFailure
                    .withDescriptionAndRepresentation(
                        TranslatableWithArgs(DescriptionIterableLikeExpectation.INDEX, index),
                        element
                    )
                    .build()
            }

        decorateAssertionWithHasNext(
            createAssertionGroupFromListOfAssertions(
                NOT_TO_HAVE,
                DescriptionIterableLikeExpectation.DUPLICATE_ELEMENTS,
                duplicates
            ),
            listAssertionContainer
        )
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy