From 475666be4ca3fd8649fd6c5ada9016a527784afd Mon Sep 17 00:00:00 2001 From: magenoxx Date: Wed, 15 Aug 2012 22:14:07 +0400 Subject: [PATCH] Enhanced test framework for multiplayer games --- .../base/CardTestMultiPlayerBase.java | 298 ++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestMultiPlayerBase.java diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestMultiPlayerBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestMultiPlayerBase.java new file mode 100644 index 00000000000..c9e50741a85 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestMultiPlayerBase.java @@ -0,0 +1,298 @@ +package org.mage.test.serverside.base; + +import mage.Constants; +import mage.Constants.PhaseStep; +import mage.cards.Card; +import mage.cards.decks.Deck; +import mage.cards.decks.importer.DeckImporterUtil; +import mage.filter.Filter; +import mage.game.*; +import mage.game.permanent.Permanent; +import mage.players.Player; +import org.junit.Assert; +import org.junit.Before; +import org.mage.test.player.TestPlayer; +import org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl; + +import java.io.File; +import java.io.FileNotFoundException; + +/** + * Base class for testing single cards and effects in multiplayer game. + * For PvP games {@see CardTestPlayerBase} + * + * @author magenoxx_at_gmail.com + */ +public abstract class CardTestMultiPlayerBase extends CardTestPlayerAPIImpl { + + protected enum ExpectedType { + TURN_NUMBER, + RESULT, + LIFE, + BATTLEFIELD, + GRAVEYARD, + UNKNOWN + } + + protected GameOptions gameOptions; + + @Before + public void reset() throws GameException, FileNotFoundException { + if (currentGame != null) { + logger.debug("Resetting previous game and creating new one!"); + currentGame = null; + System.gc(); + } + + Game game = new FreeForAll(Constants.MultiplayerAttackOption.LEFT, Constants.RangeOfInfluence.ONE); + + playerA = createPlayer(game, playerA, "PlayerA"); + playerB = createPlayer(game, playerB, "PlayerB"); + playerC = createPlayer(game, playerC, "PlayerC"); + playerD = createPlayer(game, playerD, "PlayerD"); + + activePlayer = playerA; + currentGame = game; + + 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(); + } + + gameOptions = new GameOptions(); + } + + public void load(String path) 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.debug("Resetting previous game and creating new one!"); + currentGame = null; + System.gc(); + } + + Game game = new TwoPlayerDuel(Constants.MultiplayerAttackOption.LEFT, Constants.RangeOfInfluence.ALL); + + playerA = createNewPlayer("ComputerA"); + playerA.setTestMode(true); + + Deck deck = Deck.load(DeckImporterUtil.importDeck("RB Aggro.dck")); + + if (deck.getCards().size() < 40) { + throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck.getCards().size()); + } + game.addPlayer(playerA, deck); + game.loadCards(deck.getCards(), playerA.getId()); + + playerB = createNewPlayer("ComputerB"); + playerB.setTestMode(true); + Deck deck2 = Deck.load(DeckImporterUtil.importDeck("RB Aggro.dck")); + if (deck2.getCards().size() < 40) { + throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck2.getCards().size()); + } + game.addPlayer(playerB, deck2); + game.loadCards(deck2.getCards(), playerB.getId()); + + parseScenario(cardPath); + + activePlayer = playerA; + 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."); + } + + 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)); + } + + boolean testMode = true; + long t1 = System.nanoTime(); + + gameOptions.testMode = true; + gameOptions.stopOnTurn = stopOnTurn; + gameOptions.stopAtStep = stopAtStep; + currentGame.start(activePlayer.getId(), gameOptions); + long t2 = System.nanoTime(); + logger.debug("Winner: " + currentGame.getWinner()); + logger.info("Test has been executed. Execution time: " + (t2 - t1) / 1000000 + " ms"); + + assertTheResults(); + } + + /** + * Assert expected and actual results. + */ + private void assertTheResults() { + logger.debug("Matching expected results:"); + for (String line : expectedResults) { + boolean ok = false; + try { + ExpectedType type = getExpectedType(line); + if (type.equals(CardTestMultiPlayerBase.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 CardTestMultiPlayerBase.ExpectedType.TURN_NUMBER; + } + if (line.startsWith("result:")) { + return CardTestMultiPlayerBase.ExpectedType.RESULT; + } + if (line.startsWith("life:")) { + return CardTestMultiPlayerBase.ExpectedType.LIFE; + } + if (line.startsWith("battlefield:")) { + return CardTestMultiPlayerBase.ExpectedType.BATTLEFIELD; + } + if (line.startsWith("graveyard:")) { + return CardTestMultiPlayerBase.ExpectedType.GRAVEYARD; + } + return CardTestMultiPlayerBase.ExpectedType.UNKNOWN; + } + + private void parseType(ExpectedType type, String line) { + if (type.equals(CardTestMultiPlayerBase.ExpectedType.TURN_NUMBER)) { + int turn = getIntParam(line, 1); + Assert.assertEquals("Turn numbers are not equal", turn, currentGame.getTurnNum()); + return; + } + if (type.equals(CardTestMultiPlayerBase.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(CardTestMultiPlayerBase.ExpectedType.LIFE)) { + String player = getStringParam(line, 1); + int expected = getIntParam(line, 2); + if (player.equals("ComputerA")) { + int actual = currentGame.getPlayer(playerA.getId()).getLife(); + Assert.assertEquals("Life amounts are not equal", expected, actual); + } else if (player.equals("ComputerB")) { + int actual = currentGame.getPlayer(playerB.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(CardTestMultiPlayerBase.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(playerA.getId()); + } else if (playerName.equals("ComputerB")) { + player = currentGame.getPlayer(playerB.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(CardTestMultiPlayerBase.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(playerA.getId()); + } else if (playerName.equals("ComputerB")) { + player = currentGame.getPlayer(playerB.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); + } + } + + 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."); + } + + 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; + } + } + } + + protected void skipInitShuffling() { + gameOptions.skipInitShuffling = true; + } +}