Skip to content

Commit

Permalink
unwinding this deep function nest slowly
Browse files Browse the repository at this point in the history
  • Loading branch information
robertfmurdock committed Jul 19, 2023
1 parent 2b091c7 commit 262e9e5
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ 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
import kotlinx.coroutines.channels.ReceiveChannel

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

val immediateReturn = mutableMapOf<Any, Any?>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import com.zegreatrob.coupling.model.map
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.SimpleExecutableAction
import com.zegreatrob.testmints.action.async.SimpleSuspendAction
import kotools.types.collection.NotEmptyList

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

interface Dispatcher : PlayerCandidatesFinder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,30 @@ 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.async.SimpleSuspendAction
import kotools.types.collection.NotEmptyList
import com.zegreatrob.coupling.server.action.CannonProvider
import com.zegreatrob.testmints.action.annotation.ActionMint

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

interface Dispatcher<out D> {

val execute: ExecutableActionExecutor<CreatePairCandidateReportListAction.Dispatcher>
interface Dispatcher<out D> : CannonProvider<D> where D : CreatePairCandidateReportListAction.Dispatcher {

suspend fun perform(action: NextPlayerAction): PairCandidateReport = with(action.createPairCandidateReports()) {
toList().fold(head) { reportWithLongestTime, report ->
when {
reportWithLongestTime.timeResult == report.timeResult ->
withFewestPartners(report, reportWithLongestTime)

report.timeResult is NeverPaired -> report
timeSinceLastPairedIsLonger(report, reportWithLongestTime) -> report
else -> reportWithLongestTime
}
}
}

private fun NextPlayerAction.createPairCandidateReports(): NotEmptyList<PairCandidateReport> =
execute(CreatePairCandidateReportListAction(gameSpin))
private suspend fun NextPlayerAction.createPairCandidateReports() = cannon.fire(
CreatePairCandidateReportListAction(gameSpin),
)

private fun withFewestPartners(report: PairCandidateReport, reportWithLongestTime: PairCandidateReport) =
when {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,83 +8,105 @@ import com.zegreatrob.coupling.server.action.pairassignmentdocument.CreatePairCa
import com.zegreatrob.coupling.server.action.pairassignmentdocument.GameSpin
import com.zegreatrob.coupling.server.action.pairassignmentdocument.NextPlayerAction
import com.zegreatrob.coupling.server.action.pairassignmentdocument.PairCandidateReport
import com.zegreatrob.coupling.server.action.stubActionExecutor
import com.zegreatrob.coupling.testaction.StubCannon
import com.zegreatrob.minassert.assertIsEqualTo
import com.zegreatrob.testmints.async.ScopeMint
import com.zegreatrob.testmints.async.asyncSetup
import kotlinx.coroutines.channels.produce
import kotools.types.collection.NotEmptyList
import kotools.types.collection.notEmptyListOf
import kotlin.test.Test

class NextPlayerActionTest : NextPlayerAction.Dispatcher<CreatePairCandidateReportListAction.Dispatcher> {

override val execute = stubActionExecutor(CreatePairCandidateReportListAction::class)
class NextPlayerActionTest {

private val bill = Player(id = "Bill", avatarType = null)
private val ted = Player(id = "Ted", avatarType = null)
private val amadeus = Player(id = "Mozart", avatarType = null)
private val shorty = Player(id = "Napoleon", avatarType = null)

@Test
fun willUseHistoryToProduceSequenceInOrderOfLongestTimeSinceLastPairedToShortest() = asyncSetup(object {
fun willUseHistoryToProduceSequenceInOrderOfLongestTimeSinceLastPairedToShortest() = asyncSetup(object :
NextPlayerAction.Dispatcher<CreatePairCandidateReportListAction.Dispatcher>, ScopeMint() {
val players = notEmptyListOf(bill, ted, amadeus, shorty)

val billsPairCandidates = PairCandidateReport(bill, emptyList(), TimeResultValue(3))
val tedsPairCandidates = PairCandidateReport(ted, emptyList(), TimeResultValue(7))
val amadeusPairCandidates = PairCandidateReport(amadeus, emptyList(), TimeResultValue(4))
val shortyPairCandidates = PairCandidateReport(shorty, emptyList(), TimeResultValue(5))
}) {
execute.spyWillReturn(
notEmptyListOf(billsPairCandidates, tedsPairCandidates, amadeusPairCandidates, shortyPairCandidates),
override val cannon = StubCannon<CreatePairCandidateReportListAction.Dispatcher>(
receivedActions = mutableListOf(),
resultChannel = exerciseScope.produce<Any> {
send(
notEmptyListOf(
billsPairCandidates,
tedsPairCandidates,
amadeusPairCandidates,
shortyPairCandidates,
),
)
},
)
} exercise {
}) exercise {
perform(NextPlayerAction(longestTimeSpin(players)))
} verify { result ->
result.assertIsEqualTo(tedsPairCandidates)
}

@Test
fun aPersonWhoJustPairedHasLowerPriorityThanSomeoneWhoHasNotPairedInALongTime() = asyncSetup(object {
fun aPersonWhoJustPairedHasLowerPriorityThanSomeoneWhoHasNotPairedInALongTime() = asyncSetup(object :
NextPlayerAction.Dispatcher<CreatePairCandidateReportListAction.Dispatcher>, ScopeMint() {
val players = notEmptyListOf(bill, ted, amadeus, shorty)
val amadeusPairCandidates = PairCandidateReport(amadeus, emptyList(), TimeResultValue(5))
val shortyPairCandidates = PairCandidateReport(shorty, emptyList(), TimeResultValue(0))
}) {
execute.spyWillReturn(notEmptyListOf(amadeusPairCandidates, shortyPairCandidates))
} exercise {
override val cannon = StubCannon<CreatePairCandidateReportListAction.Dispatcher>(
receivedActions = mutableListOf(),
resultChannel = exerciseScope.produce<Any> {
send(notEmptyListOf(amadeusPairCandidates, shortyPairCandidates))
},
)
}) exercise {
perform(NextPlayerAction(longestTimeSpin(players)))
} verify { it.assertIsEqualTo(amadeusPairCandidates) }

@Test
fun sequenceWillBeFromLongestToShortest() = asyncSetup(object {
fun sequenceWillBeFromLongestToShortest() = asyncSetup(object :
NextPlayerAction.Dispatcher<CreatePairCandidateReportListAction.Dispatcher>, ScopeMint() {
val players = notEmptyListOf(bill, amadeus, shorty)

val billsPairCandidates = PairCandidateReport(bill, emptyList(), TimeResultValue(3))
val amadeusPairCandidates = PairCandidateReport(amadeus, emptyList(), TimeResultValue(4))
val shortyPairCandidates = PairCandidateReport(shorty, emptyList(), TimeResultValue(5))

val pairCandidates = notEmptyListOf(billsPairCandidates, amadeusPairCandidates, shortyPairCandidates)
}) {
execute.spyWillReturn(pairCandidates)
} exercise {
override val cannon = StubCannon<CreatePairCandidateReportListAction.Dispatcher>(
receivedActions = mutableListOf(),
resultChannel = exerciseScope.produce<Any> { send(pairCandidates) },
)
}) exercise {
perform(NextPlayerAction(longestTimeSpin(players)))
} verify { it.assertIsEqualTo(shortyPairCandidates) }

@Test
fun sequenceWillPreferPlayerWhoHasNeverPaired() = asyncSetup(object {
fun sequenceWillPreferPlayerWhoHasNeverPaired() = asyncSetup(object :
NextPlayerAction.Dispatcher<CreatePairCandidateReportListAction.Dispatcher>, ScopeMint() {
val players = notEmptyListOf(bill, amadeus, shorty)

val billsPairCandidates = PairCandidateReport(bill, emptyList(), TimeResultValue(3))
val amadeusPairCandidates = PairCandidateReport(amadeus, emptyList(), TimeResultValue(4))
val shortyPairCandidates = PairCandidateReport(shorty, emptyList(), NeverPaired)
}) {
execute.spyWillReturn(
notEmptyListOf(billsPairCandidates, amadeusPairCandidates, shortyPairCandidates),
override val cannon = StubCannon<CreatePairCandidateReportListAction.Dispatcher>(
receivedActions = mutableListOf(),
resultChannel = exerciseScope.produce<Any> {
send(notEmptyListOf(billsPairCandidates, amadeusPairCandidates, shortyPairCandidates))
},
)
} exercise {
}) exercise {
perform(NextPlayerAction(longestTimeSpin(players)))
} verify { it.assertIsEqualTo(shortyPairCandidates) }

@Test
fun willPrioritizeTheReportWithFewestPlayersGivenEqualAmountsOfTime() = asyncSetup(object {
fun willPrioritizeTheReportWithFewestPlayersGivenEqualAmountsOfTime() = asyncSetup(object :
NextPlayerAction.Dispatcher<CreatePairCandidateReportListAction.Dispatcher>, ScopeMint() {
val players = notEmptyListOf(bill, amadeus, shorty)

val billsPairCandidates = PairCandidateReport(
Expand All @@ -102,11 +124,13 @@ class NextPlayerActionTest : NextPlayerAction.Dispatcher<CreatePairCandidateRepo
listOf(Player(avatarType = null), Player(avatarType = null)),
NeverPaired,
)
}) {
execute.spyWillReturn(
notEmptyListOf(billsPairCandidates, amadeusPairCandidates, shortyPairCandidates),
override val cannon = StubCannon<CreatePairCandidateReportListAction.Dispatcher>(
receivedActions = mutableListOf(),
resultChannel = exerciseScope.produce<Any> {
send(notEmptyListOf(billsPairCandidates, amadeusPairCandidates, shortyPairCandidates))
},
)
} exercise {
}) exercise {
perform(NextPlayerAction(longestTimeSpin(players)))
} verify { it.assertIsEqualTo(amadeusPairCandidates) }

Expand Down

0 comments on commit 262e9e5

Please sign in to comment.