test: add comprehensive DamageMonitor unit tests (Closes #38) #71

Merged
shahondin1624 merged 1 commits from feature/issue-38-damage-monitor-test into main 2026-03-13 14:12:28 +01:00

View File

@@ -0,0 +1,245 @@
package org.shahondin1624
import org.shahondin1624.model.attributes.Attribute
import org.shahondin1624.model.attributes.AttributeType
import org.shahondin1624.model.attributes.Attributes
import org.shahondin1624.model.charactermodel.DamageMonitor
import org.shahondin1624.model.charactermodel.DamageTrackType
import org.shahondin1624.model.charactermodel.createDamageMonitor
import kotlin.test.Test
import kotlin.test.assertEquals
/**
* Tests for DamageMonitor damage tracking, wound modifiers,
* toggle behavior, and overflow transitions.
*/
class DamageMonitorTest {
// Body=6, Willpower=4 -> physicalMax = 7 + (6/2) = 10, stunMax = 7 + (4/2) = 9, overflowMax = (6/2) = 3
private val testAttributes = Attributes(
body = Attribute(AttributeType.Body, 6),
agility = Attribute(AttributeType.Agility, 3),
reaction = Attribute(AttributeType.Reaction, 3),
strength = Attribute(AttributeType.Strength, 3),
willpower = Attribute(AttributeType.Willpower, 4),
logic = Attribute(AttributeType.Logic, 3),
intuition = Attribute(AttributeType.Intuition, 3),
charisma = Attribute(AttributeType.Charisma, 3),
edge = 3
)
private fun freshMonitor(): DamageMonitor = DamageMonitor(testAttributes)
// ---- Max calculations ----
@Test
fun stunMaxIsBasePlusHalfWillpower() {
val monitor = freshMonitor()
// 7 + (4 / 2.0).toInt() = 7 + 2 = 9
assertEquals(9, monitor.stunMax())
}
@Test
fun physicalMaxIsBasePlusHalfBody() {
val monitor = freshMonitor()
// 7 + (6 / 2.0).toInt() = 7 + 3 = 10
assertEquals(10, monitor.physicalMax())
}
@Test
fun overflowMaxIsHalfBody() {
val monitor = freshMonitor()
// (6 / 2.0).toInt() = 3
assertEquals(3, monitor.overflowMax())
}
// ---- Initial state ----
@Test
fun freshMonitorHasZeroDamage() {
val monitor = freshMonitor()
assertEquals(0, monitor.stunCurrent())
assertEquals(0, monitor.physicalCurrent())
assertEquals(0, monitor.overflowCurrent())
}
// ---- Setting damage values ----
@Test
fun withStunDamageSetsCorrectValue() {
val monitor = freshMonitor().withStunDamage(5)
assertEquals(5, monitor.stunCurrent())
}
@Test
fun withPhysicalDamageSetsCorrectValue() {
val monitor = freshMonitor().withPhysicalDamage(7)
assertEquals(7, monitor.physicalCurrent())
}
@Test
fun withOverflowDamageSetsCorrectValue() {
val monitor = freshMonitor().withOverflowDamage(2)
assertEquals(2, monitor.overflowCurrent())
}
@Test
fun damageIsClamtedToMax() {
val monitor = freshMonitor()
val overStun = monitor.withStunDamage(100)
assertEquals(9, overStun.stunCurrent()) // clamped to stunMax=9
val overPhys = monitor.withPhysicalDamage(100)
assertEquals(10, overPhys.physicalCurrent()) // clamped to physicalMax=10
val overFlow = monitor.withOverflowDamage(100)
assertEquals(3, overFlow.overflowCurrent()) // clamped to overflowMax=3
}
@Test
fun damageIsClampedToZero() {
val monitor = freshMonitor()
val negStun = monitor.withStunDamage(-5)
assertEquals(0, negStun.stunCurrent())
}
// ---- Wound modifier ----
@Test
fun woundModifierIsZeroWithNoDamage() {
assertEquals(0, freshMonitor().woundModifier())
}
@Test
fun woundModifierIsZeroUnderThreshold() {
// 1 and 2 physical damage -> no wound modifier yet
assertEquals(0, freshMonitor().withPhysicalDamage(1).woundModifier())
assertEquals(0, freshMonitor().withPhysicalDamage(2).woundModifier())
}
@Test
fun woundModifierNegOneAtThreePhysical() {
val monitor = freshMonitor().withPhysicalDamage(3)
assertEquals(-1, monitor.woundModifier())
}
@Test
fun woundModifierNegTwoAtSixPhysical() {
val monitor = freshMonitor().withPhysicalDamage(6)
assertEquals(-2, monitor.woundModifier())
}
@Test
fun woundModifierScalesWithDamage() {
val monitor = freshMonitor().withPhysicalDamage(9)
assertEquals(-3, monitor.woundModifier())
}
// ---- Toggle damage box ----
@Test
fun toggleEmptyBoxMarksDamage() {
val monitor = freshMonitor()
// Toggle position 3 when current=0 -> should set to 3
val toggled = monitor.toggleDamageBox(DamageTrackType.Physical, 3)
assertEquals(3, toggled.physicalCurrent())
}
@Test
fun toggleFilledBoxHealsToPreviousPosition() {
val monitor = freshMonitor().withPhysicalDamage(5)
// Toggle position 3 when current=5 -> position 3 is filled, heal to 2
val toggled = monitor.toggleDamageBox(DamageTrackType.Physical, 3)
assertEquals(2, toggled.physicalCurrent())
}
@Test
fun toggleLastFilledBoxClearsDamage() {
val monitor = freshMonitor().withPhysicalDamage(3)
// Toggle position 1 -> heal to 0
val toggled = monitor.toggleDamageBox(DamageTrackType.Physical, 1)
assertEquals(0, toggled.physicalCurrent())
}
@Test
fun toggleStunTrackWorks() {
val monitor = freshMonitor()
val damaged = monitor.toggleDamageBox(DamageTrackType.Stun, 5)
assertEquals(5, damaged.stunCurrent())
// Toggle lower position to heal
val healed = damaged.toggleDamageBox(DamageTrackType.Stun, 3)
assertEquals(2, healed.stunCurrent())
}
@Test
fun toggleOverflowTrackWorks() {
val monitor = freshMonitor()
val damaged = monitor.toggleDamageBox(DamageTrackType.Overflow, 2)
assertEquals(2, damaged.overflowCurrent())
val healed = damaged.toggleDamageBox(DamageTrackType.Overflow, 1)
assertEquals(0, healed.overflowCurrent())
}
// ---- Physical-to-overflow transition ----
@Test
fun physicalCanBeFilled() {
val monitor = freshMonitor().withPhysicalDamage(10) // physicalMax=10
assertEquals(10, monitor.physicalCurrent())
assertEquals(0, monitor.overflowCurrent())
}
@Test
fun overflowCanBeSetWhenPhysicalIsFull() {
val monitor = freshMonitor()
.withPhysicalDamage(10) // fill physical track
.withOverflowDamage(2) // then add overflow
assertEquals(10, monitor.physicalCurrent())
assertEquals(2, monitor.overflowCurrent())
}
@Test
fun fullPhysicalAndFullOverflow() {
val monitor = freshMonitor()
.withPhysicalDamage(10)
.withOverflowDamage(3) // overflowMax=3
assertEquals(10, monitor.physicalCurrent())
assertEquals(3, monitor.overflowCurrent())
}
// ---- createDamageMonitor ----
@Test
fun createDamageMonitorStartsAtMaxValues() {
val monitor = createDamageMonitor(testAttributes)
assertEquals(monitor.stunMax(), monitor.stunCurrent())
assertEquals(monitor.physicalMax(), monitor.physicalCurrent())
assertEquals(monitor.overflowMax(), monitor.overflowCurrent())
}
// ---- Wound modifier updates past thresholds ----
@Test
fun woundModifierUpdatesCorrectlyAsDamageIncreases() {
var monitor = freshMonitor()
assertEquals(0, monitor.woundModifier())
monitor = monitor.withPhysicalDamage(1)
assertEquals(0, monitor.woundModifier())
monitor = monitor.withPhysicalDamage(3)
assertEquals(-1, monitor.woundModifier())
monitor = monitor.withPhysicalDamage(6)
assertEquals(-2, monitor.woundModifier())
monitor = monitor.withPhysicalDamage(9)
assertEquals(-3, monitor.woundModifier())
// Heal back
monitor = monitor.withPhysicalDamage(2)
assertEquals(0, monitor.woundModifier())
}
}