Files
Flora/tests/test_bosses.py
T
Lena feb4500c6c small update
boss prototype, auto planter, visual reworks, bug fixes
2026-08-29 10:45:34 +02:00

139 lines
4.7 KiB
Python

import atexit
import os
import pathlib
import tempfile
import unittest
# Point the engine at a fresh empty save to keep collection-dependent tests hermetic.
import engine.collection as collection
from engine import bosses
from engine.battle import Battle
from engine.plants import make_leveled
from engine.unit import TEAM_ENEMY, TEAM_PLAYER
_fd, _tmp_path = tempfile.mkstemp(suffix=".json")
os.close(_fd)
_TMP = pathlib.Path(_tmp_path)
_ORIG_DATA_FILE = collection._DATA_FILE
collection._DATA_FILE = _TMP
@atexit.register
def _restore_collection():
collection._DATA_FILE = _ORIG_DATA_FILE
if _TMP.exists():
_TMP.unlink()
class BossSchedulingTest(unittest.TestCase):
def test_boss_appears_on_multiples_of_20(self):
self.assertEqual(bosses.boss_for_floor(20), "Stones")
self.assertEqual(bosses.boss_for_floor(40), "Stones")
self.assertEqual(bosses.boss_for_floor(100), "Stones")
self.assertIsNone(bosses.boss_for_floor(19))
self.assertIsNone(bosses.boss_for_floor(1))
def test_boss_stats_are_extreme(self):
u = bosses.make_boss("Stones", 20)
# very low speed, medium defense, high health, medium attack
self.assertLessEqual(u.speed, 40)
self.assertGreaterEqual(u.max_hp, 900)
self.assertGreaterEqual(u.defense, 80)
self.assertTrue(60 <= u.attack <= 200)
class BossMechanicTest(unittest.TestCase):
def _battle(self):
a = make_leveled("Rose", TEAM_PLAYER, 20, 1)
a.max_hp = 5000
a.hp = 5000
u = bosses.make_boss("Stones", 20)
b = Battle([a], [u])
b.start()
return b, a, u
def test_landslide_blocked_until_three_stacks(self):
b, a, u = self._battle()
b.current = u
pebble, landslide = u.skills
u.acted = False
self.assertFalse(b.use_skill(u, landslide, a)) # 0 stacks: blocked
self.assertEqual(b.valid_skill_targets(u, landslide), [])
for _ in range(3):
u.acted = False
self.assertTrue(b.use_skill(u, pebble, a))
self.assertEqual(u.status["boss_stacks"], 3)
u.acted = False
self.assertTrue(b.use_skill(u, landslide, a)) # now available
self.assertEqual(u.status["boss_stacks"], 0) # released
def test_boss_stacks_cap_at_three(self):
b, a, u = self._battle()
b.current = u
pebble, _ = u.skills
for _ in range(6):
u.acted = False
self.assertTrue(b.use_skill(u, pebble, a))
self.assertEqual(u.status["boss_stacks"], 3) # never exceeds 3
def test_boss_ai_pebbles_then_landslides_then_repeats(self):
b, a, u = self._battle()
moves = []
guard = 0
while len(moves) < 7 and guard < 120 and b.winner is None:
guard += 1
if b.current is u and not u.acted:
before = u.status.get("boss_stacks", 0)
used = b.enemy_ai(u)
after = u.status.get("boss_stacks", 0)
if used:
moves.append("Pebble" if after > before else
("Landslide" if before >= 3 and after == 0 else "?"))
b.next_turn()
self.assertEqual(moves[:4], ["Pebble", "Pebble", "Pebble", "Landslide"])
self.assertEqual(moves[4:], ["Pebble", "Pebble", "Pebble"])
def test_landslide_hits_harder_than_pebble(self):
b, a, u = self._battle()
b.current = u
pebble, landslide = u.skills
for _ in range(3):
u.acted = False
b.use_skill(u, pebble, a)
u.acted = False
pebble_dmg = b._hit_damage.get(id(a), 0)
a.hp = a.max_hp # reset before landslide
u.status["boss_stacks"] = 3
b.use_skill(u, landslide, a)
landslide_dmg = b._hit_damage.get(id(a), 0)
self.assertGreater(landslide_dmg, pebble_dmg * 2)
class BossRewardTest(unittest.TestCase):
def setUp(self):
data = collection.load()
data["owned"] = ["Rose"]
data["bosses_fought"] = []
data["runes"] = []
collection.save(data)
def test_mark_boss_fought(self):
self.assertEqual(collection.bosses_fought(), set())
collection.mark_boss_fought("Stones")
self.assertEqual(collection.bosses_fought(), {"Stones"})
def test_boss_rune_drop_is_high_chance_and_select(self):
colors = set()
total = 0
for _ in range(300):
r = collection.boss_rune_drop("Stones")
if r:
total += 1
self.assertIn(r["color"], ("ruby", "amethyst"))
colors.add(r["color"])
self.assertGreaterEqual(total, 150) # ~80% chance
self.assertEqual(colors, {"ruby", "amethyst"})
if __name__ == "__main__":
unittest.main()