b03a61d8ab
Verified field-by-field against the SRD knowledge base (pathfinder-1e-rules, spells/): - levels: abundant_ammunition 0->1, comprehend_languages 0->1, deja_vu 0->1, create_water 1->0, enhance_water 2->1 - saves: blindness_deafness will->fort, enhance_water none->fort - spell resistance: summon_monster_i/ii declared false (SRD RM: no) - schools: arcane_mark ->universal, color_spray ->illusion, dancing_lights ->evocation, deja_vu ->enchantment, enhance_water ->transmutation, abundant_ammunition ->conjuration - ranges: deja_vu personal->medium, dancing_lights close->medium, enhance_water personal->touch, create_water medium->close Registry pins in test_spell_registry_batch1.py updated to match; descriptions that stated the old values reworded consistently.
126 lines
5.0 KiB
Python
126 lines
5.0 KiB
Python
"""Batch 1 (V6a): the 32 PC-sheet spells added to data/spells/.
|
|
|
|
Given: the registry directory with the 11 original spells plus batch 1
|
|
When: load_spell_registry / load_spell is called
|
|
Then: every new spell loads with the expected level/school/range/save,
|
|
the registry grew by exactly 32, and every effect validates against the
|
|
schema (parsing raises on any unknown field value or condition).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from pf1e_simulator.conditions import CONDITIONS_BY_NAME
|
|
from pf1e_simulator.spells import (
|
|
AreaEffect,
|
|
BuffEffect,
|
|
ConditionEffect,
|
|
DamageEffect,
|
|
HealEffect,
|
|
SpellEffect,
|
|
SpellSpec,
|
|
SummonEffect,
|
|
load_spell,
|
|
load_spell_registry,
|
|
)
|
|
|
|
_SPELLS_DIR = Path(__file__).resolve().parent.parent / "data" / "spells"
|
|
|
|
_ORIGINAL_COUNT = 11
|
|
|
|
# name -> (file stem, level, school, range, save)
|
|
_BATCH1: dict[str, tuple[str, int, str, str, str]] = {
|
|
"Abundant Ammunition": ("abundant_ammunition", 1, "conjuration", "close", "none"),
|
|
"Acid Splash": ("acid_splash", 0, "conjuration", "close", "none"),
|
|
"Aid": ("aid", 2, "enchantment", "touch", "none"),
|
|
"Air Bubble": ("air_bubble", 1, "conjuration", "personal", "none"),
|
|
"Alarm": ("alarm", 1, "abjuration", "medium", "none"),
|
|
"Arcane Mark": ("arcane_mark", 0, "universal", "touch", "none"),
|
|
"Bane": ("bane", 1, "enchantment", "medium", "will"),
|
|
"Bear's Endurance": ("bears_endurance", 2, "transmutation", "touch", "will"),
|
|
"Bladed Dash": ("bladed_dash", 2, "transmutation", "personal", "none"),
|
|
"Bleed": ("bleed", 0, "necromancy", "close", "will"),
|
|
"Bless": ("bless", 1, "enchantment", "medium", "none"),
|
|
"Blindness/Deafness": ("blindness_deafness", 2, "necromancy", "medium", "fort"),
|
|
"Charm Person": ("charm_person", 1, "enchantment", "medium", "will"),
|
|
"Color Spray": ("color_spray", 1, "illusion", "close", "will"),
|
|
"Comprehend Languages": ("comprehend_languages", 1, "divination", "personal", "none"),
|
|
"Create Alcool": ("create_alcool", 0, "conjuration", "close", "none"),
|
|
"Create Water": ("create_water", 0, "conjuration", "close", "none"),
|
|
"Dancing Lights": ("dancing_lights", 0, "evocation", "medium", "none"),
|
|
"Darkness": ("darkness", 2, "evocation", "touch", "none"),
|
|
"Daze": ("daze", 0, "enchantment", "close", "will"),
|
|
"Deja Vu": ("deja_vu", 1, "enchantment", "medium", "none"),
|
|
"Delay Disease": ("delay_disease", 3, "abjuration", "touch", "fort"),
|
|
"Delay Poison": ("delay_poison", 2, "abjuration", "touch", "fort"),
|
|
"Detect Fiendish Presence": ("detect_fiendish_presence", 0, "divination", "close", "none"),
|
|
"Detect Magic": ("detect_magic", 0, "divination", "close", "none"),
|
|
"Detect Poison": ("detect_poison", 0, "divination", "close", "none"),
|
|
"Disrupt Undead": ("disrupt_undead", 0, "necromancy", "close", "none"),
|
|
"Divine Favor": ("divine_favor", 1, "evocation", "personal", "none"),
|
|
"Doom": ("doom", 1, "necromancy", "medium", "will"),
|
|
"Drunkard's Breath": ("drunkards_breath", 1, "abjuration", "personal", "none"),
|
|
"Endure Elements": ("endure_elements", 1, "abjuration", "personal", "none"),
|
|
"Enhance Water": ("enhance_water", 1, "transmutation", "touch", "fort"),
|
|
}
|
|
|
|
_EFFECT_TYPES = (
|
|
DamageEffect,
|
|
ConditionEffect,
|
|
HealEffect,
|
|
BuffEffect,
|
|
AreaEffect,
|
|
SummonEffect,
|
|
)
|
|
|
|
|
|
def _walk_effects(effects: tuple[SpellEffect, ...]) -> list[SpellEffect]:
|
|
flat: list[SpellEffect] = []
|
|
for effect in effects:
|
|
flat.append(effect)
|
|
if isinstance(effect, AreaEffect):
|
|
flat.extend(_walk_effects(effect.effects))
|
|
return flat
|
|
|
|
|
|
class TestBatch1Loading:
|
|
"""Each batch-1 spell loads with the expected metadata."""
|
|
|
|
@pytest.mark.parametrize(
|
|
("name", "stem", "level", "school", "range_", "save"),
|
|
[
|
|
(name, *fields) for name, fields in sorted(_BATCH1.items())
|
|
],
|
|
)
|
|
def test_spell_fields(
|
|
self, name: str, stem: str, level: int, school: str, range_: str, save: str
|
|
) -> None:
|
|
spell = load_spell(_SPELLS_DIR / f"{stem}.json")
|
|
assert spell.name == name
|
|
assert spell.level == level
|
|
assert spell.school == school
|
|
assert spell.range == range_
|
|
assert spell.save == save
|
|
assert spell.base_dc == 10
|
|
assert spell.description
|
|
|
|
def test_registry_grew_by_exactly_32(self) -> None:
|
|
reg = load_spell_registry(_SPELLS_DIR)
|
|
# exact total is pinned by test_spell_registry_batch2
|
|
assert len(reg) >= _ORIGINAL_COUNT + 32
|
|
assert set(_BATCH1) <= set(reg)
|
|
|
|
def test_every_effect_validates(self) -> None:
|
|
reg = load_spell_registry(_SPELLS_DIR)
|
|
for name in _BATCH1:
|
|
spell: SpellSpec = reg[name]
|
|
for effect in _walk_effects(spell.effects):
|
|
assert isinstance(effect, _EFFECT_TYPES)
|
|
if isinstance(effect, ConditionEffect):
|
|
assert effect.condition_name in CONDITIONS_BY_NAME
|
|
if isinstance(effect, BuffEffect):
|
|
assert effect.modifiers
|