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 f8d33b3ffb..e526a907aa 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 @@ -660,13 +660,17 @@ public class TestPlayer implements Player { } } } else if (action.getAction().startsWith("waitStackResolved")) { + boolean oneTime = action.getAction().equals("waitStackResolved:1"); if (game.getStack().isEmpty()) { // all done, can use next command actions.remove(action); continue; } else { - // need to wait (don't remove command) + // need to wait (don't remove command, except one time) tryToPlayPriority(game); + if (oneTime) { + actions.remove(action); + } return true; } } else if (action.getAction().startsWith("playerAction:")) { @@ -844,6 +848,20 @@ public class TestPlayer implements Player { actions.remove(action); wasProccessed = true; } + + // check stack size: need size + if (params[0].equals(CHECK_COMMAND_STACK_SIZE) && params.length == 2) { + assertStackSize(action, game, Integer.parseInt(params[1])); + actions.remove(action); + wasProccessed = true; + } + + // check stack object: stack ability name, amount + if (params[0].equals(CHECK_COMMAND_STACK_OBJECT) && params.length == 3) { + assertStackObject(action, game, params[1], Integer.parseInt(params[2])); + actions.remove(action); + wasProccessed = true; + } } if (wasProccessed) { return true; @@ -941,6 +959,15 @@ public class TestPlayer implements Player { actions.remove(action); wasProccessed = true; } + + // show stack + if (params[0].equals(SHOW_COMMAND_STACK) && params.length == 1) { + printStart(action.getActionName()); + printStack(game); + printEnd(); + actions.remove(action); + wasProccessed = true; + } } if (wasProccessed) { @@ -1121,6 +1148,13 @@ public class TestPlayer implements Player { } } + private void printStack(Game game) { + System.out.println("Stack objects: " + game.getStack().size()); + game.getStack().forEach(stack -> { + System.out.println(stack.getStackAbility().toString()); + }); + } + private void assertPT(PlayerAction action, Game game, Player player, String permanentName, int Power, int Toughness) { Permanent perm = findPermanentWithAssert(action, game, player, permanentName); @@ -1361,6 +1395,21 @@ public class TestPlayer implements Player { } } + private void assertStackSize(PlayerAction action, Game game, int needStackSize) { + Assert.assertEquals(action.getActionName() + " - stack size must be " + needStackSize + " but is " + game.getStack().size(), needStackSize, game.getStack().size()); + } + + private void assertStackObject(PlayerAction action, Game game, String stackAbilityName, int needAmount) { + long foundedAmount = game.getStack() + .stream() + .filter(stack -> stack.getStackAbility().toString().startsWith(stackAbilityName)) + .count(); + if (needAmount != foundedAmount) { + printStack(game); + Assert.fail(action.getActionName() + " - stack must have " + needAmount + " objects with ability [" + stackAbilityName + "] but have " + foundedAmount); + } + } + private void assertManaPoolInner(PlayerAction action, Player player, ManaType manaType, Integer amount) { Integer normal = player.getManaPool().getMana().get(manaType); Integer conditional = player.getManaPool().getConditionalMana().stream().mapToInt(a -> a.get(manaType)).sum(); // calcs FULL conditional mana, not real conditions diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index 7b39681940..3dc3eec69d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -1,13 +1,5 @@ package org.mage.test.serverside.base.impl; -import java.io.FileNotFoundException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.UUID; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; import mage.MageObject; import mage.Mana; import mage.ObjectColor; @@ -43,6 +35,15 @@ import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestAPI; import org.mage.test.serverside.base.MageTestPlayerBase; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + /** * API for test initialization and asserting the test results. * @@ -103,6 +104,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement public static final String CHECK_COMMAND_MANA_POOL = "MANA_POOL"; public static final String CHECK_COMMAND_ALIAS_ZONE = "ALIAS_ZONE"; public static final String CHECK_COMMAND_PLAYER_IN_GAME = "PLAYER_IN_GAME"; + public static final String CHECK_COMMAND_STACK_SIZE = "STACK_COUNT"; + public static final String CHECK_COMMAND_STACK_OBJECT = "STACK_OBJECT"; // TODO: add target player param to commands public static final String SHOW_COMMAND_LIBRARY = "LIBRARY"; @@ -114,6 +117,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement public static final String SHOW_COMMAND_AVAILABLE_ABILITIES = "AVAILABLE_ABILITIES"; public static final String SHOW_COMMAND_AVAILABLE_MANA = "AVAILABLE_MANA"; public static final String SHOW_COMMAND_ALIASES = "ALIASES"; + public static final String SHOW_COMMAND_STACK = "STACK"; // TODO: add target player param to commands public static final String ALIAS_COMMAND_ADD = "ADD"; @@ -274,7 +278,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } } Assert.assertFalse("Wrong stop command on " + this.stopOnTurn + " / " + this.stopAtStep + " (" + this.stopAtStep.getIndex() + ")" - + " (found actions after stop on " + maxTurn + " / " + maxPhase + ")", + + " (found actions after stop on " + maxTurn + " / " + maxPhase + ")", (maxTurn > this.stopOnTurn) || (maxTurn == this.stopOnTurn && maxPhase > this.stopAtStep.getIndex())); for (Player player : currentGame.getPlayers().values()) { @@ -425,6 +429,14 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement check(checkName, turnNum, step, player, CHECK_COMMAND_ALIAS_ZONE, alias, zone.toString(), mustHave.toString()); } + public void checkStackSize(String checkName, int turnNum, PhaseStep step, TestPlayer player, Integer needStackSize) { + check(checkName, turnNum, step, player, CHECK_COMMAND_STACK_SIZE, needStackSize.toString()); + } + + public void checkStackObject(String checkName, int turnNum, PhaseStep step, TestPlayer player, String spellAbilityOnStack, Integer needAmount) { + check(checkName, turnNum, step, player, CHECK_COMMAND_STACK_OBJECT, spellAbilityOnStack, needAmount.toString()); + } + // show commands private void show(String showName, int turnNum, PhaseStep step, TestPlayer player, String command, String... params) { String res = "show:" + command; @@ -470,6 +482,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement show(showName, turnNum, step, player, SHOW_COMMAND_ALIASES); } + public void showStack(String showName, int turnNum, PhaseStep step, TestPlayer player) { + show(showName, turnNum, step, player, SHOW_COMMAND_STACK); + } + /** * Removes all cards from player's library from the game. Usually this * should be used once before initialization to form the library in certain @@ -507,8 +523,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Add a card to specified zone of specified player. * * @param gameZone {@link mage.constants.Zone} to add cards to. - * @param player {@link Player} to add cards for. Use either playerA or - * playerB. + * @param player {@link Player} to add cards for. Use either playerA or + * playerB. * @param cardName Card name in string format. */ @Override @@ -520,10 +536,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Add any amount of cards to specified zone of specified player. * * @param gameZone {@link mage.constants.Zone} to add cards to. - * @param player {@link Player} to add cards for. Use either playerA or - * playerB. + * @param player {@link Player} to add cards for. Use either playerA or + * playerB. * @param cardName Card name in string format. - * @param count Amount of cards to be added. + * @param count Amount of cards to be added. */ @Override public void addCard(Zone gameZone, TestPlayer player, String cardName, int count) { @@ -534,13 +550,13 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Add any amount of cards to specified zone of specified player. * * @param gameZone {@link mage.constants.Zone} to add cards to. - * @param player {@link Player} to add cards for. Use either playerA or - * playerB. + * @param player {@link Player} to add cards for. Use either playerA or + * playerB. * @param cardName Card name in string format. - * @param count Amount of cards to be added. - * @param tapped In case gameZone is Battlefield, determines whether - * permanent should be tapped. In case gameZone is other than Battlefield, - * {@link IllegalArgumentException} is thrown + * @param count Amount of cards to be added. + * @param tapped In case gameZone is Battlefield, determines whether + * permanent should be tapped. In case gameZone is other than Battlefield, + * {@link IllegalArgumentException} is thrown */ @Override public void addCard(Zone gameZone, TestPlayer player, String cardName, int count, boolean tapped) { @@ -621,7 +637,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Set player's initial life count. * * @param player {@link Player} to set life count for. - * @param life Life count to set. + * @param life Life count to set. */ @Override public void setLife(TestPlayer player, int life) { @@ -698,7 +714,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Assert player's life count after test execution. * * @param player {@link Player} to get life for comparison. - * @param life Expected player's life to compare with. + * @param life Expected player's life to compare with. */ @Override public void assertLife(Player player, int life) throws AssertionError { @@ -715,14 +731,14 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * params 3b. all: there is at least one creature with the cardName with the * different p\t params * - * @param player {@link Player} to get creatures for comparison. - * @param cardName Card name to compare with. - * @param power Expected power to compare with. + * @param player {@link Player} to get creatures for comparison. + * @param cardName Card name to compare with. + * @param power Expected power to compare with. * @param toughness Expected toughness to compare with. - * @param scope {@link mage.filter.Filter.ComparisonScope} Use ANY, if you - * want "at least one creature with given name should have specified p\t" - * Use ALL, if you want "all creature with gived name should have specified - * p\t" + * @param scope {@link mage.filter.Filter.ComparisonScope} Use ANY, if you + * want "at least one creature with given name should have specified p\t" + * Use ALL, if you want "all creature with gived name should have specified + * p\t" */ @Override public void assertPowerToughness(Player player, String cardName, int power, int toughness, Filter.ComparisonScope scope) @@ -812,8 +828,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param cardName * @param ability * @param mustHave true if creature should contain ability, false if it - * should NOT contain it instead - * @param count number of permanents with that ability + * should NOT contain it instead + * @param count number of permanents with that ability * @throws AssertionError */ public void assertAbility(Player player, String cardName, Ability ability, boolean mustHave, int count) throws AssertionError { @@ -846,7 +862,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Assert permanent count under player's control. * * @param player {@link Player} which permanents should be counted. - * @param count Expected count. + * @param count Expected count. */ @Override public void assertPermanentCount(Player player, int count) throws AssertionError { @@ -862,9 +878,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement /** * Assert permanent count under player's control. * - * @param player {@link Player} which permanents should be counted. + * @param player {@link Player} which permanents should be counted. * @param cardName Name of the cards that should be counted. - * @param count Expected count. + * @param count Expected count. */ @Override public void assertPermanentCount(Player player, String cardName, int count) throws AssertionError { @@ -914,8 +930,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Assert counter count on a permanent * * @param cardName Name of the cards that should be counted. - * @param type Type of the counter that should be counted. - * @param count Expected count. + * @param type Type of the counter that should be counted. + * @param count Expected count. */ public void assertCounterCount(String cardName, CounterType type, int count) throws AssertionError { this.assertCounterCount(null, cardName, type, count); @@ -938,8 +954,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Assert counter count on a card in exile * * @param cardName Name of the cards that should be counted. - * @param type Type of the counter that should be counted. - * @param count Expected count. + * @param type Type of the counter that should be counted. + * @param count Expected count. */ public void assertCounterOnExiledCardCount(String cardName, CounterType type, int count) throws AssertionError { //Assert.assertNotEquals("", cardName); @@ -962,8 +978,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Assert counter count on a player * * @param player The player whos counters should be counted. - * @param type Type of the counter that should be counted. - * @param count Expected count. + * @param type Type of the counter that should be counted. + * @param count Expected count. */ public void assertCounterCount(Player player, CounterType type, int count) throws AssertionError { Assert.assertEquals("(Battlefield) Counter counts are not equal (" + player.getName() + ':' + type + ')', count, player.getCounters().getCount(type)); @@ -973,7 +989,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Assert whether a permanent is a specified type or not * * @param cardName Name of the permanent that should be checked. - * @param type A type to test for + * @param type A type to test for * @param mustHave true if creature should have type, false if it should not */ public void assertType(String cardName, CardType type, boolean mustHave) throws AssertionError { @@ -998,8 +1014,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Assert whether a permanent is a specified type * * @param cardName Name of the permanent that should be checked. - * @param type A type to test for - * @param subType a subtype to test for + * @param type A type to test for + * @param subType a subtype to test for */ public void assertType(String cardName, CardType type, SubType subType) throws AssertionError { //Assert.assertNotEquals("", cardName); @@ -1014,7 +1030,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Assert whether a permanent is not a specified type * * @param cardName Name of the permanent that should be checked. - * @param type A type to test for + * @param type A type to test for */ public void assertNotType(String cardName, CardType type) throws AssertionError { //Assert.assertNotEquals("", cardName); @@ -1026,7 +1042,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Assert whether a permanent is not a specified subtype * * @param cardName Name of the permanent that should be checked. - * @param subType a subtype to test for + * @param subType a subtype to test for */ public void assertNotSubtype(String cardName, SubType subType) throws AssertionError { //Assert.assertNotEquals("", cardName); @@ -1039,10 +1055,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement /** * Assert permanent color * - * @param player player to check - * @param cardName card name on battlefield from player + * @param player player to check + * @param cardName card name on battlefield from player * @param searchColors colors list with searchable values - * @param mustHave must or not must have that colors + * @param mustHave must or not must have that colors */ public void assertColor(Player player, String cardName, ObjectColor searchColors, boolean mustHave) { //Assert.assertNotEquals("", cardName); @@ -1077,7 +1093,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Assert whether a permanent is tapped or not * * @param cardName Name of the permanent that should be checked. - * @param tapped Whether the permanent is tapped or not + * @param tapped Whether the permanent is tapped or not */ public void assertTapped(String cardName, boolean tapped) throws AssertionError { //Assert.assertNotEquals("", cardName); @@ -1104,8 +1120,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Assert whether X permanents of the same name are tapped or not. * * @param cardName Name of the permanent that should be checked. - * @param tapped Whether the permanent is tapped or not - * @param count The amount of this permanents that should be tapped + * @param tapped Whether the permanent is tapped or not + * @param count The amount of this permanents that should be tapped */ public void assertTappedCount(String cardName, boolean tapped, int count) throws AssertionError { //Assert.assertNotEquals("", cardName); @@ -1127,7 +1143,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement /** * Assert whether a permanent is attacking or not * - * @param cardName Name of the permanent that should be checked. + * @param cardName Name of the permanent that should be checked. * @param attacking Whether the permanent is attacking or not */ public void assertAttacking(String cardName, boolean attacking) throws AssertionError { @@ -1149,7 +1165,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Assert card count in player's hand. * * @param player {@link Player} who's hand should be counted. - * @param count Expected count. + * @param count Expected count. */ public void assertHandCount(Player player, int count) throws AssertionError { int actual = currentGame.getPlayer(player.getId()).getHand().size(); @@ -1159,9 +1175,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement /** * Assert card count in player's hand. * - * @param player {@link Player} who's hand should be counted. + * @param player {@link Player} who's hand should be counted. * @param cardName Name of the cards that should be counted. - * @param count Expected count. + * @param count Expected count. */ public void assertHandCount(Player player, String cardName, int count) throws AssertionError { //Assert.assertNotEquals("", cardName); @@ -1209,7 +1225,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Assert card count in player's graveyard. * * @param player {@link Player} who's graveyard should be counted. - * @param count Expected count. + * @param count Expected count. */ public void assertGraveyardCount(Player player, int count) throws AssertionError { int actual = currentGame.getPlayer(player.getId()).getGraveyard().size(); @@ -1220,7 +1236,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Assert card count in exile. * * @param cardName Name of the cards that should be counted. - * @param count Expected count. + * @param count Expected count. */ public void assertExileCount(String cardName, int count) throws AssertionError { //Assert.assertNotEquals("", cardName); @@ -1258,9 +1274,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement /** * Assert card count in player's exile. * - * @param owner {@link Player} who's exile should be counted. + * @param owner {@link Player} who's exile should be counted. * @param cardName Name of the cards that should be counted. - * @param count Expected count. + * @param count Expected count. */ public void assertExileCount(Player owner, String cardName, int count) throws AssertionError { //Assert.assertNotEquals("", cardName); @@ -1279,9 +1295,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement /** * Assert card count in player's graveyard. * - * @param player {@link Player} who's graveyard should be counted. + * @param player {@link Player} who's graveyard should be counted. * @param cardName Name of the cards that should be counted. - * @param count Expected count. + * @param count Expected count. */ public void assertGraveyardCount(Player player, String cardName, int count) throws AssertionError { assertAliaseSupportInActivateCommand(cardName, true); @@ -1300,7 +1316,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Assert library card count. * * @param player {@link Player} who's library should be counted. - * @param count Expected count. + * @param count Expected count. */ public void assertLibraryCount(Player player, int count) throws AssertionError { List libraryList = player.getLibrary().getCards(currentGame); @@ -1311,9 +1327,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement /** * Assert specific card count in player's library. * - * @param player {@link Player} who's library should be counted. + * @param player {@link Player} who's library should be counted. * @param cardName Name of the cards that should be counted. - * @param count Expected count. + * @param count Expected count. */ public void assertLibraryCount(Player player, String cardName, int count) throws AssertionError { //Assert.assertNotEquals("", cardName); @@ -1467,7 +1483,12 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void waitStackResolved(int turnNum, PhaseStep step, TestPlayer player) { - player.addAction(turnNum, step, "waitStackResolved"); + + } + + public void waitStackResolved(int turnNum, PhaseStep step, TestPlayer player, boolean oneTime) { + String command = "waitStackResolved" + (oneTime ? ":1" : ""); + player.addAction(turnNum, step, command); } /** @@ -1500,8 +1521,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param player * @param cardName * @param targetName for modes you can add "mode=3" before target name, - * multiple targets can be seperated by ^, not target marks as - * TestPlayer.NO_TARGET + * multiple targets can be seperated by ^, not target marks as + * TestPlayer.NO_TARGET */ public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName) { //Assert.assertNotEquals("", cardName); @@ -1524,8 +1545,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param step * @param player * @param cardName - * @param targetName for modal spells add the mode to the name e.g. - * "mode=2SilvercoatLion^mode3=PillarfieldOx" + * @param targetName for modal spells add the mode to the name e.g. + * "mode=2SilvercoatLion^mode3=PillarfieldOx" * @param spellOnStack */ public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName, String spellOnStack) { @@ -1612,7 +1633,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param step * @param player * @param ability - * @param targetName use NO_TARGET if there is no target to set + * @param targetName use NO_TARGET if there is no target to set * @param spellOnStack */ public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String targetName, String spellOnStack) { @@ -1625,8 +1646,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param step * @param player * @param ability - * @param targetName if not target has to be defined use the constant - * NO_TARGET + * @param targetName if not target has to be defined use the constant + * NO_TARGET * @param spellOnStack * @param clause */ @@ -1721,10 +1742,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * * @param player * @param choice starting with "1" for mode 1, "2" for mode 2 and so on (to - * set multiple modes call the command multiple times). If a spell mode can - * be used only once like Demonic Pact, the value has to be set to the - * number of the remaining modes (e.g. if only 2 are left the number need to - * be 1 or 2). + * set multiple modes call the command multiple times). If a spell mode can + * be used only once like Demonic Pact, the value has to be set to the + * number of the remaining modes (e.g. if only 2 are left the number need to + * be 1 or 2). */ public void setModeChoice(TestPlayer player, String choice) { player.addModeChoice(choice); @@ -1735,12 +1756,12 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * * @param player * @param target you can add multiple targets by separating them by the "^" - * character e.g. "creatureName1^creatureName2" you can qualify the target - * additional by setcode e.g. "creatureName-M15" you can add [no copy] to - * the end of the target name to prohibit targets that are copied you can - * add [only copy] to the end of the target name to allow only targets that - * are copies. For modal spells use a prefix with the mode number: - * mode=1Lightning Bolt^mode=2Silvercoat Lion + * character e.g. "creatureName1^creatureName2" you can qualify the target + * additional by setcode e.g. "creatureName-M15" you can add [no copy] to + * the end of the target name to prohibit targets that are copied you can + * add [only copy] to the end of the target name to allow only targets that + * are copies. For modal spells use a prefix with the mode number: + * mode=1Lightning Bolt^mode=2Silvercoat Lion */ // TODO: mode options doesn't work here (see BrutalExpulsionTest) public void addTarget(TestPlayer player, String target) { @@ -1772,7 +1793,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement /** * @param player * @param target use TestPlayer.TARGET_SKIP to 0 targets selects or to stop - * "up two xxx" selection + * "up two xxx" selection * @param amount */ public void addTargetAmount(TestPlayer player, String target, int amount) { @@ -1821,17 +1842,21 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void waitStackResolved(int turnNum, PhaseStep step) { + waitStackResolved(turnNum, step, false); + } + + public void waitStackResolved(int turnNum, PhaseStep step, boolean oneTime) { if (playerA != null) { - waitStackResolved(turnNum, step, playerA); + waitStackResolved(turnNum, step, playerA, oneTime); } if (playerB != null) { - waitStackResolved(turnNum, step, playerB); + waitStackResolved(turnNum, step, playerB, oneTime); } if (playerC != null) { - waitStackResolved(turnNum, step, playerC); + waitStackResolved(turnNum, step, playerC, oneTime); } if (playerD != null) { - waitStackResolved(turnNum, step, playerD); + waitStackResolved(turnNum, step, playerD, oneTime); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/testapi/WaitStackResolvedTest.java b/Mage.Tests/src/test/java/org/mage/test/testapi/WaitStackResolvedTest.java new file mode 100644 index 0000000000..75effe8401 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/testapi/WaitStackResolvedTest.java @@ -0,0 +1,100 @@ +package org.mage.test.testapi; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author JayDi85 + */ +public class WaitStackResolvedTest extends CardTestPlayerBase { + + @Test + public void test_Spells() { + addCard(Zone.HAND, playerA, "Firebolt", 1); // sorcery + addCard(Zone.HAND, playerA, "Lightning Bolt", 2); // instant + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + + checkStackSize("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 0); + + // prepare - cast 3 spells + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Firebolt", playerB); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + checkStackSize("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 3); + checkStackObject("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Firebolt", 1); + checkStackObject("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Lightning Bolt", 2); + + // skip 1 (bolt) + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, true); + checkStackSize("after 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2); + checkStackObject("after 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Firebolt", 1); + checkStackObject("after 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Lightning Bolt", 1); + + // skip 2 (bolt) + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, true); + checkStackSize("after 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 1); + checkStackObject("after 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Firebolt", 1); + checkStackObject("after 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Lightning Bolt", 0); + + // skip 3 (firebolt) + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, true); + checkStackSize("after 3", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 0); + checkStackObject("after 3", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Firebolt", 0); + checkStackObject("after 3", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Lightning Bolt", 0); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_Abilities() { + // {1}{R}, Sacrifice Pyromania: Pyromania deals 1 damage to any target. + addCard(Zone.BATTLEFIELD, playerA, "Pyromania", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + // + // {2}: Goblin Cannon deals 1 damage to any target. Sacrifice Goblin Cannon. + addCard(Zone.BATTLEFIELD, playerA, "Goblin Cannon", 2); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2 * 2); + + String goblinAbility = "{2}:"; + String pyroAbility = "{1}{R}, Sacrifice"; + + checkStackSize("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 0); + + // prepare - activate 3 abilities + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, goblinAbility, playerB); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, pyroAbility, playerB); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, goblinAbility, playerB); + checkStackSize("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 3); + checkStackObject("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, pyroAbility, 1); + checkStackObject("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, goblinAbility, 2); + showStack("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA); + + // skip 1 (goblin) + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, true); + checkStackSize("after 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2); + checkStackObject("after 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, pyroAbility, 1); + checkStackObject("after 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, goblinAbility, 1); + + // skip 2 (pyro) + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, true); + checkStackSize("after 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 1); + checkStackObject("after 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, pyroAbility, 0); + checkStackObject("after 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, goblinAbility, 1); + + // skip 3 (goblin) + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, true); + checkStackSize("after 3", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 0); + checkStackObject("after 3", 1, PhaseStep.PRECOMBAT_MAIN, playerA, pyroAbility, 0); + checkStackObject("after 3", 1, PhaseStep.PRECOMBAT_MAIN, playerA, goblinAbility, 0); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } +}