from compiler.parser import AbilityParser from engine.models.ability import ( AbilityCostType, ConditionType, EffectType, TriggerType, ) def test_nico_dual_trigger(): """Test PL!-PR-009-PR: Dual trigger ON_PLAY / ON_LIVE_START""" text = "{{toujyou.png|登場}}/{{live_start.png|ライブ開始時}}このメンバーをウェイトにしてもよい:相手のステージにいるコスト4以下のメンバー1人をウェイトにする。" abilities = AbilityParser.parse_ability_text(text) assert len(abilities) == 2, "Should parse into 2 abilities" assert abilities[0].trigger == TriggerType.ON_PLAY assert abilities[1].trigger == TriggerType.ON_LIVE_START for abi in abilities: assert len(abi.costs) == 1 assert abi.costs[0].type == AbilityCostType.TAP_SELF assert len(abi.effects) == 1 assert abi.effects[0].effect_type == EffectType.TAP_OPPONENT def test_kanata_reveal_hand(): """Test PL!N-PR-008-PR: Reveal hand cost + condition""" text = "{{kidou.png|起動}}{{turn1.png|ターン1回}}手札をすべて公開する:自分のステージにほかのメンバーがおり、かつこれにより公開した手札の中にライブカードがない場合、自分のデッキの上からカードを5枚見る。その中からライブカードを1枚公開して手札に加えてもよい。残りを控え室に置く。" abilities = AbilityParser.parse_ability_text(text) assert len(abilities) == 1 abi = abilities[0] # Check Cost assert any(c.type == AbilityCostType.REVEAL_HAND_ALL for c in abi.costs), "Should have REVEAL_HAND_ALL cost" # Check Condition assert any(c.type == ConditionType.HAND_HAS_NO_LIVE for c in abi.conditions), ( "Should have HAND_HAS_NO_LIVE condition" ) # Check Effect assert abi.effects[0].effect_type == EffectType.LOOK_DECK assert abi.effects[0].value == 5 def test_ginko_parsing(): """Test PL!N-PR-012-PR: Look 5, Choose 1 Member""" text = "【登場時】手札を1枚捨ててもよい:そうしたら、デッキの上から5枚見る。その中からメンバーを1枚まで公開し、手札に加える。残りを山札の一番下に望む順番で置く。" abilities = AbilityParser.parse_ability_text(text) assert len(abilities) == 1 abi = abilities[0] # Check Effects chain # 1. Look Deck 5 assert abi.effects[0].effect_type == EffectType.LOOK_DECK assert abi.effects[0].value == 5 # 2. Look and Choose (Member) assert abi.effects[1].effect_type == EffectType.LOOK_AND_CHOOSE assert abi.effects[1].params.get("filter") == "member", "Should capture member filter" # 3. Order Deck (Remainder to bottom) assert any(e.effect_type in (EffectType.ORDER_DECK, EffectType.MOVE_TO_DECK) for e in abi.effects), ( "Should handle remainder" ) def test_honoka_parsing(): """Test PL!-sd1-001-SD: Count Success Live Condition & Recover Live Effect""" text = "【登場時】自分の成功ライブカード置き場にカードが2枚以上ある場合、自分の控え室からライブカードを1枚手札に加える。" abilities = AbilityParser.parse_ability_text(text) print(f"DEBUG: Honoka abilities: {abilities}") assert len(abilities) == 1 abi = abilities[0] # Verify Trigger assert abi.trigger == TriggerType.ON_PLAY # Verify Condition assert len(abi.conditions) == 1, f"Expected 1 condition, found {len(abi.conditions)}: {abi.conditions}" assert abi.conditions[0].type == ConditionType.COUNT_SUCCESS_LIVE assert abi.conditions[0].params.get("min") == 2 # Verify Effect assert len(abi.effects) == 1, f"Expected 1 effect, found {len(abi.effects)}: {abi.effects}" assert abi.effects[0].effect_type == EffectType.RECOVER_LIVE