tests: added test for LKI from copied spell (related to Swan Song fix from #12883)

This commit is contained in:
Oleg Agafonov 2024-09-25 09:55:19 +04:00
parent afde449a0f
commit 701bd68d97
3 changed files with 55 additions and 3 deletions

View file

@ -22,7 +22,7 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
/** /**
* @author LevelX2 * @author LevelX2, JayDi85
*/ */
public class CopySpellTest extends CardTestPlayerBase { public class CopySpellTest extends CardTestPlayerBase {
@ -905,4 +905,56 @@ public class CopySpellTest extends CardTestPlayerBase {
Assert.fail(infoPrefix + " - " + "cards must have same zone and zcc: " + zcc1 + " - " + zone1 + " != " + zcc2 + " - " + zone2); Assert.fail(infoPrefix + " - " + "cards must have same zone and zcc: " + zcc1 + " - " + zone1 + " != " + zcc2 + " - " + zone2);
} }
} }
/**
* Bug: If Swan Song is used to counter a copied spell, no tokens are created #12883
*/
@Test
public void test_LKI() {
// Counter target enchantment, instant, or sorcery spell.
// Its controller creates a 2/2 blue Bird creature token with flying.
addCard(Zone.HAND, playerA, "Swan Song", 1); // {U}
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
//
// Until end of turn, whenever a player casts an instant or sorcery spell, that player copies it and
// may choose new targets for the copy.
addCard(Zone.HAND, playerA, "Bonus Round", 1); // {1}{R}{R}
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
//
addCard(Zone.HAND, playerA, "Lightning Bolt", 1); // {R}
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 1);
addCard(Zone.BATTLEFIELD, playerB, "Augmenting Automaton", 1);
checkPermanentCount("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, playerA, "Bird Token", 0);
checkPermanentCount("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, playerB, "Grizzly Bears", 1);
checkPermanentCount("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, playerB, "Augmenting Automaton", 1);
// prepare copy effect
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}", 3);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bonus Round");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
// cast and duplicate bolt
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt");
addTarget(playerA, "Grizzly Bears"); // original target
setChoice(playerA, true); // use new target
addTarget(playerA, "Augmenting Automaton"); // copy target
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, true); // resolve copy trigger
checkStackObject("on copy", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Lightning Bolt", 2);
// counter copy and save Augmenting Automaton
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {U}", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Swan Song", "Lightning Bolt[only copy]", "Lightning Bolt", StackClause.WHILE_COPY_ON_STACK);
setChoice(playerA, false); // no change target for duplicated counter spell (non-relevant here)
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, playerA, "Bird Token", 1);
checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, playerB, "Grizzly Bears", 0);
checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, playerB, "Augmenting Automaton", 1);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_COMBAT);
execute();
}
} }

View file

@ -1291,7 +1291,7 @@ public class TestPlayer implements Player {
private void printStack(Game game) { private void printStack(Game game) {
System.out.println("Stack objects: " + game.getStack().size()); System.out.println("Stack objects: " + game.getStack().size());
game.getStack().forEach(stack -> { game.getStack().forEach(stack -> {
System.out.println(stack.getStackAbility().toString()); System.out.println(stack.getStackAbility().toString() + (stack.isCopy() ? " [copy]" : ""));
}); });
} }

View file

@ -83,7 +83,7 @@ public class SpellStack extends ArrayDeque<StackObject> {
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.COUNTER, objectId, source, stackObject.getControllerId()))) { if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.COUNTER, objectId, source, stackObject.getControllerId()))) {
// spells are removed from stack by the card movement // spells are removed from stack by the card movement
if (!(stackObject instanceof Spell) if (!(stackObject instanceof Spell)
|| stackObject.isCopy()) { // ensure that copies of stackobjects have their history recorded ie: Swan Song || stackObject.isCopy()) { // !ensure that copies of stackobjects have their history recorded ie: Swan Song
this.remove(stackObject, game); this.remove(stackObject, game);
game.rememberLKI(Zone.STACK, stackObject); game.rememberLKI(Zone.STACK, stackObject);
} }