tests: added verify test to check miss of controlled filter in equip abilities (related to #11473);

This commit is contained in:
Oleg Agafonov 2023-11-27 23:08:23 +04:00
parent a4c90d9b71
commit 3a92d67d10
9 changed files with 68 additions and 9 deletions

View file

@ -28,7 +28,10 @@ import mage.choices.Choice;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.filter.Filter;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.Predicates;
import mage.game.command.Dungeon;
import mage.game.command.Plane;
import mage.game.draft.DraftCube;
@ -2064,6 +2067,25 @@ public class VerifyCardDataTest {
}
}
// special check: equip abilities must have controlled predicate due rules
List<EquipAbility> equipAbilities = card.getAbilities()
.stream()
.filter(a -> a instanceof EquipAbility)
.map(a -> (EquipAbility) a)
.collect(Collectors.toList());
equipAbilities.forEach(a -> {
List<Predicate> allPredicates = new ArrayList<>();
a.getTargets().forEach(t -> Predicates.collectAllComponents(t.getFilter().getPredicates(), t.getFilter().getExtraPredicates(), allPredicates));
boolean hasControlledFilter = allPredicates
.stream()
.filter(p -> p instanceof TargetController.ControllerPredicate)
.map(p -> ((TargetController.ControllerPredicate) p).getController())
.anyMatch(tc -> tc.equals(TargetController.YOU));
if (!hasControlledFilter) {
fail(card, "abilities", "card has equip ability, but it doesn't use controllered filter - " + a.getRule());
}
});
// spells have only 1 ability
if (card.isInstantOrSorcery()) {
return;

View file

@ -452,7 +452,7 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
// wait dependency
// extraPredicates from some filters is player related, you don't need it here
List<Predicate> list = new ArrayList<>();
Predicates.collectAllComponents(filter.getPredicates(), list);
Predicates.collectAllComponents(filter.getPredicates(), filter.getExtraPredicates(), list);
if (list.stream().anyMatch(SubType.SubTypePredicate.class::isInstance)) {
this.addDependedToType(DependencyType.AddingCreatureType);
}

View file

@ -184,5 +184,12 @@ public enum TargetController {
public String toString() {
return "TargetController (" + controller.toString() + ')';
}
/**
* For tests
*/
public TargetController getController() {
return this.controller;
}
}
}

View file

@ -5,6 +5,7 @@ import mage.game.Game;
import mage.util.Copyable;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
@ -35,4 +36,8 @@ public interface Filter<E> extends Serializable, Copyable<Filter<E>> {
public void setLockedFilter(boolean lockedFilter);
List<Predicate<? super E>> getPredicates();
default List<Predicate> getExtraPredicates() {
return new ArrayList<>();
}
}

View file

@ -91,12 +91,17 @@ public class FilterCard extends FilterObject<Card> {
return new FilterCard(this);
}
@Override
public List<Predicate> getExtraPredicates() {
return new ArrayList<>(extraPredicates);
}
public static void checkPredicateIsSuitableForCardFilter(Predicate predicate) {
// card filter can't contain controller predicate (only permanents on battlefield have controller)
List<Predicate> list = new ArrayList<>();
Predicates.collectAllComponents(predicate, list);
if (list.stream().anyMatch(TargetController.ControllerPredicate.class::isInstance)) {
throw new IllegalArgumentException("Card filter doesn't support controller predicate");
throw new IllegalArgumentException("Wrong code usage: card filter doesn't support controller predicate");
}
}

View file

@ -4,6 +4,7 @@ import mage.abilities.Ability;
import mage.constants.SubType;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.filter.predicate.Predicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
@ -11,6 +12,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author North
@ -69,4 +71,9 @@ public class FilterPermanent extends FilterObject<Permanent> implements FilterIn
public FilterPermanent copy() {
return new FilterPermanent(this);
}
@Override
public List<Predicate> getExtraPredicates() {
return new ArrayList<>(extraPredicates);
}
}

View file

@ -3,6 +3,7 @@ package mage.filter;
import mage.abilities.Ability;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.filter.predicate.Predicate;
import mage.game.Game;
import mage.players.Player;
@ -56,4 +57,9 @@ public class FilterPlayer extends FilterImpl<Player> {
public FilterPlayer copy() {
return new FilterPlayer(this);
}
@Override
public List<Predicate> getExtraPredicates() {
return new ArrayList<>(extraPredicates);
}
}

View file

@ -3,6 +3,7 @@ package mage.filter;
import mage.abilities.Ability;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.filter.predicate.Predicate;
import mage.game.Game;
import mage.game.stack.StackObject;
@ -49,4 +50,9 @@ public class FilterStackObject extends FilterObject<StackObject> {
public FilterStackObject copy() {
return new FilterStackObject(this);
}
@Override
public List<Predicate> getExtraPredicates() {
return new ArrayList<>(extraPredicates);
}
}

View file

@ -232,17 +232,18 @@ public final class Predicates {
if (predicate instanceof NotPredicate) {
collectAllComponents(((NotPredicate) predicate).predicate, res);
} else if (predicate instanceof AndPredicate) {
collectAllComponents(((AndPredicate) predicate).components, res);
collectAllComponents(((AndPredicate) predicate).components, null, res);
} else if (predicate instanceof OrPredicate) {
collectAllComponents(((OrPredicate) predicate).components, res);
collectAllComponents(((OrPredicate) predicate).components, null, res);
} else {
res.add(predicate);
}
}
public static void collectAllComponents(List<Predicate> predicates, List<Predicate> res) {
predicates.forEach(p -> {
collectAllComponents(p, res);
});
public static void collectAllComponents(List<Predicate> predicates, List<Predicate> extraPredicates, List<Predicate> res) {
predicates.forEach(p -> collectAllComponents(p, res));
if (extraPredicates != null) {
extraPredicates.forEach(p -> collectAllComponents(p, res));
}
}
}