exorcist-game/tests/test_data.py
2026-05-09 11:55:14 -05:00

155 lines
5.4 KiB
Python

"""Tests for data module validation."""
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
from data import (
get_categories,
get_verse_by_id,
get_verses_by_category,
get_verses_by_max_difficulty,
load_verses,
normalize_text,
)
class TestLoadVerses:
"""Tests for verse data loading."""
def test_load_returns_list(self) -> None:
"""Verses load as a list."""
verses = load_verses()
assert isinstance(verses, list)
def test_minimum_verses(self) -> None:
"""At least 12 verses loaded."""
verses = load_verses()
assert len(verses) >= 12
def test_verse_structure(self) -> None:
"""Each verse has required fields: id, text, category, difficulty, reference."""
verses = load_verses()
required_fields = {"id", "text", "category", "difficulty", "reference"}
for verse in verses:
assert required_fields.issubset(verse.keys()), (
f"Missing fields in {verse.get('id', 'unknown')}"
)
def test_unique_ids(self) -> None:
"""All verse IDs are unique."""
verses = load_verses()
ids = [v["id"] for v in verses]
assert len(ids) == len(set(ids))
def test_categories_present(self) -> None:
"""All four categories represented: Binding, Healing, Exorcism, Protection, Judgment."""
verses = load_verses()
categories = get_categories(verses)
expected = {"Binding", "Healing", "Exorcism", "Protection", "Judgment"}
assert expected.issubset(set(categories))
def test_difficulty_range(self) -> None:
"""All difficulties are between 1 and 5."""
verses = load_verses()
for verse in verses:
assert 1 <= verse["difficulty"] <= 5
def test_easy_verses_count(self) -> None:
"""At least 4 easy (difficulty 1) verses for starting players."""
verses = load_verses()
easy = get_verses_by_max_difficulty(verses, 1)
assert len(easy) >= 4
class TestNormalizeText:
"""Tests for text normalization used in verse matching."""
def test_removes_punctuation(self) -> None:
"""Punctuation is stripped from text."""
result = normalize_text("Hello, world! How are you?")
assert result == "hello world how are you"
def test_lowercases(self) -> None:
"""Text is converted to lowercase."""
result = normalize_text("HELLO WORLD")
assert result == "hello world"
def test_collapses_whitespace(self) -> None:
"""Multiple spaces are collapsed to single space."""
result = normalize_text("Hello world")
assert result == "hello world"
def test_combined(self) -> None:
"""Combined punctuation, case, and whitespace normalization."""
result = normalize_text(" Hello, World! ")
assert result == "hello world"
def test_empty_string(self) -> None:
"""Empty string returns empty string."""
assert normalize_text("") == ""
def test_identical_verses_match(self) -> None:
"""Same verse text normalizes to identical strings."""
verse = "I have given you authority to trample on snakes and scorpions."
typed = "I have given you authority to trample on snakes and scorpions."
assert normalize_text(verse) == normalize_text(typed)
def test_punctuation_difference_ignored(self) -> None:
"""Punctuation differences are ignored in normalization."""
verse = "He heals the brokenhearted and binds up their wounds."
typed = "He heals the brokenhearted, and binds up their wounds!"
assert normalize_text(verse) == normalize_text(typed)
class TestGetVerseById:
"""Tests for verse lookup by ID."""
def test_finds_existing_verse(self) -> None:
"""Existing verse ID returns the verse."""
verses = load_verses()
verse = get_verse_by_id(verses, "binding_001")
assert verse is not None
assert verse["id"] == "binding_001"
def test_returns_none_for_missing(self) -> None:
"""Non-existent ID returns None."""
verses = load_verses()
assert get_verse_by_id(verses, "nonexistent_999") is None
class TestGetVersesByCategory:
"""Tests for filtering verses by category."""
def test_filter_by_category(self) -> None:
"""Returns only verses matching the category."""
verses = load_verses()
binding = get_verses_by_category(verses, "Binding")
assert all(v["category"] == "Binding" for v in binding)
assert len(binding) >= 3
def test_case_insensitive(self) -> None:
"""Category filtering is case-insensitive."""
verses = load_verses()
result1 = get_verses_by_category(verses, "Binding")
result2 = get_verses_by_category(verses, "binding")
assert result1 == result2
class TestGetVersesByMaxDifficulty:
"""Tests for filtering verses by maximum difficulty."""
def test_filters_correctly(self) -> None:
"""Returns only verses at or below max difficulty."""
verses = load_verses()
easy = get_verses_by_max_difficulty(verses, 1)
assert all(v["difficulty"] <= 1 for v in easy)
def test_includes_all_at_level(self) -> None:
"""All verses up to max difficulty are included."""
verses = load_verses()
all_verses = load_verses()
result = get_verses_by_max_difficulty(verses, 5)
assert len(result) == len(all_verses)