diff options
| author | historia <[not public]> | 2026-09-18 05:31:09 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-09-18 05:31:09 -0400 |
| commit | 153acb7f644d755c45533b7c5311e3ffa47e8973 (patch) | |
| tree | 7645e6f7b65bc3830b078e3b9336d2e6b199d584 /internal/validate/hardening_mob_stats_validation_test.go | |
| parent | 87d08f0151e643951769e323995f1c5ed89ee200 (diff) | |
| download | thehouseoficarus-153acb7f644d755c45533b7c5311e3ffa47e8973.tar.gz | |
fix: harden engine across casino, economy, concurrency, security, and content
Diffstat (limited to 'internal/validate/hardening_mob_stats_validation_test.go')
| -rw-r--r-- | internal/validate/hardening_mob_stats_validation_test.go | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/internal/validate/hardening_mob_stats_validation_test.go b/internal/validate/hardening_mob_stats_validation_test.go new file mode 100644 index 0000000..1ea30f9 --- /dev/null +++ b/internal/validate/hardening_mob_stats_validation_test.go @@ -0,0 +1,107 @@ +package validate + +import ( + "path/filepath" + "testing" +) + +// Regression: validateMobs must reject a fighting mob authored without an +// attack speed (engine.ToTicks clips 0 to 1, so the mob would attack every +// tick) or without a max hit for a declared attack type (a silent no-op). +// Task worksites are explicitly exempt: data/mobs/examples/solar_panel_frame.yaml +// ships max_melee_hit: 0 and must remain valid. + +func writeMob(t *testing.T, dir, name, body string) { + t.Helper() + writeFile(t, filepath.Join(dir, "mobs", name+".yaml"), body) +} + +func TestMobMissingSpeedIsError(t *testing.T) { + dir := t.TempDir() + writeMob(t, dir, "test_mob", `id: test_mob +name: test mob +combat: + kind: combat + attack_types: [crush] + stats: + hp: 10 + speed: 0 + max_melee_hit: 5 +`) + issues := validateMobs(newSource(dir)) + if !containsMsg(issues, "stats.speed") { + t.Fatalf("expected missing-speed error, got: %+v", issues) + } +} + +func TestMobMissingMaxMeleeHitIsError(t *testing.T) { + dir := t.TempDir() + writeMob(t, dir, "test_mob", `id: test_mob +name: test mob +combat: + kind: combat + attack_types: [crush] + stats: + hp: 10 + speed: 5 + max_melee_hit: 0 +`) + issues := validateMobs(newSource(dir)) + if !containsMsg(issues, "max_melee_hit") { + t.Fatalf("expected missing-melee-hit error, got: %+v", issues) + } +} + +func TestMobMissingMaxRangedHitIsError(t *testing.T) { + dir := t.TempDir() + writeMob(t, dir, "test_mob", `id: test_mob +name: test mob +combat: + kind: combat + attack_types: [crush, ranged] + stats: + hp: 10 + speed: 5 + max_melee_hit: 3 +`) + issues := validateMobs(newSource(dir)) + if !containsMsg(issues, "max_ranged_hit") { + t.Fatalf("expected missing-ranged-hit error, got: %+v", issues) + } +} + +func TestTaskWorksiteMobExemptFromCombatStatChecks(t *testing.T) { + dir := t.TempDir() + writeMob(t, dir, "test_worksite", `id: test_worksite +name: test worksite +combat: + kind: task + attack_types: [crush] + stats: + hp: 10 + speed: 0 + max_melee_hit: 0 +`) + if issues := validateMobs(newSource(dir)); len(issues) != 0 { + t.Fatalf("task worksite must be exempt from combat-stat checks, got: %+v", issues) + } +} + +func TestValidCombatMobProducesNoIssue(t *testing.T) { + dir := t.TempDir() + writeMob(t, dir, "test_mob", `id: test_mob +name: test mob +combat: + kind: combat + attack_types: [slash, ranged, science] + stats: + hp: 10 + speed: 4 + max_melee_hit: 3 + max_ranged_hit: 4 + max_science_hit: 5 +`) + if issues := validateMobs(newSource(dir)); len(issues) != 0 { + t.Fatalf("valid combat mob must validate cleanly, got: %+v", issues) + } +} |
