mirror of
https://github.com/RichieCahill/dotfiles.git
synced 2026-04-17 04:58:19 -04:00
Add comprehensive test suite achieving 99% code coverage
Added 35 test files with 502 tests covering all Python modules including API routes, ORM models, splendor game logic/TUI, heater controller, weather service, NixOS installer, ZFS dataset management, and utilities. Coverage improved from 11% to 99% (2540/2564 statements covered). https://claude.ai/code/session_01SVzgLDUS1Cdc4eh1ijETTh
This commit is contained in:
230
tests/test_splendor_bot_extended.py
Normal file
230
tests/test_splendor_bot_extended.py
Normal file
@@ -0,0 +1,230 @@
|
||||
"""Extended tests for python/splendor/bot.py to improve coverage."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
|
||||
from python.splendor.base import (
|
||||
BASE_COLORS,
|
||||
GEM_COLORS,
|
||||
BuyCard,
|
||||
BuyCardReserved,
|
||||
Card,
|
||||
GameConfig,
|
||||
GameState,
|
||||
PlayerState,
|
||||
ReserveCard,
|
||||
TakeDifferent,
|
||||
create_random_cards,
|
||||
create_random_nobles,
|
||||
new_game,
|
||||
run_game,
|
||||
)
|
||||
from python.splendor.bot import (
|
||||
PersonalizedBot,
|
||||
PersonalizedBot2,
|
||||
PersonalizedBot3,
|
||||
PersonalizedBot4,
|
||||
RandomBot,
|
||||
buy_card,
|
||||
buy_card_reserved,
|
||||
estimate_value_of_card,
|
||||
estimate_value_of_token,
|
||||
take_tokens,
|
||||
)
|
||||
|
||||
|
||||
def _make_card(tier: int = 1, points: int = 0, color: str = "white", cost: dict | None = None) -> Card:
|
||||
if cost is None:
|
||||
cost = dict.fromkeys(GEM_COLORS, 0)
|
||||
return Card(tier=tier, points=points, color=color, cost=cost)
|
||||
|
||||
|
||||
def _make_game(num_players: int = 2) -> tuple[GameState, list]:
|
||||
bots = [RandomBot(f"bot{i}") for i in range(num_players)]
|
||||
cards = create_random_cards()
|
||||
nobles = create_random_nobles()
|
||||
config = GameConfig(cards=cards, nobles=nobles)
|
||||
game = new_game(bots, config)
|
||||
return game, bots
|
||||
|
||||
|
||||
def test_random_bot_buys_affordable() -> None:
|
||||
"""Test RandomBot buys affordable cards."""
|
||||
random.seed(1)
|
||||
game, bots = _make_game(2)
|
||||
p = game.players[0]
|
||||
for c in BASE_COLORS:
|
||||
p.tokens[c] = 10
|
||||
# Should sometimes buy
|
||||
actions = [bots[0].choose_action(game, p) for _ in range(20)]
|
||||
buy_actions = [a for a in actions if isinstance(a, BuyCard)]
|
||||
assert len(buy_actions) > 0
|
||||
|
||||
|
||||
def test_random_bot_reserves() -> None:
|
||||
"""Test RandomBot reserves cards sometimes."""
|
||||
random.seed(3)
|
||||
game, bots = _make_game(2)
|
||||
actions = [bots[0].choose_action(game, game.players[0]) for _ in range(50)]
|
||||
reserve_actions = [a for a in actions if isinstance(a, ReserveCard)]
|
||||
assert len(reserve_actions) > 0
|
||||
|
||||
|
||||
def test_random_bot_choose_discard() -> None:
|
||||
"""Test RandomBot.choose_discard."""
|
||||
bot = RandomBot("test")
|
||||
p = PlayerState(strategy=bot)
|
||||
p.tokens["white"] = 5
|
||||
p.tokens["blue"] = 3
|
||||
discards = bot.choose_discard(None, p, 2)
|
||||
assert sum(discards.values()) == 2
|
||||
|
||||
|
||||
def test_personalized_bot_takes_different() -> None:
|
||||
"""Test PersonalizedBot takes different when no affordable cards."""
|
||||
random.seed(42)
|
||||
bot = PersonalizedBot("pbot")
|
||||
game, _ = _make_game(2)
|
||||
p = game.players[0]
|
||||
action = bot.choose_action(game, p)
|
||||
assert action is not None
|
||||
|
||||
|
||||
def test_personalized_bot_choose_discard() -> None:
|
||||
"""Test PersonalizedBot.choose_discard."""
|
||||
bot = PersonalizedBot("pbot")
|
||||
p = PlayerState(strategy=bot)
|
||||
p.tokens["white"] = 5
|
||||
discards = bot.choose_discard(None, p, 2)
|
||||
assert sum(discards.values()) == 2
|
||||
|
||||
|
||||
def test_personalized_bot2_buys_reserved() -> None:
|
||||
"""Test PersonalizedBot2 buys reserved cards."""
|
||||
random.seed(42)
|
||||
bot = PersonalizedBot2("pbot2")
|
||||
game, _ = _make_game(2)
|
||||
p = game.players[0]
|
||||
p.strategy = bot
|
||||
# Add affordable reserved card
|
||||
card = _make_card(cost=dict.fromkeys(GEM_COLORS, 0))
|
||||
p.reserved.append(card)
|
||||
# Clear table cards to force reserved buy
|
||||
for tier in (1, 2, 3):
|
||||
game.table_by_tier[tier] = []
|
||||
action = bot.choose_action(game, p)
|
||||
assert isinstance(action, BuyCardReserved)
|
||||
|
||||
|
||||
def test_personalized_bot2_reserves_from_deck() -> None:
|
||||
"""Test PersonalizedBot2 reserves from deck when few colors available."""
|
||||
random.seed(42)
|
||||
bot = PersonalizedBot2("pbot2")
|
||||
game, _ = _make_game(2)
|
||||
p = game.players[0]
|
||||
p.strategy = bot
|
||||
# Clear table and set only 2 bank colors
|
||||
for tier in (1, 2, 3):
|
||||
game.table_by_tier[tier] = []
|
||||
for c in BASE_COLORS:
|
||||
game.bank[c] = 0
|
||||
game.bank["white"] = 1
|
||||
game.bank["blue"] = 1
|
||||
action = bot.choose_action(game, p)
|
||||
assert isinstance(action, (ReserveCard, TakeDifferent))
|
||||
|
||||
|
||||
def test_personalized_bot2_choose_discard() -> None:
|
||||
"""Test PersonalizedBot2.choose_discard."""
|
||||
bot = PersonalizedBot2("pbot2")
|
||||
p = PlayerState(strategy=bot)
|
||||
p.tokens["red"] = 5
|
||||
discards = bot.choose_discard(None, p, 2)
|
||||
assert sum(discards.values()) == 2
|
||||
|
||||
|
||||
def test_personalized_bot3_choose_action() -> None:
|
||||
"""Test PersonalizedBot3.choose_action."""
|
||||
random.seed(42)
|
||||
bot = PersonalizedBot3("pbot3")
|
||||
game, _ = _make_game(2)
|
||||
p = game.players[0]
|
||||
p.strategy = bot
|
||||
action = bot.choose_action(game, p)
|
||||
assert action is not None
|
||||
|
||||
|
||||
def test_personalized_bot3_choose_discard() -> None:
|
||||
"""Test PersonalizedBot3.choose_discard."""
|
||||
bot = PersonalizedBot3("pbot3")
|
||||
p = PlayerState(strategy=bot)
|
||||
p.tokens["green"] = 5
|
||||
discards = bot.choose_discard(None, p, 2)
|
||||
assert sum(discards.values()) == 2
|
||||
|
||||
|
||||
def test_personalized_bot4_choose_action() -> None:
|
||||
"""Test PersonalizedBot4.choose_action."""
|
||||
random.seed(42)
|
||||
bot = PersonalizedBot4("pbot4")
|
||||
game, _ = _make_game(2)
|
||||
p = game.players[0]
|
||||
p.strategy = bot
|
||||
action = bot.choose_action(game, p)
|
||||
assert action is not None
|
||||
|
||||
|
||||
def test_personalized_bot4_filter_actions() -> None:
|
||||
"""Test PersonalizedBot4.filter_actions."""
|
||||
bot = PersonalizedBot4("pbot4")
|
||||
actions = [
|
||||
TakeDifferent(colors=["white", "blue", "green"]),
|
||||
TakeDifferent(colors=["white", "blue"]),
|
||||
BuyCard(tier=1, index=0),
|
||||
]
|
||||
filtered = bot.filter_actions(actions)
|
||||
# Should keep 3-color TakeDifferent and BuyCard, remove 2-color TakeDifferent
|
||||
assert len(filtered) == 2
|
||||
|
||||
|
||||
def test_personalized_bot4_choose_discard() -> None:
|
||||
"""Test PersonalizedBot4.choose_discard."""
|
||||
bot = PersonalizedBot4("pbot4")
|
||||
p = PlayerState(strategy=bot)
|
||||
p.tokens["black"] = 5
|
||||
discards = bot.choose_discard(None, p, 2)
|
||||
assert sum(discards.values()) == 2
|
||||
|
||||
|
||||
def test_estimate_value_of_card() -> None:
|
||||
"""Test estimate_value_of_card."""
|
||||
game, _ = _make_game(2)
|
||||
p = game.players[0]
|
||||
result = estimate_value_of_card(game, p, "white")
|
||||
assert isinstance(result, int)
|
||||
|
||||
|
||||
def test_estimate_value_of_token() -> None:
|
||||
"""Test estimate_value_of_token."""
|
||||
game, _ = _make_game(2)
|
||||
p = game.players[0]
|
||||
result = estimate_value_of_token(game, p, "white")
|
||||
assert isinstance(result, int)
|
||||
|
||||
|
||||
def test_full_game_with_personalized_bots() -> None:
|
||||
"""Test a full game with different bot types."""
|
||||
random.seed(42)
|
||||
bots = [
|
||||
RandomBot("random"),
|
||||
PersonalizedBot("p1"),
|
||||
PersonalizedBot2("p2"),
|
||||
]
|
||||
cards = create_random_cards()
|
||||
nobles = create_random_nobles()
|
||||
config = GameConfig(cards=cards, nobles=nobles, turn_limit=200)
|
||||
game = new_game(bots, config)
|
||||
winner, turns = run_game(game)
|
||||
assert winner is not None
|
||||
assert turns > 0
|
||||
Reference in New Issue
Block a user