package org.mage.test.serverside.base.impl;
import java.io.FileNotFoundException;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import mage.abilities.Ability;
import mage.cards.Card;
import mage.cards.decks.Deck;
import mage.cards.decks.importer.DeckImporterUtil;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.cards.repository.CardScanner;
import mage.constants.CardType;
import mage.constants.PhaseStep;
import mage.constants.RangeOfInfluence;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.Filter;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.game.*;
import mage.game.command.CommandObject;
import mage.game.match.MatchType;
import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentCard;
import mage.players.Player;
import org.junit.Assert;
import org.junit.Before;
import org.mage.test.player.TestPlayer;
import org.mage.test.serverside.base.CardTestAPI;
import org.mage.test.serverside.base.MageTestPlayerBase;
/**
* API for test initialization and asserting the test results.
*
* @author ayratn
*/
public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implements CardTestAPI {
// Defines the constant if for activate ability is not target but a ability on the stack to define
public static final String NO_TARGET = "NO_TARGET";
protected GameOptions gameOptions;
protected String deckNameA;
protected String deckNameB;
protected String deckNameC;
protected String deckNameD;
protected enum ExpectedType {
TURN_NUMBER,
RESULT,
LIFE,
BATTLEFIELD,
GRAVEYARD,
UNKNOWN
}
static {
// CardScanner.scanned = true;
CardScanner.scan();
}
/**
* Default game initialization params for red player (that plays with
* Mountains)
*/
@Override
public void useRedDefault() {
// *** ComputerA ***
// battlefield:ComputerA:Mountain:5
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
// hand:ComputerA:Mountain:4
addCard(Zone.HAND, playerA, "Mountain", 5);
// library:ComputerA:clear:0
removeAllCardsFromLibrary(playerA);
// library:ComputerA:Mountain:10
addCard(Zone.LIBRARY, playerA, "Mountain", 10);
// *** ComputerB ***
// battlefield:ComputerB:Plains:2
addCard(Zone.BATTLEFIELD, playerB, "Plains", 2);
// hand:ComputerB:Plains:2
addCard(Zone.HAND, playerB, "Plains", 2);
// library:ComputerB:clear:0
removeAllCardsFromLibrary(playerB);
// library:ComputerB:Plains:10
addCard(Zone.LIBRARY, playerB, "Plains", 10);
}
/**
* Default game initialization params for white player (that plays with
* Plains)
*/
public void useWhiteDefault() {
// *** ComputerA ***
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
addCard(Zone.HAND, playerA, "Plains", 5);
removeAllCardsFromLibrary(playerA);
addCard(Zone.LIBRARY, playerA, "Plains", 10);
// *** ComputerB ***
addCard(Zone.BATTLEFIELD, playerB, "Plains", 2);
addCard(Zone.HAND, playerB, "Plains", 2);
removeAllCardsFromLibrary(playerB);
addCard(Zone.LIBRARY, playerB, "Plains", 10);
}
@Before
public void reset() throws GameException, FileNotFoundException {
if (currentGame != null) {
logger.debug("Resetting previous game and creating new one!");
currentGame = null;
System.gc();
}
currentGame = createNewGameAndPlayers();
activePlayer = playerA;
stopOnTurn = 2;
stopAtStep = PhaseStep.UNTAP;
for (Player player : currentGame.getPlayers().values()) {
TestPlayer testPlayer = (TestPlayer) player;
getCommands(testPlayer).clear();
getLibraryCards(testPlayer).clear();
getHandCards(testPlayer).clear();
getBattlefieldCards(testPlayer).clear();
getGraveCards(testPlayer).clear();
// Reset the turn counter for tests
((TestPlayer) player).setInitialTurns(0);
}
gameOptions = new GameOptions();
}
abstract protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException;
protected TestPlayer createPlayer(Game game, TestPlayer player, String name) throws GameException {
return createPlayer(game, player, name, "RB Aggro.dck");
}
protected TestPlayer createPlayer(Game game, TestPlayer player, String name, String deckName) throws GameException {
player = createNewPlayer(name, game.getRangeOfInfluence());
player.setTestMode(true);
logger.debug("Loading deck...");
Deck deck = Deck.load(DeckImporterUtil.importDeck(deckName), false, false);
logger.debug("Done!");
if (deck.getCards().size() < 40) {
throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck.getCards().size());
}
game.loadCards(deck.getCards(), player.getId());
game.loadCards(deck.getSideboard(), player.getId());
game.addPlayer(player, deck);
return player;
}
public void execute() throws IllegalStateException {
if (currentGame == null || activePlayer == null) {
throw new IllegalStateException("Game is not initialized. Use load method to load a test case and initialize a game.");
}
for (Player player : currentGame.getPlayers().values()) {
TestPlayer testPlayer = (TestPlayer) player;
currentGame.cheat(player.getId(), getCommands(testPlayer));
currentGame.cheat(player.getId(), getLibraryCards(testPlayer), getHandCards(testPlayer),
getBattlefieldCards(testPlayer), getGraveCards(testPlayer));
}
long t1 = System.nanoTime();
gameOptions.testMode = true;
gameOptions.stopOnTurn = stopOnTurn;
gameOptions.stopAtStep = stopAtStep;
currentGame.setGameOptions(gameOptions);
currentGame.start(activePlayer.getId());
long t2 = System.nanoTime();
logger.debug("Winner: " + currentGame.getWinner());
logger.info("Test has been executed. Execution time: " + (t2 - t1) / 1000000 + " ms");
}
protected TestPlayer createNewPlayer(String playerName, RangeOfInfluence rangeOfInfluence) {
return createPlayer(playerName, rangeOfInfluence);
}
protected Player getPlayerFromName(String playerName, String line) {
Player player = null;
switch (playerName) {
case "ComputerA":
player = currentGame.getPlayer(playerA.getId());
break;
case "ComputerB":
player = currentGame.getPlayer(playerB.getId());
break;
case "ComputerC":
player = currentGame.getPlayer(playerC.getId());
break;
case "ComputerD":
player = currentGame.getPlayer(playerD.getId());
break;
default:
throw new IllegalArgumentException("Wrong player in 'battlefield' line, player=" + player + ", line=" + line);
}
return player;
}
/**
* Removes all cards from player's library from the game. Usually this
* should be used once before initialization to form the library in certain
* order.
*
* @param player {@link Player} to remove all library cards from.
*/
@Override
public void removeAllCardsFromLibrary(TestPlayer player) {
getCommands(player).put(Zone.LIBRARY, "clear");
}
/**
* Removes all cards from player's hand from the game. Usually this should
* be used once before initialization to set the players hand.
*
* @param player {@link Player} to remove all cards from hand.
*/
public void removeAllCardsFromHand(TestPlayer player) {
getCommands(player).put(Zone.HAND, "clear");
}
/**
* 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 cardName Card name in string format.
*/
@Override
public void addCard(Zone gameZone, TestPlayer player, String cardName) {
addCard(gameZone, player, cardName, 1, false);
}
/**
* 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 cardName Card name in string format.
* @param count Amount of cards to be added.
*/
@Override
public void addCard(Zone gameZone, TestPlayer player, String cardName, int count) {
addCard(gameZone, player, cardName, count, false);
}
/**
* 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 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
*/
@Override
public void addCard(Zone gameZone, TestPlayer player, String cardName, int count, boolean tapped) {
if (gameZone == Zone.BATTLEFIELD) {
for (int i = 0; i < count; i++) {
CardInfo cardInfo = CardRepository.instance.findCard(cardName);
Card card = cardInfo != null ? cardInfo.getCard() : null;
if (card == null) {
throw new IllegalArgumentException("[TEST] Couldn't find a card: " + cardName);
}
PermanentCard p = new PermanentCard(card.copy(), player.getId(), currentGame);
p.setTapped(tapped);
getBattlefieldCards(player).add(p);
}
} else {
if (tapped) {
throw new IllegalArgumentException("Parameter tapped=true can be used only for Zone.BATTLEFIELD.");
}
List<Card> cards = getCardList(gameZone, player);
for (int i = 0; i < count; i++) {
CardInfo cardInfo = CardRepository.instance.findCard(cardName);
Card card = cardInfo != null ? cardInfo.getCard() : null;
if (card == null) {
throw new AssertionError("Couldn't find a card: " + cardName);
}
cards.add(card);
}
}
}
/**
* Returns card list container for specified game zone and player.
*
* @param gameZone
* @param player
* @return
*/
private List<Card> getCardList(Zone gameZone, TestPlayer player) {
switch (gameZone) {
case HAND:
return getHandCards(player);
case GRAVEYARD:
return getGraveCards(player);
case LIBRARY:
return getLibraryCards(player);
default:
break;
}
throw new AssertionError("Zone is not supported by test framework: " + gameZone);
}
/**
* Set player's initial life count.
*
* @param player {@link Player} to set life count for.
* @param life Life count to set.
*/
@Override
public void setLife(TestPlayer player, int life) {
getCommands(player).put(Zone.OUTSIDE, "life:" + String.valueOf(life));
}
/**
* Define turn number to stop the game on.
*
* @param turn
*/
@Override
public void setStopOnTurn(int turn) {
stopOnTurn = turn == -1 ? null : turn;
stopAtStep = PhaseStep.UNTAP;
}
/**
* Define turn number and step to stop the game on. The game stops after
* executing the step
*
* @param turn
* @param step
*/
@Override
public void setStopAt(int turn, PhaseStep step) {
stopOnTurn = turn == -1 ? null : turn;
stopAtStep = step;
}
/**
* Assert turn number after test execution.
*
* @param turn Expected turn number to compare with. 1-based.
*/
@Override
public void assertTurn(int turn) throws AssertionError {
Assert.assertEquals("Turn numbers are not equal", turn, currentGame.getTurnNum());
}
/**
* Assert game result after test execution.
*
* @param result Expected {@link GameResult} to compare with.
*/
@Override
public void assertResult(Player player, GameResult result) throws AssertionError {
if (player.equals(playerA)) {
GameResult actual = CardTestAPI.GameResult.DRAW;
switch (currentGame.getWinner()) {
case "Player PlayerA is the winner":
actual = CardTestAPI.GameResult.WON;
break;
case "Player PlayerB is the winner":
actual = CardTestAPI.GameResult.LOST;
break;
}
Assert.assertEquals("Game results are not equal", result, actual);
} else if (player.equals(playerB)) {
GameResult actual = CardTestAPI.GameResult.DRAW;
switch (currentGame.getWinner()) {
case "Player PlayerB is the winner":
actual = CardTestAPI.GameResult.WON;
break;
case "Player PlayerA is the winner":
actual = CardTestAPI.GameResult.LOST;
break;
}
Assert.assertEquals("Game results are not equal", result, actual);
}
}
/**
* 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.
*/
@Override
public void assertLife(Player player, int life) throws AssertionError {
int actual = currentGame.getPlayer(player.getId()).getLife();
Assert.assertEquals("Life amounts are not equal for player " + player.getName(), life, actual);
}
/**
* Assert creature's power and toughness by card name.
* <p/>
* Throws {@link AssertionError} in the following cases: 1. no such player
* 2. no such creature under player's control 3. depending on comparison
* scope: 3a. any: no creature under player's control with the specified p\t
* 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 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"
*/
@Override
public void assertPowerToughness(Player player, String cardName, int power, int toughness, Filter.ComparisonScope scope)
throws AssertionError {
int count = 0;
int fit = 0;
int foundPower = 0;
int foundToughness = 0;
int found = 0;
for (Permanent permanent : currentGame.getBattlefield().getAllPermanents()) {
if (permanent.getName().equals(cardName) && permanent.getControllerId().equals(player.getId())) {
count++;
if (scope == Filter.ComparisonScope.All) {
Assert.assertEquals("Power is not the same (" + power + " vs. " + permanent.getPower().getValue() + ')',
power, permanent.getPower().getValue());
Assert.assertEquals("Toughness is not the same (" + toughness + " vs. " + permanent.getToughness().getValue() + ')',
toughness, permanent.getToughness().getValue());
} else if (scope == Filter.ComparisonScope.Any) {
if (power == permanent.getPower().getValue() && toughness == permanent.getToughness().getValue()) {
fit++;
break;
}
found++;
foundPower = permanent.getPower().getValue();
foundToughness = permanent.getToughness().getValue();
}
}
}
Assert.assertTrue("There is no such permanent under player's control, player=" + player.getName()
+ ", cardName=" + cardName, count > 0);
if (scope == Filter.ComparisonScope.Any) {
Assert.assertTrue("There is no such creature under player's control with specified p/t of " + power + '/' + toughness + ", player=" + player.getName()
+ ", cardName=" + cardName + " (found similar: " + found + ", one of them: power=" + foundPower + " toughness=" + foundToughness + ')', fit > 0);
}
}
/**
* See
* {@link #assertPowerToughness(mage.players.Player, String, int, int, mage.filter.Filter.ComparisonScope)}
*
* @param player
* @param cardName
* @param power
* @param toughness
*/
public void assertPowerToughness(Player player, String cardName, int power, int toughness) {
assertPowerToughness(player, cardName, power, toughness, Filter.ComparisonScope.Any);
}
/**
* {@inheritDoc}
*/
@Override
public void assertAbilities(Player player, String cardName, List<Ability> abilities)
throws AssertionError {
int count = 0;
Permanent found = null;
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(player.getId())) {
if (permanent.getName().equals(cardName)) {
found = permanent;
count++;
}
}
Assert.assertNotNull("There is no such permanent under player's control, player=" + player.getName()
+ ", cardName=" + cardName, found);
Assert.assertTrue("There is more than one such permanent under player's control, player=" + player.getName()
+ ", cardName=" + cardName, count == 1);
for (Ability ability : abilities) {
Assert.assertTrue("No such ability=" + ability.toString() + ", player=" + player.getName()
+ ", cardName" + cardName, found.getAbilities().contains(ability));
}
}
public void assertAbility(Player player, String cardName, Ability ability, boolean flag) throws AssertionError {
assertAbility(player, cardName, ability, flag, 1);
}
/**
*
* @param player
* @param cardName
* @param ability
* @param flag true if creature should contain ability, false if it 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 flag, int count) throws AssertionError {
int foundCount = 0;
Permanent found = null;
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(player.getId())) {
if (permanent.getName().equals(cardName)) {
found = permanent;
foundCount++;
}
}
Assert.assertNotNull("There is no such permanent under player's control, player=" + player.getName()
+ ", cardName=" + cardName, found);
Assert.assertTrue("There is another number (" + foundCount + ") as defined (" + count + ") of such permanents under player's control, player=" + player.getName()
+ ", cardName=" + cardName, count == foundCount);
if (flag) {
Assert.assertTrue("No such ability=" + ability.toString() + ", player=" + player.getName()
+ ", cardName" + cardName, found.getAbilities(currentGame).containsRule(ability));
} else {
Assert.assertFalse("Card shouldn't have such ability=" + ability.toString() + ", player=" + player.getName()
+ ", cardName" + cardName, found.getAbilities(currentGame).containsRule(ability));
}
}
/**
* Assert permanent count under player's control.
*
* @param player {@link Player} which permanents should be counted.
* @param count Expected count.
*/
@Override
public void assertPermanentCount(Player player, int count) throws AssertionError {
int actualCount = 0;
for (Permanent permanent : currentGame.getBattlefield().getAllPermanents()) {
if (permanent.getControllerId().equals(player.getId())) {
actualCount++;
}
}
Assert.assertEquals("(Battlefield) Card counts are not equal ", count, actualCount);
}
/**
* Assert permanent count under player's control.
*
* @param player {@link Player} which permanents should be counted.
* @param cardName Name of the cards that should be counted.
* @param count Expected count.
*/
@Override
public void assertPermanentCount(Player player, String cardName, int count) throws AssertionError {
int actualCount = 0;
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) {
if (permanent.getControllerId().equals(player.getId())) {
if (permanent.getName().equals(cardName)) {
actualCount++;
}
}
}
Assert.assertEquals("(Battlefield) Permanents counts for " + player.getName() + " are not equal (" + cardName + ')', count, actualCount);
}
@Override
public void assertCommandZoneCount(Player player, String commandZoneObjectName, int count) throws AssertionError {
int actualCount = 0;
for (CommandObject commandObject : currentGame.getState().getCommand()) {
if (commandObject.getControllerId().equals(player.getId()) && commandObject.getName().equals(commandZoneObjectName)) {
actualCount++;
}
}
Assert.assertEquals("(Command Zone) Card counts are not equal (" + commandZoneObjectName + ')', count, actualCount);
}
/**
* Assert emblem count under player's control
*
* @param player
* @param count
* @throws AssertionError
*/
@Override
public void assertEmblemCount(Player player, int count) throws AssertionError {
int actualCount = 0;
for (CommandObject commandObject : currentGame.getState().getCommand()) {
if (commandObject.getControllerId().equals(player.getId())) {
actualCount++;
}
}
Assert.assertEquals("Emblem counts are not equal", count, actualCount);
}
/**
* 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.
*/
public void assertCounterCount(String cardName, CounterType type, int count) throws AssertionError {
this.assertCounterCount(null, cardName, type, count);
}
public void assertCounterCount(Player player, String cardName, CounterType type, int count) throws AssertionError {
Permanent found = null;
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) {
if (permanent.getName().equals(cardName) && (player == null || permanent.getControllerId().equals(player.getId()))) {
found = permanent;
break;
}
}
Assert.assertNotNull("There is no such permanent " + (player == null ? "" : "for player " + player.getName()) + " on the battlefield, cardName=" + cardName, found);
Assert.assertEquals("(Battlefield) Counter counts are not equal (" + cardName + ':' + type + ')', count, found.getCounters(currentGame).getCount(type));
}
/**
* 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.
*/
public void assertCounterOnExiledCardCount(String cardName, CounterType type, int count) throws AssertionError {
Card found = null;
if (found == null) {
for (Card card : currentGame.getExile().getAllCards(currentGame)) {
if (card.getName().equals(cardName)) {
found = card;
break;
}
}
}
Assert.assertNotNull("There is no such card in the exile, cardName=" + cardName, found);
Assert.assertEquals("(Exile) Counter counts are not equal (" + cardName + ':' + type + ')', count, found.getCounters(currentGame).getCount(type));
}
/**
* 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.
*/
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));
}
/**
* 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 flag true if creature should have type, false if it should not
*/
public void assertType(String cardName, CardType type, boolean flag) throws AssertionError {
Permanent found = null;
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) {
if (permanent.getName().equals(cardName)) {
found = permanent;
break;
}
}
Assert.assertNotNull("There is no such permanent on the battlefield, cardName=" + cardName, found);
Assert.assertTrue("(Battlefield) card type not found (" + cardName + ':' + type + ')', (found.getCardType().contains(type) == flag));
}
/**
* 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
*/
public void assertType(String cardName, CardType type, String subType) throws AssertionError {
Permanent found = getPermanent(cardName);
Assert.assertTrue("(Battlefield) card type not found (" + cardName + ':' + type + ')', found.getCardType().contains(type));
if (subType != null) {
Assert.assertTrue("(Battlefield) card sub-type not equal (" + cardName + ':' + subType + ')', found.getSubtype(currentGame).contains(subType));
}
}
/**
* 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
*/
public void assertNotType(String cardName, CardType type) throws AssertionError {
Permanent found = getPermanent(cardName);
Assert.assertFalse("(Battlefield) card type found (" + cardName + ':' + type + ')', found.getCardType().contains(type));
}
/**
* 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
*/
public void assertNotSubtype(String cardName, String subType) throws AssertionError {
Permanent found = getPermanent(cardName);
if (subType != null) {
Assert.assertFalse("(Battlefield) card sub-type equal (" + cardName + ':' + subType + ')', found.getSubtype(currentGame).contains(subType));
}
}
/**
* 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
*/
public void assertTapped(String cardName, boolean tapped) throws AssertionError {
Permanent found = null;
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) {
if (permanent.getName().equals(cardName)) {
if (found == null) {
found = permanent;
} else if (tapped != found.isTapped()) { // try to find a not correct permanent
found = permanent;
break;
}
}
}
Assert.assertNotNull("There is no such permanent on the battlefield, cardName=" + cardName, found);
Assert.assertEquals("(Battlefield) Tapped state is not equal (" + cardName + ')', tapped, found.isTapped());
}
/**
* 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
*/
public void assertTappedCount(String cardName, boolean tapped, int count) throws AssertionError {
int tappedAmount = 0;
Permanent found = null;
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) {
if (permanent.getName().equals(cardName)) {
if (permanent.isTapped() == tapped) {
tappedAmount++;
}
found = permanent;
}
}
Assert.assertNotNull("There is no such permanent on the battlefield, cardName=" + cardName, found);
Assert.assertEquals("(Battlefield) " + count + " permanents (" + cardName + ") are not " + ((tapped) ? "" : "un") + "tapped.", count, tappedAmount);
}
/**
* Assert whether a permanent is attacking or not
*
* @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 {
Permanent found = null;
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) {
if (permanent.getName().equals(cardName)) {
found = permanent;
}
}
Assert.assertNotNull("There is no such permanent on the battlefield, cardName=" + cardName, found);
Assert.assertEquals("(Battlefield) Attacking state is not equal (" + cardName + ')', attacking, found.isAttacking());
}
/**
* Assert card count in player's hand.
*
* @param player {@link Player} who's hand should be counted.
* @param count Expected count.
*/
public void assertHandCount(Player player, int count) throws AssertionError {
int actual = currentGame.getPlayer(player.getId()).getHand().size();
Assert.assertEquals("(Hand " + player.getName() + ") Card counts are not equal ", count, actual);
}
/**
* Assert card count in player's hand.
*
* @param player {@link Player} who's hand should be counted.
* @param cardName Name of the cards that should be counted.
* @param count Expected count.
*/
public void assertHandCount(Player player, String cardName, int count) throws AssertionError {
int actual;
if (cardName.contains("//")) { // special logic for cheched split cards, because in game logic of card name filtering is different than for test
actual = 0;
for (Card card : currentGame.getPlayer(player.getId()).getHand().getCards(currentGame)) {
if (card.getName().equals(cardName)) {
actual++;
}
}
} else {
FilterCard filter = new FilterCard();
filter.add(new NamePredicate(cardName));
actual = currentGame.getPlayer(player.getId()).getHand().count(filter, player.getId(), currentGame);
}
Assert.assertEquals("(Hand) Card counts for card " + cardName + " for " + player.getName() + " are not equal ", count, actual);
}
/**
* Assert card count in player's graveyard.
*
* @param player {@link Player} who's graveyard should be counted.
* @param count Expected count.
*/
public void assertGraveyardCount(Player player, int count) throws AssertionError {
int actual = currentGame.getPlayer(player.getId()).getGraveyard().size();
Assert.assertEquals("(Graveyard) Card counts are not equal ", count, actual);
}
/**
* Assert card count in exile.
*
* @param cardName Name of the cards that should be counted.
* @param count Expected count.
*/
public void assertExileCount(String cardName, int count) throws AssertionError {
int actualCount = 0;
for (ExileZone exile : currentGame.getExile().getExileZones()) {
for (Card card : exile.getCards(currentGame)) {
if (card.getName().equals(cardName)) {
actualCount++;
}
}
}
Assert.assertEquals("(Exile) Card counts are not equal (" + cardName + ')', count, actualCount);
}
/**
* Assert card count in exile by owner.
*
* @param owner player that owns the cards.
* @param count Expected count.
*/
public void assertExileCount(Player owner, int count) throws AssertionError {
int actualCount = 0;
for (ExileZone exile : currentGame.getExile().getExileZones()) {
for (Card card : exile.getCards(currentGame)) {
if (card.getOwnerId().equals(owner.getId())) {
actualCount++;
}
}
}
Assert.assertEquals("(Exile) Card counts for player " + owner.getName() + " is not equal.", count, actualCount);
}
/**
* Assert card count in player's exile.
*
* @param owner {@link Player} who's exile should be counted.
* @param cardName Name of the cards that should be counted.
* @param count Expected count.
*/
public void assertExileCount(Player owner, String cardName, int count) throws AssertionError {
int actualCount = 0;
for (ExileZone exile : currentGame.getExile().getExileZones()) {
for (Card card : exile.getCards(currentGame)) {
if (card.getOwnerId().equals(owner.getId()) && card.getName().equals(cardName)) {
actualCount++;
}
}
}
Assert.assertEquals("(Exile " + owner.getName() + ") Card counts are not equal (" + cardName + ')', count, actualCount);
}
/**
* Assert card count in player's graveyard.
*
* @param player {@link Player} who's graveyard should be counted.
* @param cardName Name of the cards that should be counted.
* @param count Expected count.
*/
public void assertGraveyardCount(Player player, String cardName, int count) throws AssertionError {
int actualCount = 0;
for (Card card : player.getGraveyard().getCards(currentGame)) {
if (card.getName().equals(cardName)) {
actualCount++;
}
}
Assert.assertEquals("(Graveyard " + player.getName() + ") Card counts are not equal (" + cardName + ')', count, actualCount);
}
/**
* Assert library card count.
*
* @param player {@link Player} who's library should be counted.
* @param count Expected count.
*/
public void assertLibraryCount(Player player, int count) throws AssertionError {
List<Card> libraryList = player.getLibrary().getCards(currentGame);
int actualCount = libraryList != null && !libraryList.isEmpty() ? libraryList.size() : 0;
Assert.assertEquals("(Library " + player.getName() + ") counts are not equal", count, actualCount);
}
/**
* Assert specific card count in player's library.
*
* @param player {@link Player} who's library should be counted.
* @param cardName Name of the cards that should be counted.
* @param count Expected count.
*/
public void assertLibraryCount(Player player, String cardName, int count) throws AssertionError {
int actualCount = 0;
for (Card card : player.getLibrary().getCards(currentGame)) {
if (card.getName().equals(cardName)) {
actualCount++;
}
}
Assert.assertEquals("(Library " + player.getName() + ") Card counts are not equal (" + cardName + ')', count, actualCount);
}
/**
* Asserts added actions count. Useful to make sure that all actions were
* executed.
*
* @param player
* @param count
*/
public void assertActionCount(TestPlayer player, int count) {
Assert.assertEquals("Actions left are not equal: ", count, player.getActionCount());
}
public void assertActivePlayer(TestPlayer player) {
Assert.assertEquals("message", currentGame.getState().getActivePlayerId(), player.getId());
}
public Permanent getPermanent(String cardName, UUID controller) {
Permanent found = null;
Pattern indexedName = Pattern.compile("^([\\w| ]+):(\\d+)$"); // Ends with <:number>
Matcher indexedMatcher = indexedName.matcher(cardName);
int index = 0;
int count = 0;
if(indexedMatcher.matches()) {
cardName = indexedMatcher.group(1);
index = Integer.valueOf(indexedMatcher.group(2));
}
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) {
if (permanent.getName().equals(cardName)) {
if (controller == null || permanent.getControllerId().equals(controller)) {
found = permanent;
if(count != index) {
count++;
}
}
}
}
Assert.assertNotNull("Couldn't find a card with specified name: " + cardName, found);
Assert.assertEquals("Only " + count + " permanents were found and " + cardName + ":" + index + " was requested", index, count);
return found;
}
public Permanent getPermanent(String cardName, Player player) {
return getPermanent(cardName, player.getId());
}
public Permanent getPermanent(String cardName) {
return getPermanent(cardName, (UUID)null);
}
public void playLand(int turnNum, PhaseStep step, TestPlayer player, String cardName) {
player.addAction(turnNum, step, "activate:Play " + cardName);
}
public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName) {
player.addAction(turnNum, step, "activate:Cast " + cardName);
}
public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, Player target) {
player.addAction(turnNum, step, "activate:Cast " + cardName + "$targetPlayer=" + target.getName());
}
public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, Player target, int manaInPool) {
player.addAction(turnNum, step, "activate:Cast " + cardName + "$targetPlayer=" + target.getName() + "$manaInPool=" + manaInPool);
}
/**
* Rollback the number of given turns: 0 = rollback to the start of the
* current turn
*
* @param turnNum
* @param step
* @param player
* @param turns
*/
public void rollbackTurns(int turnNum, PhaseStep step, TestPlayer player, int turns) {
player.addAction(turnNum, step, "playerAction:Rollback" + "$turns=" + turns);
}
/**
*
* @param turnNum
* @param step
* @param player
* @param cardName
* @param targetName for modes you can add "mode=3" before target name,
* multiple targets can be seperated by ^
*/
public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName) {
player.addAction(turnNum, step, "activate:Cast " + cardName + "$target=" + targetName);
}
public enum StackClause {
WHILE_ON_STACK,
WHILE_COPY_ON_STACK,
WHILE_NOT_ON_STACK
}
/**
* Spell will only be cast, if a spell / ability with the given name is on
* the stack
*
* @param turnNum
* @param step
* @param player
* @param cardName
* @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) {
castSpell(turnNum, step, player, cardName, targetName, spellOnStack, StackClause.WHILE_ON_STACK);
}
/**
* Spell will only be cast, if a spell / ability with the given name IS or
* IS NOT on the stack
*
* @param turnNum
* @param step
* @param player
* @param cardName
* @param targetName
* @param spellOnStack
* @param clause
*/
public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName, String spellOnStack, StackClause clause) {
if (StackClause.WHILE_ON_STACK == clause) {
player.addAction(turnNum, step, "activate:Cast " + cardName
+ '$' + (targetName != null && targetName.startsWith("target") ? targetName : "target=" + targetName)
+ "$spellOnStack=" + spellOnStack);
} else {
player.addAction(turnNum, step, "activate:Cast " + cardName
+ '$' + (targetName != null && targetName.startsWith("target") ? targetName : "target=" + targetName)
+ "$!spellOnStack=" + spellOnStack);
}
}
public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName, String spellOnStack, String spellOnTopOfStack) {
String action = "activate:Cast " + cardName + "$target=" + targetName;
if (spellOnStack != null && !spellOnStack.isEmpty()) {
action += "$spellOnStack=" + spellOnStack;
}
if (spellOnTopOfStack != null && !spellOnTopOfStack.isEmpty()) {
action += "$spellOnTopOfStack=" + spellOnTopOfStack;
}
player.addAction(turnNum, step, action);
}
public void activateManaAbility(int turnNum, PhaseStep step, TestPlayer player, String ability) {
player.addAction(turnNum, step, "manaActivate:" + ability);
}
public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability) {
player.addAction(turnNum, step, "activate:" + ability);
}
public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, Player target) {
player.addAction(turnNum, step, "activate:" + ability + "$targetPlayer=" + target.getName());
}
public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String ... targetNames) {
player.addAction(turnNum, step, "activate:" + ability + "$target=" + String.join("^", targetNames));
}
public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String targetName, String spellOnStack) {
this.activateAbility(turnNum, step, player, ability, targetName, spellOnStack, StackClause.WHILE_ON_STACK);
}
/**
*
* @param turnNum
* @param step
* @param player
* @param ability
* @param targetName if not target has to be defined use the constant
* NO_TARGET
* @param spellOnStack
* @param clause
*/
public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String targetName, String spellOnStack, StackClause clause) {
StringBuilder sb = new StringBuilder("activate:").append(ability);
if (targetName != null && !targetName.isEmpty()) {
sb.append("$target=").append(targetName);
}
if (spellOnStack != null && !spellOnStack.isEmpty()) {
sb.append('$');
switch (clause) {
case WHILE_ON_STACK:
sb.append("spellOnStack=");
break;
case WHILE_NOT_ON_STACK:
sb.append("!spellOnStack=");
break;
case WHILE_COPY_ON_STACK:
sb.append("spellCopyOnStack=");
break;
}
sb.append(spellOnStack);
}
player.addAction(turnNum, step, sb.toString());
}
public void addCounters(int turnNum, PhaseStep step, TestPlayer player, String cardName, CounterType type, int count) {
player.addAction(turnNum, step, "addCounters:" + cardName + '$' + type.getName() + '$' + count);
}
public void attack(int turnNum, TestPlayer player, String attacker) {
player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, "attack:" + attacker);
}
public void attack(int turnNum, TestPlayer player, String attacker, TestPlayer defendingPlayer) {
player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, "attack:" + attacker + "$defendingPlayer=" + defendingPlayer.getName());
}
public void attack(int turnNum, TestPlayer player, String attacker, String planeswalker) {
player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, new StringBuilder("attack:").append(attacker).append("$planeswalker=").append(planeswalker).toString());
}
public void block(int turnNum, TestPlayer player, String blocker, String attacker) {
player.addAction(turnNum, PhaseStep.DECLARE_BLOCKERS, "block:" + blocker + '$' + attacker);
}
/**
* For use choices set "Yes" or "No" the the choice string. For X values set
* "X=[xValue]" example: for X=3 set choice string to "X=3".
*
* @param player
* @param choice
*/
public void setChoice(TestPlayer player, String choice) {
player.addChoice(choice);
}
/**
* Set the modes for modal spells
*
* @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).
*/
public void setModeChoice(TestPlayer player, String choice) {
player.addModeChoice(choice);
}
/**
* Set target permanents
*
* @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
*/
public void addTarget(TestPlayer player, String target) {
player.addTarget(target);
}
/**
* Sets a player as target
*
* @param player
* @param targetPlayer
*/
public void addTarget(TestPlayer player, TestPlayer targetPlayer) {
player.addTarget("targetPlayer=" + targetPlayer.getName());
}
public void setDecknamePlayerA(String deckname) {
deckNameA = deckname;
}
public void setDecknamePlayerB(String deckname) {
deckNameB = deckname;
}
public void setDecknamePlayerC(String deckname) {
deckNameC = deckname;
}
public void setDecknamePlayerD(String deckname) {
deckNameD = deckname;
}
protected void skipInitShuffling() {
gameOptions.skipInitShuffling = true;
}
protected void checkPermanentPT(Player player, String cardName, int power, int toughness, Filter.ComparisonScope scope) {
if (currentGame == null) {
throw new IllegalStateException("Current game is null");
}
if (scope == Filter.ComparisonScope.All) {
throw new UnsupportedOperationException("ComparisonScope.All is not implemented.");
}
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(player.getId())) {
if (permanent.getName().equals(cardName)) {
Assert.assertEquals("Power is not the same", power, permanent.getPower().getValue());
Assert.assertEquals("Toughness is not the same", toughness, permanent.getToughness().getValue());
break;
}
}
}
}