mirror of
https://github.com/magefree/mage.git
synced 2026-01-26 21:29:17 -08:00
tests: improved show playable abilities to print playable list instead unique (see showAvailableAbilities), added custom effect for transform tests (see addCustomEffect_TransformTarget);
This commit is contained in:
parent
3b603595a2
commit
50fd029c3b
5 changed files with 100 additions and 25 deletions
|
|
@ -1026,10 +1026,10 @@ public class TestPlayer implements Player {
|
|||
wasProccessed = true;
|
||||
}
|
||||
|
||||
// show available abilities
|
||||
if (params[0].equals(SHOW_COMMAND_AVAILABLE_ABILITIES) && params.length == 1) {
|
||||
// show available abilities: show only unique list
|
||||
if (params[0].equals(SHOW_COMMAND_AVAILABLE_ABILITIES) && params.length == 2) {
|
||||
printStart(game, action.getActionName());
|
||||
printAbilities(game, computerPlayer.getPlayable(game, true));
|
||||
printAbilities(game, computerPlayer.getPlayable(game, true, Zone.ALL, Boolean.parseBoolean(params[1])));
|
||||
printEnd();
|
||||
actions.remove(action);
|
||||
wasProccessed = true;
|
||||
|
|
@ -1247,13 +1247,12 @@ public class TestPlayer implements Player {
|
|||
if (abilities == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> data = abilities.stream()
|
||||
.map(a -> (a.getZone() + " -> "
|
||||
+ a.getSourceObject(game).getIdName() + " -> "
|
||||
+ (a.toString().startsWith("Cast ") ? "[" + a.getManaCostsToPay().getText() + "] -> " : "") // printed cost, not modified
|
||||
+ (a.toString().length() > 0
|
||||
? a.toString().substring(0, Math.min(40, a.toString().length())) + "..."
|
||||
? CardUtil.substring(a.toString(), 40, "...")
|
||||
: a.getClass().getSimpleName())
|
||||
))
|
||||
.sorted()
|
||||
|
|
|
|||
|
|
@ -9,10 +9,7 @@ import mage.abilities.common.SimpleActivatedAbility;
|
|||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.DamageTargetEffect;
|
||||
import mage.abilities.effects.common.DestroyTargetEffect;
|
||||
import mage.abilities.effects.common.ReturnFromExileEffect;
|
||||
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
|
||||
import mage.abilities.effects.common.*;
|
||||
import mage.abilities.effects.common.cost.SpellsCostIncreasingAllEffect;
|
||||
import mage.abilities.effects.common.cost.SpellsCostReductionAllEffect;
|
||||
import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
|
||||
|
|
@ -519,6 +516,21 @@ public abstract class MageTestPlayerBase {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add target transform ability that can be called by text "target transform"
|
||||
*
|
||||
* @param controller
|
||||
*/
|
||||
protected void addCustomEffect_TransformTarget(TestPlayer controller) {
|
||||
Ability ability = new SimpleActivatedAbility(new TransformTargetEffect().setText("target transform"), new ManaCostsImpl<>(""));
|
||||
ability.addTarget(new TargetPermanent());
|
||||
addCustomCardWithAbility(
|
||||
"target transform for " + controller.getName(),
|
||||
controller,
|
||||
ability
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return target card to hand that can be called by text "return from ..."
|
||||
*
|
||||
|
|
|
|||
|
|
@ -540,7 +540,14 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
}
|
||||
|
||||
public void showAvailableAbilities(String showName, int turnNum, PhaseStep step, TestPlayer player) {
|
||||
show(showName, turnNum, step, player, SHOW_COMMAND_AVAILABLE_ABILITIES);
|
||||
showAvailableAbilities(showName, turnNum, step, player, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param showOnlyUniqueAbilities return full list or unique only (duplicated abilities with same name will be combined in one)
|
||||
*/
|
||||
public void showAvailableAbilities(String showName, int turnNum, PhaseStep step, TestPlayer player, Boolean showOnlyUniqueAbilities) {
|
||||
show(showName, turnNum, step, player, SHOW_COMMAND_AVAILABLE_ABILITIES, showOnlyUniqueAbilities.toString());
|
||||
}
|
||||
|
||||
public void showAvailableMana(String showName, int turnNum, PhaseStep step, TestPlayer player) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ package org.mage.test.utils;
|
|||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import mage.util.CardUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
|
|
@ -75,7 +77,7 @@ public class CardUtilTest extends CardTestPlayerBase {
|
|||
@Test
|
||||
public void testJadziPlayingLandAndCast() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, jadzi);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1+1+1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1 + 1 + 1);
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt", 2);
|
||||
addCard(Zone.LIBRARY, playerA, "Cragcrown Pathway");
|
||||
addCard(Zone.LIBRARY, playerA, akoumWarrior);
|
||||
|
|
@ -92,4 +94,32 @@ public class CardUtilTest extends CardTestPlayerBase {
|
|||
assertPermanentCount(playerA, akoumWarrior, 1);
|
||||
assertPermanentCount(playerA, "Cragcrown Pathway", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Substring() {
|
||||
String str = "12345";
|
||||
String ending = "...";
|
||||
|
||||
Assert.assertEquals("", CardUtil.substring(str, 0));
|
||||
Assert.assertEquals("1", CardUtil.substring(str, 1));
|
||||
Assert.assertEquals("12", CardUtil.substring(str, 2));
|
||||
Assert.assertEquals("123", CardUtil.substring(str, 3));
|
||||
Assert.assertEquals("1234", CardUtil.substring(str, 4));
|
||||
Assert.assertEquals("12345", CardUtil.substring(str, 5));
|
||||
Assert.assertEquals("12345", CardUtil.substring(str, 6));
|
||||
Assert.assertEquals("12345", CardUtil.substring(str, 7));
|
||||
Assert.assertEquals("12345", CardUtil.substring(str, 8));
|
||||
Assert.assertEquals("12345", CardUtil.substring(str, 9));
|
||||
|
||||
Assert.assertEquals("", CardUtil.substring(str, 0, ending));
|
||||
Assert.assertEquals(".", CardUtil.substring(str, 1, ending));
|
||||
Assert.assertEquals("..", CardUtil.substring(str, 2, ending));
|
||||
Assert.assertEquals("...", CardUtil.substring(str, 3, ending));
|
||||
Assert.assertEquals("1...", CardUtil.substring(str, 4, ending));
|
||||
Assert.assertEquals("12345", CardUtil.substring(str, 5, ending));
|
||||
Assert.assertEquals("12345", CardUtil.substring(str, 6, ending));
|
||||
Assert.assertEquals("12345", CardUtil.substring(str, 7, ending));
|
||||
Assert.assertEquals("12345", CardUtil.substring(str, 8, ending));
|
||||
Assert.assertEquals("12345", CardUtil.substring(str, 9, ending));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -905,7 +905,7 @@ public final class CardUtil {
|
|||
}
|
||||
|
||||
public static String getSimpleCountersText(int amount, String forOne, String counterType) {
|
||||
return numberToText(amount, forOne)+" "+counterType+" counter"+ (amount==1 ? "" : "s");
|
||||
return numberToText(amount, forOne) + " " + counterType + " counter" + (amount == 1 ? "" : "s");
|
||||
}
|
||||
|
||||
public static String getOneOneCountersText(int amount) {
|
||||
|
|
@ -1654,6 +1654,7 @@ public final class CardUtil {
|
|||
}
|
||||
return zcc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a MageObjectReference of the ability's source
|
||||
* Subtract 1 zcc if not on the stack, referencing when it was on the stack if it's a resolved permanent.
|
||||
|
|
@ -1702,19 +1703,21 @@ public final class CardUtil {
|
|||
}
|
||||
return costTags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a specific tag exists in the cost tags of either the source ability, or the permanent source of the ability.
|
||||
* Works in any moment (even before source ability activated)
|
||||
*
|
||||
* @param game
|
||||
* @param source
|
||||
* @param tag The tag's string identifier to look up
|
||||
* @param tag The tag's string identifier to look up
|
||||
* @return if the tag was found
|
||||
*/
|
||||
public static boolean checkSourceCostsTagExists(Game game, Ability source, String tag) {
|
||||
Map<String, Object> costTags = getSourceCostsTagsMap(game, source);
|
||||
return costTags != null && costTags.containsKey(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a specific tag in the cost tags of either the source ability, or the permanent source of the ability.
|
||||
* Works in any moment (even before source ability activated)
|
||||
|
|
@ -1722,11 +1725,11 @@ public final class CardUtil {
|
|||
*
|
||||
* @param game
|
||||
* @param source
|
||||
* @param tag The tag's string identifier to look up
|
||||
* @param tag The tag's string identifier to look up
|
||||
* @param defaultValue A default value to return if the tag is not found
|
||||
* @return The object stored by the tag if found, the default if not
|
||||
*/
|
||||
public static <T> T getSourceCostsTag(Game game, Ability source, String tag, T defaultValue){
|
||||
public static <T> T getSourceCostsTag(Game game, Ability source, String tag, T defaultValue) {
|
||||
Map<String, Object> costTags = getSourceCostsTagsMap(game, source);
|
||||
if (costTags != null) {
|
||||
Object value = costTags.getOrDefault(tag, defaultValue);
|
||||
|
|
@ -1748,13 +1751,14 @@ public final class CardUtil {
|
|||
return "pay " + text;
|
||||
}
|
||||
|
||||
private static boolean isImmutableObject(Object o){
|
||||
private static boolean isImmutableObject(Object o) {
|
||||
return o == null
|
||||
|| o instanceof Number || o instanceof Boolean || o instanceof String
|
||||
|| o instanceof MageObjectReference || o instanceof UUID
|
||||
|| o instanceof Enum;
|
||||
}
|
||||
public static <T> T deepCopyObject(T value){
|
||||
|
||||
public static <T> T deepCopyObject(T value) {
|
||||
if (isImmutableObject(value)) {
|
||||
return value;
|
||||
} else if (value instanceof Copyable) {
|
||||
|
|
@ -1781,53 +1785,58 @@ public final class CardUtil {
|
|||
return (T) deepCopyHashMap((HashMap) value);
|
||||
} else if (value instanceof List) {
|
||||
return (T) deepCopyList((List) value);
|
||||
} else if (value instanceof AbstractMap.SimpleImmutableEntry){ //Used by Leonin Arbiter, Vessel Of The All Consuming Wanderer as a generic Pair class
|
||||
} else if (value instanceof AbstractMap.SimpleImmutableEntry) { //Used by Leonin Arbiter, Vessel Of The All Consuming Wanderer as a generic Pair class
|
||||
AbstractMap.SimpleImmutableEntry entryValue = (AbstractMap.SimpleImmutableEntry) value;
|
||||
return (T) new AbstractMap.SimpleImmutableEntry(deepCopyObject(entryValue.getKey()),deepCopyObject(entryValue.getValue()));
|
||||
return (T) new AbstractMap.SimpleImmutableEntry(deepCopyObject(entryValue.getKey()), deepCopyObject(entryValue.getValue()));
|
||||
} else {
|
||||
throw new IllegalStateException("Unhandled object " + value.getClass().getSimpleName() + " during deep copy, must add explicit handling of all Object types");
|
||||
}
|
||||
}
|
||||
|
||||
private static <T extends Comparable<T>> TreeSet<T> deepCopyTreeSet(TreeSet<T> original) {
|
||||
if (original.getClass() != TreeSet.class) {
|
||||
throw new IllegalStateException("Unhandled TreeSet type " + original.getClass().getSimpleName() + " in deep copy");
|
||||
}
|
||||
TreeSet<T> newSet = new TreeSet<>();
|
||||
for (T value : original){
|
||||
for (T value : original) {
|
||||
newSet.add((T) deepCopyObject(value));
|
||||
}
|
||||
return newSet;
|
||||
}
|
||||
|
||||
private static <T> HashSet<T> deepCopyHashSet(Set<T> original) {
|
||||
if (original.getClass() != HashSet.class) {
|
||||
throw new IllegalStateException("Unhandled HashSet type " + original.getClass().getSimpleName() + " in deep copy");
|
||||
}
|
||||
HashSet<T> newSet = new HashSet<>(original.size());
|
||||
for (T value : original){
|
||||
for (T value : original) {
|
||||
newSet.add((T) deepCopyObject(value));
|
||||
}
|
||||
return newSet;
|
||||
}
|
||||
|
||||
private static <T> LinkedHashSet<T> deepCopyLinkedHashSet(LinkedHashSet<T> original) {
|
||||
if (original.getClass() != LinkedHashSet.class) {
|
||||
throw new IllegalStateException("Unhandled LinkedHashSet type " + original.getClass().getSimpleName() + " in deep copy");
|
||||
}
|
||||
LinkedHashSet<T> newSet = new LinkedHashSet<>(original.size());
|
||||
for (T value : original){
|
||||
for (T value : original) {
|
||||
newSet.add((T) deepCopyObject(value));
|
||||
}
|
||||
return newSet;
|
||||
}
|
||||
|
||||
private static <T> List<T> deepCopyList(List<T> original) { //always returns an ArrayList
|
||||
if (original.getClass() != ArrayList.class) {
|
||||
throw new IllegalStateException("Unhandled List type " + original.getClass().getSimpleName() + " in deep copy");
|
||||
}
|
||||
ArrayList<T> newList = new ArrayList<>(original.size());
|
||||
for (T value : original){
|
||||
for (T value : original) {
|
||||
newList.add((T) deepCopyObject(value));
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
private static <K, V> HashMap<K, V> deepCopyHashMap(Map<K, V> original) {
|
||||
if (original.getClass() != HashMap.class) {
|
||||
throw new IllegalStateException("Unhandled HashMap type " + original.getClass().getSimpleName() + " in deep copy");
|
||||
|
|
@ -1838,6 +1847,7 @@ public final class CardUtil {
|
|||
}
|
||||
return newMap;
|
||||
}
|
||||
|
||||
private static <K, V> LinkedHashMap<K, V> deepCopyLinkedHashMap(Map<K, V> original) {
|
||||
if (original.getClass() != LinkedHashMap.class) {
|
||||
throw new IllegalStateException("Unhandled LinkedHashMap type " + original.getClass().getSimpleName() + " in deep copy");
|
||||
|
|
@ -1848,6 +1858,7 @@ public final class CardUtil {
|
|||
}
|
||||
return newMap;
|
||||
}
|
||||
|
||||
private static <K extends Enum<K>, V> EnumMap<K, V> deepCopyEnumMap(Map<K, V> original) {
|
||||
if (original.getClass() != EnumMap.class) {
|
||||
throw new IllegalStateException("Unhandled EnumMap type " + original.getClass().getSimpleName() + " in deep copy");
|
||||
|
|
@ -2076,18 +2087,34 @@ public final class CardUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public static String substring(String str, int maxLength) {
|
||||
return substring(str, maxLength, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't raise exception, so must be used instead standard substring calls all the time
|
||||
*
|
||||
* @param str
|
||||
* @param maxLength
|
||||
* @param overflowEnding can add ... at the end
|
||||
* @return
|
||||
*/
|
||||
public static String substring(String str, int maxLength) {
|
||||
public static String substring(String str, int maxLength, String overflowEnding) {
|
||||
if (str == null || str.isEmpty()) {
|
||||
return str;
|
||||
}
|
||||
return str.substring(0, Math.min(str.length(), maxLength));
|
||||
|
||||
// full
|
||||
if (str.length() <= maxLength) {
|
||||
return str;
|
||||
}
|
||||
|
||||
// short
|
||||
if (maxLength <= overflowEnding.length()) {
|
||||
return overflowEnding.substring(0, maxLength);
|
||||
} else {
|
||||
return (str + overflowEnding).substring(0, maxLength - overflowEnding.length()) + overflowEnding;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue