MosswartOverlord/go-services/tracker-go/combat_test.go
Erik 7350b00341 feat(go-services): Phase 2 — combat_stats accumulator (cross-language exact)
Ports main.py's _combat_session_delta / _combat_merge_into_lifetime (incl. the
documented "offense/defense use latest, additively" quirk) and the combat_stats
handler (session delta -> DB-backed lifetime merge -> delete-then-insert of
combat_stats + combat_stats_sessions). Read handlers gain the live combat
overlay (union live + DB), like Python.

Validation:
- combat.go `combat-merge` CLI folds snapshots through the accumulator; diffed
  against the Python functions on identical input -> byte-IDENTICAL.
- combat_test.go golden test runs in the build (go test now part of the tracker
  Dockerfile).
- Live: 40 combat lifetime rows + 40 session snapshots + rare_events flowing in
  dereth_go via the shadow consumer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 10:42:15 +02:00

54 lines
2 KiB
Go

package main
import "testing"
// Golden values cross-checked against the Python _combat_session_delta /
// _combat_merge_into_lifetime on identical input (see compare run). Folds two
// cumulative snapshots; the first is treated as the whole delta.
func TestCombatMerge(t *testing.T) {
snap1 := map[string]any{
"total_damage_given": 100.0, "total_kills": 2.0,
"monsters": map[string]any{
"Drudge": map[string]any{
"name": "Drudge", "kill_count": 2.0, "damage_given": 100.0,
"offense": map[string]any{"melee": map[string]any{"slashing": map[string]any{
"total_attacks": 10.0, "max_normal_damage": 15.0,
}}},
},
},
}
snap2 := map[string]any{
"total_damage_given": 250.0, "total_kills": 5.0,
"monsters": map[string]any{
"Drudge": map[string]any{
"name": "Drudge", "kill_count": 4.0, "damage_given": 200.0,
"offense": map[string]any{"melee": map[string]any{"slashing": map[string]any{
"total_attacks": 20.0, "max_normal_damage": 18.0,
}}},
},
},
}
lifetime := map[string]any{}
lifetime = combatMergeIntoLifetime(lifetime, snap1) // first = whole delta
lifetime = combatMergeIntoLifetime(lifetime, combatSessionDelta(snap2, snap1))
if got := num(lifetime["total_kills"]); got != 5 {
t.Errorf("total_kills = %v, want 5", got)
}
if got := num(lifetime["total_damage_given"]); got != 250 {
t.Errorf("total_damage_given = %v, want 250", got)
}
drudge := asMap(asMap(lifetime["monsters"])["Drudge"])
if got := num(drudge["kill_count"]); got != 4 {
t.Errorf("Drudge.kill_count = %v, want 4", got)
}
slashing := asMap(asMap(asMap(drudge["offense"])["melee"])["slashing"])
// offense uses the latest snapshot additively (the documented quirk): 10 + 20.
if got := num(slashing["total_attacks"]); got != 30 {
t.Errorf("offense slashing total_attacks = %v, want 30 (latest-additive quirk)", got)
}
if got := num(slashing["max_normal_damage"]); got != 18 {
t.Errorf("offense slashing max_normal_damage = %v, want 18 (max)", got)
}
}