Files
Code_of_Conquest/api/tests/test_stats.py
Phillip Tarrant 03ab783eeb Combat Backend & Data Models
- Implement Combat Service
- Implement Damage Calculator
- Implement Effect Processor
- Implement Combat Actions
- Created Combat API Endpoints
2025-11-26 15:43:20 -06:00

251 lines
6.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Unit tests for Stats dataclass.
Tests computed properties, serialization, and basic operations.
"""
import pytest
from app.models.stats import Stats
def test_stats_default_values():
"""Test that Stats initializes with default values."""
stats = Stats()
assert stats.strength == 10
assert stats.dexterity == 10
assert stats.constitution == 10
assert stats.intelligence == 10
assert stats.wisdom == 10
assert stats.charisma == 10
def test_stats_custom_values():
"""Test creating Stats with custom values."""
stats = Stats(
strength=15,
dexterity=12,
constitution=14,
intelligence=8,
wisdom=10,
charisma=11,
)
assert stats.strength == 15
assert stats.dexterity == 12
assert stats.constitution == 14
assert stats.intelligence == 8
assert stats.wisdom == 10
assert stats.charisma == 11
def test_hit_points_calculation():
"""Test HP calculation: 10 + (constitution × 2)."""
stats = Stats(constitution=10)
assert stats.hit_points == 30 # 10 + (10 × 2)
stats = Stats(constitution=15)
assert stats.hit_points == 40 # 10 + (15 × 2)
stats = Stats(constitution=20)
assert stats.hit_points == 50 # 10 + (20 × 2)
def test_mana_points_calculation():
"""Test MP calculation: 10 + (intelligence × 2)."""
stats = Stats(intelligence=10)
assert stats.mana_points == 30 # 10 + (10 × 2)
stats = Stats(intelligence=15)
assert stats.mana_points == 40 # 10 + (15 × 2)
stats = Stats(intelligence=8)
assert stats.mana_points == 26 # 10 + (8 × 2)
def test_defense_calculation():
"""Test defense calculation: constitution // 2."""
stats = Stats(constitution=10)
assert stats.defense == 5 # 10 // 2
stats = Stats(constitution=15)
assert stats.defense == 7 # 15 // 2
stats = Stats(constitution=21)
assert stats.defense == 10 # 21 // 2
def test_resistance_calculation():
"""Test resistance calculation: wisdom // 2."""
stats = Stats(wisdom=10)
assert stats.resistance == 5 # 10 // 2
stats = Stats(wisdom=14)
assert stats.resistance == 7 # 14 // 2
stats = Stats(wisdom=9)
assert stats.resistance == 4 # 9 // 2
def test_stats_serialization():
"""Test to_dict() serialization."""
stats = Stats(
strength=15,
dexterity=12,
constitution=14,
intelligence=10,
wisdom=11,
charisma=8,
)
data = stats.to_dict()
assert data["strength"] == 15
assert data["dexterity"] == 12
assert data["constitution"] == 14
assert data["intelligence"] == 10
assert data["wisdom"] == 11
assert data["charisma"] == 8
def test_stats_deserialization():
"""Test from_dict() deserialization."""
data = {
"strength": 18,
"dexterity": 14,
"constitution": 16,
"intelligence": 12,
"wisdom": 10,
"charisma": 9,
}
stats = Stats.from_dict(data)
assert stats.strength == 18
assert stats.dexterity == 14
assert stats.constitution == 16
assert stats.intelligence == 12
assert stats.wisdom == 10
assert stats.charisma == 9
def test_stats_deserialization_with_missing_values():
"""Test from_dict() with missing values (should use defaults)."""
data = {
"strength": 15,
# Missing other stats
}
stats = Stats.from_dict(data)
assert stats.strength == 15
assert stats.dexterity == 10 # Default
assert stats.constitution == 10 # Default
assert stats.intelligence == 10 # Default
assert stats.wisdom == 10 # Default
assert stats.charisma == 10 # Default
def test_stats_round_trip_serialization():
"""Test that serialization and deserialization preserve data."""
original = Stats(
strength=20,
dexterity=15,
constitution=18,
intelligence=10,
wisdom=12,
charisma=14,
)
# Serialize then deserialize
data = original.to_dict()
restored = Stats.from_dict(data)
assert restored.strength == original.strength
assert restored.dexterity == original.dexterity
assert restored.constitution == original.constitution
assert restored.intelligence == original.intelligence
assert restored.wisdom == original.wisdom
assert restored.charisma == original.charisma
def test_stats_copy():
"""Test that copy() creates an independent copy."""
original = Stats(strength=15, dexterity=12, constitution=14)
copy = original.copy()
assert copy.strength == original.strength
assert copy.dexterity == original.dexterity
assert copy.constitution == original.constitution
# Modify copy
copy.strength = 20
# Original should be unchanged
assert original.strength == 15
assert copy.strength == 20
def test_stats_repr():
"""Test string representation."""
stats = Stats(strength=15, constitution=12, intelligence=10)
repr_str = repr(stats)
assert "STR=15" in repr_str
assert "CON=12" in repr_str
assert "INT=10" in repr_str
assert "HP=" in repr_str
assert "MP=" in repr_str
# =============================================================================
# LUK Computed Properties (Combat System Integration)
# =============================================================================
def test_crit_bonus_calculation():
"""Test crit bonus calculation: luck * 0.5%."""
stats = Stats(luck=8)
assert stats.crit_bonus == pytest.approx(0.04, abs=0.001) # 4%
stats = Stats(luck=12)
assert stats.crit_bonus == pytest.approx(0.06, abs=0.001) # 6%
stats = Stats(luck=0)
assert stats.crit_bonus == pytest.approx(0.0, abs=0.001) # 0%
def test_hit_bonus_calculation():
"""Test hit bonus (miss reduction): luck * 0.5%."""
stats = Stats(luck=8)
assert stats.hit_bonus == pytest.approx(0.04, abs=0.001) # 4%
stats = Stats(luck=12)
assert stats.hit_bonus == pytest.approx(0.06, abs=0.001) # 6%
stats = Stats(luck=20)
assert stats.hit_bonus == pytest.approx(0.10, abs=0.001) # 10%
def test_lucky_roll_chance_calculation():
"""Test lucky roll chance: 5% + (luck * 0.25%)."""
stats = Stats(luck=8)
# 5% + (8 * 0.25%) = 5% + 2% = 7%
assert stats.lucky_roll_chance == pytest.approx(0.07, abs=0.001)
stats = Stats(luck=12)
# 5% + (12 * 0.25%) = 5% + 3% = 8%
assert stats.lucky_roll_chance == pytest.approx(0.08, abs=0.001)
stats = Stats(luck=0)
# 5% + (0 * 0.25%) = 5%
assert stats.lucky_roll_chance == pytest.approx(0.05, abs=0.001)
def test_repr_includes_combat_bonuses():
"""Test that repr includes LUK-based combat bonuses."""
stats = Stats(luck=10)
repr_str = repr(stats)
assert "CRIT_BONUS=" in repr_str
assert "HIT_BONUS=" in repr_str