from pathlib import Path import pytest from engine.character_creator import CharacterCreator from engine.defs import DefRegistry from engine.game_modes import CharacterCreationFlow, MainMenu, PauseMenu DEFS_DIR = Path(__file__).resolve().parent.parent / "resources" / "defs" @pytest.fixture() def registry(): return DefRegistry.load(DEFS_DIR) # --- MainMenu ----------------------------------------------------------------------------------- def test_main_menu_without_a_save_has_no_continue_option(): menu = MainMenu(has_existing_save=False) assert "continue" not in menu.options() assert menu.selected() == "new_game" def test_main_menu_with_a_save_offers_continue_first(): menu = MainMenu(has_existing_save=True) assert menu.options()[0] == "continue" assert menu.selected() == "continue" def test_main_menu_move_wraps_around(): menu = MainMenu(has_existing_save=False) assert menu.options() == ["new_game", "controls"] menu.move(-1) assert menu.selected() == "controls" menu.move(1) assert menu.selected() == "new_game" # --- PauseMenu ------------------------------------------------------------------------------------ def test_pause_menu_defaults_to_resume(): assert PauseMenu().selected() == "resume" def test_pause_menu_cycles_through_all_options(): menu = PauseMenu() seen = {menu.selected()} for _ in range(len(PauseMenu.OPTIONS)): menu.move(1) seen.add(menu.selected()) assert seen == set(PauseMenu.OPTIONS) # --- CharacterCreationFlow ------------------------------------------------------------------------- def test_flow_locks_in_a_default_species_on_creation(registry): flow = CharacterCreationFlow(CharacterCreator(registry)) assert flow.creator.species_id == flow.species_list()[0] def test_cycle_species_updates_the_creator(registry): flow = CharacterCreationFlow(CharacterCreator(registry)) first = flow.creator.species_id flow.cycle_species(1) assert flow.creator.species_id != first assert flow.creator.species_id == flow.species_list()[1 % len(flow.species_list())] def test_advance_from_species_moves_to_name_step_without_finishing(registry): flow = CharacterCreationFlow(CharacterCreator(registry)) assert flow.advance() is False assert flow.step == "name" def test_typing_only_applies_during_the_name_step(registry): flow = CharacterCreationFlow(CharacterCreator(registry)) flow.type_char("x") # still on species step assert flow.creator.name == "" flow.advance() flow.type_char("V") flow.type_char("e") flow.type_char("x") assert flow.creator.name == "Vex" def test_backspace_removes_the_last_character(registry): flow = CharacterCreationFlow(CharacterCreator(registry)) flow.advance() flow.type_char("V") flow.type_char("x") flow.backspace() assert flow.creator.name == "V" def test_advance_on_name_step_requires_a_non_empty_name(registry): flow = CharacterCreationFlow(CharacterCreator(registry)) flow.advance() assert flow.advance() is False flow.type_char("V") assert flow.advance() is True def test_typing_is_capped_at_max_name_length(registry): flow = CharacterCreationFlow(CharacterCreator(registry)) flow.advance() for ch in "x" * 30: flow.type_char(ch) assert len(flow.creator.name) == 20 def test_go_back_from_name_returns_to_species(registry): flow = CharacterCreationFlow(CharacterCreator(registry)) flow.advance() assert flow.go_back() is True assert flow.step == "species" def test_go_back_from_species_reports_theres_nowhere_further_back(registry): flow = CharacterCreationFlow(CharacterCreator(registry)) assert flow.go_back() is False