
commonTest.com.fraktalio.fmodel.application.StateStoredAggregateTest.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of application-arrow Show documentation
Show all versions of application-arrow Show documentation
Fmodel provides just enough tactical Domain-Driven Design patterns, optimised for Event Sourcing and CQRS. The application library orchestrates the execution of the logic by loading state, executing domain components and storing new state. It is an Arrow (FP library for Kotlin) flavored implementation.
package com.fraktalio.fmodel.application
import arrow.core.Either
import com.fraktalio.fmodel.application.examples.numbers.NumberStateRepository
import com.fraktalio.fmodel.application.examples.numbers.even.command.EvenNumberStateRepository
import com.fraktalio.fmodel.application.examples.numbers.even.command.evenNumberStateRepository
import com.fraktalio.fmodel.application.examples.numbers.numberStateRepository
import com.fraktalio.fmodel.domain.IDecider
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.NumberCommand.EvenNumberCommand.AddEvenNumber
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.command.evenNumberDecider
import com.fraktalio.fmodel.domain.examples.numbers.odd.command.oddNumberDecider
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.types.shouldBeInstanceOf
import kotlinx.coroutines.FlowPreview
/**
* DSL - Given
*/
@FlowPreview
private suspend fun IDecider.given(
repository: StateRepository,
command: () -> C
): Either =
stateStoredAggregate(
decider = this,
stateRepository = repository
).handleEither(command())
/**
* DSL - When
*/
@Suppress("unused")
private fun IDecider.whenCommand(command: C): C = command
/**
* 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()
}
/**
* State-stored aggregate test
*/
@FlowPreview
class StateStoredAggregateTest : FunSpec({
val evenDecider = evenNumberDecider()
val oddDecider = oddNumberDecider()
val combinedDecider = evenDecider.combine(oddDecider)
val evenNumberStateRepository = evenNumberStateRepository() as EvenNumberStateRepository
val numberStateRepository = numberStateRepository() as NumberStateRepository
test("State-stored aggregate - add even number") {
with(evenDecider) {
evenNumberStateRepository.deleteAll()
given(evenNumberStateRepository) {
whenCommand(AddEvenNumber(Description("2"), NumberValue(2)))
} thenState EvenNumberState(Description("2"), NumberValue(2))
}
}
test("State-stored aggregate - add even number - error (large number > 1000)") {
with(evenDecider) {
evenNumberStateRepository.deleteAll()
val command = AddEvenNumber(Description("2000"), NumberValue(2000))
given(evenNumberStateRepository) {
whenCommand(command)
}.thenError()
}
}
test("Combined State-stored aggregate - add even number") {
with(combinedDecider) {
numberStateRepository.deleteAll()
given(numberStateRepository) {
whenCommand(AddEvenNumber(Description("2"), NumberValue(2)))
} thenState Pair(
EvenNumberState(Description("2"), NumberValue(2)),
OddNumberState(Description("0"), NumberValue(0))
)
}
}
})
© 2015 - 2025 Weber Informatics LLC | Privacy Policy