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

commonTest.com.fraktalio.fmodel.application.MaterializedViewTest.kt Maven / Gradle / Ivy

package com.fraktalio.fmodel.application

import arrow.core.Either
import com.fraktalio.fmodel.application.examples.numbers.NumberViewRepository
import com.fraktalio.fmodel.application.examples.numbers.even.query.EvenNumberViewRepository
import com.fraktalio.fmodel.application.examples.numbers.even.query.evenNumberViewRepository
import com.fraktalio.fmodel.application.examples.numbers.numberViewRepository
import com.fraktalio.fmodel.domain.IView
import com.fraktalio.fmodel.domain.combine
import com.fraktalio.fmodel.domain.examples.numbers.api.Description
import com.fraktalio.fmodel.domain.examples.numbers.api.EvenNumberState
import com.fraktalio.fmodel.domain.examples.numbers.api.NumberEvent.EvenNumberEvent.EvenNumberAdded
import com.fraktalio.fmodel.domain.examples.numbers.api.NumberEvent.OddNumberEvent.OddNumberAdded
import com.fraktalio.fmodel.domain.examples.numbers.api.NumberValue
import com.fraktalio.fmodel.domain.examples.numbers.api.OddNumberState
import com.fraktalio.fmodel.domain.examples.numbers.even.query.evenNumberView
import com.fraktalio.fmodel.domain.examples.numbers.odd.query.oddNumberView
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.types.shouldBeInstanceOf

/**
 * DSL - Given
 */
private suspend fun  IView.given(repository: ViewStateRepository, event: () -> E): Either =
    materializedView(
        view = this,
        viewStateRepository = repository
    ).handleEither(event())

/**
 * DSL - When
 */
@Suppress("unused")
private fun  IView.whenEvent(event: E): E = event

/**
 * DSL - Then
 */
private infix fun  Either.thenState(expected: S) {
    val state = when (this) {
        is Either.Right -> value
        is Either.Left -> throw AssertionError("Expected Either.Right, but found Either.Left with value ${this.value}")
    }
    return state shouldBe expected
}

private fun  Either.thenError() {
    val error = when (this) {
        is Either.Right -> throw AssertionError("Expected Either.Left, but found Either.Right with value ${this.value}")
        is Either.Left -> value
    }
    error.shouldBeInstanceOf()
}

/**
 * Materialized View Test
 */
class MaterializedViewTest : FunSpec({
    val evenView = evenNumberView()
    val oddView = oddNumberView()
    val combinedView = evenView.combine(oddView)
    val evenNumberViewRepository = evenNumberViewRepository() as EvenNumberViewRepository
    val numberViewRepository = numberViewRepository() as NumberViewRepository

    test("Materialized view - even number added") {
        with(evenView) {
            evenNumberViewRepository.deleteAll()

            given(evenNumberViewRepository) {
                whenEvent(EvenNumberAdded(Description("2"), NumberValue(2)))
            } thenState EvenNumberState(Description("Initial state, 2"), NumberValue(2))
        }
    }

    test("Combined Materialized view - odd number added") {
        with(combinedView) {
            numberViewRepository.deleteAll()

            given(numberViewRepository) {
                whenEvent(OddNumberAdded(Description("3"), NumberValue(3)))
            } thenState Pair(null, OddNumberState(Description("0, 3"), NumberValue(3)))
        }
    }

    test("Combined Materialized view - even number added") {
        with(combinedView) {
            numberViewRepository.deleteAll()

            given(numberViewRepository) {
                whenEvent(EvenNumberAdded(Description("4"), NumberValue(4)))
            } thenState Pair(EvenNumberState(Description("0, 4"), NumberValue(4)), null)
        }
    }

})