From 8902fb10022d45fe6e8db44813d652f4a72dc350 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Fri, 12 Jun 2020 10:15:55 +0400 Subject: [PATCH] Added and fixed tests for Meddling Mage from #6570 --- .../abilities/activated/ChaosWandTest.java | 1 - .../cards/abilities/keywords/SuspendTest.java | 2 - .../cards/restriction/MeddlingMageTest.java | 195 ++++++++++++++++++ .../java/org/mage/test/player/TestPlayer.java | 94 +++++---- 4 files changed, 244 insertions(+), 48 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/restriction/MeddlingMageTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/ChaosWandTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/ChaosWandTest.java index d570d87c7fc..4b98e27289d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/ChaosWandTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/ChaosWandTest.java @@ -25,7 +25,6 @@ public class ChaosWandTest extends CardTestPlayerBase { activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}, {T}: "); addTarget(playerA, playerB); setChoice(playerA, "Yes"); // cast for free - setChoice(playerA, "Cast Blood Tithe"); setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SuspendTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SuspendTest.java index 5f699c9382d..69db45b6dc9 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SuspendTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SuspendTest.java @@ -223,7 +223,6 @@ public class SuspendTest extends CardTestPlayerBase { checkExileCount("after counter", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", 1); // 3 time counters removes on upkeep (3, 5, 7) and cast again - setChoice(playerA, "Cast"); addTarget(playerA, playerB); checkLife("after suspend", 7, PhaseStep.PRECOMBAT_MAIN, playerB, 20 - 3); checkGraveyardCount("after suspend", 7, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", 1); @@ -258,7 +257,6 @@ public class SuspendTest extends CardTestPlayerBase { checkExileCount("after counter", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wear // Tear", 1); // 3 time counters removes on upkeep (3, 5, 7) and cast again - setChoice(playerA, "Cast Wear"); addTarget(playerA, "Bident of Thassa"); checkPermanentCount("after suspend", 7, PhaseStep.PRECOMBAT_MAIN, playerB, "Bident of Thassa", 0); checkPermanentCount("after suspend", 7, PhaseStep.PRECOMBAT_MAIN, playerB, "Bow of Nylea", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/restriction/MeddlingMageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/restriction/MeddlingMageTest.java new file mode 100644 index 00000000000..3830a9c40ee --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/restriction/MeddlingMageTest.java @@ -0,0 +1,195 @@ +package org.mage.test.cards.restriction; + +import mage.constants.EmptyNames; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class MeddlingMageTest extends CardTestPlayerBase { + + //As Meddling Mage enters the battlefield, choose a nonland card name. Spells with the chosen name can't be cast. + + @Test + public void testMeddlingMageDefaultScenario() { + addCard(Zone.HAND, playerA, "Meddling Mage"); + addCard(Zone.HAND, playerA, "Savannah Lions"); + + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + + checkPlayableAbility("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Savannah Lions", true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Meddling Mage"); + setChoice(playerA, "Savannah Lions"); // name a spell that can't be cast + + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkPlayableAbility("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Savannah Lions", false); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Meddling Mage", 1); + assertPermanentCount(playerA, "Savannah Lions", 0); + assertHandCount(playerA, "Meddling Mage", 0); + assertHandCount(playerA, "Savannah Lions", 1); + } + + @Test + public void testMeddlingMageIsochronScepterScenario() { + addCard(Zone.HAND, playerA, "Meddling Mage"); + addCard(Zone.HAND, playerA, "Isochron Scepter"); + addCard(Zone.HAND, playerA, "Lightning Bolt"); + + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 5); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Meddling Mage"); + setChoice(playerA, "Lightning Bolt"); // name a spell that can't be cast + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Isochron Scepter"); + setChoice(playerA, "Yes"); // use imprint + setChoice(playerA, "Lightning Bolt"); // target for imprint + + // copy and cast imprinted card + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{2}, {T}:"); + setChoice(playerA, "Yes"); // create copy + setChoice(playerA, "Yes"); // cast copy + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Meddling Mage", 1); + assertPermanentCount(playerA, "Isochron Scepter", 1); + assertExileCount("Lightning Bolt", 1); + assertLife(playerA, 20); + assertLife(playerB, 20); + + } + + @Test + public void testMeddlingMageFaceDownCreature() { + addCard(Zone.HAND, playerA, "Meddling Mage"); + addCard(Zone.HAND, playerA, "Ainok Tracker"); // red morph creature to prevent it casting from Islands and Plains + + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Meddling Mage"); + setChoice(playerA, "Ainok Tracker"); // name a spell that can't be cast + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ainok Tracker"); + setChoice(playerA, "Yes"); // cast it face down as 2/2 creature + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Meddling Mage", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertHandCount(playerA, "Meddling Mage", 0); + assertHandCount(playerA, "Ainok Tracker", 0); + } + + @Test + public void testMeddlingMageFuseCardStopAndCastWell() { + addCard(Zone.HAND, playerA, "Meddling Mage"); + + // Create a 3/3 green Centaur creature token. + // You gain 2 life for each creature you control. + addCard(Zone.HAND, playerA, "Alive // Well"); // {3}{G} // {W} + + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Meddling Mage"); + setChoice(playerA, "Well"); // name a spell that can't be cast + + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkPlayableAbility("all", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Alive", true); + checkPlayableAbility("all", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Well", false); + checkPlayableAbility("all", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "fused Alive // Well", false); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + + assertPermanentCount(playerA, "Meddling Mage", 1); + assertHandCount(playerA, "Meddling Mage", 0); + assertHandCount(playerA, "Alive // Well", 1); + assertLife(playerA, 20); + + } + + @Test + public void testMeddlingMageFuseCardStopAliveAndCastWell() { + addCard(Zone.HAND, playerA, "Meddling Mage"); + + // Create a 3/3 green Centaur creature token. + // You gain 2 life for each creature you control. + addCard(Zone.HAND, playerA, "Alive // Well"); // {3}{G} // {W} + + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Meddling Mage"); + setChoice(playerA, "Alive"); // name a spell that can't be cast + + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkPlayableAbility("all", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Alive", false); + checkPlayableAbility("all", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Well", true); + checkPlayableAbility("all", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "fused Alive // Well", false); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Well"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Meddling Mage", 1); + assertHandCount(playerA, "Meddling Mage", 0); + assertHandCount(playerA, "Alive // Well", 0); + assertLife(playerA, 22); + } + + @Test + public void testMeddlingMageFuseCardStopAliveAndCastFused() { + addCard(Zone.HAND, playerA, "Meddling Mage"); + + // Create a 3/3 green Centaur creature token. + // You gain 2 life for each creature you control. + addCard(Zone.HAND, playerA, "Alive // Well"); // {3}{G} // {W} + + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Meddling Mage"); + setChoice(playerA, "Alive"); // name a spell that can't be cast + + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkPlayableAbility("all", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Alive", false); + checkPlayableAbility("all", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Well", true); + checkPlayableAbility("all", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "fused Alive // Well", false); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Meddling Mage", 1); + assertHandCount(playerA, "Meddling Mage", 0); + + assertHandCount(playerA, "Alive // Well", 1); + assertLife(playerA, 20); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index f15f7c13630..a93b43236a6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -1,10 +1,5 @@ package org.mage.test.player; -import java.io.Serializable; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; import mage.MageItem; import mage.MageObject; import mage.MageObjectReference; @@ -62,6 +57,13 @@ import mage.util.CardUtil; import org.apache.log4j.Logger; import org.junit.Assert; import org.junit.Ignore; + +import java.io.Serializable; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + import static org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl.*; /** @@ -191,7 +193,7 @@ public class TestPlayer implements Player { /** * @param maxCallsWithoutAction max number of priority passes a player may - * have for this test (default = 100) + * have for this test (default = 100) */ public void setMaxCallsWithoutAction(int maxCallsWithoutAction) { this.maxCallsWithoutAction = maxCallsWithoutAction; @@ -1044,13 +1046,13 @@ public class TestPlayer implements Player { List data = cards.stream() .map(c -> (((c instanceof PermanentToken) ? "[T] " : "[C] ") - + c.getIdName() - + (c.isCopy() ? " [copy of " + c.getCopyFrom().getId().toString().substring(0, 3) + "]" : "") - + " - " + c.getPower().getValue() + "/" + c.getToughness().getValue() - + (c.isPlaneswalker() ? " - L" + c.getCounters(game).getCount(CounterType.LOYALTY) : "") - + ", " + (c.isTapped() ? "Tapped" : "Untapped") - + getPrintableAliases(", [", c.getId(), "]") - + (c.getAttachedTo() == null ? "" : ", attached to " + game.getPermanent(c.getAttachedTo()).getIdName()))) + + c.getIdName() + + (c.isCopy() ? " [copy of " + c.getCopyFrom().getId().toString().substring(0, 3) + "]" : "") + + " - " + c.getPower().getValue() + "/" + c.getToughness().getValue() + + (c.isPlaneswalker() ? " - L" + c.getCounters(game).getCount(CounterType.LOYALTY) : "") + + ", " + (c.isTapped() ? "Tapped" : "Untapped") + + getPrintableAliases(", [", c.getId(), "]") + + (c.getAttachedTo() == null ? "" : ", attached to " + game.getPermanent(c.getAttachedTo()).getIdName()))) .sorted() .collect(Collectors.toList()); @@ -1074,12 +1076,12 @@ public class TestPlayer implements Player { List data = abilities.stream() .map(a -> (a.getZone() + " -> " - + a.getSourceObject(game).getIdName() + " -> " - + (a.toString().startsWith("Cast ") ? "[" + a.getManaCostsToPay().getText() + "] -> " : "") // printed cost, not modified - + (a.toString().length() > 0 - ? a.toString().substring(0, Math.min(20, a.toString().length())) - : a.getClass().getSimpleName()) - + "...")) + + a.getSourceObject(game).getIdName() + " -> " + + (a.toString().startsWith("Cast ") ? "[" + a.getManaCostsToPay().getText() + "] -> " : "") // printed cost, not modified + + (a.toString().length() > 0 + ? a.toString().substring(0, Math.min(20, a.toString().length())) + : a.getClass().getSimpleName()) + + "...")) .sorted() .collect(Collectors.toList()); @@ -1444,7 +1446,7 @@ public class TestPlayer implements Player { UUID defenderId = null; boolean mustAttackByAction = false; boolean madeAttackByAction = false; - for (Iterator it = actions.iterator(); it.hasNext();) { + for (Iterator it = actions.iterator(); it.hasNext(); ) { PlayerAction action = it.next(); // aiXXX commands @@ -2019,7 +2021,7 @@ public class TestPlayer implements Player { // skip targets if (targets.get(0).equals(TARGET_SKIP)) { Assert.assertTrue("found skip target, but it require more targets, needs " - + (target.getMinNumberOfTargets() - target.getTargets().size()) + " more", + + (target.getMinNumberOfTargets() - target.getTargets().size()) + " more", target.getTargets().size() >= target.getMinNumberOfTargets()); targets.remove(0); return true; @@ -2324,7 +2326,7 @@ public class TestPlayer implements Player { this.chooseStrictModeFailed("choice", game, "Triggered list (total " + abilities.size() + "):\n" - + abilities.stream().map(a -> getInfo(a, game)).collect(Collectors.joining("\n"))); + + abilities.stream().map(a -> getInfo(a, game)).collect(Collectors.joining("\n"))); return computerPlayer.chooseTriggeredAbility(abilities, game); } @@ -3494,7 +3496,7 @@ public class TestPlayer implements Player { @Override public boolean choose(Outcome outcome, Target target, - UUID sourceId, Game game + UUID sourceId, Game game ) { // needed to call here the TestPlayer because it's overwitten return choose(outcome, target, sourceId, game, null); @@ -3502,7 +3504,7 @@ public class TestPlayer implements Player { @Override public boolean choose(Outcome outcome, Cards cards, - TargetCard target, Game game + TargetCard target, Game game ) { assertAliasSupportInChoices(false); if (!choices.isEmpty()) { @@ -3539,7 +3541,7 @@ public class TestPlayer implements Player { @Override public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, - Ability source, Game game + Ability source, Game game ) { // chooseTargetAmount calls for EACH target cycle (e.g. one target per click, see TargetAmount) // if use want to stop choosing then chooseTargetAmount must return false (example: up to xxx) @@ -3552,7 +3554,7 @@ public class TestPlayer implements Player { // skip targets if (targets.get(0).equals(TARGET_SKIP)) { Assert.assertTrue("found skip target, but it require more targets, needs " - + (target.getMinNumberOfTargets() - target.getTargets().size()) + " more", + + (target.getMinNumberOfTargets() - target.getTargets().size()) + " more", target.getTargets().size() >= target.getMinNumberOfTargets()); targets.remove(0); return false; // false in chooseTargetAmount = stop to choose @@ -3605,15 +3607,15 @@ public class TestPlayer implements Player { @Override public boolean choosePile(Outcome outcome, String message, - List pile1, List pile2, - Game game + List pile1, List pile2, + Game game ) { return computerPlayer.choosePile(outcome, message, pile1, pile2, game); } @Override public boolean playMana(Ability ability, ManaCost unpaid, - String promptText, Game game + String promptText, Game game ) { groupsForTargetHandling = null; @@ -3663,15 +3665,15 @@ public class TestPlayer implements Player { @Override public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, - List blockerOrder, Game game + List blockerOrder, Game game ) { return computerPlayer.chooseBlockerOrder(blockers, combatGroup, blockerOrder, game); } @Override public void assignDamage(int damage, List targets, - String singleTargetName, UUID sourceId, - Game game + String singleTargetName, UUID sourceId, + Game game ) { computerPlayer.assignDamage(damage, targets, singleTargetName, sourceId, game); } @@ -3690,14 +3692,14 @@ public class TestPlayer implements Player { @Override public void pickCard(List cards, Deck deck, - Draft draft + Draft draft ) { computerPlayer.pickCard(cards, deck, draft); } @Override public boolean scry(int value, Ability source, - Game game + Game game ) { // Don't scry at the start of the game. if (game.getTurnNum() == 1 && game.getStep() == null) { @@ -3708,44 +3710,44 @@ public class TestPlayer implements Player { @Override public boolean surveil(int value, Ability source, - Game game + Game game ) { return computerPlayer.surveil(value, source, game); } @Override public boolean moveCards(Card card, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return computerPlayer.moveCards(card, toZone, source, game); } @Override public boolean moveCards(Card card, Zone toZone, - Ability source, Game game, - boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects ) { return computerPlayer.moveCards(card, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); } @Override public boolean moveCards(Cards cards, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return computerPlayer.moveCards(cards, toZone, source, game); } @Override public boolean moveCards(Set cards, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return computerPlayer.moveCards(cards, toZone, source, game); } @Override public boolean moveCards(Set cards, Zone toZone, - Ability source, Game game, - boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects ) { return computerPlayer.moveCards(cards, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); } @@ -3833,12 +3835,14 @@ public class TestPlayer implements Player { @Override public SpellAbility chooseAbilityForCast(Card card, Game game, boolean noMana) { - String allInfo = ""; + assertAliasSupportInChoices(false); Map useable = PlayerImpl.getSpellAbilities(this.getId(), card, game.getState().getZone(card.getId()), game); - allInfo = useable.values().stream().map(Object::toString).collect(Collectors.joining("\n")); + String allInfo = useable.values().stream().map(Object::toString).collect(Collectors.joining("\n")); + if (useable.size() == 1) { + return (SpellAbility) useable.values().iterator().next(); + } - assertAliasSupportInChoices(false); if (!choices.isEmpty()) { for (ActivatedAbility ability : useable.values()) { if (ability.toString().startsWith(choices.get(0))) {