Test framework: added basic aliases support (see full info at #5451):

* generates aliases by addCard command (for one or multiple cards);
 * added support of `castSpell` command;
 * added show command to print aliases list with connected objects and zones;
 * added check command to control alias's object exists;
This commit is contained in:
Oleg Agafonov 2018-12-03 06:15:54 +04:00
parent 86ac1fcb1a
commit b172f3c44a
3 changed files with 294 additions and 24 deletions

View file

@ -1,5 +1,6 @@
package org.mage.test.player;
import mage.MageItem;
import mage.MageObject;
import mage.MageObjectReference;
import mage.ObjectColor;
@ -74,6 +75,7 @@ public class TestPlayer implements Player {
private final List<PlayerAction> actions = new ArrayList<>();
private final List<String> choices = new ArrayList<>(); // choices stack for choice
private final List<String> targets = new ArrayList<>(); // targets stack for choose (it's uses on empty direct target by cast command)
private final Map<String, UUID> aliases = new HashMap<>(); // aliases for game objects/players (use it for cards with same name to save and use)
private final List<String> modesSet = new ArrayList<>();
private final ComputerPlayer computerPlayer;
@ -102,6 +104,7 @@ public class TestPlayer implements Player {
this.actions.addAll(testPlayer.actions);
this.choices.addAll(testPlayer.choices);
this.targets.addAll(testPlayer.targets);
this.aliases.putAll(testPlayer.aliases);
this.modesSet.addAll(testPlayer.modesSet);
this.computerPlayer = testPlayer.computerPlayer.copy();
if (testPlayer.groupsForTargetHandling != null) {
@ -121,6 +124,18 @@ public class TestPlayer implements Player {
return this.targets;
}
public Map<String, UUID> getAliases() {
return this.aliases;
}
public UUID getAliasByName(String searchName) {
if (searchName.startsWith("@")) {
return this.aliases.getOrDefault(searchName.substring(1), null);
} else {
return this.aliases.getOrDefault(searchName, null);
}
}
public void addModeChoice(String mode) {
modesSet.add(mode);
}
@ -129,6 +144,10 @@ public class TestPlayer implements Player {
targets.add(target);
}
public void addAlias(String name, UUID Id) {
aliases.put(name, Id);
}
public ManaOptions getAvailableManaTest(Game game) {
return computerPlayer.getManaAvailable(game);
}
@ -314,6 +333,30 @@ public class TestPlayer implements Player {
return result;
}
public String generateAliasName(String baseAlias, boolean useMiltiNames, int iteration) {
if (useMiltiNames) {
return baseAlias + "." + iteration;
} else {
return baseAlias;
}
}
private boolean isObjectHaveTargetNameOrAliase(MageObject object, String nameOrAliase) {
if (object == null || nameOrAliase == null) {
return false;
}
if (nameOrAliase.startsWith("@") && object.getId().equals(getAliasByName(nameOrAliase))) {
return true;
}
if (nameOrAliase.isEmpty() && object.getName().isEmpty()) {
return true;
}
return object.getName().startsWith(nameOrAliase);
}
private boolean handleNonPlayerTargetTarget(String target, Ability ability, Game game) {
boolean result = true;
if (target == null) {
@ -375,28 +418,46 @@ public class TestPlayer implements Player {
for (UUID id : currentTarget.possibleTargets(ability.getSourceId(), ability.getControllerId(), game)) {
if (!currentTarget.getTargets().contains(id)) {
MageObject object = game.getObject(id);
if (object != null
&& ((object.isCopy() && !originOnly) || (!object.isCopy() && !copyOnly))
&& ((!targetName.isEmpty() && object.getName().startsWith(targetName)) || (targetName.isEmpty() && object.getName().isEmpty()))) {
if (currentTarget.getNumberOfTargets() == 1) {
currentTarget.clearChosen();
}
if (currentTarget instanceof TargetCreaturePermanentAmount) {
// supports only to set the complete amount to one target
TargetCreaturePermanentAmount targetAmount = (TargetCreaturePermanentAmount) currentTarget;
targetAmount.setAmount(ability, game);
int amount = targetAmount.getAmountRemaining();
targetAmount.addTarget(id, amount, ability, game);
targetsSet++;
} else {
currentTarget.addTarget(id, ability, game);
targetsSet++;
}
if (currentTarget.getTargets().size() == currentTarget.getMaxNumberOfTargets()) {
index++;
}
break;
if (object == null) {
continue;
}
// only origin
if (originOnly && object.isCopy()) {
continue;
}
// only copy
if (copyOnly && !object.isCopy()) {
continue;
}
// need by alias or by name
if (!isObjectHaveTargetNameOrAliase(object, targetName)) {
continue;
}
// founded, can use as target
if (currentTarget.getNumberOfTargets() == 1) {
currentTarget.clearChosen();
}
if (currentTarget instanceof TargetCreaturePermanentAmount) {
// supports only to set the complete amount to one target
TargetCreaturePermanentAmount targetAmount = (TargetCreaturePermanentAmount) currentTarget;
targetAmount.setAmount(ability, game);
int amount = targetAmount.getAmountRemaining();
targetAmount.addTarget(id, amount, ability, game);
targetsSet++;
} else {
currentTarget.addTarget(id, ability, game);
targetsSet++;
}
if (currentTarget.getTargets().size() == currentTarget.getMaxNumberOfTargets()) {
index++;
}
break;
}
}
}
@ -607,6 +668,13 @@ public class TestPlayer implements Player {
actions.remove(action);
wasProccessed = true;
}
// check aliase at zone: alias name, zone, must have (only for TestPlayer)
if (params[0].equals(CHECK_COMMAND_ALIAS_ZONE) && params.length == 4) {
assertAliasZone(action, game, this, params[1], Zone.valueOf(params[2]), Boolean.parseBoolean(params[3]));
actions.remove(action);
wasProccessed = true;
}
}
if (!wasProccessed) {
Assert.fail("Unknow check command or params: " + command);
@ -674,6 +742,15 @@ public class TestPlayer implements Player {
actions.remove(action);
wasProccessed = true;
}
// show aliases
if (params[0].equals(SHOW_COMMAND_ALIASES) && params.length == 1) {
printStart(action.getActionName());
printAliases(game, this);
printEnd();
actions.remove(action);
wasProccessed = true;
}
}
if (!wasProccessed) {
@ -777,6 +854,38 @@ public class TestPlayer implements Player {
}
}
private String getAliasInfo(Game game, TestPlayer player, String aliasName) {
MageItem item = findAliasObject(game, player, aliasName);
if (item == null) {
return aliasName + " [not exists]";
}
if (item instanceof MageObject) {
Zone zone = game.getState().getZone(item.getId());
return aliasName + " - " + ((MageObject) item).getIdName() + " - " + (zone != null ? zone.toString() : "null");
}
if (item instanceof Player) {
return aliasName + " - " + ((Player) item).getName();
}
return aliasName + " [unknown object " + item.getId() + "]";
}
private void printAliases(Game game, TestPlayer player) {
System.out.println("Total aliases: " + player.getAliases().size());
List<String> data = player.getAliases().entrySet().stream()
.map(entry -> (getAliasInfo(game, player, entry.getKey())))
.sorted()
.collect(Collectors.toList());
for (String s : data) {
System.out.println(s);
}
}
private void assertPT(PlayerAction action, Game game, Player player, String permanentName, int Power, int Toughness) {
Permanent perm = findPermanentWithAssert(action, game, player, permanentName);
@ -891,6 +1000,36 @@ public class TestPlayer implements Player {
}
}
private MageItem findAliasObject(Game game, TestPlayer player, String aliasName) {
UUID objectId = player.getAliasByName(aliasName);
if (objectId == null) {
return null;
}
MageObject itemObject = game.getObject(objectId);
if (itemObject != null) {
return itemObject;
}
Player itemPlayer = game.getPlayer(objectId);
if (itemPlayer != null) {
return itemPlayer;
}
return null;
}
private void assertAliasZone(PlayerAction action, Game game, TestPlayer player, String aliasName, Zone needZone, boolean mustHave) {
MageItem item = findAliasObject(game, player, aliasName);
Zone currentZone = (item == null ? null : game.getState().getZone(item.getId()));
if (mustHave) {
Assert.assertEquals(action.getActionName() + " - alias " + aliasName + " must have zone " + needZone.toString(), needZone, currentZone);
} else {
Assert.assertNotEquals(action.getActionName() + " - alias " + aliasName + " must have not zone " + needZone.toString(), needZone, currentZone);
}
}
private void assertManaPoolInner(PlayerAction action, Player player, ManaType manaType, Integer amount) {
Integer current = player.getManaPool().get(manaType);
Assert.assertEquals(action.getActionName() + " - mana pool must contain [" + amount.toString() + " " + manaType.toString() + "], but found [" + current.toString() + "]", amount, current);
@ -1785,6 +1924,8 @@ public class TestPlayer implements Player {
this.choices.addAll(((TestPlayer) player).choices);
this.targets.clear();
this.targets.addAll(((TestPlayer) player).targets);
this.aliases.clear();
this.aliases.putAll(((TestPlayer) player).aliases);
computerPlayer.restore(player);
}
@ -2880,7 +3021,7 @@ public class TestPlayer implements Player {
boolean founded = false;
String foundedRecord = "";
CheckTargets:
for(String targetRecord : targets) {
for (String targetRecord : targets) {
String[] choiceSettings = targetRecord.split("\\^");
if (choiceSettings.length == 2 && choiceSettings[1].startsWith("X=")) {
// can choice
@ -2890,7 +3031,7 @@ public class TestPlayer implements Player {
Assert.assertNotEquals("choice amount must be not zero", 0, choiceAmount);
Assert.assertTrue("choice amount " + choiceAmount + "must be <= remaining " + target.getAmountRemaining(), choiceAmount <= target.getAmountRemaining());
for(UUID possibleTarget : target.possibleTargets(source.getSourceId(), source.getControllerId(), game)) {
for (UUID possibleTarget : target.possibleTargets(source.getSourceId(), source.getControllerId(), game)) {
MageObject objectPermanent = game.getObject(possibleTarget);
Player objectPlayer = game.getPlayer(possibleTarget);
String objectName = objectPermanent != null ? objectPermanent.getName() : objectPlayer.getName();

View file

@ -60,6 +60,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
public static final String CHECK_COMMAND_COLOR = "COLOR";
public static final String CHECK_COMMAND_SUBTYPE = "SUBTYPE";
public static final String CHECK_COMMAND_MANA_POOL = "MANA_POOL";
public static final String CHECK_COMMAND_ALIAS_ZONE = "ALIAS_ZONE";
// TODO: add target player param to commands
public static final String SHOW_COMMAND_LIBRARY = "LIBRARY";
@ -68,6 +69,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
public static final String SHOW_COMMAND_GRAVEYEARD = "GRAVEYARD";
public static final String SHOW_COMMAND_EXILE = "EXILE";
public static final String SHOW_COMMAND_AVAILABLE_ABILITIES = "AVAILABLE_ABILITIES";
public static final String SHOW_COMMAND_ALIASES = "ALIASES";
// TODO: add target player param to commands
public static final String ALIAS_COMMAND_ADD = "ADD";
protected GameOptions gameOptions;
@ -301,6 +306,14 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
check(checkName, turnNum, step, player, CHECK_COMMAND_MANA_POOL, colors, amount.toString());
}
public void checkAliasZone(String checkName, int turnNum, PhaseStep step, TestPlayer player, String alias, Zone zone) {
checkAliasZone(checkName, turnNum, step, player, alias, zone, true);
}
public void checkAliasZone(String checkName, int turnNum, PhaseStep step, TestPlayer player, String alias, Zone zone, Boolean mustHave) {
check(checkName, turnNum, step, player, CHECK_COMMAND_ALIAS_ZONE, alias, zone.toString(), mustHave.toString());
}
// show commands
private void show(String showName, int turnNum, PhaseStep step, TestPlayer player, String command, String... params) {
@ -335,6 +348,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
show(showName, turnNum, step, player, SHOW_COMMAND_AVAILABLE_ABILITIES);
}
public void showAliases(String showName, int turnNum, PhaseStep step, TestPlayer player) {
show(showName, turnNum, step, player, SHOW_COMMAND_ALIASES);
}
/**
* Removes all cards from player's library from the game. Usually this
* should be used once before initialization to form the library in certain
@ -399,6 +416,19 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
@Override
public void addCard(Zone gameZone, TestPlayer player, String cardName, int count, boolean tapped) {
// aliases for mage objects
String aliasName = "";
boolean useAliasMultiNames = (count != 1);
if (cardName.contains("@")) {
aliasName = cardName.substring(cardName.indexOf("@") + 1);
cardName = cardName.substring(0, cardName.indexOf("@"));
}
// one card = one aliase, massive adds can use auto-name
if (!useAliasMultiNames && !aliasName.isEmpty() && player.getAliasByName(aliasName) != null) {
Assert.fail("Can't add card " + cardName + " - alias " + aliasName + " already exists for " + player.getName());
}
if (gameZone == Zone.BATTLEFIELD) {
for (int i = 0; i < count; i++) {
CardInfo cardInfo = CardRepository.instance.findCard(cardName);
@ -409,6 +439,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
PermanentCard p = new PermanentCard(card.copy(), player.getId(), currentGame);
p.setTapped(tapped);
getBattlefieldCards(player).add(p);
if (!aliasName.isEmpty()) {
player.addAlias(player.generateAliasName(aliasName, useAliasMultiNames, i + 1), p.getId());
}
}
} else {
if (tapped) {
@ -422,6 +456,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
throw new AssertionError("Couldn't find a card: " + cardName);
}
cards.add(card);
if (!aliasName.isEmpty()) {
player.addAlias(player.generateAliasName(aliasName, useAliasMultiNames, i + 1), card.getId());
}
}
}
}
@ -1246,7 +1284,6 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
public enum StackClause {
WHILE_ON_STACK,
WHILE_COPY_ON_STACK,
WHILE_NOT_ON_STACK

View file

@ -0,0 +1,92 @@
package org.mage.test.testapi;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author JayDi85
*/
public class TestAliases extends CardTestPlayerBase {
@Test
public void test_DifferentZones() {
addCard(Zone.LIBRARY, playerA, "Swamp@lib", 1);
addCard(Zone.HAND, playerA, "Swamp@hand", 1);
addCard(Zone.BATTLEFIELD, playerA, "Swamp@battle", 1);
addCard(Zone.GRAVEYARD, playerA, "Swamp@grave", 1);
showAliases("A aliases", 1, PhaseStep.UPKEEP, playerA);
checkAliasZone("lib", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "lib", Zone.LIBRARY);
checkAliasZone("hand", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "hand", Zone.HAND);
checkAliasZone("battle", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "battle", Zone.BATTLEFIELD);
checkAliasZone("grave", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "grave", Zone.GRAVEYARD);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
}
@Test
public void test_MultipleNames() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5);
addCard(Zone.BATTLEFIELD, playerA, "Island@isl", 5);
addCard(Zone.BATTLEFIELD, playerB, "Plains", 5);
addCard(Zone.BATTLEFIELD, playerB, "Mountain@mnt", 5);
checkPermanentCount("Swamp must exists", 1, PhaseStep.UPKEEP, playerA, "Swamp", 5);
checkPermanentCount("Island must exists", 1, PhaseStep.UPKEEP, playerA, "Island", 5);
checkPermanentCount("Plains must exists", 1, PhaseStep.UPKEEP, playerB, "Plains", 5);
checkPermanentCount("Mountain must exists", 1, PhaseStep.UPKEEP, playerB, "Mountain", 5);
//
showAliases("A aliases", 1, PhaseStep.UPKEEP, playerA);
showAliases("B aliases", 1, PhaseStep.UPKEEP, playerB);
// A
checkAliasZone("Swamp must not", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Swamp", Zone.BATTLEFIELD, false);
checkAliasZone("Swamp.1 must not", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Swamp.1", Zone.BATTLEFIELD, false);
checkAliasZone("Island must not", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Island", Zone.BATTLEFIELD, false);
checkAliasZone("isl must not", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "isl", Zone.BATTLEFIELD, false);
checkAliasZone("isl.1 must", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "isl.1", Zone.BATTLEFIELD, true);
checkAliasZone("isl.2 must", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "isl.2", Zone.BATTLEFIELD, true);
checkAliasZone("isl.5 must", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "isl.5", Zone.BATTLEFIELD, true);
// B
checkAliasZone("Plains must not", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "Plains", Zone.BATTLEFIELD, false);
checkAliasZone("Plains.1 must not", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "Plains.1", Zone.BATTLEFIELD, false);
checkAliasZone("Plains must not", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plains", Zone.BATTLEFIELD, false);
checkAliasZone("mnt must not", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "mnt", Zone.BATTLEFIELD, false);
checkAliasZone("mnt.1 must", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "mnt.1", Zone.BATTLEFIELD, true);
checkAliasZone("mnt.2 must", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "mnt.2", Zone.BATTLEFIELD, true);
checkAliasZone("mnt.5 must", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "mnt.5", Zone.BATTLEFIELD, true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
}
@Test
public void test_CastTarget() {
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion@lion", 5);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
addCard(Zone.HAND, playerA, "Lightning Bolt", 3);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "@lion.1");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "@lion.3");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "@lion.5");
showAliases("A aliases", 1, PhaseStep.POSTCOMBAT_MAIN, playerA);
checkAliasZone("1", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "lion.1", Zone.BATTLEFIELD, false);
checkAliasZone("2", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "lion.2", Zone.BATTLEFIELD, true);
checkAliasZone("3", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "lion.3", Zone.BATTLEFIELD, false);
checkAliasZone("4", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "lion.4", Zone.BATTLEFIELD, true);
checkAliasZone("5", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "lion.5", Zone.BATTLEFIELD, false);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertGraveyardCount(playerA, "Lightning Bolt", 3);
assertGraveyardCount(playerA, "Silvercoat Lion", 3);
}
}