Skip to content

Commit 300bb98

Browse files
liamiak1claude
andcommitted
Add a regression test for searching another player's library
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 072eab8 commit 300bb98

1 file changed

Lines changed: 98 additions & 0 deletions

File tree

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package forge.game.ability.effects;
2+
3+
import org.testng.annotations.Test;
4+
5+
import forge.ai.AITest;
6+
import forge.game.Game;
7+
import forge.game.GameObject;
8+
import forge.game.ability.AbilityUtils;
9+
import forge.game.card.Card;
10+
import forge.game.phase.PhaseType;
11+
import forge.game.player.Player;
12+
import forge.game.spellability.SpellAbility;
13+
import forge.game.zone.ZoneType;
14+
15+
import static junit.framework.Assert.assertEquals;
16+
17+
/**
18+
* Opposition Agent applies only while an opponent searches <i>their own</i> library, so searching
19+
* someone else's must not hand what is found to the Agent's controller.
20+
*/
21+
public class SearchOwnLibraryTest extends AITest {
22+
23+
private Game game;
24+
private Player me; // controls the Agent in every case below
25+
private Player opp;
26+
27+
@Test
28+
public void agentAppliesOnlyWhenAnOpponentSearchesTheirOwnLibrary() {
29+
// "search target opponent's library" retargets player, leaving me the one searching
30+
Card ring = newGame("Sol Ring", "Mountain");
31+
addCards("Island", 6, me);
32+
cast("Acquire", me, opp);
33+
assertEquals("my own Acquire must still fetch for me", ZoneType.Battlefield, zoneOf(ring));
34+
35+
// "search its controller's library" names the victim, but I am still the one looking.
36+
// Sowing Salt exiles either way, so the tell is whether the Agent claimed what was found.
37+
newGame("Bojuka Bog", "Mountain");
38+
addCards("Mountain", 6, me);
39+
cast("Sowing Salt", me, addCard("Bojuka Bog", opp));
40+
assertEquals("Sowing Salt must not feed my own Agent", 0, cardsTheAgentTook());
41+
42+
// "target player searches their library": I cast it, but the Chooser makes them the
43+
// searcher, so it is still their own search and the Agent takes what they find
44+
Card forest = newGame("Forest", "Sol Ring");
45+
addCards("Forest", 6, me);
46+
cast("Fertilid's Favor", me, opp);
47+
assertEquals("a search I handed to an opponent is still their own", ZoneType.Exile,
48+
zoneOf(forest));
49+
50+
// and the case the card is for: an opponent tutoring out of their own library
51+
Card prize = newGame("Sol Ring", "Mountain");
52+
addCards("Swamp", 6, opp);
53+
cast("Diabolic Tutor", opp, null);
54+
assertEquals("their own tutor is still exiled by the Agent", ZoneType.Exile, zoneOf(prize));
55+
}
56+
57+
/** Fresh game where I control the Agent and opp's library holds the prize plus filler. */
58+
private Card newGame(String prize, String filler) {
59+
game = initAndCreateGame();
60+
me = game.getPlayers().get(0);
61+
opp = game.getPlayers().get(1);
62+
addCard("Opposition Agent", me);
63+
Card c = addCardToZone(prize, opp, ZoneType.Library);
64+
for (int i = 0; i < 4; i++) {
65+
addCardToZone(filler, opp, ZoneType.Library);
66+
}
67+
return c;
68+
}
69+
70+
/** Casts and resolves {@code name} from {@code p}'s hand, at {@code target} if there is one. */
71+
private void cast(String name, Player p, GameObject target) {
72+
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
73+
game.getAction().checkStateEffects(true);
74+
SpellAbility sa = addCardToZone(name, p, ZoneType.Hand).getFirstSpellAbility();
75+
sa.setActivatingPlayer(p);
76+
sa.resetTargets();
77+
if (target != null) {
78+
sa.getTargets().add(target);
79+
}
80+
AbilityUtils.resolve(sa);
81+
game.getAction().checkStateEffects(true);
82+
}
83+
84+
private ZoneType zoneOf(Card c) {
85+
return game.getCardState(c, c).getZone().getZoneType();
86+
}
87+
88+
/** How many exiled cards the Agent claimed - its replacement is what grants me permission. */
89+
private int cardsTheAgentTook() {
90+
int taken = 0;
91+
for (Card c : opp.getCardsIn(ZoneType.Exile)) {
92+
if (!c.mayPlay(me).isEmpty()) {
93+
taken++;
94+
}
95+
}
96+
return taken;
97+
}
98+
}

0 commit comments

Comments
 (0)