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) } }