Files
holdem_poker/app/src/test/java/com/jsjdesigns/poker/ActionButtonsTest.kt
T

196 lines
5.8 KiB
Kotlin

package com.jsjdesigns.poker
import com.jsjdesigns.poker.game.DecisionOffer
import com.jsjdesigns.poker.game.Street
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
class ActionButtonsTest {
private fun offer(
toCall: Int = 10,
minRaiseTo: Int = 20,
maxRaiseTo: Int = 500,
canCheck: Boolean = false,
canRaise: Boolean = true,
stack: Int = 500,
) = DecisionOffer(
token = 1L,
handNumber = 1,
street = Street.FLOP,
seat = 0,
hole = listOf(0, 1),
board = emptyList(),
pot = 40,
toCall = toCall,
minRaiseTo = minRaiseTo,
maxRaiseTo = maxRaiseTo,
stack = stack,
canCheck = canCheck,
canRaise = canRaise,
activeOpponents = 1,
seatsActingAfter = 0,
bigBlind = 2,
eligiblePot = 40,
currentBet = if (canCheck) 0 else toCall,
)
// ---------- the raise omission ----------
/**
* The UI used to require maxRaiseTo > minRaiseTo, which hid an exact-minimum
* raise even though the engine accepts it.
*/
@Test
fun `an exact minimum raise is still offered`() {
val b = buttonsFor(offer(minRaiseTo = 100, maxRaiseTo = 100))
assertTrue("a raise with exactly one legal size must still be offered", b.showRaise)
assertFalse("no slider is useful for a single size", b.showSlider)
assertEquals(100, b.fixedRaiseTo)
}
/**
* A stack too short for a full min-raise may still shove; the engine clamps
* such a raise to maxRaiseTo. That was hidden too.
*/
@Test
fun `a short all-in is still offered`() {
val b = buttonsFor(offer(minRaiseTo = 200, maxRaiseTo = 120, stack = 120))
assertTrue("a legal short all-in must be offered", b.showRaise)
assertFalse(b.showSlider)
assertEquals(120, b.fixedRaiseTo)
assertEquals("All in", raiseLabel(b, b.fixedRaiseTo))
}
@Test
fun `a genuine range gets a slider`() {
val b = buttonsFor(offer(minRaiseTo = 20, maxRaiseTo = 500))
assertTrue(b.showRaise)
assertTrue(b.showSlider)
assertEquals(20, b.sliderMin)
assertEquals(500, b.sliderMax)
}
@Test
fun `no raise button when the engine would not accept one`() {
assertFalse(buttonsFor(offer(canRaise = false)).showRaise)
}
@Test
fun `raise presets use the pot after calling and legal raise-to amounts`() {
val decision = offer(
toCall = 10,
minRaiseTo = 20,
maxRaiseTo = 500,
)
assertEquals(
listOf(
RaisePreset("Min", 20),
RaisePreset("½ pot", 35),
RaisePreset("Pot", 60),
RaisePreset("All in", 500),
),
raisePresets(decision),
)
}
@Test
fun `raise presets drop clamped duplicates instead of mislabelling them`() {
val decision = offer(
toCall = 10,
minRaiseTo = 45,
maxRaiseTo = 50,
stack = 50,
)
assertEquals(
listOf(RaisePreset("Min", 45), RaisePreset("All in", 50)),
raisePresets(decision),
)
}
@Test
fun `a single legal shove has one all-in preset`() {
val decision = offer(minRaiseTo = 200, maxRaiseTo = 120, stack = 120)
assertEquals(listOf(RaisePreset("All in", 120)), raisePresets(decision))
}
// ---------- fold and call ----------
@Test
fun `fold is hidden when checking is free`() {
assertFalse(
"folding a free hand is never correct; offering it invites an accidental muck",
buttonsFor(offer(toCall = 0, canCheck = true)).showFold,
)
assertTrue(buttonsFor(offer(toCall = 10, canCheck = false)).showFold)
}
@Test
fun `the call button names the price`() {
assertEquals("Call 35", buttonsFor(offer(toCall = 35)).checkOrCallLabel)
assertEquals("Check", buttonsFor(offer(toCall = 0, canCheck = true)).checkOrCallLabel)
}
@Test
fun `the raise label switches to all in at the top of the range`() {
val b = buttonsFor(offer(minRaiseTo = 20, maxRaiseTo = 500))
assertEquals("Raise 60", raiseLabel(b, 60))
assertEquals("All in", raiseLabel(b, 500))
}
}
class CallCostTest {
private fun offer(toCall: Int, stack: Int) = DecisionOffer(
token = 1L,
handNumber = 1,
street = Street.RIVER,
seat = 0,
hole = listOf(0, 1),
board = emptyList(),
pot = 100,
toCall = toCall,
minRaiseTo = 999,
maxRaiseTo = stack,
stack = stack,
canCheck = false,
canRaise = false,
activeOpponents = 1,
seatsActingAfter = 0,
bigBlind = 2,
eligiblePot = 100,
currentBet = toCall,
)
/**
* Facing more than you have left is a call for your whole stack; the engine
* clamps the commitment. Quoting the full price promised a payment the player
* could not make and did not owe.
*/
@Test
fun `facing more than the stack is labelled as an all in for the stack`() {
val b = buttonsFor(offer(toCall = 35, stack = 20))
assertEquals("All in 20", b.checkOrCallLabel)
assertEquals(20, b.effectiveCall)
}
@Test
fun `calling exactly the stack is also an all in`() {
val b = buttonsFor(offer(toCall = 20, stack = 20))
assertEquals("All in 20", b.checkOrCallLabel)
assertEquals(20, b.effectiveCall)
}
@Test
fun `an affordable call quotes the real price`() {
val b = buttonsFor(offer(toCall = 35, stack = 500))
assertEquals("Call 35", b.checkOrCallLabel)
assertEquals(35, b.effectiveCall)
}
}