Fix trade-in-jail bug: jail handler must not roll during active trade

Added guard in jail turn handler to skip rolling when in_trade is True.
The roll happens later when '-- Command:' arrives after trade completes.

Added 5 regression tests for the exact failing sequence.
This commit is contained in:
Jarvis 2026-02-21 10:45:15 +00:00
parent d31a09e754
commit 8bbadba7d9
3 changed files with 79 additions and 2 deletions

View file

@ -250,8 +250,9 @@ class PlayerBot:
self.jail_turns = 2
else:
self.jail_turns = 1
# Try rolling doubles
self.say_delayed("roll")
# Try rolling doubles — but not if we're in a trade
if not self.in_trade:
self.say_delayed("roll")
return
if msg == "Double roll gets you out.":

View file

@ -306,6 +306,82 @@ class TestTrading(unittest.TestCase):
self.assertIn("roll", msgs)
class TestTradeInJail(unittest.TestCase):
"""Regression tests for trade-while-in-jail bug.
Sequence that caused the hang:
1. Checkpoint "charlie (3) (cash $985) on JAIL" trade initiated
2. "(This is your 2nd turn in JAIL)" roll queued (ignoring in_trade)
3. ".trade" sent, then ".roll" sent into trade prompt hang
"""
def _make_bot(self, nick="charlie"):
bot = FakePlayerBot(nick, ["alice", "bob", "charlie"], 2)
bot.setup_phase = False
bot.game_started = True
bot.turns_played = 10 # past trade threshold
return bot
def test_jail_handler_no_roll_during_trade(self):
"""Jail turn handler must not queue a roll when in_trade is True."""
bot = self._make_bot()
bot.current_player = "charlie"
bot.in_trade = True
bot.in_jail = True
msgs = bot.feed("(This is your 2nd turn in JAIL)")
self.assertNotIn("roll", msgs,
"Should not roll while in_trade is True")
def test_trade_then_jail_turn_sequence(self):
"""Simulate the exact sequence: checkpoint initiates trade, then jail prompt arrives."""
bot = self._make_bot()
# Force trade to trigger (patch random)
with patch("random.random", return_value=0.01): # < 0.10 → triggers trade
msgs = bot.feed("charlie (3) (cash $985) on JAIL")
self.assertTrue(bot.in_trade, "Trade should be initiated")
self.assertIn("trade", msgs, "Should send .trade")
self.assertNotIn("roll", msgs, "Should not also roll")
# Now jail turn prompt arrives
msgs = bot.feed("(This is your 2nd turn in JAIL)")
self.assertNotIn("roll", msgs,
"Jail handler must not roll during active trade")
self.assertTrue(bot.in_trade, "Trade should still be active")
def test_trade_which_player_prompt(self):
"""Bot should pick a trade partner when asked."""
bot = self._make_bot()
bot.current_player = "charlie"
bot.in_trade = True
msgs = bot.feed("Which player do you wish to trade with?")
self.assertTrue(len(msgs) > 0, "Should respond to trade partner prompt")
self.assertNotIn("roll", msgs)
# Should pick one of the other players
self.assertTrue(
msgs[0] in ["alice", "bob"],
f"Expected a player name, got: {msgs[0]}"
)
def test_no_trade_in_jail_still_rolls(self):
"""When NOT in a trade, jail handler should still queue a roll."""
bot = self._make_bot()
bot.current_player = "charlie"
bot.in_trade = False
bot.in_jail = True
msgs = bot.feed("(This is your 2nd turn in JAIL)")
self.assertIn("roll", msgs, "Should roll when not trading")
def test_command_prompt_after_trade_allows_roll(self):
"""After trade ends (-- Command:), bot should roll normally."""
bot = self._make_bot()
bot.current_player = "charlie"
bot.in_trade = True
bot.rolled_this_turn = False
msgs = bot.feed("-- Command:")
self.assertFalse(bot.in_trade)
self.assertIn("roll", msgs)
class TestValidInputs(unittest.TestCase):
def test_picks_first_option(self):
bot = FakePlayerBot("alice", ["alice", "bob"], 0)