Files
FFCardGame/tests/test_ability_processor_modal.py
2026-02-02 16:28:53 -05:00

219 lines
8.2 KiB
Python

#!/usr/bin/env python3
"""
Tests for the modal ability parsing in ability_processor.py
Run with: python -m pytest tests/test_ability_processor_modal.py -v
Or directly: python tests/test_ability_processor_modal.py
"""
import sys
import os
import unittest
# Add tools directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'tools'))
from ability_processor import (
extract_modal_actions,
parse_modal_ability,
parse_effects,
parse_field_ability,
)
class TestExtractModalActions(unittest.TestCase):
"""Tests for extract_modal_actions function"""
def test_extracts_quoted_actions(self):
"""Should extract all quoted action strings"""
text = '''Select 1 of the 3 following actions.
"Choose 1 Forward. Deal it 7000 damage."
"Choose 1 Monster of cost 3 or less. Break it."
"Deal 3000 damage to all the Forwards opponent controls."'''
actions = extract_modal_actions(text)
self.assertEqual(len(actions), 3)
self.assertEqual(actions[0]["index"], 0)
self.assertEqual(actions[1]["index"], 1)
self.assertEqual(actions[2]["index"], 2)
def test_preserves_action_descriptions(self):
"""Should preserve the full description text"""
text = '"Choose 1 Forward. Deal it 7000 damage." "Draw 2 cards."'
actions = extract_modal_actions(text)
self.assertEqual(actions[0]["description"], "Choose 1 Forward. Deal it 7000 damage.")
self.assertEqual(actions[1]["description"], "Draw 2 cards.")
def test_parses_effects_for_each_action(self):
"""Should parse effects for each action"""
text = '"Draw 2 cards." "Deal 5000 damage to all Forwards."'
actions = extract_modal_actions(text)
# First action should have DRAW effect
self.assertTrue(len(actions[0]["effects"]) > 0)
self.assertEqual(actions[0]["effects"][0]["type"], "DRAW")
def test_handles_empty_text(self):
"""Should return empty array for text without quotes"""
actions = extract_modal_actions("No quoted text here")
self.assertEqual(len(actions), 0)
class TestParseModalAbility(unittest.TestCase):
"""Tests for parse_modal_ability function"""
def test_parses_select_1_of_3(self):
"""Should parse 'select 1 of the 3' format"""
text = '''Select 1 of the 3 following actions.
"Option A" "Option B" "Option C"'''
result = parse_modal_ability(text)
self.assertIsNotNone(result)
self.assertEqual(result["type"], "CHOOSE_MODE")
self.assertEqual(result["select_count"], 1)
self.assertEqual(result["mode_count"], 3)
self.assertFalse(result["select_up_to"])
def test_parses_select_up_to(self):
"""Should parse 'select up to X' format"""
text = '''Select up to 2 of the 4 following actions.
"A" "B" "C" "D"'''
result = parse_modal_ability(text)
self.assertIsNotNone(result)
self.assertEqual(result["select_count"], 2)
self.assertEqual(result["mode_count"], 4)
self.assertTrue(result["select_up_to"])
def test_parses_enhanced_condition(self):
"""Should parse enhanced/conditional upgrade clause"""
text = '''Select 1 of the 3 following actions. If you have 5 or more Ifrit in your Break Zone, select up to 3 of the 3 following actions instead.
"A" "B" "C"'''
result = parse_modal_ability(text)
self.assertIsNotNone(result)
self.assertTrue("enhanced_condition" in result)
self.assertEqual(result["enhanced_condition"]["select_count"], 3)
self.assertTrue(result["enhanced_condition"]["select_up_to"])
def test_returns_none_for_non_modal(self):
"""Should return None for non-modal text"""
text = "Choose 1 Forward. Deal it 5000 damage."
result = parse_modal_ability(text)
self.assertIsNone(result)
def test_extracts_modes_with_effects(self):
"""Should extract modes with parsed effects"""
text = '''Select 1 of the 2 following actions.
"Choose 1 Forward. Deal it 7000 damage."
"Draw 2 cards."'''
result = parse_modal_ability(text)
self.assertEqual(len(result["modes"]), 2)
# First mode should have damage effect
self.assertTrue(len(result["modes"][0]["effects"]) > 0)
class TestParseEffectsModal(unittest.TestCase):
"""Tests for parse_effects handling of modal abilities"""
def test_returns_choose_mode_for_modal_text(self):
"""parse_effects should return CHOOSE_MODE for modal text"""
text = '''Select 1 of the 2 following actions.
"Draw 1 card." "Dull 1 Forward."'''
effects = parse_effects(text)
self.assertEqual(len(effects), 1)
self.assertEqual(effects[0]["type"], "CHOOSE_MODE")
def test_non_modal_returns_normal_effect(self):
"""parse_effects should return normal effects for non-modal text"""
text = "Draw 2 cards."
effects = parse_effects(text)
self.assertEqual(len(effects), 1)
self.assertEqual(effects[0]["type"], "DRAW")
class TestParseFieldAbilityModal(unittest.TestCase):
"""Tests for parse_field_ability handling of modal abilities"""
def test_returns_choose_mode_for_modal_field(self):
"""parse_field_ability should return CHOOSE_MODE for modal field ability"""
text = '''Select 1 of the 3 following actions.
"Deal 7000 damage." "Break a Monster." "Deal 3000 to all."'''
result = parse_field_ability(text, "Test Card")
self.assertIsNotNone(result)
self.assertEqual(result["type"], "CHOOSE_MODE")
class TestRealCardExamples(unittest.TestCase):
"""Tests using real card text examples"""
def test_ifrita_15_001r(self):
"""Test Ifrita card modal ability"""
text = '''Select 1 of the 3 following actions. If you have a total of 5 or more Card Name Ifrita and/or Card Name Ifrit in your Break Zone (before paying the cost for Ifrita), select up to 3 of the 3 following actions instead.
"Choose 1 Forward. Deal it 7000 damage."
"Choose 1 Monster of cost 3 or less. Break it."
"Deal 3000 damage to all the Forwards opponent controls."'''
result = parse_modal_ability(text)
self.assertIsNotNone(result)
self.assertEqual(result["type"], "CHOOSE_MODE")
self.assertEqual(result["select_count"], 1)
self.assertEqual(result["mode_count"], 3)
self.assertEqual(len(result["modes"]), 3)
# Check enhanced condition
self.assertTrue("enhanced_condition" in result)
self.assertEqual(result["enhanced_condition"]["select_count"], 3)
# Check mode descriptions
self.assertIn("7000 damage", result["modes"][0]["description"])
self.assertIn("Monster", result["modes"][1]["description"])
self.assertIn("3000 damage", result["modes"][2]["description"])
def test_warrior_10_075c(self):
"""Test Warrior card modal ability"""
text = '''Select 1 of the 2 following actions.
"Choose 1 Forward. Until the end of the turn, it gains Brave and it gains +1000 power for each point of damage you have received."
"Choose 1 Forward. Deal it 1000 damage for each point of damage you have received."'''
result = parse_modal_ability(text)
self.assertIsNotNone(result)
self.assertEqual(result["select_count"], 1)
self.assertEqual(result["mode_count"], 2)
self.assertEqual(len(result["modes"]), 2)
def test_action_ability_modal(self):
"""Test action ability with select up to"""
text = '''Select up to 2 of the 4 following actions. "Choose 1 Forward you control. It gains +1000 power until the end of the turn." "All the Forwards you control gain Brave until the end of the turn." "All the Forwards you control gain 'This Forward cannot become dull by your opponent's Summons or abilities' until the end of the turn." "Draw 1 card."'''
result = parse_modal_ability(text)
self.assertIsNotNone(result)
self.assertEqual(result["select_count"], 2)
self.assertTrue(result["select_up_to"])
self.assertEqual(result["mode_count"], 4)
self.assertEqual(len(result["modes"]), 4)
if __name__ == "__main__":
unittest.main(verbosity=2)