Skip to content

Commit f3ab772

Browse files
liamiak1claude
andcommitted
Add a regression test for the optional trigger life gate
Bringer of the Black Dawn's upkeep tutor, asserting both directions: it fires at 20 life and declines at 5, where paying 2 would drop it to 3. Drop this commit if you would rather not carry the test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent ce49e26 commit f3ab772

1 file changed

Lines changed: 62 additions & 0 deletions

File tree

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package forge.ai.ability;
2+
3+
import forge.ai.AITest;
4+
import forge.ai.SpellApiToAi;
5+
import forge.game.Game;
6+
import forge.game.ability.ApiType;
7+
import forge.game.card.Card;
8+
import forge.game.player.Player;
9+
import forge.game.spellability.SpellAbility;
10+
import forge.game.trigger.Trigger;
11+
import forge.game.zone.ZoneType;
12+
import org.testng.AssertJUnit;
13+
import org.testng.annotations.Test;
14+
15+
/**
16+
* An optional trigger must respect the AI's life-cost safety, the way the activated path already
17+
* does (the gate lives in SpellAbilityAi.doTrigger). Exercised with Bringer of the Black Dawn's
18+
* "upkeep: you may pay 2 life, tutor" trigger, asserting both directions: it fires when the AI can
19+
* spare the life, and declines when paying would drop it below the safety threshold (the bug).
20+
*/
21+
public class TriggerLifeGateTest extends AITest {
22+
23+
@Test
24+
public void optionalPayLifeTriggerRespectsLifeSafety() {
25+
AssertJUnit.assertTrue("should tutor when it can spare the life",
26+
tutors(bringerSetup(20)));
27+
AssertJUnit.assertFalse("should not pay 2 life down to 3 to tutor",
28+
tutors(bringerSetup(5))); // 5 - 2 = 3, below the threshold of 4
29+
}
30+
31+
private Player bringerSetup(int life) {
32+
Game game = initAndCreateGame();
33+
Player ai = game.getPlayers().get(1);
34+
addCard("Bringer of the Black Dawn", ai);
35+
addCardToZone("Griselbrand", ai, ZoneType.Library);
36+
for (int i = 0; i < 6; i++) addCardToZone("Forest", ai, ZoneType.Library);
37+
ai.setLife(life, null);
38+
return ai;
39+
}
40+
41+
private boolean tutors(Player ai) {
42+
Card bringer = null;
43+
for (Card c : ai.getCardsIn(ZoneType.Battlefield)) {
44+
if (c.getName().equals("Bringer of the Black Dawn")) {
45+
bringer = c;
46+
break;
47+
}
48+
}
49+
AssertJUnit.assertNotNull(bringer);
50+
SpellAbility sa = null;
51+
for (Trigger t : bringer.getTriggers()) {
52+
SpellAbility ability = t.ensureAbility();
53+
if (ability != null && ability.getApi() == ApiType.ChangeZone) {
54+
sa = ability;
55+
break;
56+
}
57+
}
58+
AssertJUnit.assertNotNull("no tutor trigger on Bringer", sa);
59+
sa.setActivatingPlayer(ai);
60+
return SpellApiToAi.Converter.get(sa).doTrigger(ai, sa, false);
61+
}
62+
}

0 commit comments

Comments
 (0)