test(engine-specific): Add unit tests for species generation logic, including edge cases and validation assertions

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Claude Code 2026-03-26 00:29:34 -07:00
parent c78443fa4b
commit 805d4306f7

View file

@ -0,0 +1,178 @@
extends GutTest
## M2b Block 1 verification — species generation diversity and constraint validation.
## Tests 1.5 (diversity) and 1.6 (constraint validation) from the M2b task list.
const SpeciesGeneratorScript = preload("res://engine/src/models/world/species_generator.gd")
const TraitSetScript = preload("res://engine/src/models/world/species_traits.gd")
const ALL_BIOMES: Array = [
"deep_ocean", "shallow_ocean", "coral_reef", "estuary", "lake", "pond",
"river", "mangrove", "tropical_rainforest", "tropical_dry_forest",
"savanna", "desert", "temperate_forest", "temperate_grassland",
"chaparral", "swamp", "bog", "boreal_forest", "tundra", "polar_desert",
"montane_forest", "cloud_forest", "alpine_meadow", "alpine_tundra",
"permanent_ice", "subterranean",
]
const TEST_SEEDS: Array = [42, 137, 256, 404, 512, 777, 999, 1234, 2048, 3141]
const MIN_PRODUCERS: int = 3
const MIN_HERBIVORES: int = 3
const MIN_PREDATORS: int = 2
func before_all() -> void:
DataLoader.load_theme("age-of-four")
## 1.5: Each biome generates at least 3 producers + 3 herbivores + 2 predators
## across 10 seeds.
func test_species_diversity_per_biome() -> void:
var report: Array[String] = []
var failures: Array[String] = []
for biome_id: String in ALL_BIOMES:
var weights: Dictionary = DataLoader.get_biome_trait_weights(biome_id)
var total_producers: int = 0
var total_herbivores: int = 0
var total_predators: int = 0
var total_species: int = 0
for seed_val: int in TEST_SEEDS:
var species: Array = SpeciesGeneratorScript.generate(
biome_id, 3, seed_val, weights
)
total_species += species.size()
for ts: Variant in species:
match ts.diet:
"producer":
total_producers += 1
"herbivore":
total_herbivores += 1
"carnivore", "omnivore":
total_predators += 1
var line: String = (
"%s: %d species, %d producers, %d herbivores, %d predators"
% [biome_id, total_species, total_producers, total_herbivores, total_predators]
)
report.append(line)
if total_producers < MIN_PRODUCERS:
failures.append("%s: only %d producers (need %d)" % [biome_id, total_producers, MIN_PRODUCERS])
if total_herbivores < MIN_HERBIVORES:
failures.append("%s: only %d herbivores (need %d)" % [biome_id, total_herbivores, MIN_HERBIVORES])
if total_predators < MIN_PREDATORS:
failures.append("%s: only %d predators (need %d)" % [biome_id, total_predators, MIN_PREDATORS])
# Print diversity report
gut.p("=== Species Diversity Report (10 seeds, quality 3) ===")
for line: String in report:
gut.p(line)
if failures.size() > 0:
gut.p("=== FAILURES ===")
for f: String in failures:
gut.p(f)
fail_test("Diversity check failed for %d biomes" % failures.size())
else:
pass_test("All biomes meet diversity minimums")
## 1.6: Zero invalid species generated across all biomes on 10 seeds.
func test_zero_invalid_species() -> void:
var invalid_count: int = 0
var total_count: int = 0
for biome_id: String in ALL_BIOMES:
var weights: Dictionary = DataLoader.get_biome_trait_weights(biome_id)
for seed_val: int in TEST_SEEDS:
var species: Array = SpeciesGeneratorScript.generate(
biome_id, 3, seed_val, weights
)
for ts: Variant in species:
total_count += 1
if not ts.validate():
invalid_count += 1
gut.p(
"INVALID: %s in %s (seed %d)" % [ts.trait_hash, biome_id, seed_val]
)
gut.p("Total species generated: %d, invalid: %d" % [total_count, invalid_count])
assert_eq(invalid_count, 0, "All generated species must pass validate()")
## Verify amphibious adjacency boost produces amphibious species.
func test_amphibious_adjacency_boost() -> void:
var weights: Dictionary = DataLoader.get_biome_trait_weights("temperate_forest")
var amphibious_without: int = 0
var amphibious_with: int = 0
var trials: int = 10
for seed_val: int in TEST_SEEDS:
var normal: Array = SpeciesGeneratorScript.generate(
"temperate_forest", 3, seed_val, weights, false
)
var boosted: Array = SpeciesGeneratorScript.generate(
"temperate_forest", 3, seed_val, weights, true
)
for ts: Variant in normal:
if ts.habitat == "amphibious":
amphibious_without += 1
for ts: Variant in boosted:
if ts.habitat == "amphibious":
amphibious_with += 1
gut.p(
"Amphibious species: without boost=%d, with boost=%d (across %d seeds)"
% [amphibious_without, amphibious_with, trials]
)
assert_true(
amphibious_with >= amphibious_without,
"Adjacency boost should not reduce amphibious species count"
)
## Verify migration pattern detection.
func test_migration_pattern_detection() -> void:
var flying_herd := TraitSetScript.new()
flying_herd.size = "medium"
flying_herd.diet = "herbivore"
flying_herd.habitat = "aerial"
flying_herd.locomotion = "flying"
flying_herd.reproduction = "k_strategy"
flying_herd.thermal = "warm_blooded"
flying_herd.social = "herd"
assert_eq(
SpeciesGeneratorScript.get_migration_pattern(flying_herd),
"seasonal",
"Aerial herd should get seasonal migration"
)
var walking_pack := TraitSetScript.new()
walking_pack.size = "medium"
walking_pack.diet = "carnivore"
walking_pack.habitat = "terrestrial"
walking_pack.locomotion = "walking"
walking_pack.reproduction = "k_strategy"
walking_pack.thermal = "warm_blooded"
walking_pack.social = "pack"
assert_eq(
SpeciesGeneratorScript.get_migration_pattern(walking_pack),
null,
"Walking pack should not get seasonal migration"
)
var flying_swarm := TraitSetScript.new()
flying_swarm.size = "tiny"
flying_swarm.diet = "herbivore"
flying_swarm.habitat = "terrestrial"
flying_swarm.locomotion = "flying"
flying_swarm.reproduction = "r_strategy"
flying_swarm.thermal = "cold_blooded"
flying_swarm.social = "swarm"
assert_eq(
SpeciesGeneratorScript.get_migration_pattern(flying_swarm),
"seasonal",
"Flying swarm should get seasonal migration"
)