Files
Code_of_Conquest/api/tests/test_class_loader.py
2025-11-24 23:10:55 -06:00

257 lines
9.2 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 ClassLoader service.
Tests loading player class definitions from YAML files.
"""
import pytest
from pathlib import Path
from app.services.class_loader import ClassLoader
from app.models.skills import PlayerClass, SkillTree, SkillNode
from app.models.stats import Stats
class TestClassLoader:
"""Test ClassLoader functionality."""
@pytest.fixture
def loader(self):
"""Create a ClassLoader instance for testing."""
return ClassLoader()
def test_load_vanguard_class(self, loader):
"""Test loading the Vanguard class."""
vanguard = loader.load_class("vanguard")
# Verify class loaded successfully
assert vanguard is not None
assert isinstance(vanguard, PlayerClass)
# Check basic properties
assert vanguard.class_id == "vanguard"
assert vanguard.name == "Vanguard"
assert "melee combat" in vanguard.description.lower()
def test_vanguard_base_stats(self, loader):
"""Test Vanguard base stats are correct."""
vanguard = loader.load_class("vanguard")
assert isinstance(vanguard.base_stats, Stats)
assert vanguard.base_stats.strength == 14
assert vanguard.base_stats.dexterity == 10
assert vanguard.base_stats.constitution == 14
assert vanguard.base_stats.intelligence == 8
assert vanguard.base_stats.wisdom == 10
assert vanguard.base_stats.charisma == 9
def test_vanguard_skill_trees(self, loader):
"""Test Vanguard has 2 skill trees."""
vanguard = loader.load_class("vanguard")
# Should have exactly 2 skill trees
assert len(vanguard.skill_trees) == 2
# Get trees by ID
shield_bearer = vanguard.get_skill_tree("shield_bearer")
weapon_master = vanguard.get_skill_tree("weapon_master")
assert shield_bearer is not None
assert weapon_master is not None
# Check tree names
assert shield_bearer.name == "Shield Bearer"
assert weapon_master.name == "Weapon Master"
def test_shield_bearer_tree_structure(self, loader):
"""Test Shield Bearer tree has correct structure."""
vanguard = loader.load_class("vanguard")
shield_bearer = vanguard.get_skill_tree("shield_bearer")
# Should have 10 nodes (5 tiers × 2 nodes)
assert len(shield_bearer.nodes) == 10
# Check tier distribution
tier_counts = {}
for node in shield_bearer.nodes:
tier_counts[node.tier] = tier_counts.get(node.tier, 0) + 1
# Should have 2 nodes per tier for tiers 1-5
assert tier_counts == {1: 2, 2: 2, 3: 2, 4: 2, 5: 2}
def test_weapon_master_tree_structure(self, loader):
"""Test Weapon Master tree has correct structure."""
vanguard = loader.load_class("vanguard")
weapon_master = vanguard.get_skill_tree("weapon_master")
# Should have 10 nodes (5 tiers × 2 nodes)
assert len(weapon_master.nodes) == 10
# Check tier distribution
tier_counts = {}
for node in weapon_master.nodes:
tier_counts[node.tier] = tier_counts.get(node.tier, 0) + 1
# Should have 2 nodes per tier for tiers 1-5
assert tier_counts == {1: 2, 2: 2, 3: 2, 4: 2, 5: 2}
def test_skill_node_prerequisites(self, loader):
"""Test skill nodes have correct prerequisites."""
vanguard = loader.load_class("vanguard")
shield_bearer = vanguard.get_skill_tree("shield_bearer")
# Find tier 1 and tier 2 nodes
tier1_nodes = [n for n in shield_bearer.nodes if n.tier == 1]
tier2_nodes = [n for n in shield_bearer.nodes if n.tier == 2]
# Tier 1 nodes should have no prerequisites
for node in tier1_nodes:
assert len(node.prerequisites) == 0
# Tier 2 nodes should have prerequisites
for node in tier2_nodes:
assert len(node.prerequisites) > 0
# Prerequisites should reference tier 1 skills
for prereq_id in node.prerequisites:
prereq_found = any(n.skill_id == prereq_id for n in tier1_nodes)
assert prereq_found, f"Prerequisite {prereq_id} not found in tier 1"
def test_skill_node_effects(self, loader):
"""Test skill nodes have proper effects defined."""
vanguard = loader.load_class("vanguard")
shield_bearer = vanguard.get_skill_tree("shield_bearer")
# Find the "fortify" skill (passive defense bonus)
fortify = next((n for n in shield_bearer.nodes if n.skill_id == "fortify"), None)
assert fortify is not None
# Should have stat bonuses in effects
assert "stat_bonuses" in fortify.effects
assert "defense" in fortify.effects["stat_bonuses"]
assert fortify.effects["stat_bonuses"]["defense"] == 5
def test_skill_node_abilities(self, loader):
"""Test skill nodes with ability unlocks."""
vanguard = loader.load_class("vanguard")
shield_bearer = vanguard.get_skill_tree("shield_bearer")
# Find the "shield_bash" skill (active ability)
shield_bash = next((n for n in shield_bearer.nodes if n.skill_id == "shield_bash"), None)
assert shield_bash is not None
# Should have abilities in effects
assert "abilities" in shield_bash.effects
assert "shield_bash" in shield_bash.effects["abilities"]
def test_starting_equipment(self, loader):
"""Test Vanguard starting equipment."""
vanguard = loader.load_class("vanguard")
# Should have starting equipment
assert len(vanguard.starting_equipment) > 0
assert "rusty_sword" in vanguard.starting_equipment
assert "cloth_armor" in vanguard.starting_equipment
assert "rusty_knife" in vanguard.starting_equipment
def test_starting_abilities(self, loader):
"""Test Vanguard starting abilities."""
vanguard = loader.load_class("vanguard")
# Should have basic_attack
assert len(vanguard.starting_abilities) > 0
assert "basic_attack" in vanguard.starting_abilities
def test_cache_functionality(self, loader):
"""Test that classes are cached after first load."""
# Load class twice
vanguard1 = loader.load_class("vanguard")
vanguard2 = loader.load_class("vanguard")
# Should be the same object (cached)
assert vanguard1 is vanguard2
def test_reload_class(self, loader):
"""Test reload_class forces a fresh load."""
# Load class
vanguard1 = loader.load_class("vanguard")
# Reload class
vanguard2 = loader.reload_class("vanguard")
# Should still be equal but different objects
assert vanguard1.class_id == vanguard2.class_id
# Note: May or may not be same object depending on implementation
def test_load_nonexistent_class(self, loader):
"""Test loading a class that doesn't exist."""
result = loader.load_class("nonexistent_class")
assert result is None
def test_get_all_class_ids(self, loader):
"""Test getting list of all class IDs."""
class_ids = loader.get_all_class_ids()
# Should include vanguard
assert "vanguard" in class_ids
# Should be a list of strings
assert all(isinstance(cid, str) for cid in class_ids)
def test_load_all_classes(self, loader):
"""Test loading all classes at once."""
classes = loader.load_all_classes()
# Should have at least 1 class (vanguard)
assert len(classes) >= 1
# All should be PlayerClass instances
assert all(isinstance(c, PlayerClass) for c in classes)
# Vanguard should be in the list
vanguard_found = any(c.class_id == "vanguard" for c in classes)
assert vanguard_found
def test_get_all_skills_method(self, loader):
"""Test PlayerClass.get_all_skills() method."""
vanguard = loader.load_class("vanguard")
all_skills = vanguard.get_all_skills()
# Should have 20 skills (2 trees × 10 nodes)
assert len(all_skills) == 20
# All should be SkillNode instances
assert all(isinstance(skill, SkillNode) for skill in all_skills)
# Should include skills from both trees
skill_ids = [s.skill_id for s in all_skills]
assert "shield_bash" in skill_ids # Shield Bearer tree
assert "power_strike" in skill_ids # Weapon Master tree
def test_tier_5_ultimate_skills(self, loader):
"""Test that tier 5 skills exist and have powerful effects."""
vanguard = loader.load_class("vanguard")
all_skills = vanguard.get_all_skills()
# Get tier 5 skills
tier5_skills = [s for s in all_skills if s.tier == 5]
# Should have 4 tier 5 skills (2 per tree)
assert len(tier5_skills) == 4
# Each tier 5 skill should have prerequisites
for skill in tier5_skills:
assert len(skill.prerequisites) > 0
# At least one tier 5 skill should have significant stat bonuses
has_major_bonuses = any(
"stat_bonuses" in s.effects and
any(v >= 10 for v in s.effects.get("stat_bonuses", {}).values())
for s in tier5_skills
)
assert has_major_bonuses
if __name__ == "__main__":
pytest.main([__file__, "-v"])