227 lines
6.8 KiB
Python
227 lines
6.8 KiB
Python
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from engine.character import Character
|
|
from engine.defs import DefRegistry
|
|
from engine.dev_config import DevConfig
|
|
from engine.dev_tools import DevFactionMenu, DevSpawnMenu, DevTurretMenu
|
|
from engine.inventory import Inventory
|
|
|
|
DEFS_DIR = Path(__file__).resolve().parent.parent / "resources" / "defs"
|
|
|
|
|
|
@pytest.fixture()
|
|
def registry():
|
|
return DefRegistry.load(DEFS_DIR)
|
|
|
|
|
|
def make_human(registry, **kwargs) -> Character:
|
|
return Character(species_id="human", default_body_parts=registry.new_default_body_parts("human"), **kwargs)
|
|
|
|
|
|
# --- DevSpawnMenu -------------------------------------------------------------------------------
|
|
|
|
|
|
def test_menu_defaults_to_every_loaded_non_secret_item_def_sorted(registry):
|
|
menu = DevSpawnMenu(registry)
|
|
expected = sorted(def_id for def_id, item_def in registry.item_defs.items() if not item_def.secret)
|
|
assert menu.item_ids == expected
|
|
assert menu.selected_item_id() == menu.item_ids[0]
|
|
|
|
|
|
def test_menu_excludes_secret_items(registry):
|
|
menu = DevSpawnMenu(registry)
|
|
assert "cyberdeck_the_miro_model_3a" not in menu.item_ids
|
|
|
|
|
|
def test_cycle_wraps_around(registry):
|
|
menu = DevSpawnMenu(registry)
|
|
menu.cycle(-1)
|
|
assert menu.selected_item_id() == menu.item_ids[-1]
|
|
|
|
|
|
def test_spawn_into_places_the_item_when_inventory_has_room(registry):
|
|
menu = DevSpawnMenu(registry)
|
|
character = make_human(registry)
|
|
character.inventory = Inventory(4, 4)
|
|
assert menu.spawn_into(character) is True
|
|
assert len(character.inventory.items()) == 1
|
|
|
|
|
|
def test_spawn_into_fails_without_an_inventory(registry):
|
|
menu = DevSpawnMenu(registry)
|
|
character = make_human(registry)
|
|
assert menu.spawn_into(character) is False
|
|
|
|
|
|
def test_spawn_into_fails_when_inventory_is_full(registry):
|
|
menu = DevSpawnMenu(registry)
|
|
character = make_human(registry)
|
|
character.inventory = Inventory(1, 1)
|
|
item_def = registry.get_item_def(menu.selected_item_id())
|
|
if item_def.width > 1 or item_def.height > 1:
|
|
pytest.skip("first item def doesn't fit a 1x1 inventory to begin with")
|
|
assert menu.spawn_into(character) is True
|
|
assert menu.spawn_into(character) is False
|
|
|
|
|
|
# --- DevTurretMenu --------------------------------------------------------------------------------
|
|
|
|
|
|
def test_turret_menu_defaults_to_every_turret_entity_def_sorted(registry):
|
|
menu = DevTurretMenu(registry)
|
|
assert menu.entity_def_ids == ["turret_autocannon", "turret_pistol"]
|
|
assert menu.selected_entity_def_id() == "turret_autocannon"
|
|
|
|
|
|
def test_turret_menu_excludes_non_turret_entity_defs(registry):
|
|
menu = DevTurretMenu(registry)
|
|
assert "player" not in menu.entity_def_ids
|
|
assert "npc_reptilian" not in menu.entity_def_ids
|
|
assert "companion_dog" not in menu.entity_def_ids
|
|
|
|
|
|
def test_turret_menu_cycle_wraps_around(registry):
|
|
menu = DevTurretMenu(registry)
|
|
menu.cycle(-1)
|
|
assert menu.selected_entity_def_id() == menu.entity_def_ids[-1]
|
|
|
|
|
|
def test_turret_menu_selected_entity_def_id_is_none_when_empty(registry):
|
|
menu = DevTurretMenu(registry)
|
|
menu.entity_def_ids = []
|
|
assert menu.selected_entity_def_id() is None
|
|
|
|
|
|
# --- DevFactionMenu --------------------------------------------------------------------------------
|
|
|
|
|
|
def test_type_char_builds_up_the_input_text():
|
|
menu = DevFactionMenu()
|
|
menu.type_char("h")
|
|
menu.type_char("i")
|
|
assert menu.input_text == "hi"
|
|
|
|
|
|
def test_backspace_removes_the_last_typed_character():
|
|
menu = DevFactionMenu()
|
|
menu.type_char("h")
|
|
menu.type_char("i")
|
|
menu.backspace()
|
|
assert menu.input_text == "h"
|
|
|
|
|
|
def test_typing_is_capped_at_max_faction_tag_length():
|
|
menu = DevFactionMenu()
|
|
for ch in "x" * 40:
|
|
menu.type_char(ch)
|
|
assert len(menu.input_text) == 24
|
|
|
|
|
|
def test_add_tag_appends_the_typed_text_and_clears_the_input(registry):
|
|
menu = DevFactionMenu()
|
|
character = make_human(registry)
|
|
menu.type_char("h")
|
|
menu.type_char("o")
|
|
menu.type_char("s")
|
|
menu.type_char("t")
|
|
menu.type_char("i")
|
|
menu.type_char("l")
|
|
menu.type_char("e")
|
|
|
|
assert menu.add_tag(character) is True
|
|
|
|
assert character.factions == ["hostile"]
|
|
assert menu.input_text == ""
|
|
|
|
|
|
def test_add_tag_trims_whitespace(registry):
|
|
menu = DevFactionMenu()
|
|
character = make_human(registry)
|
|
for ch in " crew ":
|
|
menu.type_char(ch)
|
|
menu.add_tag(character)
|
|
assert character.factions == ["crew"]
|
|
|
|
|
|
def test_add_tag_is_a_noop_for_blank_input(registry):
|
|
menu = DevFactionMenu()
|
|
character = make_human(registry)
|
|
for ch in " ":
|
|
menu.type_char(ch)
|
|
assert menu.add_tag(character) is False
|
|
assert character.factions == []
|
|
|
|
|
|
def test_add_tag_is_a_noop_for_a_duplicate(registry):
|
|
menu = DevFactionMenu()
|
|
character = make_human(registry, factions=["crew"])
|
|
for ch in "crew":
|
|
menu.type_char(ch)
|
|
assert menu.add_tag(character) is False
|
|
assert character.factions == ["crew"]
|
|
|
|
|
|
def test_cycle_selected_wraps_around(registry):
|
|
menu = DevFactionMenu()
|
|
character = make_human(registry, factions=["a", "b", "c"])
|
|
menu.cycle_selected(character, -1)
|
|
assert menu.selected_index == 2
|
|
|
|
|
|
def test_cycle_selected_is_a_noop_without_any_tags(registry):
|
|
menu = DevFactionMenu()
|
|
character = make_human(registry)
|
|
menu.cycle_selected(character, 1)
|
|
assert menu.selected_index == 0
|
|
|
|
|
|
def test_remove_selected_removes_the_highlighted_tag(registry):
|
|
menu = DevFactionMenu()
|
|
character = make_human(registry, factions=["a", "b", "c"])
|
|
menu.selected_index = 1
|
|
assert menu.remove_selected(character) is True
|
|
assert character.factions == ["a", "c"]
|
|
|
|
|
|
def test_remove_selected_clamps_the_index_after_removing_the_last_tag(registry):
|
|
menu = DevFactionMenu()
|
|
character = make_human(registry, factions=["a", "b"])
|
|
menu.selected_index = 1
|
|
menu.remove_selected(character)
|
|
assert character.factions == ["a"]
|
|
assert menu.remove_selected(character) is True
|
|
assert character.factions == []
|
|
assert menu.selected_index == 0
|
|
|
|
|
|
def test_remove_selected_is_a_noop_without_any_tags(registry):
|
|
menu = DevFactionMenu()
|
|
character = make_human(registry)
|
|
assert menu.remove_selected(character) is False
|
|
|
|
|
|
# --- DevConfig ------------------------------------------------------------------------------------
|
|
|
|
|
|
def test_dev_config_defaults_to_disabled_when_file_missing(tmp_path):
|
|
config = DevConfig.load(tmp_path / "does_not_exist.conf")
|
|
assert config.enabled is False
|
|
|
|
|
|
def test_dev_config_toggle_flips_the_flag():
|
|
config = DevConfig()
|
|
config.toggle()
|
|
assert config.enabled is True
|
|
config.toggle()
|
|
assert config.enabled is False
|
|
|
|
|
|
def test_dev_config_save_and_reload_round_trips(tmp_path):
|
|
path = tmp_path / "dev.conf"
|
|
config = DevConfig(enabled=True)
|
|
config.save(path)
|
|
reloaded = DevConfig.load(path)
|
|
assert reloaded.enabled is True
|