mud/tests/test_prompt.py

381 lines
9.4 KiB
Python

"""Tests for prompt rendering system."""
from mudlib.caps import ClientCaps
from mudlib.combat.encounter import CombatEncounter
from mudlib.combat.engine import active_encounters
from mudlib.entity import Entity
from mudlib.player import Player
from mudlib.prompt import render_prompt
def setup_function():
"""Clear global state before each test."""
active_encounters.clear()
def teardown_function():
"""Clear global state after each test."""
active_encounters.clear()
def test_normal_mode_prompt():
"""Normal mode shows stamina gauge and power level."""
player = Player(
name="Test",
stamina=50.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
)
result = render_prompt(player)
# 50% is in 30-59% range, should be yellow
assert result == "\033[33m<50%>\033[0m 200 > "
def test_combat_mode_with_opponent():
"""Combat mode includes opponent name."""
player = Player(
name="Goku",
stamina=50.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal", "combat"],
)
opponent = Entity(name="Vegeta", pl=150.0)
encounter = CombatEncounter(attacker=player, defender=opponent)
active_encounters.append(encounter)
result = render_prompt(player)
# 50% is in 30-59% range, should be yellow
assert result == "\033[33m<50%>\033[0m 200 vs Vegeta > "
def test_combat_mode_as_defender():
"""Combat mode works when player is the defender."""
player = Player(
name="Goku",
stamina=50.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal", "combat"],
)
opponent = Entity(name="Vegeta", pl=150.0)
encounter = CombatEncounter(attacker=opponent, defender=player)
active_encounters.append(encounter)
result = render_prompt(player)
# 50% is in 30-59% range, should be yellow
assert result == "\033[33m<50%>\033[0m 200 vs Vegeta > "
def test_editor_mode_static_prompt():
"""Editor mode returns static prompt."""
player = Player(
name="Test",
stamina=50.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal", "editor"],
)
result = render_prompt(player)
assert result == "editor> "
def test_if_mode_static_prompt():
"""IF mode returns minimal static prompt."""
player = Player(
name="Test",
stamina=50.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal", "if"],
)
result = render_prompt(player)
assert result == "> "
def test_zero_stamina():
"""Zero stamina renders as 0% in red."""
player = Player(
name="Test",
stamina=0.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
)
result = render_prompt(player)
# 0% is < 30%, should be red
assert result == "\033[31m<0%>\033[0m 200 > "
def test_max_stamina():
"""Full stamina renders as 100% in green."""
player = Player(
name="Test",
stamina=100.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
)
result = render_prompt(player)
# 100% is >= 60%, should be green
assert result == "\033[32m<100%>\033[0m 200 > "
def test_fractional_percentage():
"""Stamina percentage rounds to integer."""
player = Player(
name="Test",
stamina=33.3,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
)
result = render_prompt(player)
# 33% is in 30-59% range, should be yellow
assert result == "\033[33m<33%>\033[0m 200 > "
def test_fractional_pl():
"""Power level rounds to integer."""
player = Player(
name="Test",
stamina=50.0,
max_stamina=100.0,
pl=199.7,
mode_stack=["normal"],
)
result = render_prompt(player)
# 50% is in 30-59% range, should be yellow
assert result == "\033[33m<50%>\033[0m 200 > "
def test_custom_template_overrides_default():
"""Player can set custom prompt template."""
player = Player(
name="Test",
stamina=50.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
prompt_template="[{pl}] > ",
)
result = render_prompt(player)
assert result == "[200] > "
def test_custom_template_all_variables():
"""Custom template can use all supported variables."""
player = Player(
name="Test",
stamina=50.0,
max_stamina=100.0,
pl=200.0,
max_pl=250.0,
mode_stack=["normal"],
prompt_template="{stamina}/{stamina_pct}% {pl}/{max_pl} > ",
)
result = render_prompt(player)
# No color tags in this custom template, so no ANSI codes
assert result == "50/50% 200/250 > "
def test_unknown_variable_left_as_is():
"""Unknown variables in template are not substituted."""
player = Player(
name="Test",
stamina=50.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
prompt_template="{pl} {unknown} > ",
)
result = render_prompt(player)
assert result == "200 {unknown} > "
def test_opponent_var_in_normal_mode_empty():
"""Opponent variable is empty string when not in combat."""
player = Player(
name="Test",
stamina=50.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
prompt_template="{pl} vs {opponent} > ",
)
result = render_prompt(player)
assert result == "200 vs > "
def test_no_color_support():
"""Players with no ANSI support get tags stripped."""
player = Player(
name="Test",
stamina=50.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
caps=ClientCaps(ansi=False),
)
result = render_prompt(player)
# Should have no ANSI codes, just text
assert result == "<50%> 200 > "
assert "\033[" not in result
def test_stamina_gauge_green():
"""Stamina >= 60% renders green gauge."""
player = Player(
name="Test",
stamina=80.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
)
result = render_prompt(player)
# Should have green color code
assert "\033[32m<80%>\033[0m" in result
def test_stamina_gauge_yellow():
"""Stamina 30-59% renders yellow gauge."""
player = Player(
name="Test",
stamina=45.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
)
result = render_prompt(player)
# Should have yellow color code
assert "\033[33m<45%>\033[0m" in result
def test_stamina_gauge_red():
"""Stamina < 30% renders red gauge."""
player = Player(
name="Test",
stamina=20.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
)
result = render_prompt(player)
# Should have red color code
assert "\033[31m<20%>\033[0m" in result
def test_stamina_gauge_boundary_60():
"""Stamina exactly 60% renders green."""
player = Player(
name="Test",
stamina=60.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
)
result = render_prompt(player)
# Should have green color code
assert "\033[32m<60%>\033[0m" in result
def test_stamina_gauge_boundary_30():
"""Stamina exactly 30% renders yellow."""
player = Player(
name="Test",
stamina=30.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
)
result = render_prompt(player)
# Should have yellow color code
assert "\033[33m<30%>\033[0m" in result
def test_stamina_gauge_boundary_29():
"""Stamina at 29% renders red."""
player = Player(
name="Test",
stamina=29.5,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
)
result = render_prompt(player)
# Should have red color code
assert "\033[31m<29%>\033[0m" in result
def test_zero_max_stamina():
"""Zero max_stamina doesn't crash."""
player = Player(
name="Test",
stamina=0.0,
max_stamina=0.0,
pl=200.0,
mode_stack=["normal"],
)
result = render_prompt(player)
assert "0%" in result
def test_name_variable():
"""Name variable substitutes player name."""
player = Player(
name="Goku",
stamina=50.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
prompt_template="{name} > ",
)
result = render_prompt(player)
assert result == "Goku > "
def test_mode_variable():
"""Mode variable substitutes current mode."""
player = Player(
name="Test",
stamina=50.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal", "combat"],
prompt_template="[{mode}] > ",
)
result = render_prompt(player)
assert result == "[combat] > "
def test_coordinates_variables():
"""X and Y variables substitute coordinates."""
player = Player(
name="Test",
stamina=50.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
x=42,
y=13,
prompt_template="({x},{y}) > ",
)
result = render_prompt(player)
assert result == "(42,13) > "
def test_combat_state_idle():
"""Combat state is 'idle' when not in combat."""
player = Player(
name="Test",
stamina=50.0,
max_stamina=100.0,
pl=200.0,
mode_stack=["normal"],
prompt_template="[{combat_state}] > ",
)
result = render_prompt(player)
assert result == "[idle] > "