Mi2dRPGamEng/tests/test_character_creator.py

196 lines
6.5 KiB
Python

import sqlite3
from pathlib import Path
import pytest
from engine.character_creator import CharacterCreator
from engine.character_library import CharacterLibrary
from engine.defs import DefRegistry
DEFS_DIR = Path(__file__).resolve().parent.parent / "resources" / "defs"
@pytest.fixture()
def registry():
return DefRegistry.load(DEFS_DIR)
@pytest.fixture()
def library():
return CharacterLibrary(sqlite3.connect(":memory:"))
# --- species / gender selection -----------------------------------------------------------
def test_set_species_defaults_gender_to_the_first_valid_option(registry):
creator = CharacterCreator(registry)
assert creator.set_species("human") is True
assert creator.species_id == "human"
assert creator.gender == "male"
def test_set_species_rejects_unknown_species(registry):
creator = CharacterCreator(registry)
assert creator.set_species("dragon") is False
assert creator.species_id is None
def test_set_gender_accepts_a_valid_option(registry):
creator = CharacterCreator(registry)
creator.set_species("human")
assert creator.set_gender("nonbinary") is True
assert creator.gender == "nonbinary"
def test_set_gender_rejects_option_not_valid_for_species(registry):
creator = CharacterCreator(registry)
creator.set_species("alien_tri") # genders: alpha/beta/gamma
assert creator.set_gender("male") is False
assert creator.gender == "alpha" # unchanged, still the auto-picked default
def test_set_gender_before_species_is_a_no_op(registry):
creator = CharacterCreator(registry)
assert creator.set_gender("male") is False
assert creator.gender is None
def test_switching_species_resets_gender_if_no_longer_valid(registry):
creator = CharacterCreator(registry)
creator.set_species("human")
creator.set_gender("nonbinary")
creator.set_species("bot") # monogender, "none" - "nonbinary" isn't valid here
assert creator.gender == "none"
def test_switching_species_keeps_gender_if_still_valid(registry):
creator = CharacterCreator(registry)
creator.set_species("human")
creator.set_gender("female")
creator.set_species("dog") # dog also has "male"/"female"
assert creator.gender == "female"
# --- skill point budget ---------------------------------------------------------------------
def test_starts_with_the_full_budget_unspent(registry):
creator = CharacterCreator(registry)
assert creator.spent_skill_points() == 0
assert creator.remaining_skill_points() == creator.skill_points_budget
def test_increase_skill_spends_a_point(registry):
creator = CharacterCreator(registry)
assert creator.increase_skill("stealth") is True
assert creator.bio["stealth"] == 1
assert creator.remaining_skill_points() == creator.skill_points_budget - 1
def test_increase_skill_fails_once_budget_exhausted(registry):
creator = CharacterCreator(registry, skill_points_budget=2)
creator.increase_skill("stealth")
creator.increase_skill("stealth")
assert creator.increase_skill("athletics") is False
assert creator.bio["athletics"] == 0
def test_increase_skill_fails_past_max_level(registry):
creator = CharacterCreator(registry, skill_points_budget=99, max_skill_level=2)
creator.increase_skill("stealth")
creator.increase_skill("stealth")
assert creator.increase_skill("stealth") is False
assert creator.bio["stealth"] == 2
def test_increase_skill_rejects_unknown_skill(registry):
creator = CharacterCreator(registry)
assert creator.increase_skill("lockpicking") is False
def test_decrease_skill_refunds_a_point(registry):
creator = CharacterCreator(registry)
creator.increase_skill("stealth")
assert creator.decrease_skill("stealth") is True
assert creator.bio["stealth"] == 0
assert creator.remaining_skill_points() == creator.skill_points_budget
def test_decrease_skill_below_zero_is_a_no_op(registry):
creator = CharacterCreator(registry)
assert creator.decrease_skill("stealth") is False
# --- body part preview ------------------------------------------------------------------------
def test_preview_body_parts_empty_before_species_chosen(registry):
creator = CharacterCreator(registry)
assert creator.preview_body_parts() == []
def test_preview_body_parts_matches_species_defaults(registry):
creator = CharacterCreator(registry)
creator.set_species("dog")
slots = {p.slot for p in creator.preview_body_parts()}
assert slots == {"head", "torso", "front_left_leg", "front_right_leg", "back_left_leg", "back_right_leg"}
# --- readiness / build_character ----------------------------------------------------------------
def test_not_ready_without_name_species_and_gender(registry):
creator = CharacterCreator(registry)
assert creator.is_ready() is False
creator.set_name("Vex")
assert creator.is_ready() is False
creator.set_species("human")
assert creator.is_ready() is True # species auto-fills a valid gender
def test_build_character_returns_none_when_not_ready(registry):
creator = CharacterCreator(registry)
creator.set_name("Vex")
assert creator.build_character() is None
def test_build_character_produces_a_character_with_chosen_traits(registry):
creator = CharacterCreator(registry)
creator.set_name(" Vex ")
creator.set_species("reptilian_quad")
creator.increase_skill("athletics")
character = creator.build_character()
assert character is not None
assert character.name == "Vex" # whitespace trimmed
assert character.species_id == "reptilian_quad"
assert character.gender == "none"
assert character.bio["athletics"] == 1
assert {p.slot for p in character.default_body_parts} == {
"head", "torso", "left_arm", "right_arm", "left_arm_2", "right_arm_2", "left_leg", "right_leg",
}
# --- confirm: saves into the library -------------------------------------------------------------
def test_confirm_saves_into_the_library(registry, library):
creator = CharacterCreator(registry)
creator.set_name("Vex")
creator.set_species("human")
character = creator.confirm(library, "acct-1", "char-1")
assert character is not None
loaded = library.load_character("acct-1", "char-1", registry)
assert loaded is not None
assert loaded.name == "Vex"
assert loaded.species_id == "human"
def test_confirm_does_nothing_when_not_ready(registry, library):
creator = CharacterCreator(registry)
assert creator.confirm(library, "acct-1", "char-1") is None
assert library.load_character("acct-1", "char-1", registry) is None