mirror of
https://github.com/correl/mage.git
synced 2024-12-24 11:50:45 +00:00
New testing frameworks for cards. BurntheImpure test.
This commit is contained in:
parent
196f7a32d8
commit
99735b368b
25 changed files with 1297 additions and 119 deletions
|
@ -126,7 +126,7 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
|
|||
@Override
|
||||
public boolean chooseMulligan(Game game) {
|
||||
logger.debug("chooseMulligan");
|
||||
if (hand.size() < 6)
|
||||
if (hand.size() < 6 || isTestMode())
|
||||
return false;
|
||||
Set<Card> lands = hand.getCards(new FilterLandCard(), game);
|
||||
if (lands.size() < 2 || lands.size() > hand.size() - 2)
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -5,6 +5,7 @@ import mage.cards.Card;
|
|||
import mage.cards.decks.Deck;
|
||||
import mage.game.Game;
|
||||
import mage.game.GameException;
|
||||
import mage.game.GameOptions;
|
||||
import mage.game.TwoPlayerDuel;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
import mage.players.Player;
|
||||
|
@ -23,18 +24,6 @@ import java.util.regex.Matcher;
|
|||
*/
|
||||
public class PlayGameTest extends MageTestBase {
|
||||
|
||||
private List<Card> handCardsA = new ArrayList<Card>();
|
||||
private List<Card> handCardsB = new ArrayList<Card>();
|
||||
private List<PermanentCard> battlefieldCardsA = new ArrayList<PermanentCard>();
|
||||
private List<PermanentCard> battlefieldCardsB = new ArrayList<PermanentCard>();
|
||||
private List<Card> graveyardCardsA = new ArrayList<Card>();
|
||||
private List<Card> graveyardCardsB = new ArrayList<Card>();
|
||||
private List<Card> libraryCardsA = new ArrayList<Card>();
|
||||
private List<Card> libraryCardsB = new ArrayList<Card>();
|
||||
|
||||
private Map<Constants.Zone, String> commandsA = new HashMap<Constants.Zone, String>();
|
||||
private Map<Constants.Zone, String> commandsB = new HashMap<Constants.Zone, String>();
|
||||
|
||||
@Test
|
||||
public void playOneGame() throws GameException, FileNotFoundException, IllegalArgumentException {
|
||||
Game game = new TwoPlayerDuel(Constants.MultiplayerAttackOption.LEFT, Constants.RangeOfInfluence.ALL);
|
||||
|
@ -68,7 +57,9 @@ public class PlayGameTest extends MageTestBase {
|
|||
boolean testMode = true;
|
||||
|
||||
long t1 = System.nanoTime();
|
||||
game.start(computerA.getId(), testMode);
|
||||
GameOptions options = new GameOptions();
|
||||
options.testMode = true;
|
||||
game.start(computerA.getId(), options);
|
||||
long t2 = System.nanoTime();
|
||||
|
||||
logger.info("Winner: " + game.getWinner());
|
||||
|
@ -77,100 +68,4 @@ public class PlayGameTest extends MageTestBase {
|
|||
throw new RuntimeException("Lost :(");
|
||||
}*/
|
||||
}
|
||||
|
||||
private void addCard(List<Card> cards, String name, int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
Card card = Sets.findCard(name, true);
|
||||
if (card == null) {
|
||||
throw new IllegalArgumentException("Couldn't find a card for test: " + name);
|
||||
}
|
||||
cards.add(card);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseScenario(String filename) throws FileNotFoundException {
|
||||
File f = new File(filename);
|
||||
Scanner scanner = new Scanner(f);
|
||||
try {
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine().trim();
|
||||
if (line == null || line.isEmpty() || line.startsWith("#")) continue;
|
||||
Matcher m = pattern.matcher(line);
|
||||
if (m.matches()) {
|
||||
|
||||
String zone = m.group(1);
|
||||
String nickname = m.group(2);
|
||||
|
||||
if (nickname.equals("ComputerA") || nickname.equals("ComputerB")) {
|
||||
List<Card> cards = null;
|
||||
List<PermanentCard> perms = null;
|
||||
Constants.Zone gameZone;
|
||||
if ("hand".equalsIgnoreCase(zone)) {
|
||||
gameZone = Constants.Zone.HAND;
|
||||
cards = nickname.equals("ComputerA") ? handCardsA : handCardsB;
|
||||
} else if ("battlefield".equalsIgnoreCase(zone)) {
|
||||
gameZone = Constants.Zone.BATTLEFIELD;
|
||||
perms = nickname.equals("ComputerA") ? battlefieldCardsA : battlefieldCardsB;
|
||||
} else if ("graveyard".equalsIgnoreCase(zone)) {
|
||||
gameZone = Constants.Zone.GRAVEYARD;
|
||||
cards = nickname.equals("ComputerA") ? graveyardCardsA : graveyardCardsB;
|
||||
} else if ("library".equalsIgnoreCase(zone)) {
|
||||
gameZone = Constants.Zone.LIBRARY;
|
||||
cards = nickname.equals("ComputerA") ? libraryCardsA : libraryCardsB;
|
||||
} else if ("player".equalsIgnoreCase(zone)) {
|
||||
String command = m.group(3);
|
||||
if ("life".equals(command)) {
|
||||
if (nickname.equals("ComputerA")) {
|
||||
commandsA.put(Constants.Zone.OUTSIDE, "life:" + m.group(4));
|
||||
} else {
|
||||
commandsB.put(Constants.Zone.OUTSIDE, "life:" + m.group(4));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
continue; // go parse next line
|
||||
}
|
||||
|
||||
String cardName = m.group(3);
|
||||
Integer amount = Integer.parseInt(m.group(4));
|
||||
boolean tapped = m.group(5) != null && m.group(5).equals(":{tapped}");
|
||||
|
||||
if (cardName.equals("clear")) {
|
||||
if (nickname.equals("ComputerA")) {
|
||||
commandsA.put(gameZone, "clear");
|
||||
} else {
|
||||
commandsB.put(gameZone, "clear");
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < amount; i++) {
|
||||
Card card = Sets.findCard(cardName, true);
|
||||
if (card != null) {
|
||||
if (gameZone.equals(Constants.Zone.BATTLEFIELD)) {
|
||||
PermanentCard p = new PermanentCard(card, null);
|
||||
p.setTapped(tapped);
|
||||
perms.add(p);
|
||||
} else {
|
||||
cards.add(card);
|
||||
}
|
||||
} else {
|
||||
logger.fatal("Couldn't find a card: " + cardName);
|
||||
logger.fatal("line: " + line);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.warn("Unknown player: " + nickname);
|
||||
}
|
||||
} else {
|
||||
logger.warn("Init string wasn't parsed: " + line);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
scanner.close();
|
||||
}
|
||||
}
|
||||
|
||||
private Player createPlayer(String name, String playerType) {
|
||||
return PlayerFactory.getInstance().createPlayer(playerType, name, Constants.RangeOfInfluence.ALL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
package org.mage.test.serverside.base;
|
||||
|
||||
import mage.Constants;
|
||||
import mage.filter.Filter;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
* Interface for all test initialization and assertion operations.
|
||||
*/
|
||||
public interface CardTestAPI {
|
||||
|
||||
/**
|
||||
* Types of game result.
|
||||
*/
|
||||
public enum GameResult {
|
||||
WON,
|
||||
LOST,
|
||||
DRAW
|
||||
}
|
||||
|
||||
//******* INITIALIZATION METHODS *******/
|
||||
|
||||
/**
|
||||
* Default game initialization params for red player (that plays with Mountains)
|
||||
*/
|
||||
void useRedDefault();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void removeAllCardsFromLibrary(Player player);
|
||||
|
||||
/**
|
||||
* Add a card to specified zone of specified player.
|
||||
*
|
||||
* @param gameZone {@link Constants.Zone} to add cards to.
|
||||
* @param player {@link Player} to add cards for. Use either computerA or computerB.
|
||||
* @param cardName Card name in string format.
|
||||
*/
|
||||
void addCard(Constants.Zone gameZone, Player player, String cardName);
|
||||
|
||||
/**
|
||||
* Add any amount of cards to specified zone of specified player.
|
||||
*
|
||||
* @param gameZone {@link Constants.Zone} to add cards to.
|
||||
* @param player {@link Player} to add cards for. Use either computerA or computerB.
|
||||
* @param cardName Card name in string format.
|
||||
* @param count Amount of cards to be added.
|
||||
*/
|
||||
void addCard(Constants.Zone gameZone, Player player, String cardName, int count);
|
||||
|
||||
/**
|
||||
* Add any amount of cards to specified zone of specified player.
|
||||
*
|
||||
* @param gameZone {@link Constants.Zone} to add cards to.
|
||||
* @param player {@link Player} to add cards for. Use either computerA or computerB.
|
||||
* @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
|
||||
*/
|
||||
void addCard(Constants.Zone gameZone, Player player, String cardName, int count, boolean tapped);
|
||||
|
||||
/**
|
||||
* Set player's initial life count.
|
||||
*
|
||||
* @param player {@link Player} to set life count for.
|
||||
* @param life Life count to set.
|
||||
*/
|
||||
void setLife(Player player, int life);
|
||||
|
||||
//******* GAME OPTIONS *******/
|
||||
|
||||
/**
|
||||
* Define turn number to stop the game on.
|
||||
*/
|
||||
void setStopOnTurn(int turn);
|
||||
|
||||
//******* ASSERT METHODS *******/
|
||||
|
||||
/**
|
||||
* Assert turn number after test execution.
|
||||
*
|
||||
* @param turn Expected turn number to compare with.
|
||||
*/
|
||||
void assertTurn(int turn) throws AssertionError;
|
||||
|
||||
/**
|
||||
* Assert game result for the player after test execution.
|
||||
*
|
||||
* @param player {@link Player} to get game result for.
|
||||
* @param result Expected {@link GameResult} to compare with.
|
||||
*/
|
||||
void assertResult(Player player, GameResult result) throws AssertionError;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void assertLife(Player player, int life) throws AssertionError;
|
||||
|
||||
/**
|
||||
* 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 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"
|
||||
*/
|
||||
void assertPowerToughness(Player player, String cardName, int power, int toughness, Filter.ComparisonScope scope)
|
||||
throws AssertionError;
|
||||
|
||||
/**
|
||||
* Assert permanent count under player's control.
|
||||
*
|
||||
* @param player {@link Player} which permanents should be counted.
|
||||
* @param count Expected count.
|
||||
*/
|
||||
void assertPermanentCount(Player player, int count) throws AssertionError;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void assertPermanentCount(Player player, String cardName, int count) throws AssertionError;
|
||||
}
|
|
@ -0,0 +1,335 @@
|
|||
package org.mage.test.serverside.base;
|
||||
|
||||
import mage.Constants;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.filter.Filter;
|
||||
import mage.game.Game;
|
||||
import mage.game.GameException;
|
||||
import mage.game.GameOptions;
|
||||
import mage.game.TwoPlayerDuel;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.sets.Sets;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.mage.test.serverside.base.impl.CardTestAPIImpl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
/**
|
||||
* Base class for testing single cards and effects.
|
||||
*
|
||||
* @author ayratn
|
||||
*/
|
||||
public abstract class CardTestBase extends CardTestAPIImpl {
|
||||
|
||||
protected enum AIType {
|
||||
MinimaxHybrid,
|
||||
MAD
|
||||
}
|
||||
|
||||
protected enum ExpectedType {
|
||||
TURN_NUMBER,
|
||||
RESULT,
|
||||
LIFE,
|
||||
BATTLEFIELD,
|
||||
GRAVEYARD,
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
/**
|
||||
* Computer types used to test cards.
|
||||
* By default: MAD.
|
||||
*/
|
||||
private AIType aiTypeA, aiTypeB;
|
||||
|
||||
public CardTestBase() {
|
||||
aiTypeA = CardTestBase.AIType.MAD;
|
||||
aiTypeB = CardTestBase.AIType.MAD;
|
||||
}
|
||||
|
||||
public CardTestBase(AIType aiTypeA, AIType aiTypeB) {
|
||||
this.aiTypeA = aiTypeA;
|
||||
this.aiTypeB = aiTypeB;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void reset() throws GameException, FileNotFoundException {
|
||||
if (currentGame != null) {
|
||||
logger.info("Resetting previous game and creating new one!");
|
||||
currentGame = null;
|
||||
System.gc();
|
||||
}
|
||||
|
||||
Game game = new TwoPlayerDuel(Constants.MultiplayerAttackOption.LEFT, Constants.RangeOfInfluence.ALL);
|
||||
|
||||
computerA = aiTypeA.equals(CardTestBase.AIType.MinimaxHybrid) ?
|
||||
createPlayer("ComputerA", "Computer - minimax hybrid") :
|
||||
createPlayer("ComputerA", "Computer - mad");
|
||||
computerA.setTestMode(true);
|
||||
Deck deck = Deck.load(Sets.loadDeck("RB Aggro.dck"));
|
||||
if (deck.getCards().size() < 40) {
|
||||
throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck.getCards().size());
|
||||
}
|
||||
game.addPlayer(computerA, deck);
|
||||
game.loadCards(deck.getCards(), computerA.getId());
|
||||
|
||||
computerB = aiTypeB.equals(CardTestBase.AIType.MinimaxHybrid) ?
|
||||
createPlayer("ComputerB", "Computer - minimax hybrid") :
|
||||
createPlayer("ComputerB", "Computer - mad");
|
||||
computerB.setTestMode(true);
|
||||
Deck deck2 = Deck.load(Sets.loadDeck("RB Aggro.dck"));
|
||||
if (deck2.getCards().size() < 40) {
|
||||
throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck2.getCards().size());
|
||||
}
|
||||
game.addPlayer(computerB, deck2);
|
||||
game.loadCards(deck2.getCards(), computerB.getId());
|
||||
activePlayer = computerA;
|
||||
currentGame = game;
|
||||
|
||||
stopOnTurn = null;
|
||||
handCardsA.clear();
|
||||
handCardsB.clear();
|
||||
battlefieldCardsA.clear();
|
||||
battlefieldCardsB.clear();
|
||||
graveyardCardsA.clear();
|
||||
graveyardCardsB.clear();
|
||||
libraryCardsA.clear();
|
||||
libraryCardsB.clear();
|
||||
commandsA.clear();
|
||||
commandsB.clear();
|
||||
}
|
||||
|
||||
public void load(String path) throws FileNotFoundException, GameException {
|
||||
load(path, AIType.MAD, AIType.MAD);
|
||||
}
|
||||
|
||||
public void load(String path, AIType aiTypeA, AIType aiTypeB) throws FileNotFoundException, GameException {
|
||||
String cardPath = TESTS_PATH + path;
|
||||
File checkFile = new File(cardPath);
|
||||
if (!checkFile.exists()) {
|
||||
throw new FileNotFoundException("Couldn't find test file: " + cardPath);
|
||||
}
|
||||
if (checkFile.isDirectory()) {
|
||||
throw new FileNotFoundException("Couldn't find test file: " + cardPath + ". It is directory.");
|
||||
}
|
||||
|
||||
if (currentGame != null) {
|
||||
logger.info("Resetting previous game and creating new one!");
|
||||
currentGame = null;
|
||||
System.gc();
|
||||
}
|
||||
|
||||
Game game = new TwoPlayerDuel(Constants.MultiplayerAttackOption.LEFT, Constants.RangeOfInfluence.ALL);
|
||||
|
||||
computerA = aiTypeA.equals(CardTestBase.AIType.MinimaxHybrid) ?
|
||||
createPlayer("ComputerA", "Computer - minimax hybrid") :
|
||||
createPlayer("ComputerA", "Computer - mad");
|
||||
computerA.setTestMode(true);
|
||||
|
||||
Deck deck = Deck.load(Sets.loadDeck("RB Aggro.dck"));
|
||||
|
||||
if (deck.getCards().size() < 40) {
|
||||
throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck.getCards().size());
|
||||
}
|
||||
game.addPlayer(computerA, deck);
|
||||
game.loadCards(deck.getCards(), computerA.getId());
|
||||
|
||||
computerB = aiTypeB.equals(CardTestBase.AIType.MinimaxHybrid) ?
|
||||
createPlayer("ComputerB", "Computer - minimax hybrid") :
|
||||
createPlayer("ComputerB", "Computer - mad");
|
||||
computerB.setTestMode(true);
|
||||
Deck deck2 = Deck.load(Sets.loadDeck("RB Aggro.dck"));
|
||||
if (deck2.getCards().size() < 40) {
|
||||
throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck2.getCards().size());
|
||||
}
|
||||
game.addPlayer(computerB, deck2);
|
||||
game.loadCards(deck2.getCards(), computerB.getId());
|
||||
|
||||
parseScenario(cardPath);
|
||||
|
||||
activePlayer = computerA;
|
||||
currentGame = game;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts testing card by starting current game.
|
||||
*
|
||||
* @throws IllegalStateException In case game wasn't created previously. Use {@link #load} method to initialize the game.
|
||||
*/
|
||||
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.");
|
||||
}
|
||||
|
||||
currentGame.cheat(computerA.getId(), commandsA);
|
||||
currentGame.cheat(computerA.getId(), libraryCardsA, handCardsA, battlefieldCardsA, graveyardCardsA);
|
||||
currentGame.cheat(computerB.getId(), commandsB);
|
||||
currentGame.cheat(computerB.getId(), libraryCardsB, handCardsB, battlefieldCardsB, graveyardCardsB);
|
||||
|
||||
boolean testMode = true;
|
||||
long t1 = System.nanoTime();
|
||||
GameOptions gameOptions = new GameOptions();
|
||||
gameOptions.testMode = true;
|
||||
gameOptions.stopOnTurn = stopOnTurn;
|
||||
currentGame.start(activePlayer.getId(), gameOptions);
|
||||
long t2 = System.nanoTime();
|
||||
logger.info("Winner: " + currentGame.getWinner());
|
||||
logger.info("Time: " + (t2 - t1) / 1000000 + " ms");
|
||||
|
||||
assertTheResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert expected and actual results.
|
||||
*/
|
||||
private void assertTheResults() {
|
||||
logger.info("Matching expected results:");
|
||||
for (String line : expectedResults) {
|
||||
boolean ok = false;
|
||||
try {
|
||||
ExpectedType type = getExpectedType(line);
|
||||
if (type.equals(CardTestBase.ExpectedType.UNKNOWN)) {
|
||||
throw new AssertionError("Unknown expected type, check the line in $expected section=" + line);
|
||||
}
|
||||
parseType(type, line);
|
||||
ok = true;
|
||||
} finally {
|
||||
logger.info(" " + line + " - " + (ok ? "OK" : "ERROR"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ExpectedType getExpectedType(String line) {
|
||||
if (line.startsWith("turn:")) {
|
||||
return CardTestBase.ExpectedType.TURN_NUMBER;
|
||||
}
|
||||
if (line.startsWith("result:")) {
|
||||
return CardTestBase.ExpectedType.RESULT;
|
||||
}
|
||||
if (line.startsWith("life:")) {
|
||||
return CardTestBase.ExpectedType.LIFE;
|
||||
}
|
||||
if (line.startsWith("battlefield:")) {
|
||||
return CardTestBase.ExpectedType.BATTLEFIELD;
|
||||
}
|
||||
if (line.startsWith("graveyard:")) {
|
||||
return CardTestBase.ExpectedType.GRAVEYARD;
|
||||
}
|
||||
return CardTestBase.ExpectedType.UNKNOWN;
|
||||
}
|
||||
|
||||
private void parseType(ExpectedType type, String line) {
|
||||
if (type.equals(CardTestBase.ExpectedType.TURN_NUMBER)) {
|
||||
int turn = getIntParam(line, 1);
|
||||
Assert.assertEquals("Turn numbers are not equal", turn, currentGame.getTurnNum());
|
||||
return;
|
||||
}
|
||||
if (type.equals(CardTestBase.ExpectedType.RESULT)) {
|
||||
String expected = getStringParam(line, 1);
|
||||
String actual = "draw";
|
||||
if (currentGame.getWinner().equals("Player ComputerA is the winner")) {
|
||||
actual = "won";
|
||||
} else if (currentGame.getWinner().equals("Player ComputerB is the winner")) {
|
||||
actual = "lost";
|
||||
}
|
||||
Assert.assertEquals("Game results are not equal", expected, actual);
|
||||
return;
|
||||
}
|
||||
if (type.equals(CardTestBase.ExpectedType.LIFE)) {
|
||||
String player = getStringParam(line, 1);
|
||||
int expected = getIntParam(line, 2);
|
||||
if (player.equals("ComputerA")) {
|
||||
int actual = currentGame.getPlayer(computerA.getId()).getLife();
|
||||
Assert.assertEquals("Life amounts are not equal", expected, actual);
|
||||
} else if (player.equals("ComputerB")) {
|
||||
int actual = currentGame.getPlayer(computerB.getId()).getLife();
|
||||
Assert.assertEquals("Life amounts are not equal", expected, actual);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Wrong player in 'life' line, player=" + player + ", line=" + line);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (type.equals(CardTestBase.ExpectedType.BATTLEFIELD)) {
|
||||
String playerName = getStringParam(line, 1);
|
||||
String cardName = getStringParam(line, 2);
|
||||
int expectedCount = getIntParam(line, 3);
|
||||
Player player = null;
|
||||
if (playerName.equals("ComputerA")) {
|
||||
player = currentGame.getPlayer(computerA.getId());
|
||||
} else if (playerName.equals("ComputerB")) {
|
||||
player = currentGame.getPlayer(computerB.getId());
|
||||
} else {
|
||||
throw new IllegalArgumentException("Wrong player in 'battlefield' line, player=" + player + ", line=" + line);
|
||||
}
|
||||
int actualCount = 0;
|
||||
for (Permanent permanent : currentGame.getBattlefield().getAllPermanents()) {
|
||||
if (permanent.getControllerId().equals(player.getId())) {
|
||||
if (permanent.getName().equals(cardName)) {
|
||||
actualCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
Assert.assertEquals("(Battlefield) Card counts are not equal (" + cardName + ")", expectedCount, actualCount);
|
||||
return;
|
||||
}
|
||||
if (type.equals(CardTestBase.ExpectedType.GRAVEYARD)) {
|
||||
String playerName = getStringParam(line, 1);
|
||||
String cardName = getStringParam(line, 2);
|
||||
int expectedCount = getIntParam(line, 3);
|
||||
Player player = null;
|
||||
if (playerName.equals("ComputerA")) {
|
||||
player = currentGame.getPlayer(computerA.getId());
|
||||
} else if (playerName.equals("ComputerB")) {
|
||||
player = currentGame.getPlayer(computerB.getId());
|
||||
} else {
|
||||
throw new IllegalArgumentException("Wrong player in 'graveyard' line, player=" + player + ", line=" + line);
|
||||
}
|
||||
int actualCount = 0;
|
||||
for (Card card : player.getGraveyard().getCards(currentGame)) {
|
||||
if (card.getName().equals(cardName)) {
|
||||
actualCount++;
|
||||
}
|
||||
}
|
||||
Assert.assertEquals("(Graveyard) Card counts are not equal (" + cardName + ")", expectedCount, actualCount);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private int getIntParam(String line, int index) {
|
||||
String[] params = line.split(":");
|
||||
if (index > params.length - 1) {
|
||||
throw new IllegalArgumentException("Not correct line: " + line);
|
||||
}
|
||||
return Integer.parseInt(params[index]);
|
||||
}
|
||||
|
||||
private String getStringParam(String line, int index) {
|
||||
String[] params = line.split(":");
|
||||
if (index > params.length - 1) {
|
||||
throw new IllegalArgumentException("Not correct line: " + line);
|
||||
}
|
||||
return params[index];
|
||||
}
|
||||
|
||||
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.equals(Filter.ComparisonScope.All)) {
|
||||
throw new UnsupportedOperationException("ComparisonScope.All is not implemented.");
|
||||
}
|
||||
int count = 0;
|
||||
int fit = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,12 @@
|
|||
package org.mage.test.serverside.base;
|
||||
|
||||
import mage.Constants;
|
||||
import mage.cards.Card;
|
||||
import mage.game.Game;
|
||||
import mage.game.match.MatchType;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
import mage.game.tournament.TournamentType;
|
||||
import mage.players.Player;
|
||||
import mage.server.game.DeckValidatorFactory;
|
||||
import mage.server.game.GameFactory;
|
||||
import mage.server.game.PlayerFactory;
|
||||
|
@ -10,19 +15,25 @@ import mage.server.util.ConfigSettings;
|
|||
import mage.server.util.PluginClassLoader;
|
||||
import mage.server.util.config.GamePlugin;
|
||||
import mage.server.util.config.Plugin;
|
||||
import mage.sets.Sets;
|
||||
import mage.util.Copier;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FilenameFilter;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.Logger;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Base class for all tests.
|
||||
*
|
||||
* @author ayratn
|
||||
*/
|
||||
public class MageTestBase {
|
||||
public abstract class MageTestBase {
|
||||
protected static Logger logger = Logger.getLogger(MageTestBase.class);
|
||||
|
||||
public static PluginClassLoader classLoader = new PluginClassLoader();
|
||||
|
@ -31,6 +42,58 @@ public class MageTestBase {
|
|||
|
||||
protected Pattern pattern = Pattern.compile("([a-zA-Z]*):([\\w]*):([a-zA-Z ,\\-.!'\\d]*):([\\d]*)(:\\{tapped\\})?");
|
||||
|
||||
protected List<Card> handCardsA = new ArrayList<Card>();
|
||||
protected List<Card> handCardsB = new ArrayList<Card>();
|
||||
protected List<PermanentCard> battlefieldCardsA = new ArrayList<PermanentCard>();
|
||||
protected List<PermanentCard> battlefieldCardsB = new ArrayList<PermanentCard>();
|
||||
protected List<Card> graveyardCardsA = new ArrayList<Card>();
|
||||
protected List<Card> graveyardCardsB = new ArrayList<Card>();
|
||||
protected List<Card> libraryCardsA = new ArrayList<Card>();
|
||||
protected List<Card> libraryCardsB = new ArrayList<Card>();
|
||||
|
||||
protected Map<Constants.Zone, String> commandsA = new HashMap<Constants.Zone, String>();
|
||||
protected Map<Constants.Zone, String> commandsB = new HashMap<Constants.Zone, String>();
|
||||
|
||||
protected Player computerA;
|
||||
protected Player computerB;
|
||||
|
||||
/**
|
||||
* Game instance initialized in load method.
|
||||
*/
|
||||
protected static Game currentGame = null;
|
||||
|
||||
/**
|
||||
* Player thats starts the game first.
|
||||
* By default, it is ComputerA.
|
||||
*/
|
||||
protected static Player activePlayer = null;
|
||||
|
||||
protected Integer stopOnTurn;
|
||||
|
||||
protected enum ParserState {
|
||||
INIT,
|
||||
OPTIONS,
|
||||
EXPECTED
|
||||
}
|
||||
|
||||
protected ParserState parserState;
|
||||
|
||||
/**
|
||||
* Expected results of the test.
|
||||
* Read from test case in {@link String} based format:
|
||||
* <p/>
|
||||
* Example:
|
||||
* turn:1
|
||||
* result:won:ComputerA
|
||||
* life:ComputerA:20
|
||||
* life:ComputerB:0
|
||||
* battlefield:ComputerB:Tine Shrike:0
|
||||
* graveyard:ComputerB:Tine Shrike:1
|
||||
*/
|
||||
protected List<String> expectedResults = new ArrayList<String>();
|
||||
|
||||
protected static final String TESTS_PATH = "tests" + File.separator;
|
||||
|
||||
@BeforeClass
|
||||
public static void init() {
|
||||
Logger.getRootLogger().setLevel(Level.DEBUG);
|
||||
|
@ -108,4 +171,128 @@ public class MageTestBase {
|
|||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseScenario(String filename) throws FileNotFoundException {
|
||||
parserState = ParserState.INIT;
|
||||
File f = new File(filename);
|
||||
Scanner scanner = new Scanner(f);
|
||||
try {
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine().trim();
|
||||
if (line == null || line.isEmpty() || line.startsWith("#")) continue;
|
||||
if (line.startsWith("$include")) {
|
||||
includeFrom(line);
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("$expected")) {
|
||||
parserState = ParserState.EXPECTED;
|
||||
continue;
|
||||
}
|
||||
parseLine(line);
|
||||
}
|
||||
} finally {
|
||||
scanner.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void parseLine(String line) {
|
||||
if (parserState.equals(ParserState.EXPECTED)) {
|
||||
expectedResults.add(line); // just remember for future use
|
||||
return;
|
||||
}
|
||||
|
||||
Matcher m = pattern.matcher(line);
|
||||
if (m.matches()) {
|
||||
|
||||
String zone = m.group(1);
|
||||
String nickname = m.group(2);
|
||||
|
||||
if (nickname.equals("ComputerA") || nickname.equals("ComputerB")) {
|
||||
List<Card> cards = null;
|
||||
List<PermanentCard> perms = null;
|
||||
Constants.Zone gameZone;
|
||||
if ("hand".equalsIgnoreCase(zone)) {
|
||||
gameZone = Constants.Zone.HAND;
|
||||
cards = nickname.equals("ComputerA") ? handCardsA : handCardsB;
|
||||
} else if ("battlefield".equalsIgnoreCase(zone)) {
|
||||
gameZone = Constants.Zone.BATTLEFIELD;
|
||||
perms = nickname.equals("ComputerA") ? battlefieldCardsA : battlefieldCardsB;
|
||||
} else if ("graveyard".equalsIgnoreCase(zone)) {
|
||||
gameZone = Constants.Zone.GRAVEYARD;
|
||||
cards = nickname.equals("ComputerA") ? graveyardCardsA : graveyardCardsB;
|
||||
} else if ("library".equalsIgnoreCase(zone)) {
|
||||
gameZone = Constants.Zone.LIBRARY;
|
||||
cards = nickname.equals("ComputerA") ? libraryCardsA : libraryCardsB;
|
||||
} else if ("player".equalsIgnoreCase(zone)) {
|
||||
String command = m.group(3);
|
||||
if ("life".equals(command)) {
|
||||
if (nickname.equals("ComputerA")) {
|
||||
commandsA.put(Constants.Zone.OUTSIDE, "life:" + m.group(4));
|
||||
} else {
|
||||
commandsB.put(Constants.Zone.OUTSIDE, "life:" + m.group(4));
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
return; // go parse next line
|
||||
}
|
||||
|
||||
String cardName = m.group(3);
|
||||
Integer amount = Integer.parseInt(m.group(4));
|
||||
boolean tapped = m.group(5) != null && m.group(5).equals(":{tapped}");
|
||||
|
||||
if (cardName.equals("clear")) {
|
||||
if (nickname.equals("ComputerA")) {
|
||||
commandsA.put(gameZone, "clear");
|
||||
} else {
|
||||
commandsB.put(gameZone, "clear");
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < amount; i++) {
|
||||
Card card = Sets.findCard(cardName, true);
|
||||
if (card != null) {
|
||||
if (gameZone.equals(Constants.Zone.BATTLEFIELD)) {
|
||||
PermanentCard p = new PermanentCard(card, null);
|
||||
p.setTapped(tapped);
|
||||
perms.add(p);
|
||||
} else {
|
||||
cards.add(card);
|
||||
}
|
||||
} else {
|
||||
logger.fatal("Couldn't find a card: " + cardName);
|
||||
logger.fatal("line: " + line);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.warn("Unknown player: " + nickname);
|
||||
}
|
||||
} else {
|
||||
logger.warn("Init string wasn't parsed: " + line);
|
||||
}
|
||||
}
|
||||
|
||||
private void includeFrom(String line) throws FileNotFoundException {
|
||||
String[] params = line.split(" ");
|
||||
if (params.length == 2) {
|
||||
String paramName = params[1];
|
||||
if (!paramName.contains("..")) {
|
||||
String includePath = TESTS_PATH + paramName;
|
||||
File f = new File(includePath);
|
||||
if (f.exists()) {
|
||||
parseScenario(includePath);
|
||||
} else {
|
||||
logger.warn("Ignored (file doesn't exist): " + line);
|
||||
}
|
||||
} else {
|
||||
logger.warn("Ignored (wrong charactres): " + line);
|
||||
}
|
||||
} else {
|
||||
logger.warn("Ignored (wrong size): " + line);
|
||||
}
|
||||
}
|
||||
|
||||
protected Player createPlayer(String name, String playerType) {
|
||||
return PlayerFactory.getInstance().createPlayer(playerType, name, Constants.RangeOfInfluence.ALL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,296 @@
|
|||
package org.mage.test.serverside.base.impl;
|
||||
|
||||
import mage.Constants;
|
||||
import mage.cards.Card;
|
||||
import mage.filter.Filter;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
import mage.players.Player;
|
||||
import mage.sets.Sets;
|
||||
import org.junit.Assert;
|
||||
import org.mage.test.serverside.base.CardTestAPI;
|
||||
import org.mage.test.serverside.base.MageTestBase;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* API for test initialization and asserting the test results.
|
||||
*
|
||||
* @author ayratn
|
||||
*/
|
||||
public abstract class CardTestAPIImpl extends MageTestBase implements CardTestAPI {
|
||||
|
||||
/**
|
||||
* Default game initialization params for red player (that plays with Mountains)
|
||||
*/
|
||||
public void useRedDefault() {
|
||||
// *** ComputerA ***
|
||||
// battlefield:ComputerA:Mountain:5
|
||||
addCard(Constants.Zone.BATTLEFIELD, computerA, "Mountain", 5);
|
||||
// hand:ComputerA:Mountain:4
|
||||
addCard(Constants.Zone.HAND, computerA, "Mountain", 5);
|
||||
// library:ComputerA:clear:0
|
||||
removeAllCardsFromLibrary(computerA);
|
||||
// library:ComputerA:Mountain:10
|
||||
addCard(Constants.Zone.LIBRARY, computerA, "Mountain", 10);
|
||||
|
||||
// *** ComputerB ***
|
||||
// battlefield:ComputerB:Plains:2
|
||||
addCard(Constants.Zone.BATTLEFIELD, computerB, "Plains", 2);
|
||||
// hand:ComputerB:Plains:2
|
||||
addCard(Constants.Zone.HAND, computerB, "Plains", 2);
|
||||
// library:ComputerB:clear:0
|
||||
removeAllCardsFromLibrary(computerB);
|
||||
// library:ComputerB:Plains:10
|
||||
addCard(Constants.Zone.LIBRARY, computerB, "Plains", 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public void removeAllCardsFromLibrary(Player player) {
|
||||
if (player.equals(computerA)) {
|
||||
commandsA.put(Constants.Zone.LIBRARY, "clear");
|
||||
} else if (player.equals(computerB)) {
|
||||
commandsB.put(Constants.Zone.LIBRARY, "clear");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a card to specified zone of specified player.
|
||||
*
|
||||
* @param gameZone {@link Constants.Zone} to add cards to.
|
||||
* @param player {@link Player} to add cards for. Use either computerA or computerB.
|
||||
* @param cardName Card name in string format.
|
||||
*/
|
||||
public void addCard(Constants.Zone gameZone, Player player, String cardName) {
|
||||
addCard(gameZone, player, cardName, 1, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any amount of cards to specified zone of specified player.
|
||||
*
|
||||
* @param gameZone {@link Constants.Zone} to add cards to.
|
||||
* @param player {@link Player} to add cards for. Use either computerA or computerB.
|
||||
* @param cardName Card name in string format.
|
||||
* @param count Amount of cards to be added.
|
||||
*/
|
||||
public void addCard(Constants.Zone gameZone, Player 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 Constants.Zone} to add cards to.
|
||||
* @param player {@link Player} to add cards for. Use either computerA or computerB.
|
||||
* @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
|
||||
*/
|
||||
public void addCard(Constants.Zone gameZone, Player player, String cardName, int count, boolean tapped) {
|
||||
|
||||
|
||||
if (gameZone.equals(Constants.Zone.BATTLEFIELD)) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
Card card = Sets.findCard(cardName, true);
|
||||
PermanentCard p = new PermanentCard(card, null);
|
||||
p.setTapped(tapped);
|
||||
if (player.equals(computerA)) {
|
||||
battlefieldCardsA.add(p);
|
||||
} else if (player.equals(computerB)) {
|
||||
battlefieldCardsB.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++) {
|
||||
Card card = Sets.findCard(cardName, true);
|
||||
cards.add(card);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns card list containter for specified game zone and player.
|
||||
*
|
||||
* @param gameZone
|
||||
* @param player
|
||||
* @return
|
||||
*/
|
||||
private List<Card> getCardList(Constants.Zone gameZone, Player player) {
|
||||
if (player.equals(computerA)) {
|
||||
if (gameZone.equals(Constants.Zone.HAND)) {
|
||||
return handCardsA;
|
||||
} else if (gameZone.equals(Constants.Zone.GRAVEYARD)) {
|
||||
return graveyardCardsA;
|
||||
} else if (gameZone.equals(Constants.Zone.LIBRARY)) {
|
||||
return libraryCardsA;
|
||||
}
|
||||
} else if (player.equals(computerB)) {
|
||||
if (gameZone.equals(Constants.Zone.HAND)) {
|
||||
return handCardsB;
|
||||
} else if (gameZone.equals(Constants.Zone.GRAVEYARD)) {
|
||||
return graveyardCardsB;
|
||||
} else if (gameZone.equals(Constants.Zone.LIBRARY)) {
|
||||
return libraryCardsB;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set player's initial life count.
|
||||
*
|
||||
* @param player {@link Player} to set life count for.
|
||||
* @param life Life count to set.
|
||||
*/
|
||||
public void setLife(Player player, int life) {
|
||||
if (player.equals(computerA)) {
|
||||
commandsA.put(Constants.Zone.OUTSIDE, "life:" + String.valueOf(life));
|
||||
} else if (player.equals(computerB)) {
|
||||
commandsB.put(Constants.Zone.OUTSIDE, "life:" + String.valueOf(life));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Define turn number to stop the game on.
|
||||
*/
|
||||
public void setStopOnTurn(int turn) {
|
||||
stopOnTurn = turn == -1 ? null : Integer.valueOf(turn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert turn number after test execution.
|
||||
*
|
||||
* @param turn Expected turn number to compare with. 1-based.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public void assertResult(Player player, GameResult result) throws AssertionError {
|
||||
if (player.equals(computerA)) {
|
||||
GameResult actual = CardTestAPI.GameResult.DRAW;
|
||||
if (currentGame.getWinner().equals("Player ComputerA is the winner")) {
|
||||
actual = CardTestAPI.GameResult.WON;
|
||||
} else if (currentGame.getWinner().equals("Player ComputerB is the winner")) {
|
||||
actual = CardTestAPI.GameResult.LOST;
|
||||
}
|
||||
Assert.assertEquals("Game results are not equal", result, actual);
|
||||
} else if (player.equals(computerB)) {
|
||||
GameResult actual = CardTestAPI.GameResult.DRAW;
|
||||
if (currentGame.getWinner().equals("Player ComputerB is the winner")) {
|
||||
actual = CardTestAPI.GameResult.WON;
|
||||
} else if (currentGame.getWinner().equals("Player ComputerA is the winner")) {
|
||||
actual = CardTestAPI.GameResult.LOST;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
public void assertLife(Player player, int life) throws AssertionError {
|
||||
int actual = currentGame.getPlayer(player.getId()).getLife();
|
||||
Assert.assertEquals("Life amounts are not equal", 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"
|
||||
*/
|
||||
public void assertPowerToughness(Player player, String cardName, int power, int toughness, Filter.ComparisonScope scope)
|
||||
throws AssertionError {
|
||||
int count = 0;
|
||||
int fit = 0;
|
||||
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(player.getId())) {
|
||||
if (permanent.getName().equals(cardName)) {
|
||||
count++;
|
||||
if (scope.equals(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.equals(Filter.ComparisonScope.Any)) {
|
||||
if (power == permanent.getPower().getValue() && toughness == permanent.getToughness().getValue()) {
|
||||
fit++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Assert.assertTrue("There is no such permanent under player's control, player=" + player.getName() +
|
||||
", cardName=" + cardName, count > 0);
|
||||
|
||||
if (scope.equals(Filter.ComparisonScope.Any)) {
|
||||
Assert.assertTrue("There is no such creature under player's control with specified power&toughness, player=" + player.getName() +
|
||||
", cardName=" + cardName, fit > 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert permanent count under player's control.
|
||||
*
|
||||
* @param player {@link Player} which permanents should be counted.
|
||||
* @param count Expected count.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public void assertPermanentCount(Player player, String cardName, int count) throws AssertionError {
|
||||
int actualCount = 0;
|
||||
for (Permanent permanent : currentGame.getBattlefield().getAllPermanents()) {
|
||||
if (permanent.getControllerId().equals(player.getId())) {
|
||||
if (permanent.getName().equals(cardName)) {
|
||||
actualCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
Assert.assertEquals("(Battlefield) Card counts are not equal (" + cardName + ")", count, actualCount);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package org.mage.test.serverside.cards.effects;
|
||||
|
||||
import com.sun.xml.bind.v2.schemagen.xmlschema.Any;
|
||||
import mage.filter.Filter;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestBase;
|
||||
|
||||
/**
|
||||
* Tests continuous boost effect like "White creatures you control get +1/+1".
|
||||
*
|
||||
* @author ayratn
|
||||
*/
|
||||
public class BoostContinuousEffectTest extends CardTestBase {
|
||||
|
||||
@Test
|
||||
public void testHonorOfThePoor() throws Exception {
|
||||
load("M11/Honor of the Pure.test");
|
||||
execute();
|
||||
|
||||
checkPermanentPT(computerA, "Tine Shrike", 3, 2, Filter.ComparisonScope.Any);
|
||||
checkPermanentPT(computerA, "Runeclaw Bear", 2, 2, Filter.ComparisonScope.Any);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package org.mage.test.serverside.cards.single.mbs;
|
||||
|
||||
import mage.Constants;
|
||||
import mage.filter.Filter;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestAPI;
|
||||
import org.mage.test.serverside.base.CardTestBase;
|
||||
|
||||
/**
|
||||
* First JUnit tests for Mage card.
|
||||
*
|
||||
* @ayratn
|
||||
*/
|
||||
public class BurntheImpureTest extends CardTestBase {
|
||||
|
||||
/**
|
||||
* Reproduces the test written in MBS/Burn the Impure.test
|
||||
*
|
||||
* Actually it can be tested with one java line that loads all test metadata from text file:
|
||||
* load("MBS/Burn the Impure.test");
|
||||
*
|
||||
* But it was decided to use java code only.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testVersusInfectCreature() throws Exception {
|
||||
// $include red.default
|
||||
useRedDefault();
|
||||
// hand:ComputerA:Burn the Impure:1
|
||||
addCard(Constants.Zone.HAND, computerA, "Burn the Impure");
|
||||
// battlefield:ComputerB:Tine Shrike:1
|
||||
addCard(Constants.Zone.BATTLEFIELD, computerB, "Tine Shrike");
|
||||
// player:ComputerB:life:3
|
||||
setLife(computerB, 3);
|
||||
|
||||
setStopOnTurn(2);
|
||||
execute();
|
||||
|
||||
// turn:1
|
||||
assertTurn(1);
|
||||
// result:won
|
||||
assertResult(computerA, CardTestAPI.GameResult.WON);
|
||||
// life:ComputerA:20
|
||||
assertLife(computerA, 20);
|
||||
// life:ComputerB:0
|
||||
assertLife(computerB, 0);
|
||||
// assert Tine Shrike has been killed
|
||||
assertPermanentCount(computerB, "Tine Shrike", 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* load("MBS/Burn the Impure - no infect.test");
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testVersusNonInfectCreature() throws Exception {
|
||||
useRedDefault();
|
||||
addCard(Constants.Zone.HAND, computerA, "Burn the Impure");
|
||||
addCard(Constants.Zone.BATTLEFIELD, computerB, "Runeclaw Bear", 3);
|
||||
setLife(computerB, 3);
|
||||
|
||||
setStopOnTurn(2);
|
||||
execute();
|
||||
|
||||
assertTurn(2);
|
||||
assertResult(computerA, CardTestAPI.GameResult.DRAW);
|
||||
assertLife(computerA, 20);
|
||||
assertLife(computerB, 3);
|
||||
assertPermanentCount(computerB, "Runeclaw Bear", 2);
|
||||
assertPowerToughness(computerB, "Runeclaw Bear", 2, 2, Filter.ComparisonScope.Any);
|
||||
assertPowerToughness(computerB, "Runeclaw Bear", 2, 2, Filter.ComparisonScope.All);
|
||||
}
|
||||
}
|
29
Mage.Tests/tests/M11/Honor of the Pure.test
Normal file
29
Mage.Tests/tests/M11/Honor of the Pure.test
Normal file
|
@ -0,0 +1,29 @@
|
|||
### Test playing Honor of the Pure ###
|
||||
#######################################
|
||||
|
||||
$include green.white.default
|
||||
|
||||
### ComputerA ###
|
||||
# Hand
|
||||
hand:ComputerA:Honor of the Pure:1
|
||||
# Battlefield
|
||||
battlefield:ComputerB:Tine Shrike:1
|
||||
battlefield:ComputerB:Runeclaw Bear:1
|
||||
|
||||
|
||||
### ComputerB ###
|
||||
# nothing
|
||||
|
||||
$options
|
||||
|
||||
exit_on_turn:2
|
||||
|
||||
$expected
|
||||
|
||||
turn:1
|
||||
result:draw
|
||||
life:ComputerA:20
|
||||
life:ComputerB:20
|
||||
battlefield:ComputerA:Tine Shrike:1
|
||||
battlefield:ComputerA:Runeclaw Bear:1
|
||||
# note: abilities are tested in code
|
30
Mage.Tests/tests/MBS/Burn the Impure - no infect.test
Normal file
30
Mage.Tests/tests/MBS/Burn the Impure - no infect.test
Normal file
|
@ -0,0 +1,30 @@
|
|||
### Test playing Burn the Impure ###
|
||||
### Target: creature with no Infect ###
|
||||
#######################################
|
||||
|
||||
$include red.default
|
||||
|
||||
### ComputerA ###
|
||||
# Hand
|
||||
hand:ComputerA:Burn the Impure:1
|
||||
|
||||
### ComputerB ###
|
||||
# Battlefield
|
||||
battlefield:ComputerB:Runeclaw Bear:1
|
||||
# Life
|
||||
player:ComputerB:life:3
|
||||
|
||||
$options
|
||||
|
||||
exit_on_turn:2
|
||||
|
||||
$expected
|
||||
|
||||
turn:1
|
||||
result:draw
|
||||
life:ComputerA:20
|
||||
life:ComputerB:3
|
||||
#battlefield:ComputerB:Runeclaw Bear:0
|
||||
#graveyard:ComputerB:Runeclaw Bear:1
|
||||
|
||||
|
29
Mage.Tests/tests/MBS/Burn the Impure.test
Normal file
29
Mage.Tests/tests/MBS/Burn the Impure.test
Normal file
|
@ -0,0 +1,29 @@
|
|||
### Test playing Burn the Impure ###
|
||||
### Target: creature with Infect ###
|
||||
#######################################
|
||||
|
||||
$include red.default
|
||||
|
||||
### ComputerA ###
|
||||
# Hand
|
||||
hand:ComputerA:Burn the Impure:1
|
||||
|
||||
### ComputerB ###
|
||||
# Battlefield
|
||||
battlefield:ComputerB:Tine Shrike:1
|
||||
# Life
|
||||
player:ComputerB:life:3
|
||||
|
||||
$options
|
||||
|
||||
exit_on_turn:2
|
||||
|
||||
$expected
|
||||
|
||||
turn:1
|
||||
result:won
|
||||
life:ComputerA:20
|
||||
life:ComputerB:0
|
||||
#battlefield:ComputerB:Tine Shrike:0
|
||||
#graveyard:ComputerB:Tine Shrike:1
|
||||
|
31
Mage.Tests/tests/green.white.default
Normal file
31
Mage.Tests/tests/green.white.default
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Default init game state for white player (that plays with Plains)
|
||||
|
||||
### ComputerA ###
|
||||
|
||||
# Battlefield
|
||||
battlefield:ComputerA:Plains:5
|
||||
battlefield:ComputerA:Forest:5
|
||||
|
||||
# Hand
|
||||
hand:ComputerA:Plains:2
|
||||
hand:ComputerA:Forest:2
|
||||
|
||||
# Library
|
||||
# from down to top
|
||||
library:ComputerA:clear:0
|
||||
library:ComputerA:Plains:5
|
||||
library:ComputerA:Forest:5
|
||||
|
||||
### ComputerB ###
|
||||
|
||||
# Battlefield
|
||||
battlefield:ComputerB:Mountain:2
|
||||
|
||||
# Hand
|
||||
hand:ComputerB:Mountain:2
|
||||
|
||||
# Library
|
||||
# from down to top
|
||||
library:ComputerB:clear:0
|
||||
library:ComputerB:Mountain:10
|
||||
|
28
Mage.Tests/tests/red.default
Normal file
28
Mage.Tests/tests/red.default
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Default init game state for red player (that plays with Mountains)
|
||||
|
||||
### ComputerA ###
|
||||
|
||||
# Battlefield
|
||||
battlefield:ComputerA:Mountain:5
|
||||
|
||||
# Hand
|
||||
hand:ComputerA:Mountain:4
|
||||
|
||||
# Library
|
||||
# from down to top
|
||||
library:ComputerA:clear:0
|
||||
library:ComputerA:Mountain:10
|
||||
|
||||
### ComputerB ###
|
||||
|
||||
# Battlefield
|
||||
battlefield:ComputerB:Plains:2
|
||||
|
||||
# Hand
|
||||
hand:ComputerB:Plains:2
|
||||
|
||||
# Library
|
||||
# from down to top
|
||||
library:ComputerB:clear:0
|
||||
library:ComputerB:Plains:10
|
||||
|
28
Mage.Tests/tests/white.default
Normal file
28
Mage.Tests/tests/white.default
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Default init game state for white player (that plays with Plains)
|
||||
|
||||
### ComputerA ###
|
||||
|
||||
# Battlefield
|
||||
battlefield:ComputerA:Plains:5
|
||||
|
||||
# Hand
|
||||
hand:ComputerA:Plains:4
|
||||
|
||||
# Library
|
||||
# from down to top
|
||||
library:ComputerA:clear:0
|
||||
library:ComputerA:Plains:10
|
||||
|
||||
### ComputerB ###
|
||||
|
||||
# Battlefield
|
||||
battlefield:ComputerB:Mountain:2
|
||||
|
||||
# Hand
|
||||
hand:ComputerB:Mountain:2
|
||||
|
||||
# Library
|
||||
# from down to top
|
||||
library:ComputerB:clear:0
|
||||
library:ComputerB:Mountain:10
|
||||
|
|
@ -139,7 +139,7 @@ public interface Game extends MageItem, Serializable {
|
|||
//game play methods
|
||||
//public void init(UUID choosingPlayerId);
|
||||
public void start(UUID choosingPlayerId);
|
||||
public void start(UUID choosingPlayerId, boolean testMode);
|
||||
public void start(UUID choosingPlayerId, GameOptions options);
|
||||
public void end();
|
||||
public void mulligan(UUID playerId);
|
||||
public void quit(UUID playerId);
|
||||
|
|
|
@ -292,19 +292,20 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
|
|||
|
||||
@Override
|
||||
public void start(UUID choosingPlayerId) {
|
||||
start(choosingPlayerId, false);
|
||||
start(choosingPlayerId, GameOptions.getDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(UUID choosingPlayerId, boolean testMode) {
|
||||
init(choosingPlayerId, testMode);
|
||||
public void start(UUID choosingPlayerId, GameOptions options) {
|
||||
init(choosingPlayerId, options.testMode);
|
||||
PlayerList players = state.getPlayerList(startingPlayerId);
|
||||
Player player = getPlayer(players.get());
|
||||
while (!isGameOver()) {
|
||||
if (player.getId().equals(startingPlayerId)) {
|
||||
//if (player.getId().equals(startingPlayerId)) {
|
||||
state.setTurnNum(state.getTurnNum() + 1);
|
||||
fireInformEvent("Turn " + Integer.toString(state.getTurnNum()));
|
||||
}
|
||||
//}
|
||||
if (checkStopOnTurnOption(options)) return;
|
||||
state.setActivePlayerId(player.getId());
|
||||
state.getTurn().play(this, player.getId());
|
||||
if (isGameOver())
|
||||
|
@ -318,6 +319,17 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
|
|||
saveState();
|
||||
}
|
||||
|
||||
private boolean checkStopOnTurnOption(GameOptions options) {
|
||||
if (options.stopOnTurn != null) {
|
||||
if (options.stopOnTurn.equals(state.getTurnNum())) {
|
||||
winnerId = null; //DRAW
|
||||
saveState();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void init(UUID choosingPlayerId, boolean testMode) {
|
||||
for (Player player: state.getPlayers().values()) {
|
||||
player.beginTurn(this);
|
||||
|
|
27
Mage/src/mage/game/GameOptions.java
Normal file
27
Mage/src/mage/game/GameOptions.java
Normal file
|
@ -0,0 +1,27 @@
|
|||
package mage.game;
|
||||
|
||||
/**
|
||||
* Game options for Mage game.
|
||||
* Mainly used in tests to configure {@link GameImpl} with specific params.
|
||||
*
|
||||
* @author ayratn
|
||||
*/
|
||||
public class GameOptions {
|
||||
|
||||
private static GameOptions defInstance = new GameOptions();
|
||||
|
||||
public static GameOptions getDefault() {
|
||||
return defInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the running mode. There are some exclusions made for test mode.
|
||||
*/
|
||||
public boolean testMode = false;
|
||||
|
||||
/**
|
||||
* Defines the turn number game should stop on.
|
||||
* By default, is null meaning that game shouldn't stop on any specific turn.
|
||||
*/
|
||||
public Integer stopOnTurn = null;
|
||||
}
|
|
@ -96,6 +96,9 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
public boolean hasLeft();
|
||||
public ManaPool getManaPool();
|
||||
public Set<UUID> getInRange();
|
||||
|
||||
public boolean isTestMode();
|
||||
public void setTestMode(boolean value);
|
||||
|
||||
public void init(Game game);
|
||||
public void init(Game game, boolean testMode);
|
||||
|
|
|
@ -98,6 +98,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
|||
protected boolean left;
|
||||
protected RangeOfInfluence range;
|
||||
protected Set<UUID> inRange = new HashSet<UUID>();
|
||||
protected boolean isTestMode = false;
|
||||
|
||||
@Override
|
||||
public abstract T copy();
|
||||
|
@ -1013,4 +1014,11 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isTestMode() {
|
||||
return isTestMode;
|
||||
}
|
||||
|
||||
public void setTestMode(boolean value) {
|
||||
this.isTestMode = value;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue