first commit

This commit is contained in:
2025-11-24 23:10:55 -06:00
commit 8315fa51c9
279 changed files with 74600 additions and 0 deletions

View File

@@ -0,0 +1,256 @@
"""
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"])