Skip to content

Commit

Permalink
more cannon
Browse files Browse the repository at this point in the history
  • Loading branch information
robertfmurdock committed Jul 18, 2023
1 parent 9790e96 commit 4a36384
Show file tree
Hide file tree
Showing 12 changed files with 95 additions and 82 deletions.
1 change: 1 addition & 0 deletions client/components/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ dependencies {
jsMainImplementation(npmConstrained("html2canvas"))

jsTestImplementation(project(":libraries:test-react"))
jsTestImplementation(project(":libraries:test-action"))
jsTestImplementation(project(":libraries:stub-model"))
jsTestImplementation(project(":libraries:test-logging"))
jsTestImplementation("com.zegreatrob.testmints:async")
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.zegreatrob.coupling.client.components

import com.zegreatrob.coupling.testaction.StubCannon
import kotlinx.coroutines.channels.Channel

class StubDispatcher {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.zegreatrob.coupling.testaction

import com.zegreatrob.testmints.action.ActionCannon
import com.zegreatrob.testmints.action.ActionWrapper
import com.zegreatrob.testmints.action.async.SuspendAction
import kotlinx.coroutines.channels.Channel

class StubCannon<D>(
private val receivedActions: MutableList<Any?>,
private val resultChannel: Channel<*>,
) : ActionCannon<D> {

val immediateReturn = mutableMapOf<Any, Any?>()

override suspend fun <R> fire(action: SuspendAction<D, R>): R {
println("fire $action")
val element = action.unwrap()
receivedActions.add(element)

if (immediateReturn.containsKey(element)) {
@Suppress("UNCHECKED_CAST")
return immediateReturn[element] as R
} else {
@Suppress("UNCHECKED_CAST")
return resultChannel.receive() as R
}
}

private fun <R> SuspendAction<D, R>.unwrap() =
if (this is ActionWrapper<*>) {
action
} else {
this
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,19 @@ import com.zegreatrob.coupling.model.pairassignmentdocument.PairAssignmentDocume
import com.zegreatrob.coupling.model.pairassignmentdocument.pairOf
import com.zegreatrob.coupling.model.party.PairingRule
import com.zegreatrob.coupling.model.player.Player
import com.zegreatrob.testmints.action.ExecutableActionExecutor
import com.zegreatrob.testmints.action.async.SimpleSuspendAction
import com.zegreatrob.coupling.server.action.CannonProvider
import com.zegreatrob.testmints.action.annotation.ActionMint
import kotools.types.collection.NotEmptyList
import kotools.types.collection.notEmptyListOf
import kotools.types.collection.toNotEmptyList

data class FindNewPairsAction(val game: Game) :
SimpleSuspendAction<FindNewPairsAction.Dispatcher, NotEmptyList<CouplingPair>> {
override val performFunc = link(Dispatcher::perform)

interface Dispatcher {

val execute: ExecutableActionExecutor<NextPlayerAction.Dispatcher>
@ActionMint
data class FindNewPairsAction(val game: Game) {
interface Dispatcher<out D : NextPlayerAction.Dispatcher> : CannonProvider<D> {

val wheel: Wheel

fun perform(action: FindNewPairsAction): NotEmptyList<CouplingPair> = with(action) {
suspend fun perform(action: FindNewPairsAction): NotEmptyList<CouplingPair> = with(action) {
val firstGameSpin = game.spinWith(game.players)
val firstPlayerReport = firstGameSpin.getNextPlayer()
val newPair = firstPlayerReport.spinForPartner()
Expand All @@ -36,7 +32,7 @@ data class FindNewPairsAction(val game: Game) :
rule = rule,
)

private fun Round.spinForNextPair(): NotEmptyList<CouplingPair> = gameSpin
private suspend fun Round.spinForNextPair(): NotEmptyList<CouplingPair> = gameSpin
?.getNextPlayer()
?.let { playerReport ->
val newPair = playerReport.spinForPartner()
Expand All @@ -47,7 +43,7 @@ data class FindNewPairsAction(val game: Game) :
}
?: pairs

private fun GameSpin.getNextPlayer() = this@Dispatcher.execute(NextPlayerAction(this))
private suspend fun GameSpin.getNextPlayer() = cannon.fire(NextPlayerAction(this))

private fun Pair<Round, CouplingPair>.nextRound(): Round = let { (round, newPair) ->
Round(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package com.zegreatrob.coupling.server.action.pairassignmentdocument
import com.zegreatrob.coupling.model.pairassignmentdocument.NeverPaired
import com.zegreatrob.coupling.model.pairassignmentdocument.TimeResultValue
import com.zegreatrob.testmints.action.ExecutableActionExecutor
import com.zegreatrob.testmints.action.SimpleExecutableAction
import com.zegreatrob.testmints.action.async.SimpleSuspendAction
import kotools.types.collection.NotEmptyList

data class NextPlayerAction(val gameSpin: GameSpin) :
SimpleExecutableAction<NextPlayerAction.Dispatcher, PairCandidateReport> {
SimpleSuspendAction<NextPlayerAction.Dispatcher, PairCandidateReport> {
override val performFunc = link(Dispatcher::perform)

interface Dispatcher {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ interface ServerSpinCommandDispatcher<out D> :
PartyIdLoadPlayersSyntax,
PartyIdHistorySyntax,
PartyIdPinRecordsSyntax,
CannonProvider<D> where D : FindNewPairsAction.Dispatcher,
CannonProvider<D> where D : NextPlayerAction.Dispatcher,
D : FindNewPairsAction.Dispatcher<D>,
D : AssignPinsActionDispatcher,
D : ShufflePairsAction.Dispatcher<D> {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ data class ShufflePairsAction(
val pins: List<Pin>,
val history: List<PairAssignmentDocument>,
) {
interface Dispatcher<out D> :
Clock,
CannonProvider<D> where D : FindNewPairsAction.Dispatcher, D : AssignPinsActionDispatcher {
interface Dispatcher<out D> : Clock, CannonProvider<D>
where D : NextPlayerAction.Dispatcher,
D : FindNewPairsAction.Dispatcher<D>,
D : AssignPinsActionDispatcher {

suspend fun perform(action: ShufflePairsAction) = action.assignPinsToPairs().let(::pairAssignmentDocument)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,42 @@ import com.zegreatrob.coupling.model.pairassignmentdocument.TimeResultValue
import com.zegreatrob.coupling.model.pairassignmentdocument.pairOf
import com.zegreatrob.coupling.model.party.PairingRule
import com.zegreatrob.coupling.model.player.Player
import com.zegreatrob.coupling.server.action.stubActionExecutor
import com.zegreatrob.coupling.testaction.StubCannon
import com.zegreatrob.minassert.assertContains
import com.zegreatrob.minassert.assertIsEqualTo
import com.zegreatrob.minspy.Spy
import com.zegreatrob.minspy.SpyData
import com.zegreatrob.minspy.spyFunction
import com.zegreatrob.testmints.setup
import com.zegreatrob.testmints.async.asyncSetup
import kotlinx.coroutines.channels.Channel
import kotools.types.collection.notEmptyListOf
import kotlin.test.Test

class FindNewPairsActionTest {

@Test
fun withTwoPlayersEachShouldBeRemovedFromWheelBeforeEachPlay() = setup(object :
FindNewPairsAction.Dispatcher {
override val execute = stubActionExecutor(NextPlayerAction::class)
fun withTwoPlayersEachShouldBeRemovedFromWheelBeforeEachPlay() = asyncSetup(object :
FindNewPairsAction.Dispatcher<NextPlayerAction.Dispatcher> {
override val wheel = StubWheel()
override val cannon = StubCannon<NextPlayerAction.Dispatcher>(mutableListOf(), Channel<Any>())
val bill: Player = Player(id = "Bill", avatarType = null)
val ted: Player = Player(id = "Ted", avatarType = null)
val players = notEmptyListOf(bill, ted)
}) {
wheel.spyReturnValues.add(bill)
execute.spyReturnValues.add(PairCandidateReport(ted, listOf(bill), TimeResultValue(0)))
cannon.immediateReturn[NextPlayerAction(GameSpin(players, listOf(), PairingRule.LongestTime))] =
PairCandidateReport(ted, listOf(bill), TimeResultValue(0))
} exercise {
perform(FindNewPairsAction(Game(players, listOf(), PairingRule.LongestTime)))
} verify { result ->
result.assertIsEqualTo(notEmptyListOf(pairOf(ted, bill)))
execute.spyReceivedValues.getOrNull(0)
.assertIsEqualTo(NextPlayerAction(GameSpin(players, listOf(), PairingRule.LongestTime)))
wheel.spyReceivedValues.assertContains(listOf(bill))
}

@Test
fun shouldRemoveAPlayerFromTheWheelBeforeEachPlay() = setup(object :
FindNewPairsAction.Dispatcher {
override val execute = stubActionExecutor(NextPlayerAction::class)
fun shouldRemoveAPlayerFromTheWheelBeforeEachPlay() = asyncSetup(object :
FindNewPairsAction.Dispatcher<NextPlayerAction.Dispatcher> {
override val cannon = StubCannon<NextPlayerAction.Dispatcher>(mutableListOf(), Channel<Any>())
override val wheel = StubWheel()
val bill: Player = Player(id = "Bill", avatarType = null)
val ted: Player = Player(id = "Ted", avatarType = null)
Expand All @@ -52,21 +52,17 @@ class FindNewPairsActionTest {
)
val history: List<PairAssignmentDocument> = emptyList()
}) {
execute.spyWillReturn(pairCandidateReports)
cannon.immediateReturn[NextPlayerAction(GameSpin(players, history, PairingRule.LongestTime))] =
pairCandidateReports[0]
cannon.immediateReturn[NextPlayerAction(GameSpin(notEmptyListOf(ted), history, PairingRule.LongestTime))] =
pairCandidateReports[1]
wheel.spyWillReturn(bill)
} exercise {
perform(FindNewPairsAction(Game(players, history, PairingRule.LongestTime)))
} verify { result ->
result.assertIsEqualTo(
notEmptyListOf(pairOf(mozart, bill), pairOf(ted)),
)
execute.spyReceivedValues
.assertIsEqualTo(
listOf(
NextPlayerAction(GameSpin(players, history, PairingRule.LongestTime)),
NextPlayerAction(GameSpin(notEmptyListOf(ted), history, PairingRule.LongestTime)),
),
)
wheel.spyReceivedValues
.assertContains(listOf(bill, ted))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class GameExamplesTest {

companion object :
ShufflePairsAction.Dispatcher<Companion>,
FindNewPairsAction.Dispatcher,
FindNewPairsAction.Dispatcher<Companion>,
AssignPinsActionDispatcher,
NextPlayerAction.Dispatcher,
CreatePairCandidateReportAction.Dispatcher,
Expand All @@ -40,7 +40,7 @@ class GameExamplesTest {
Wheel {
override val wheel = this
override val actionDispatcher = this
override val cannon = ActionCannon.invoke(this)
override val cannon = ActionCannon(this)
override val execute = this
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.zegreatrob.coupling.server.action.pairassignmentdocument

import com.zegreatrob.coupling.action.pairassignmentdocument.AssignPinsAction
import com.zegreatrob.coupling.action.pairassignmentdocument.AssignPinsActionDispatcher
import com.zegreatrob.coupling.model.map
import com.zegreatrob.coupling.model.pairassignmentdocument.CouplingPair
import com.zegreatrob.coupling.model.pairassignmentdocument.PairAssignmentDocument
import com.zegreatrob.coupling.model.pairassignmentdocument.PinnedCouplingPair
import com.zegreatrob.coupling.model.pairassignmentdocument.pairOf
Expand All @@ -12,28 +12,30 @@ import com.zegreatrob.coupling.model.party.PartyDetails
import com.zegreatrob.coupling.model.party.PartyId
import com.zegreatrob.coupling.model.pin.Pin
import com.zegreatrob.coupling.model.player.Player
import com.zegreatrob.coupling.server.action.stubActionExecutor
import com.zegreatrob.coupling.stubmodel.stubPlayer
import com.zegreatrob.coupling.testaction.StubCannon
import com.zegreatrob.minassert.assertIsEqualTo
import com.zegreatrob.minspy.SpyData
import com.zegreatrob.minspy.spyFunction
import com.zegreatrob.testmints.action.ActionCannon
import com.zegreatrob.testmints.async.ScopeMint
import com.zegreatrob.testmints.async.asyncSetup
import kotlinx.coroutines.channels.Channel
import kotlinx.datetime.Clock
import kotools.types.collection.NotEmptyList
import kotools.types.collection.notEmptyListOf
import kotlin.test.Test

class ShufflePairsActionTest {

interface ShufflePairsActionInner : FindNewPairsAction.Dispatcher, AssignPinsActionDispatcher
interface ShufflePairsActionInner :
FindNewPairsAction.Dispatcher<ShufflePairsActionInner>,
AssignPinsActionDispatcher,
NextPlayerAction.Dispatcher

@Test
fun willBuildAGameRunWithAllAvailablePlayersAndThenReturnTheResults() = asyncSetup(object :
ShufflePairsAction.Dispatcher<ShufflePairsActionInner>, ShufflePairsActionInner {
override val cannon = ActionCannon(this)
override val execute = stubActionExecutor(NextPlayerAction::class)
override val wheel: Wheel get() = throw NotImplementedError("Stubbed")
ScopeMint(),
ShufflePairsAction.Dispatcher<ShufflePairsActionInner> {
val resultChannel = Channel<Any>()
val receivedActions = mutableListOf<Any?>()
override val cannon = StubCannon<ShufflePairsActionInner>(receivedActions, resultChannel)

val expectedDate = Clock.System.now()
override fun currentDate() = expectedDate
Expand All @@ -45,21 +47,21 @@ class ShufflePairsActionTest {
pairOf(Player(avatarType = null)),
pairOf(Player(avatarType = null)),
)
val spy = SpyData<FindNewPairsAction, NotEmptyList<CouplingPair>>().apply {
spyReturnValues.add(expectedPairingAssignments)
val expectedPinnedPairs = expectedPairingAssignments.map {
PinnedCouplingPair(it.toNotEmptyList().map { player -> player.withPins() })
}

override fun perform(action: FindNewPairsAction): NotEmptyList<CouplingPair> = spy.spyFunction(action)
}) exercise {
}) {
cannon.immediateReturn[FindNewPairsAction(Game(players, history, party.pairingRule))] =
expectedPairingAssignments
cannon.immediateReturn[AssignPinsAction(expectedPairingAssignments, pins, history)] = expectedPinnedPairs
} exercise {
perform(ShufflePairsAction(party, players, pins, history))
} verify { result ->
result.assertIsEqualTo(
PairAssignmentDocument(
id = result.id,
date = expectedDate,
pairs = expectedPairingAssignments.map {
PinnedCouplingPair(it.toNotEmptyList().map { player -> player.withPins() })
},
pairs = expectedPinnedPairs,
),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ import com.zegreatrob.testmints.action.ExecutableActionExecutor

interface PairAssignmentDispatcher<D> :
ShufflePairsAction.Dispatcher<D>,
FindNewPairsAction.Dispatcher,
FindNewPairsAction.Dispatcher<D>,
NextPlayerAction.Dispatcher,
CreatePairCandidateReportListAction.Dispatcher,
CreatePairCandidateReportAction.Dispatcher,
Wheel where D : AssignPinsActionDispatcher, D : FindNewPairsAction.Dispatcher {
Wheel where D : NextPlayerAction.Dispatcher,
D : AssignPinsActionDispatcher,
D : FindNewPairsAction.Dispatcher<D> {
override val execute: ExecutableActionExecutor<PairAssignmentDispatcher<D>>
override val wheel: Wheel get() = this
}

0 comments on commit 4a36384

Please sign in to comment.