diff --git a/Mage.Sets/src/mage/cards/w/WireflyHive.java b/Mage.Sets/src/mage/cards/w/WireflyHive.java index 69a56320ac5..63715aed8bf 100644 --- a/Mage.Sets/src/mage/cards/w/WireflyHive.java +++ b/Mage.Sets/src/mage/cards/w/WireflyHive.java @@ -30,7 +30,7 @@ public final class WireflyHive extends CardImpl { public WireflyHive(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); - // {3}, {tap}: Flip a coin. If you win the flip, create a 2/2 colorless Insect artifact creature token with flying named Wirefly. + // {3}, {T}: Flip a coin. If you win the flip, create a 2/2 colorless Insect artifact creature token with flying named Wirefly. // If you lose the flip, destroy all permanents named Wirefly. Ability ability = new SimpleActivatedAbility(new FlipCoinEffect( new CreateTokenEffect(new WireflyToken()), new DestroyAllEffect(filter) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/IdentityThiefTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/IdentityThiefTest.java index 4b175739f1e..a549c9e747a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/IdentityThiefTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/IdentityThiefTest.java @@ -29,6 +29,7 @@ public class IdentityThiefTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Identity Thief"); // {2}{U}{U} castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Molten Sentry"); + setFlipCoinResult(playerA, true); attack(2, playerB, "Identity Thief"); setChoice(playerB, "Yes"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/flipcoin/FlipCoinTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/flipcoin/FlipCoinTest.java new file mode 100644 index 00000000000..6b183a428eb --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/flipcoin/FlipCoinTest.java @@ -0,0 +1,69 @@ +package org.mage.test.cards.flipcoin; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author JayDi85 + */ +public class FlipCoinTest extends CardTestPlayerBase { + + @Test + public void test_RandomResult() { + // {3}, {T}: Flip a coin. If you win the flip, create a 2/2 colorless Insect artifact creature token with flying named Wirefly. + // If you lose the flip, destroy all permanents named Wirefly. + addCard(Zone.BATTLEFIELD, playerA, "Wirefly Hive"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}"); + + //setStrictChooseMode(true); // normal play without errors + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertAllCommandsUsed(); + } + + @Test(expected = AssertionError.class) + public void test_StrictMode_MustFailWithoutResultSetup() { + // {3}, {T}: Flip a coin. If you win the flip, create a 2/2 colorless Insect artifact creature token with flying named Wirefly. + // If you lose the flip, destroy all permanents named Wirefly. + addCard(Zone.BATTLEFIELD, playerA, "Wirefly Hive"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}"); + + setStrictChooseMode(true); // no coinresult in choices, so it must fail + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_StrictMode_MustWorkWithResultSetup() { + // {3}, {T}: Flip a coin. If you win the flip, create a 2/2 colorless Insect artifact creature token with flying named Wirefly. + // If you lose the flip, destroy all permanents named Wirefly. + addCard(Zone.BATTLEFIELD, playerA, "Wirefly Hive"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + + // activates 5 times with same flip coin result + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}"); + setFlipCoinResult(playerA, true); + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}"); + setFlipCoinResult(playerA, true); + activateAbility(5, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}"); + setFlipCoinResult(playerA, true); + activateAbility(7, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}"); + setFlipCoinResult(playerA, true); + activateAbility(9, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}"); + setFlipCoinResult(playerA, true); + + setStrictChooseMode(true); + setStopAt(9, PhaseStep.BEGIN_COMBAT); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Wirefly", 5); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/OboshThePreypiercerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/OboshThePreypiercerTest.java index 5f5b7d467d7..38f45e22587 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/OboshThePreypiercerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/OboshThePreypiercerTest.java @@ -8,13 +8,10 @@ package org.mage.test.cards.single.iko; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Assert; import org.junit.Test; - import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ @@ -29,11 +26,14 @@ public class OboshThePreypiercerTest extends CardTestPlayerBase { // Companion — Your starting deck contains only cards with odd converted mana costs and land cards. // If a source you control with an odd converted mana cost would deal damage to a permanent or player, it deals double that damage to that permanent or player instead. addCard(Zone.BATTLEFIELD, playerA, "Obosh, the Preypiercer"); - + + // lose the flip + setFlipCoinResult(playerA, false); + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); execute(); assertAllCommandsUsed(); - - Assert.assertTrue("Life has to be 20 or 17 but was " + playerA.getLife() , playerA.getLife() == 17 || playerA.getLife() == 20); + + assertLife(playerA, 20 - 3); } } \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java index 87a712f6a87..e3e1269dd6d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java @@ -12,7 +12,19 @@ import java.util.UUID; * @author JayDi85 */ -// mock class to override to override AI logic for test +/** + * Mock class to override AI logic for test, cause PlayerImpl uses inner calls for other methods. If you + * want to override that methods for tests then call it here. + *
+ * It's a workaround and can be bugged (if you catch overflow error with new method then TestPlayer + * class must re-implement full method code without computerPlayer calls). + *
+ * Example 1: TestPlayer's code uses outer computerPlayer call to discard but discard's inner code must call choose from TestPlayer + * Example 2: TestPlayer's code uses outer computerPlayer call to flipCoin but flipCoin's inner code must call flipCoinResult from TestPlayer + *
+ * Don't forget to add new methods in another classes like TestComputerPlayer7 or TestComputerPlayerMonteCarlo
+ */
+
public class TestComputerPlayer extends ComputerPlayer {
private TestPlayer testPlayerLink;
@@ -27,10 +39,13 @@ public class TestComputerPlayer extends ComputerPlayer {
@Override
public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) {
- // copy-paste for TestComputerXXX
-
- // workaround for discard spells
- // reason: TestPlayer uses outer computerPlayer to discard but inner code uses choose
return testPlayerLink.choose(outcome, target, sourceId, game);
}
+
+ @Override
+ public boolean flipCoinResult(Game game) {
+ return testPlayerLink.flipCoinResult(game);
+ }
}
+
+
diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java
index dc92e509a27..cd313a54973 100644
--- a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java
+++ b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java
@@ -9,10 +9,11 @@ import mage.target.Target;
import java.util.UUID;
/**
+ * Copy paste methods from TestComputerPlayer, see docs in there
+ *
* @author JayDi85
*/
-// mock class to override AI logic in tests
public class TestComputerPlayer7 extends ComputerPlayer7 {
private TestPlayer testPlayerLink;
@@ -27,10 +28,11 @@ public class TestComputerPlayer7 extends ComputerPlayer7 {
@Override
public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) {
- // copy-paste for TestComputerXXX
-
- // workaround for discard spells
- // reason: TestPlayer uses outer computerPlayer to discard but inner code uses choose
return testPlayerLink.choose(outcome, target, sourceId, game);
}
+
+ @Override
+ public boolean flipCoinResult(Game game) {
+ return testPlayerLink.flipCoinResult(game);
+ }
}
diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayerMonteCarlo.java b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayerMonteCarlo.java
index 154dbfe450f..ee5d787f24b 100644
--- a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayerMonteCarlo.java
+++ b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayerMonteCarlo.java
@@ -9,10 +9,11 @@ import mage.target.Target;
import java.util.UUID;
/**
+ * Copy paste methods from TestComputerPlayer, see docs in there
+ *
* @author JayDi85
*/
-// mock class to override AI logic in tests
public class TestComputerPlayerMonteCarlo extends ComputerPlayerMCTS {
private TestPlayer testPlayerLink;
@@ -27,10 +28,11 @@ public class TestComputerPlayerMonteCarlo extends ComputerPlayerMCTS {
@Override
public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) {
- // copy-paste for TestComputerXXX
-
- // workaround for discard spells
- // reason: TestPlayer uses outer computerPlayer to discard but inner code uses choose
return testPlayerLink.choose(outcome, target, sourceId, game);
}
+
+ @Override
+ public boolean flipCoinResult(Game game) {
+ return testPlayerLink.flipCoinResult(game);
+ }
}
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 d025829913f..8ade40e88c9 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
@@ -54,6 +54,7 @@ import mage.players.net.UserData;
import mage.target.*;
import mage.target.common.*;
import mage.util.CardUtil;
+import mage.util.RandomUtil;
import org.apache.log4j.Logger;
import org.junit.Assert;
import org.junit.Ignore;
@@ -83,6 +84,8 @@ public class TestPlayer implements Player {
public static final String BLOCK_SKIP = "[block_skip]";
public static final String ATTACK_SKIP = "[attack_skip]";
public static final String NO_TARGET = "NO_TARGET"; // cast spell or activate ability without target defines
+ public static final String FLIPCOIN_RESULT_TRUE = "[flipcoin_true]";
+ public static final String FLIPCOIN_RESULT_FALSE = "[flipcoin_false]";
private int maxCallsWithoutAction = 400;
private int foundNoAction = 0;
@@ -3304,6 +3307,25 @@ public class TestPlayer implements Player {
return computerPlayer.flipCoin(source, game, true, appliedEffects);
}
+ @Override
+ public boolean flipCoinResult(Game game) {
+ assertAliasSupportInChoices(false);
+ if (!choices.isEmpty()) {
+ String nextResult = choices.get(0);
+ if (nextResult.equals(FLIPCOIN_RESULT_TRUE)) {
+ choices.remove(0);
+ return true;
+ } else if (nextResult.equals(FLIPCOIN_RESULT_FALSE)) {
+ choices.remove(0);
+ return false;
+ }
+ }
+ this.chooseStrictModeFailed("flipcoin result", game, "Use setFlipCoinResult to setup it in unit tests");
+
+ // implementation from PlayerImpl:
+ return RandomUtil.nextBoolean();
+ }
+
@Override
public int rollDice(Ability source, Game game, int numSides) {
return computerPlayer.rollDice(source, game, numSides);
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 61c2dc80dfa..10f196b1ded 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
@@ -1876,6 +1876,17 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
player.addModeChoice(choice);
}
+ /**
+ * Set next result of next flipCoin's try (one flipCoin event can call multiple tries under some effects)
+ * TestPlayer/ComputerPlayer always selects Heads in good winable events
+ *
+ * @param player
+ * @param result
+ */
+ public void setFlipCoinResult(TestPlayer player, boolean result) {
+ player.addChoice(result ? TestPlayer.FLIPCOIN_RESULT_TRUE : TestPlayer.FLIPCOIN_RESULT_FALSE);
+ }
+
/**
* Set target permanents
*
diff --git a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java
index 82e3aed0d92..3283b6d50ae 100644
--- a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java
+++ b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java
@@ -629,6 +629,11 @@ public class PlayerStub implements Player {
return false;
}
+ @Override
+ public boolean flipCoinResult(Game game) {
+ return false;
+ }
+
@Override
public int rollDice(Ability source, Game game, int numSides) {
return 1;
diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java
index 6f25b849030..2b644b6b922 100644
--- a/Mage/src/main/java/mage/players/Player.java
+++ b/Mage/src/main/java/mage/players/Player.java
@@ -444,6 +444,8 @@ public interface Player extends MageItem, Copyable