#!/usr/bin/env python3 """Tests for the Magic: The Gathering Rules Engine""" import sys import os # Add parent directory to path for importing mtg_rules_engine sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from mtg_rules_engine import ( ABILITY_WORDS, KEYWORD_ACTIONS, KEYWORD_ABILITIES, get_all_keywords, get_keyword_info, is_valid_keyword, get_keyword_type, KeywordValidator, RulesEngine, ) def test_keyword_database(): """Test the keyword database is properly populated.""" print("=" * 60) print("TEST: Keyword Database") print("=" * 60) # Test ability words assert len(ABILITY_WORDS) > 0, "Ability words should not be empty" assert "adamant" in ABILITY_WORDS, "adamant should be in ability words" print(f" ✓ {len(ABILITY_WORDS)} ability words loaded") # Test keyword actions assert len(KEYWORD_ACTIONS) > 0, "Keyword actions should not be empty" assert "fly" not in KEYWORD_ACTIONS and "flying" in KEYWORD_ABILITIES, "flying should be a keyword ability" assert "cast" in KEYWORD_ACTIONS, "cast should be a keyword action" assert "destroy" in KEYWORD_ACTIONS, "destroy should be a keyword action" print(f" ✓ {len(KEYWORD_ACTIONS)} keyword actions loaded") # Test keyword abilities assert len(KEYWORD_ABILITIES) > 0, "Keyword abilities should not be empty" assert "flying" in KEYWORD_ABILITIES, "flying should be a keyword ability" assert "haste" in KEYWORD_ABILITIES, "haste should be a keyword ability" assert "deathtouch" in KEYWORD_ABILITIES, "deathtouch should be a keyword ability" assert "trample" in KEYWORD_ABILITIES, "trample should be a keyword ability" assert "hexproof" in KEYWORD_ABILITIES, "hexproof should be a keyword ability" assert "flying" in KEYWORD_ABILITIES, "flying should be a keyword ability" print(f" ✓ {len(KEYWORD_ABILITIES)} keyword abilities loaded") # Test get_all_keywords all_keywords = get_all_keywords() assert len(all_keywords) > 0, "get_all_keywords should return keywords" print(f" ✓ {len(all_keywords)} total keywords loaded") # Test get_keyword_info info = get_keyword_info("flying") assert info is not None, "get_keyword_info should return info" assert "rule" in info, "Keyword info should have 'rule'" assert "definition" in info, "Keyword info should have 'definition'" print(f" ✓ Keyword info for 'flying': rule={info['rule'][:40]}...") # Test get_keyword_type type_flying = get_keyword_type("flying") assert type_flying == "keyword_ability", f"Expected keyword_ability, got {type_flying}" type_cast = get_keyword_type("cast") assert type_cast == "keyword_action", f"Expected keyword_action, got {type_cast}" print(f" ✓ Keyword type for 'flying': {type_flying}") print(f" ✓ Keyword type for 'cast': {type_cast}") print(" ✓ All keyword database tests passed!\n") def test_keyword_validator(): """Test the keyword validator.""" print("=" * 60) print("TEST: Keyword Validator") print("=" * 60) validator = KeywordValidator() # Test is_valid_keyword assert validator.is_valid_keyword("flying"), "flying should be valid" assert validator.is_valid_keyword("haste"), "haste should be valid" assert not validator.is_valid_keyword("notarealkeyword"), "notarealkeyword should be invalid" print(" ✓ is_valid_keyword works correctly") # Test find_keywords_in_text text = "Flying creatures can't be blocked except by flying creatures with flying abilities." found = validator.find_keywords_in_text(text) assert "flying" in found, "flying should be found" assert found["flying"] == 3, f"Expected 3 'flying', got {found['flying']}" print(f" ✓ find_keywords_in_text found {found}") # Test validate_card_text card_text = "Flying, trample. Haste. When this creature attacks, it deals extra damage." errors = validator.validate_card_text(card_text) # No errors expected for valid keywords print(f" ✓ validate_card_text: {len(errors)} errors (expected 0)") # Test check_for_misspelled_keywords misspelled = validator.check_for_misspelled_keywords("I want to fly with this haste creature.") # "fly" should suggest "flying" print(f" ✓ check_for_misspelled_keywords found {len(misspelled)} potential misspellings") # Test export_keywords exported = validator.export_keywords() assert "total_keywords" in exported, "export_keywords should have total_keywords" assert "ability_words" in exported, "export_keywords should have ability_words" assert "keyword_actions" in exported, "export_keywords should have keyword_actions" assert "keyword_abilities" in exported, "export_keywords should have keyword_abilities" print(f" ✓ export_keywords has all expected fields") print(" ✓ All keyword validator tests passed!\n") def test_rules_engine(): """Test the rules engine.""" print("=" * 60) print("TEST: Rules Engine") print("=" * 60) engine = RulesEngine() # Test validate_card with a valid creature valid_card = { "name": "Garruk the Wreathshaper", "text": "Flying, trample. When Garruk enters, create a 1/1 green Elf creature token.", "type": "CREATURE", "power_toughness": (6, 6), "color": ["GREEN"], "abilities": ["flying", "trample"], } errors = engine.validate_card(valid_card) # Some errors expected (text analysis, etc.) print(f" ✓ validate_card returned {len(errors)} errors") # Test validate_action with a valid attack valid_attack = { "type": "attack", "attacker": { "name": "Garruk the Wreathshaper", "type": "CREATURE", "power": 6, "toughness": 6, "abilities": ["flying", "trample"], }, "blocking_creatures": [ { "name": "Garruk the Wreathshaper", "type": "CREATURE", "power": 6, "toughness": 6, "abilities": ["flying", "trample"], } ], } errors = engine.validate_action(valid_attack) # Some errors expected (flying creature can't be blocked) print(f" ✓ validate_action returned {len(errors)} errors") # Test get_rule_text rule = engine.get_rule_text("702.9") assert rule is not None, "get_rule_text should return a result" print(f" ✓ get_rule_text returned: {rule[:80]}...") # Test get_keyword_info_summary summary = engine.get_keyword_info_summary("flying") assert summary is not None, "get_keyword_info_summary should return a summary" assert summary["keyword"] == "flying", "Summary should have correct keyword" assert summary["rule"] is not None, "Summary should have rule" print(f" ✓ get_keyword_info_summary works: {summary}") # Test search_keywords results = engine.search_keywords("flying") assert len(results) > 0, "search_keywords should find matches" print(f" ✓ search_keywords found {len(results)} matches for 'flying'") # Test validate_game_state valid_state = { "players": [ { "name": "Player 1", "hand": [], "creatures": [], }, { "name": "Player 2", "hand": [], "creatures": [], }, ], "zones": { "stack": [], }, } errors = engine.validate_game_state(valid_state) # No errors expected for valid state print(f" ✓ validate_game_state returned {len(errors)} errors") print(" ✓ All rules engine tests passed!\n") def test_integration(): """Integration test with the full pipeline.""" print("=" * 60) print("TEST: Integration") print("=" * 60) # End-to-end test: Create a card, validate it, analyze its keywords engine = RulesEngine() card = { "name": "Mighty Hero", "text": "Flying, trample, trample over planeswalkers. Haste. When this creature enters, create a 1/1 token.", "type": "CREATURE", "power_toughness": (4, 4), "color": ["RED"], "abilities": ["flying", "trample", "haste"], } # Validate card errors = engine.validate_card(card) print(f" Card validation: {len(errors)} errors") # Find keywords in card text keywords = engine.validator.find_keywords_in_text(card["text"]) print(f" Keywords found in card text: {list(keywords.keys())}") # Get keyword info for each found keyword for keyword in keywords: info = engine.get_keyword_info_summary(keyword) print(f" - {keyword}: {info.get('rule', 'N/A')}") # Validate an attack attack = { "type": "attack", "attacker": { "name": "Mighty Hero", "type": "CREATURE", "power": 4, "toughness": 4, "abilities": ["flying", "trample"], }, "blocking_creatures": [ { "name": "Opponent's Flying Creature", "type": "CREATURE", "power": 3, "toughness": 3, "abilities": ["flying"], } ], } errors = engine.validate_action(attack) print(f" Attack validation: {len(errors)} errors") for error in errors: print(f" - {error['message']}") print(" ✓ Integration test passed!\n") if __name__ == "__main__": print("\n" + "=" * 60) print("Magic: The Gathering Rules Engine - Test Suite") print("=" * 60 + "\n") test_keyword_database() test_keyword_validator() test_rules_engine() test_integration() print("=" * 60) print("ALL TESTS PASSED!") print("=" * 60)