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 new file mode 100644 index 00000000000..cb9a9059628 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java @@ -0,0 +1,62 @@ +package org.mage.test.player; + +import mage.MageObject; +import mage.abilities.ActivatedAbility; +import mage.abilities.SpellAbility; +import mage.constants.RangeOfInfluence; +import mage.game.Game; +import mage.player.ai.ComputerPlayer; + +import java.util.LinkedHashMap; +import java.util.UUID; + +/** + * @author JayDi85 + */ + +// mock class to override to override AI logic for test +public class TestComputerPlayer extends ComputerPlayer { + + private TestPlayer testPlayerLink; + + public TestComputerPlayer(String name, RangeOfInfluence range) { + super(name, range); + } + + public void setTestPlayerLink(TestPlayer testPlayerLink) { + this.testPlayerLink = testPlayerLink; + } + + @Override + public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) { + // copy-paste for TestComputerXXX + + // workaround to cast fused cards in tests by it's NAMES (Wear, Tear, Wear // Tear) + // reason: TestPlayer uses outer computerPlayer to cast, not TestPlayer + switch (ability.getSpellAbilityType()) { + case SPLIT: + case SPLIT_FUSED: + case SPLIT_AFTERMATH: + if (!this.testPlayerLink.getChoices().isEmpty()) { + MageObject object = game.getObject(ability.getSourceId()); + if (object != null) { + LinkedHashMap useableAbilities = this.getSpellAbilities(object, game.getState().getZone(object.getId()), game); + + // left, right or fused cast + for (String choose : this.testPlayerLink.getChoices()) { + for (ActivatedAbility activatedAbility : useableAbilities.values()) { + if (activatedAbility instanceof SpellAbility) { + if (((SpellAbility) activatedAbility).getCardName().equals(choose)) { + return (SpellAbility) activatedAbility; + } + } + } + } + } + } + } + + // default implementation by AI + return super.chooseSpellAbilityForCast(ability, game, noMana); + } +} 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 new file mode 100644 index 00000000000..3bff4150705 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java @@ -0,0 +1,62 @@ +package org.mage.test.player; + +import mage.MageObject; +import mage.abilities.ActivatedAbility; +import mage.abilities.SpellAbility; +import mage.constants.RangeOfInfluence; +import mage.game.Game; +import mage.player.ai.ComputerPlayer7; + +import java.util.LinkedHashMap; +import java.util.UUID; + +/** + * @author JayDi85 + */ + +// mock class to override AI logic in tests +public class TestComputerPlayer7 extends ComputerPlayer7 { + + private TestPlayer testPlayerLink; + + public TestComputerPlayer7(String name, RangeOfInfluence range, int skill) { + super(name, range, skill); + } + + public void setTestPlayerLink(TestPlayer testPlayerLink) { + this.testPlayerLink = testPlayerLink; + } + + @Override + public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) { + // copy-paste for TestComputerXXX + + // workaround to cast fused cards in tests by it's NAMES (Wear, Tear, Wear // Tear) + // reason: TestPlayer uses outer computerPlayer to cast, not TestPlayer + switch (ability.getSpellAbilityType()) { + case SPLIT: + case SPLIT_FUSED: + case SPLIT_AFTERMATH: + if (!this.testPlayerLink.getChoices().isEmpty()) { + MageObject object = game.getObject(ability.getSourceId()); + if (object != null) { + LinkedHashMap useableAbilities = this.getSpellAbilities(object, game.getState().getZone(object.getId()), game); + + // left, right or fused cast + for (String choose : this.testPlayerLink.getChoices()) { + for (ActivatedAbility activatedAbility : useableAbilities.values()) { + if (activatedAbility instanceof SpellAbility) { + if (((SpellAbility) activatedAbility).getCardName().equals(choose)) { + return (SpellAbility) activatedAbility; + } + } + } + } + } + } + } + + // default implementation by AI + return super.chooseSpellAbilityForCast(ability, game, noMana); + } +} 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 932c63de59e..c6939d329e3 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 @@ -43,7 +43,6 @@ import mage.player.ai.ComputerPlayer; import mage.players.Library; import mage.players.ManaPool; import mage.players.Player; -import mage.players.PlayerList; import mage.players.net.UserData; import mage.target.*; import mage.target.common.*; @@ -84,9 +83,16 @@ public class TestPlayer implements Player { // Before actual turns start. Needed for checking attacker/blocker legality in the tests private static int initialTurns = 0; - public TestPlayer(ComputerPlayer computerPlayer) { + public TestPlayer(TestComputerPlayer computerPlayer) { this.computerPlayer = computerPlayer; AIPlayer = false; + computerPlayer.setTestPlayerLink(this); + } + + public TestPlayer(TestComputerPlayer7 computerPlayer) { + this.computerPlayer = computerPlayer; + AIPlayer = false; + computerPlayer.setTestPlayerLink(this); } public TestPlayer(final TestPlayer testPlayer) { @@ -106,6 +112,10 @@ public class TestPlayer implements Player { choices.add(choice); } + public List getChoices() { + return this.choices; + } + public void addModeChoice(String mode) { modesSet.add(mode); } @@ -1146,9 +1156,9 @@ public class TestPlayer implements Player { Boolean canEquals = canSupportChars.contains("="); // how to fix: change target definition for addTarget in test's code or update choose from targets implementation in TestPlayer - if((foundMulti && !canMulti) || (foundSpecialStart && !canSpecialStart) || (foundSpecialClose && !canSpecialClose)|| (foundEquals && !canEquals)) { + if ((foundMulti && !canMulti) || (foundSpecialStart && !canSpecialStart) || (foundSpecialClose && !canSpecialClose) || (foundEquals && !canEquals)) { Assert.fail("Targets list was setup by addTarget with " + targets + ", but target definition [" + targetDefinition + "]" - + " is not supported by ["+ canSupportChars + "] for target class " + needTarget.getClass().getSimpleName()); + + " is not supported by [" + canSupportChars + "] for target class " + needTarget.getClass().getSimpleName()); } } @@ -1330,14 +1340,14 @@ public class TestPlayer implements Player { List needPlayers = game.getState().getPlayersInRange(getId(), game).toList(); // fix for opponent graveyard - if(target instanceof TargetCardInOpponentsGraveyard) { + if (target instanceof TargetCardInOpponentsGraveyard) { // current player remove Assert.assertTrue(needPlayers.contains(getId())); needPlayers.remove(getId()); Assert.assertFalse(needPlayers.contains(getId())); } // fix for your graveyard - if(target instanceof TargetCardInYourGraveyard) { + if (target instanceof TargetCardInYourGraveyard) { // only current player Assert.assertTrue(needPlayers.contains(getId())); needPlayers.clear(); @@ -1400,10 +1410,10 @@ public class TestPlayer implements Player { // wrong target settings by addTarget // how to fix: implement target class processing above - if(!targets.isEmpty()) { + if (!targets.isEmpty()) { String message; - if(source != null) { + if (source != null) { message = "Targets list was setup by addTarget with " + targets + ", but not used in [" + "card " + source.getSourceObject(game) + " -> ability " + source.getClass().getSimpleName() + " (" + source.getRule().substring(0, Math.min(20, source.getRule().length()) - 1) + "..." + ")" @@ -1792,6 +1802,8 @@ public class TestPlayer implements Player { @Override public boolean cast(SpellAbility ability, Game game, boolean noMana, MageObjectReference reference) { + // TestPlayer, ComputerPlayer always call inherited cast() from PlayerImpl + // that's why chooseSpellAbilityForCast will be ignored in TestPlayer, see workaround with TestComputerPlayerXXX return computerPlayer.cast(ability, game, noMana, reference); } @@ -2586,24 +2598,7 @@ public class TestPlayer implements Player { @Override public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) { - switch (ability.getSpellAbilityType()) { - case SPLIT: - case SPLIT_FUSED: - case SPLIT_AFTERMATH: - if (!choices.isEmpty()) { - MageObject object = game.getObject(ability.getSourceId()); - if (object != null) { - LinkedHashMap useableAbilities = computerPlayer.getSpellAbilities(object, game.getState().getZone(object.getId()), game); - for (String choose : choices) { - for (ActivatedAbility actiavtedAbility : useableAbilities.values()) { - if (actiavtedAbility.getRule().startsWith(choose)) { - return (SpellAbility) actiavtedAbility; - } - } - } - } - } - } + Assert.fail("That's method calls only from computerPlayer->cast(), see TestComputerPlayerXXX"); return computerPlayer.chooseSpellAbilityForCast(ability, game, noMana); } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBaseAI.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBaseAI.java index fa1a5241d29..89e522fd5af 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBaseAI.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBaseAI.java @@ -1,18 +1,17 @@ - package org.mage.test.serverside.base; -import java.io.FileNotFoundException; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.game.Game; import mage.game.GameException; import mage.game.TwoPlayerDuel; -import mage.player.ai.ComputerPlayer7; +import org.mage.test.player.TestComputerPlayer7; import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl; +import java.io.FileNotFoundException; + /** - * * @author LevelX2 */ public abstract class CardTestPlayerBaseAI extends CardTestPlayerAPIImpl { @@ -31,7 +30,7 @@ public abstract class CardTestPlayerBaseAI extends CardTestPlayerAPIImpl { @Override protected TestPlayer createPlayer(String name, RangeOfInfluence rangeOfInfluence) { if (name.equals("PlayerA")) { - TestPlayer testPlayer = new TestPlayer(new ComputerPlayer7("PlayerA", RangeOfInfluence.ONE, skill)); + TestPlayer testPlayer = new TestPlayer(new TestComputerPlayer7("PlayerA", RangeOfInfluence.ONE, skill)); testPlayer.setAIPlayer(true); return testPlayer; } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java index b514cc68b4d..c6ad3f2f681 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java @@ -1,16 +1,6 @@ package org.mage.test.serverside.base; -import java.io.File; -import java.io.FileNotFoundException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Scanner; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import mage.cards.Card; -import mage.cards.decks.Deck; import mage.cards.decks.DeckCardLists; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; @@ -21,7 +11,6 @@ import mage.game.Game; import mage.game.match.MatchType; import mage.game.permanent.PermanentCard; import mage.game.tournament.TournamentType; -import mage.player.ai.ComputerPlayer; import mage.players.Player; import mage.server.game.GameFactory; import mage.server.util.ConfigSettings; @@ -32,8 +21,15 @@ import mage.util.Copier; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.junit.BeforeClass; +import org.mage.test.player.TestComputerPlayer; import org.mage.test.player.TestPlayer; +import java.io.File; +import java.io.FileNotFoundException; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * Base class for all tests. * @@ -334,7 +330,7 @@ public abstract class MageTestPlayerBase { } protected TestPlayer createPlayer(String name, RangeOfInfluence rangeOfInfluence) { - return new TestPlayer(new ComputerPlayer(name, rangeOfInfluence)); + return new TestPlayer(new TestComputerPlayer(name, rangeOfInfluence)); } }