updated test framework - added TestPlayer which only performs instructed actions

This commit is contained in:
BetaSteward 2012-02-17 10:40:57 -05:00
parent 2e14adfde0
commit 86906c633a
28 changed files with 1425 additions and 103 deletions

View file

@ -3,6 +3,7 @@ package org.mage.test.ai;
import junit.framework.Assert;
import mage.Constants;
import mage.game.permanent.Permanent;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestBase;
@ -14,6 +15,7 @@ import org.mage.test.serverside.base.CardTestBase;
public class EquipAbilityTest extends CardTestBase {
@Test
@Ignore
public void testLevelUpAbilityUsage() {
addCard(Constants.Zone.BATTLEFIELD, playerA, "Steel Wall");
addCard(Constants.Zone.BATTLEFIELD, playerA, "Blade of the Bloodchief");
@ -22,6 +24,7 @@ public class EquipAbilityTest extends CardTestBase {
addCard(Constants.Zone.BATTLEFIELD, playerA, "Plains", 2);
addCard(Constants.Zone.BATTLEFIELD, playerA, "Sacred Foundry", 1);
setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT);
execute();
Permanent wall = getPermanent("Steel Wall", playerA.getId());

View file

@ -9,6 +9,7 @@ import org.junit.Test;
import org.mage.test.serverside.base.CardTestBase;
import java.util.Map;
import org.junit.Ignore;
/**
* Make sure AI uses level up ability, but not too much (over the max useful level - Issue 441).
@ -18,6 +19,7 @@ import java.util.Map;
public class LevelUpAbilityTest extends CardTestBase {
@Test
@Ignore
public void testLevelUpAbilityUsage() {
addCard(Constants.Zone.BATTLEFIELD, playerA, "Transcendent Master");
addCard(Constants.Zone.BATTLEFIELD, playerA, "Swamp", 15);

View file

@ -4,6 +4,7 @@ import junit.framework.Assert;
import mage.Constants;
import mage.counters.CounterType;
import mage.game.permanent.Permanent;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestBase;
@ -16,6 +17,7 @@ public class NimShamblerTest extends CardTestBase {
* Reproduces the bug when AI sacrifices its creatures for no reason.
*/
@Test
@Ignore
public void testNoCreatureWasSacrificed() {
addCard(Constants.Zone.BATTLEFIELD, playerA, "Nim Shambler");
addCard(Constants.Zone.BATTLEFIELD, playerA, "Blood Cultist");
@ -32,6 +34,7 @@ public class NimShamblerTest extends CardTestBase {
}
@Test
@Ignore
public void testAttackAndKillBlockerWithAdditionalDamage() {
addCard(Constants.Zone.BATTLEFIELD, playerA, "Nim Shambler");
addCard(Constants.Zone.BATTLEFIELD, playerA, "Blood Cultist");

View file

@ -3,6 +3,7 @@ package org.mage.test.ai;
import junit.framework.Assert;
import mage.Constants;
import mage.game.permanent.Permanent;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestBase;
@ -15,6 +16,7 @@ public class ObNixilistheFallenTest extends CardTestBase {
* Reproduces bug when AI doesn't use good "may" ability.
*/
@Test
@Ignore
public void testMayAbilityUsed() {
addCard(Constants.Zone.BATTLEFIELD, playerA, "Ob Nixilis, the Fallen");
addCard(Constants.Zone.HAND, playerA, "Swamp", 1);

View file

@ -3,6 +3,7 @@ package org.mage.test.ai;
import mage.Constants;
import mage.game.permanent.Permanent;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestBase;
@ -14,6 +15,7 @@ import org.mage.test.serverside.base.CardTestBase;
public class RegenerateAbilityTest extends CardTestBase {
@Test
@Ignore
public void testRegenerateUsage() {
addCard(Constants.Zone.BATTLEFIELD, playerA, "Quicksilver Gargantuan", 1);
addCard(Constants.Zone.BATTLEFIELD, playerA, "Thousand-legged Kami", 1);

View file

@ -3,12 +3,14 @@ package org.mage.test.ai.bugs;
import junit.framework.Assert;
import mage.Constants;
import mage.game.permanent.Permanent;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestBase;
public class BugCantFindCardInLibrary extends CardTestBase {
@Test
@Ignore
public void testWithSquadronHawk() {
addCard(Constants.Zone.HAND, playerA, "Squadron Hawk");
addCard(Constants.Zone.BATTLEFIELD, playerA, "Plains");

View file

@ -1,6 +1,7 @@
package org.mage.test.ai.bugs;
import mage.Constants;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestBase;
@ -12,6 +13,7 @@ import org.mage.test.serverside.base.CardTestBase;
public class BugDoesntAttackTest extends CardTestBase {
@Test
@Ignore
public void testAttackWithZephyrSprite() throws Exception {
addCard(Constants.Zone.HAND, playerA, "Zephyr Sprite");
addCard(Constants.Zone.HAND, playerA, "Island");
@ -25,6 +27,7 @@ public class BugDoesntAttackTest extends CardTestBase {
}
@Test
@Ignore
public void testAttackWithGoblinGuide() throws Exception {
addCard(Constants.Zone.HAND, playerA, "Goblin Guide");
addCard(Constants.Zone.HAND, playerA, "Mountain");

View file

@ -17,6 +17,7 @@ import org.mage.test.serverside.base.CardTestBase;
public class BugTapsItselfTest extends CardTestBase {
@Test
@Ignore
public void testVersusInfectCreature() throws Exception {
useWhiteDefault();
addCard(Constants.Zone.BATTLEFIELD, playerA, "Blinding Mage");

View file

@ -16,6 +16,7 @@ public class SejiriMerfolkTest extends CardTestBase {
@Test
public void testWithoutPlains() {
addCard(Constants.Zone.BATTLEFIELD, playerA, "Sejiri Merfolk");
setStopAt(1, Constants.PhaseStep.DRAW);
execute();
Permanent merfolk = getPermanent("Sejiri Merfolk", playerA.getId());
Assert.assertNotNull(merfolk);
@ -27,6 +28,7 @@ public class SejiriMerfolkTest extends CardTestBase {
public void testWithPlains() {
addCard(Constants.Zone.BATTLEFIELD, playerA, "Sejiri Merfolk");
addCard(Constants.Zone.BATTLEFIELD, playerA, "Plains");
setStopAt(1, Constants.PhaseStep.DRAW);
execute();
Permanent merfolk = getPermanent("Sejiri Merfolk", playerA.getId());
Assert.assertNotNull(merfolk);

View file

@ -1,23 +1,23 @@
package org.mage.test.cards.damage;
import mage.Constants;
import mage.Constants.PhaseStep;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestBase;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author ayrat
*/
public class LightningBoltTest extends CardTestBase {
public class LightningBoltTest extends CardTestPlayerBase {
@Test
public void testDamageOpponent() {
addCard(Constants.Zone.HAND, playerA, "Mountain");
addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain");
addCard(Constants.Zone.HAND, playerA, "Lightning Bolt");
playLand(playerA, "Mountain");
castSpell(playerA, "Lightning Bolt");
// not specifying target, AI should choose opponent by itself
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT);
execute();
assertLife(playerA, 20);
assertLife(playerB, 17);
@ -25,14 +25,12 @@ public class LightningBoltTest extends CardTestBase {
@Test
public void testDamageSelf() {
addCard(Constants.Zone.HAND, playerA, "Mountain");
addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain");
addCard(Constants.Zone.HAND, playerA, "Lightning Bolt");
playLand(playerA, "Mountain");
castSpell(playerA, "Lightning Bolt");
addFixedTarget(playerA, "Lightning Bolt", playerA);
playerA.setAllowBadMoves(true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerA);
setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT);
execute();
assertLife(playerA, 17);
assertLife(playerB, 20);
@ -40,28 +38,26 @@ public class LightningBoltTest extends CardTestBase {
@Test
public void testDamageSmallCreature() {
addCard(Constants.Zone.HAND, playerA, "Mountain");
addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain");
addCard(Constants.Zone.HAND, playerA, "Lightning Bolt");
addCard(Constants.Zone.BATTLEFIELD, playerB, "Sejiri Merfolk");
playLand(playerA, "Mountain");
castSpell(playerA, "Lightning Bolt");
addFixedTarget(playerA, "Lightning Bolt", "Sejiri Merfolk");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Sejiri Merfolk");
setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerB, "Sejiri Merfolk", 0);
}
@Test
public void testDamageBigCreature() {
addCard(Constants.Zone.HAND, playerA, "Mountain");
addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain");
addCard(Constants.Zone.HAND, playerA, "Lightning Bolt");
addCard(Constants.Zone.BATTLEFIELD, playerB, "Craw Wurm");
playLand(playerA, "Mountain");
castSpell(playerA, "Lightning Bolt");
addFixedTarget(playerA, "Lightning Bolt", "Craw Wurm");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Craw Wurm");
setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerB, "Craw Wurm", 1);
}
@ -74,11 +70,10 @@ public class LightningBoltTest extends CardTestBase {
addCard(Constants.Zone.HAND, playerA, "Lightning Bolt");
addCard(Constants.Zone.BATTLEFIELD, playerB, "Craw Wurm");
castSpell(playerA, "Lightning Bolt");
addFixedTarget(playerA, "Lightning Bolt", "Craw Wurm");
castSpell(playerA, "Lightning Bolt");
addFixedTarget(playerA, "Lightning Bolt", "Craw Wurm");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Craw Wurm");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Craw Wurm");
setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerB, "Craw Wurm", 0);
}

View file

@ -17,6 +17,7 @@ public class PsionicBlastTest extends CardTestBase {
addCard(Constants.Zone.HAND, playerA, "Psionic Blast");
castSpell(playerA, "Psionic Blast");
setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT);
execute();
assertLife(playerA, 18);

View file

@ -18,6 +18,7 @@ public class HideousEndTest extends CardTestBase {
castSpell(playerA, "Hideous End");
addFixedTarget(playerA, "Hideous End", "Copper Myr");
setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerB, "Copper Myr", 0);
assertLife(playerB, 18);
@ -34,6 +35,7 @@ public class HideousEndTest extends CardTestBase {
castSpell(playerA, "Hideous End");
addFixedTarget(playerA, "Hideous End", "Zombie Goliath");
setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerB, "Zombie Goliath", 1);
assertLife(playerB, 20);
@ -54,6 +56,7 @@ public class HideousEndTest extends CardTestBase {
castSpell(playerA, "Hideous End");
addFixedTarget(playerA, "Hideous End", "Copper Myr");
setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerB, "Copper Myr", 1);
assertLife(playerB, 20);

View file

@ -22,6 +22,7 @@ public class LeaveNoTraceTest extends CardTestBase {
castSpell(playerA, "Leave No Trace");
addFixedTarget(playerA, "Leave No Trace", "Asceticism");
setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerB, "Asceticism", 0);
assertPermanentCount(playerB, "Awakening Zone", 0);

View file

@ -21,6 +21,7 @@ public class OneEyedScarecrowTest extends CardTestBase {
addCard(Constants.Zone.BATTLEFIELD, playerB, "Screeching Bat");
addCard(Constants.Zone.BATTLEFIELD, playerB, "Runeclaw Bear");
setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT);
execute();
Permanent scarecrow = getPermanent("One-Eyed Scarecrow", playerA.getId());
@ -59,6 +60,7 @@ public class OneEyedScarecrowTest extends CardTestBase {
addCard(Constants.Zone.BATTLEFIELD, playerB, "Screeching Bat");
addCard(Constants.Zone.BATTLEFIELD, playerB, "Runeclaw Bear");
setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT);
execute();
// -1/2

View file

@ -2,13 +2,14 @@ package org.mage.test.cards.targets.attacking;
import junit.framework.Assert;
import mage.Constants;
import mage.Constants.PhaseStep;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestBase;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author ayratn
*/
public class CondemnTest extends CardTestBase {
public class CondemnTest extends CardTestPlayerBase {
@Test
public void testIllegalTarget() {
@ -16,10 +17,10 @@ public class CondemnTest extends CardTestBase {
addCard(Constants.Zone.HAND, playerA, "Condemn");
addCard(Constants.Zone.BATTLEFIELD, playerB, "Sejiri Merfolk");
castSpell(playerA, "Condemn");
// check with illegal target
addFixedTarget(playerA, "Condemn", "Sejiri Merfolk");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Condemn", "Sejiri Merfolk");
setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT);
execute();
// spell shouldn't work
assertPermanentCount(playerB, "Sejiri Merfolk", 1);
@ -29,21 +30,20 @@ public class CondemnTest extends CardTestBase {
@Test
public void testLegalTarget() {
addCard(Constants.Zone.BATTLEFIELD, playerA, "Plains");
addCard(Constants.Zone.HAND, playerA, "Condemn");
addCard(Constants.Zone.BATTLEFIELD, playerB, "Sejiri Merfolk");
addCard(Constants.Zone.BATTLEFIELD, playerB, "Plains");
addCard(Constants.Zone.HAND, playerB, "Condemn");
addCard(Constants.Zone.BATTLEFIELD, playerA, "Sejiri Merfolk");
attack(playerB, "Sejiri Merfolk");
castSpell(playerA, "Condemn");
addFixedTarget(playerA, "Condemn", "Sejiri Merfolk");
attack(1, playerA, "Sejiri Merfolk");
castSpell(1, PhaseStep.DECLARE_ATTACKERS, playerB, "Condemn", "Sejiri Merfolk");
setStopOnTurn(3);
setStopAt(1, Constants.PhaseStep.END_COMBAT);
execute();
assertPermanentCount(playerB, "Sejiri Merfolk", 0);
assertLife(playerA, 20);
assertLife(playerB, 21);
assertPermanentCount(playerA, "Sejiri Merfolk", 0);
assertLife(playerB, 20);
assertLife(playerA, 21);
// check was put on top
Assert.assertEquals(currentGame.getPlayer(playerB.getId()).getLibrary().size(), 60);
Assert.assertEquals(currentGame.getPlayer(playerA.getId()).getLibrary().size(), 61);
}
}

View file

@ -1,6 +1,7 @@
package org.mage.test.cards.triggers;
import mage.Constants;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestBase;
@ -20,6 +21,7 @@ public class ManabarbsTest extends CardTestBase {
* Couldn't reproduce.
*/
@Test
@Ignore
public void testMultiTriggers() {
addCard(Constants.Zone.BATTLEFIELD, playerA, "Manabarbs");
addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain", 7);
@ -28,8 +30,13 @@ public class ManabarbsTest extends CardTestBase {
castSpell(playerA, "Ball Lightning");
castSpell(playerA, "Lightning Elemental");
attack(playerA, "Ball Lightning");
attack(playerA, "Lightning Elemental");
playerA.setAllowBadMoves(true);
setStopAt(2, Constants.PhaseStep.UNTAP);
execute();
assertLife(playerA, 13); // burns from Manabarbs
assertLife(playerB, 10); // ai should attack with 4/1 + 6/1
assertPermanentCount(playerA, "Lightning Elemental", 1);

View file

@ -0,0 +1,43 @@
package org.mage.test.cards.triggers;
import mage.Constants;
import mage.Constants.PhaseStep;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author ayratn
*
* Card: Whenever a player taps a land for mana, Manabarbs deals 1 damage to that player.
*/
public class ManabarbsTest2 extends CardTestPlayerBase {
/**
* Issue 374: manabarb enchantment
* Games goes into a freeze loop.
*
* version: 0.8.1
*
* Couldn't reproduce.
*/
@Test
public void testMultiTriggers() {
addCard(Constants.Zone.BATTLEFIELD, playerA, "Manabarbs");
addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain", 7);
addCard(Constants.Zone.HAND, playerA, "Lightning Elemental");
addCard(Constants.Zone.HAND, playerA, "Ball Lightning");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ball Lightning");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Elemental");
attack(1, playerA, "Ball Lightning");
attack(1, playerA, "Lightning Elemental");
setStopAt(2, Constants.PhaseStep.UNTAP);
execute();
assertLife(playerA, 13); // burns from Manabarbs
assertLife(playerB, 10); // ai should attack with 4/1 + 6/1
assertPermanentCount(playerA, "Lightning Elemental", 1);
assertPermanentCount(playerA, "Ball Lightning", 0); // sacrificed at EOT
}
}

View file

@ -4,13 +4,13 @@ import junit.framework.Assert;
import mage.Constants;
import mage.game.permanent.Permanent;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestBase;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author ayrat
*/
public class DamageDistributionTest extends CardTestBase {
public class DamageDistributionTest extends CardTestPlayerBase {
@Test
public void testDoubleStrike() {
@ -18,6 +18,9 @@ public class DamageDistributionTest extends CardTestBase {
addCard(Constants.Zone.BATTLEFIELD, playerB, "Merfolk Looter");
setLife(playerB, 4);
attack(1, playerA, "Warren Instigator");
block(1, playerB, "Merfolk Looter", "Warren Instigator");
setStopAt(1, Constants.PhaseStep.END_COMBAT);
execute();
Permanent instigator = getPermanent("Warren Instigator", playerA.getId());
@ -36,7 +39,11 @@ public class DamageDistributionTest extends CardTestBase {
public void testDoubleStrikeUnblocked() {
addCard(Constants.Zone.BATTLEFIELD, playerA, "Warren Instigator");
setLife(playerB, 4);
attack(1, playerA, "Warren Instigator");
setStopAt(1, Constants.PhaseStep.END_COMBAT);
execute();
assertLife(playerB, 2);
}
@ -45,7 +52,8 @@ public class DamageDistributionTest extends CardTestBase {
addCard(Constants.Zone.BATTLEFIELD, playerA, "Merfolk Looter");
addCard(Constants.Zone.BATTLEFIELD, playerB, "Warren Instigator");
setLife(playerB, 4);
setStopAt(1, Constants.PhaseStep.END_COMBAT);
execute();
// should block and die

View file

@ -0,0 +1,61 @@
/*
* Copyright 2012 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package org.mage.test.player;
import mage.Constants.PhaseStep;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class PlayerAction {
private int turnNum;
private PhaseStep step;
private String action;
public PlayerAction(int turnNum, PhaseStep step, String action) {
this.turnNum = turnNum;
this.step = step;
this.action = action;
}
public int getTurnNum() {
return turnNum;
}
public PhaseStep getStep() {
return step;
}
public String getAction() {
return action;
}
}

View file

@ -0,0 +1,169 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package org.mage.test.player;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.Constants;
import mage.Constants.PhaseStep;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterAttackingCreature;
import mage.filter.common.FilterCreatureForCombat;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.player.ai.ComputerPlayer;
import mage.players.Player;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class TestPlayer extends ComputerPlayer<TestPlayer> {
private List<PlayerAction> actions = new ArrayList<PlayerAction>();
public TestPlayer(String name, Constants.RangeOfInfluence range) {
super(name, range);
human = false;
}
public TestPlayer(final TestPlayer player) {
super(player);
}
public void addAction(int turnNum, PhaseStep step, String action) {
actions.add(new PlayerAction(turnNum, step, action));
}
@Override
public TestPlayer copy() {
return new TestPlayer(this);
}
@Override
public boolean priority(Game game) {
for (PlayerAction action: actions) {
if (action.getTurnNum() == game.getTurnNum() && action.getStep() == game.getStep().getType()) {
if (action.getAction().startsWith("activate:")) {
String command = action.getAction();
command = command.substring(command.indexOf("activate:") + 9);
String[] groups = command.split(";");
for (Ability ability: this.getPlayable(game, true)) {
if (ability.toString().equals(groups[0])) {
if (groups.length > 1) {
addTargets(ability, groups, game);
}
this.activateAbility((ActivatedAbility)ability, game);
actions.remove(action);
return true;
}
}
}
}
}
pass();
return true;
}
@Override
public void selectAttackers(Game game) {
UUID opponentId = game.getCombat().getDefenders().iterator().next();
for (PlayerAction action: actions) {
if (action.getTurnNum() == game.getTurnNum() && action.getAction().startsWith("attack:")) {
String command = action.getAction();
command = command.substring(command.indexOf("attack:") + 7);
FilterCreatureForCombat filter = new FilterCreatureForCombat();
filter.getName().add(command);
Permanent attacker = findPermanent(filter, playerId, game);
if (attacker != null && attacker.canAttack(game)) {
this.declareAttacker(attacker.getId(), opponentId, game);
}
}
}
}
@Override
public void selectBlockers(Game game) {
UUID opponentId = game.getOpponents(playerId).iterator().next();
for (PlayerAction action: actions) {
if (action.getTurnNum() == game.getTurnNum() && action.getAction().startsWith("block:")) {
String command = action.getAction();
command = command.substring(command.indexOf("block:") + 6);
String[] groups = command.split(";");
FilterCreatureForCombat filterBlocker = new FilterCreatureForCombat();
filterBlocker.getName().add(groups[0]);
Permanent blocker = findPermanent(filterBlocker, playerId, game);
if (blocker != null) {
FilterAttackingCreature filterAttacker = new FilterAttackingCreature();
filterAttacker.getName().add(groups[1]);
Permanent attacker = findPermanent(filterAttacker, opponentId, game);
if (attacker != null) {
this.declareBlocker(blocker.getId(), attacker.getId(), game);
}
}
}
}
}
protected Permanent findPermanent(FilterPermanent filter, UUID controllerId, Game game) {
List<Permanent> permanents = game.getBattlefield().getAllActivePermanents(filter, controllerId);
if (permanents.size() > 0)
return permanents.get(0);
return null;
}
private void addTargets(Ability ability, String[] groups, Game game) {
for (int i = 1; i < groups.length; i++) {
String group = groups[i];
String target;
if (group.startsWith("targetPlayer=")) {
target = group.substring(group.indexOf("targetPlayer=") + 13);
for (Player player: game.getPlayers().values()) {
if (player.getName().equals(target)) {
ability.getTargets().get(0).addTarget(player.getId(), ability, game);
break;
}
}
}
else if (group.startsWith("target=")) {
target = group.substring(group.indexOf("target=") + 7);
for (Permanent permanent: game.getBattlefield().getAllActivePermanents()) {
if (permanent.getName().equals(target)) {
ability.getTargets().get(0).addTarget(permanent.getId(), ability, game);
break;
}
}
}
}
}
}

View file

@ -28,7 +28,8 @@ public abstract class CardTestBase extends CardTestAPIImpl {
protected enum AIType {
MinimaxHybrid,
MAD
MAD,
MonteCarlo
}
protected enum ExpectedType {
@ -56,6 +57,22 @@ public abstract class CardTestBase extends CardTestAPIImpl {
this.aiTypeB = aiTypeB;
}
protected Player createNewPlayer(String playerName, AIType aiType) {
Player player = null;
switch (aiType) {
case MinimaxHybrid:
player = createPlayer(playerName, "Computer - minimax hybrid");
break;
case MAD:
player = createPlayer(playerName, "Computer - mad");
break;
case MonteCarlo:
player = createPlayer(playerName, "Computer - monte carlo");
break;
}
return player;
}
@Before
public void reset() throws GameException, FileNotFoundException {
if (currentGame != null) {
@ -66,9 +83,7 @@ public abstract class CardTestBase extends CardTestAPIImpl {
Game game = new TwoPlayerDuel(Constants.MultiplayerAttackOption.LEFT, Constants.RangeOfInfluence.ALL);
playerA = aiTypeA.equals(CardTestBase.AIType.MinimaxHybrid) ?
createPlayer("PlayerA", "Computer - minimax hybrid") :
createPlayer("PlayerA", "Computer - mad");
playerA = createNewPlayer("PlayerA", aiTypeA);
playerA.setTestMode(true);
logger.info("Loading deck...");
Deck deck = Deck.load(Sets.loadDeck("RB Aggro.dck"));
@ -79,9 +94,7 @@ public abstract class CardTestBase extends CardTestAPIImpl {
game.addPlayer(playerA, deck);
game.loadCards(deck.getCards(), playerA.getId());
playerB = aiTypeB.equals(CardTestBase.AIType.MinimaxHybrid) ?
createPlayer("PlayerB", "Computer - minimax hybrid") :
createPlayer("PlayerB", "Computer - mad");
playerB = createNewPlayer("PlayerB", aiTypeB);
playerB.setTestMode(true);
Deck deck2 = Deck.load(Sets.loadDeck("RB Aggro.dck"));
if (deck2.getCards().size() < 40) {
@ -128,9 +141,7 @@ public abstract class CardTestBase extends CardTestAPIImpl {
Game game = new TwoPlayerDuel(Constants.MultiplayerAttackOption.LEFT, Constants.RangeOfInfluence.ALL);
playerA = aiTypeA.equals(CardTestBase.AIType.MinimaxHybrid) ?
createPlayer("ComputerA", "Computer - minimax hybrid") :
createPlayer("ComputerA", "Computer - mad");
playerA = createNewPlayer("ComputerA", aiTypeA);
playerA.setTestMode(true);
Deck deck = Deck.load(Sets.loadDeck("RB Aggro.dck"));
@ -141,9 +152,7 @@ public abstract class CardTestBase extends CardTestAPIImpl {
game.addPlayer(playerA, deck);
game.loadCards(deck.getCards(), playerA.getId());
playerB = aiTypeB.equals(CardTestBase.AIType.MinimaxHybrid) ?
createPlayer("ComputerB", "Computer - minimax hybrid") :
createPlayer("ComputerB", "Computer - mad");
playerB = createNewPlayer("ComputerB", aiTypeB);
playerB.setTestMode(true);
Deck deck2 = Deck.load(Sets.loadDeck("RB Aggro.dck"));
if (deck2.getCards().size() < 40) {

View file

@ -0,0 +1,314 @@
package org.mage.test.serverside.base;
import java.io.File;
import java.io.FileNotFoundException;
import mage.Constants;
import mage.Constants.PhaseStep;
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.player.TestPlayer;
import org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl;
/**
* Base class for testing single cards and effects.
*
* @author ayratn
*/
public abstract class CardTestPlayerBase extends CardTestPlayerAPIImpl {
protected enum ExpectedType {
TURN_NUMBER,
RESULT,
LIFE,
BATTLEFIELD,
GRAVEYARD,
UNKNOWN
}
public CardTestPlayerBase() {
}
protected TestPlayer createNewPlayer(String playerName) {
return createPlayer(playerName);
}
@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);
playerA = createNewPlayer("PlayerA");
playerA.setTestMode(true);
logger.info("Loading deck...");
Deck deck = Deck.load(Sets.loadDeck("RB Aggro.dck"));
logger.info("Done!");
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("PlayerB");
playerB.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(playerB, deck2);
game.loadCards(deck2.getCards(), playerB.getId());
activePlayer = playerA;
currentGame = game;
stopOnTurn = 2;
stopAtStep = PhaseStep.UNTAP;
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 {
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);
playerA = createNewPlayer("ComputerA");
playerA.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(playerA, deck);
game.loadCards(deck.getCards(), playerA.getId());
playerB = createNewPlayer("ComputerB");
playerB.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(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.");
}
currentGame.cheat(playerA.getId(), commandsA);
currentGame.cheat(playerA.getId(), libraryCardsA, handCardsA, battlefieldCardsA, graveyardCardsA);
currentGame.cheat(playerB.getId(), commandsB);
currentGame.cheat(playerB.getId(), libraryCardsB, handCardsB, battlefieldCardsB, graveyardCardsB);
boolean testMode = true;
long t1 = System.nanoTime();
GameOptions gameOptions = new GameOptions();
gameOptions.testMode = true;
gameOptions.stopOnTurn = stopOnTurn;
gameOptions.stopAtStep = stopAtStep;
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(CardTestPlayerBase.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 CardTestPlayerBase.ExpectedType.TURN_NUMBER;
}
if (line.startsWith("result:")) {
return CardTestPlayerBase.ExpectedType.RESULT;
}
if (line.startsWith("life:")) {
return CardTestPlayerBase.ExpectedType.LIFE;
}
if (line.startsWith("battlefield:")) {
return CardTestPlayerBase.ExpectedType.BATTLEFIELD;
}
if (line.startsWith("graveyard:")) {
return CardTestPlayerBase.ExpectedType.GRAVEYARD;
}
return CardTestPlayerBase.ExpectedType.UNKNOWN;
}
private void parseType(ExpectedType type, String line) {
if (type.equals(CardTestPlayerBase.ExpectedType.TURN_NUMBER)) {
int turn = getIntParam(line, 1);
Assert.assertEquals("Turn numbers are not equal", turn, currentGame.getTurnNum());
return;
}
if (type.equals(CardTestPlayerBase.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(CardTestPlayerBase.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(CardTestPlayerBase.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(CardTestPlayerBase.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);
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;
}
}
}
}

View file

@ -113,9 +113,9 @@ public abstract class MageTestBase {
for (Plugin plugin : config.getPlayerTypes()) {
PlayerFactory.getInstance().addPlayerType(plugin.getName(), loadPlugin(plugin));
}
for (Plugin plugin : config.getDeckTypes()) {
DeckValidatorFactory.getInstance().addDeckType(plugin.getName(), loadPlugin(plugin));
}
// for (Plugin plugin : config.getDeckTypes()) {
// DeckValidatorFactory.getInstance().addDeckType(plugin.getName(), loadPlugin(plugin));
// }
Copier.setLoader(classLoader);
}
@ -296,6 +296,6 @@ public abstract class MageTestBase {
}
protected Player createPlayer(String name, String playerType) {
return PlayerFactory.getInstance().createPlayer(playerType, name, Constants.RangeOfInfluence.ALL, 10);
return PlayerFactory.getInstance().createPlayer(playerType, name, Constants.RangeOfInfluence.ALL, 5);
}
}

View file

@ -0,0 +1,302 @@
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;
import mage.server.tournament.TournamentFactory;
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 java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import mage.Constants.PhaseStep;
import org.mage.test.player.TestPlayer;
/**
* Base class for all tests.
*
* @author ayratn
*/
public abstract class MageTestPlayerBase {
protected static Logger logger = Logger.getLogger(MageTestPlayerBase.class);
public static PluginClassLoader classLoader = new PluginClassLoader();
private final static String pluginFolder = "plugins";
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 TestPlayer playerA;
protected TestPlayer playerB;
/**
* 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 PhaseStep stopAtStep = PhaseStep.UNTAP;
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);
logger.info("Starting MAGE tests");
logger.info("Logging level: " + logger.getLevel());
deleteSavedGames();
ConfigSettings config = ConfigSettings.getInstance();
for (GamePlugin plugin : config.getGameTypes()) {
GameFactory.getInstance().addGameType(plugin.getName(), loadGameType(plugin), loadPlugin(plugin));
}
// for (GamePlugin plugin : config.getTournamentTypes()) {
// TournamentFactory.getInstance().addTournamentType(plugin.getName(), loadTournamentType(plugin), loadPlugin(plugin));
// }
// for (Plugin plugin : config.getPlayerTypes()) {
// PlayerFactory.getInstance().addPlayerType(plugin.getName(), loadPlugin(plugin));
// }
// for (Plugin plugin : config.getDeckTypes()) {
// DeckValidatorFactory.getInstance().addDeckType(plugin.getName(), loadPlugin(plugin));
// }
Copier.setLoader(classLoader);
}
private static Class<?> loadPlugin(Plugin plugin) {
try {
classLoader.addURL(new File(pluginFolder + "/" + plugin.getJar()).toURI().toURL());
logger.info("Loading plugin: " + plugin.getClassName());
return Class.forName(plugin.getClassName(), true, classLoader);
} catch (ClassNotFoundException ex) {
logger.warn("Plugin not Found:" + plugin.getJar() + " - check plugin folder");
} catch (Exception ex) {
logger.fatal("Error loading plugin " + plugin.getJar(), ex);
}
return null;
}
private static MatchType loadGameType(GamePlugin plugin) {
try {
classLoader.addURL(new File(pluginFolder + "/" + plugin.getJar()).toURI().toURL());
logger.info("Loading game type: " + plugin.getClassName());
return (MatchType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance();
} catch (ClassNotFoundException ex) {
logger.warn("Game type not found:" + plugin.getJar() + " - check plugin folder");
} catch (Exception ex) {
logger.fatal("Error loading game type " + plugin.getJar(), ex);
}
return null;
}
private static TournamentType loadTournamentType(GamePlugin plugin) {
try {
classLoader.addURL(new File(pluginFolder + "/" + plugin.getJar()).toURI().toURL());
logger.info("Loading tournament type: " + plugin.getClassName());
return (TournamentType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance();
} catch (ClassNotFoundException ex) {
logger.warn("Tournament type not found:" + plugin.getJar() + " - check plugin folder");
} catch (Exception ex) {
logger.fatal("Error loading game type " + plugin.getJar(), ex);
}
return null;
}
private static void deleteSavedGames() {
File directory = new File("saved/");
if (!directory.exists())
directory.mkdirs();
File[] files = directory.listFiles(
new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".game");
}
}
);
for (File file : files) {
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 TestPlayer createPlayer(String name) {
return new TestPlayer(name, Constants.RangeOfInfluence.ALL);
}
}

View file

@ -0,0 +1,405 @@
package org.mage.test.serverside.base.impl;
import mage.Constants;
import mage.abilities.Ability;
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.MageTestPlayerBase;
import java.util.List;
import java.util.UUID;
import mage.Constants.PhaseStep;
import org.mage.test.player.TestPlayer;
/**
* API for test initialization and asserting the test results.
*
* @author ayratn
*/
public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase 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, playerA, "Mountain", 5);
// hand:ComputerA:Mountain:4
addCard(Constants.Zone.HAND, playerA, "Mountain", 5);
// library:ComputerA:clear:0
removeAllCardsFromLibrary(playerA);
// library:ComputerA:Mountain:10
addCard(Constants.Zone.LIBRARY, playerA, "Mountain", 10);
// *** ComputerB ***
// battlefield:ComputerB:Plains:2
addCard(Constants.Zone.BATTLEFIELD, playerB, "Plains", 2);
// hand:ComputerB:Plains:2
addCard(Constants.Zone.HAND, playerB, "Plains", 2);
// library:ComputerB:clear:0
removeAllCardsFromLibrary(playerB);
// library:ComputerB:Plains:10
addCard(Constants.Zone.LIBRARY, playerB, "Plains", 10);
}
/**
* Default game initialization params for white player (that plays with Plains)
*/
public void useWhiteDefault() {
// *** ComputerA ***
addCard(Constants.Zone.BATTLEFIELD, playerA, "Plains", 5);
addCard(Constants.Zone.HAND, playerA, "Plains", 5);
removeAllCardsFromLibrary(playerA);
addCard(Constants.Zone.LIBRARY, playerA, "Plains", 10);
// *** ComputerB ***
addCard(Constants.Zone.BATTLEFIELD, playerB, "Plains", 2);
addCard(Constants.Zone.HAND, playerB, "Plains", 2);
removeAllCardsFromLibrary(playerB);
addCard(Constants.Zone.LIBRARY, playerB, "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(playerA)) {
commandsA.put(Constants.Zone.LIBRARY, "clear");
} else if (player.equals(playerB)) {
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 playerA or playerB.
* @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 playerA or playerB.
* @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 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
*/
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);
if (card == null) {
throw new IllegalArgumentException("[TEST] Couldn't find a card: " + cardName);
}
PermanentCard p = new PermanentCard(card, null);
p.setTapped(tapped);
if (player.equals(playerA)) {
battlefieldCardsA.add(p);
} else if (player.equals(playerB)) {
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(playerA)) {
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(playerB)) {
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(playerA)) {
commandsA.put(Constants.Zone.OUTSIDE, "life:" + String.valueOf(life));
} else if (player.equals(playerB)) {
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);
stopAtStep = PhaseStep.UNTAP;
}
/**
* Define turn number and step to stop the game on.
*/
public void setStopAt(int turn, PhaseStep step) {
stopOnTurn = turn == -1 ? null : Integer.valueOf(turn);
stopAtStep = step;
}
/**
* 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(playerA)) {
GameResult actual = CardTestAPI.GameResult.DRAW;
if (currentGame.getWinner().equals("Player PlayerA is the winner")) {
actual = CardTestAPI.GameResult.WON;
} else if (currentGame.getWinner().equals("Player PlayerB is the winner")) {
actual = CardTestAPI.GameResult.LOST;
}
Assert.assertEquals("Game results are not equal", result, actual);
} else if (player.equals(playerB)) {
GameResult actual = CardTestAPI.GameResult.DRAW;
if (currentGame.getWinner().equals("Player PlayerB is the winner")) {
actual = CardTestAPI.GameResult.WON;
} else if (currentGame.getWinner().equals("Player PlayerA 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);
}
}
/**
* {@inheritDoc}
*/
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;
}
}
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));
}
}
/**
* 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);
}
public Permanent getPermanent(String cardName, UUID controller) {
Permanent permanent0 = null;
int count = 0;
for (Permanent permanent : currentGame.getBattlefield().getAllPermanents()) {
if (permanent.getControllerId().equals(controller)) {
if (permanent.getName().equals(cardName)) {
permanent0 = permanent;
count++;
}
}
}
Assert.assertNotNull("Couldn't find a card with specified name: " + cardName, permanent0);
Assert.assertEquals("More than one permanent was found: " + cardName + "(" + count + ")", 1, count);
return permanent0;
}
public void playLand(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.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, String targetName) {
player.addAction(turnNum, step, "activate:Cast " + cardName + ";target=" + targetName);
}
public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, Player target) {
player.addAction(turnNum, step, "activate:" + ability + ";target=" + target.getName());
}
public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String targetName) {
player.addAction(turnNum, step, "activate:" + ability + ";target=" + targetName);
}
public void useAbility(int turnNum, PhaseStep step, TestPlayer player, String cardName) {
}
public void attack(int turnNum, TestPlayer player, String attacker) {
player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, "attack:"+attacker);
}
public void block(int turnNum, TestPlayer player, String blocker, String attacker) {
player.addAction(turnNum, PhaseStep.DECLARE_BLOCKERS, "block:"+blocker+";"+attacker);
}
}

View file

@ -1,56 +1,42 @@
package org.mage.test.serverside.cards.abilities;
import mage.Constants;
import mage.Constants.PhaseStep;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestAPI;
import org.mage.test.serverside.base.CardTestBase;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author ayratn
*/
public class ProtectionFromColorTest extends CardTestBase {
public class ProtectionFromColorTest extends CardTestPlayerBase {
@Test
public void testAgainstAbilityInTheStack() {
useRedDefault();
addCard(Constants.Zone.BATTLEFIELD, playerA, "Royal Assassin");
// tapped White Knight with Protection from Black
addCard(Constants.Zone.BATTLEFIELD, playerB, "White Knight", 1, true);
addCard(Constants.Zone.BATTLEFIELD, playerB, "Runeclaw Bear", 1, true);
// one not tapped White Knight to prevent AI from attacking
addCard(Constants.Zone.BATTLEFIELD, playerB, "White Knight", 1, false);
setStopOnTurn(2);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Destroy target tapped creature. ", "White Knight");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertTurn(2);
assertResult(playerA, CardTestAPI.GameResult.DRAW);
assertLife(playerA, 20);
assertLife(playerB, 20);
// no one should be destroyed
assertPermanentCount(playerB, "White Knight", 2);
assertPermanentCount(playerB, "Runeclaw Bear", 0);
assertPermanentCount(playerB, "White Knight", 1);
}
@Test
public void testAgainstAbilityInTheStackNoProtection() {
useRedDefault();
addCard(Constants.Zone.BATTLEFIELD, playerA, "Royal Assassin");
addCard(Constants.Zone.BATTLEFIELD, playerB, "Runeclaw Bear", 1, true);
addCard(Constants.Zone.BATTLEFIELD, playerB, "Runeclaw Bear", 1, false);
setStopOnTurn(2);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Destroy target tapped creature. ", "Runeclaw Bear");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertTurn(2);
assertResult(playerA, CardTestAPI.GameResult.DRAW);
assertLife(playerA, 20);
assertLife(playerB, 20);
// One should have beendestroyed by Royal Assassin
assertPermanentCount(playerB, "Runeclaw Bear", 1);
assertPermanentCount(playerB, "Runeclaw Bear", 0);
}
}

View file

@ -3,27 +3,24 @@ package org.mage.test.serverside.cards.abilities;
import mage.Constants;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestBase;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author ayratn
*/
public class ProtectionFromTypeTest extends CardTestBase {
public class ProtectionFromTypeTest extends CardTestPlayerBase {
@Test
public void testProtectionFromArtifacts() {
useRedDefault();
addCard(Constants.Zone.HAND, playerA, "Trigon of Corruption");
addCard(Constants.Zone.BATTLEFIELD, playerA, "Trigon of Corruption");
addCard(Constants.Zone.BATTLEFIELD, playerB, "Tel-Jilad Fallen");
setStopOnTurn(2);
activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{2},Remove a Charge counter from {this}, {T}: put a -1/-1 counter on target creature. ", "Tel-Jilad Fallen");
setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT);
execute();
assertTurn(2);
assertResult(playerA, GameResult.DRAW);
assertLife(playerA, 20);
assertLife(playerB, 20);
// no one should be destroyed
assertPermanentCount(playerB, "Tel-Jilad Fallen", 1);
}
@ -31,19 +28,15 @@ public class ProtectionFromTypeTest extends CardTestBase {
@Test
public void testNoProtection() {
useRedDefault();
addCard(Constants.Zone.HAND, playerA, "Trigon of Corruption");
addCard(Constants.Zone.BATTLEFIELD, playerA, "Trigon of Corruption");
addCard(Constants.Zone.BATTLEFIELD, playerB, "Coral Merfolk");
setStopOnTurn(2);
activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{2},Remove a Charge counter from {this}, {T}: put a -1/-1 counter on target creature. ", "Coral Merfolk");
setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT);
execute();
assertTurn(2);
assertResult(playerA, GameResult.DRAW);
assertLife(playerA, 20);
assertLife(playerB, 20);
// no one should be destroyed
// Coral Merfolk should be destroyed
assertPermanentCount(playerB, "Coral Merfolk", 0);
}
}