Files
2026-05-23 16:11:16 -04:00

125 lines
4.0 KiB
Python

"""
tests/test_widgets.py
---------------------
Tests for ui/widgets.py — ball_color() is pure and testable without a display.
BallsBar creation tests require Tkinter and are skipped when unavailable.
"""
import pytest
from ui.widgets import ball_color, BallsBar
def _has_display():
try:
import tkinter as tk
r = tk.Tk(); r.withdraw(); r.destroy()
return True
except Exception:
return False
# ── ball_color — pure function, no display needed ─────────────────────────────
def test_ball_color_returns_two_hex_strings():
bg, fg = ball_color(7)
assert bg.startswith("#") and len(bg) == 7
assert fg.startswith("#") and len(fg) == 7
def test_ball_color_bonus_is_red():
bg, _ = ball_color(7, is_bonus=True)
assert bg == "#e74c3c"
def test_ball_color_bonus_same_regardless_of_number():
assert ball_color(1, is_bonus=True) == ball_color(26, is_bonus=True)
assert ball_color(99, is_bonus=True) == ball_color(5, is_bonus=True)
def test_ball_color_different_ranges_have_different_colors():
bgs = {ball_color(n)[0] for n in [1, 15, 25, 35, 45, 55, 65, 75]}
assert len(bgs) >= 5 # at least 5 distinct background colors
def test_ball_color_boundary_values():
# Each range boundary should resolve without error
for n in [1, 9, 10, 19, 20, 29, 30, 39, 40, 49, 50, 59, 60, 69, 70, 99]:
bg, fg = ball_color(n)
assert bg.startswith("#")
assert fg.startswith("#")
def test_ball_color_out_of_defined_range():
# Number > 99 falls back gracefully
bg, fg = ball_color(200)
assert bg.startswith("#")
assert fg.startswith("#")
def test_ball_color_is_deterministic():
for n in [1, 7, 14, 22, 35, 49, 69]:
assert ball_color(n) == ball_color(n)
def test_ball_color_non_bonus_not_red():
# Main balls in defined ranges should not be the bonus red
for n in range(1, 70):
bg, _ = ball_color(n, is_bonus=False)
assert bg != "#e74c3c" or n >= 60 # only 60-69 range is red
# ── BallsBar — needs display ──────────────────────────────────────────────────
@pytest.mark.skipif(not _has_display(), reason="no display available")
def test_ballsbar_creates_widget():
import tkinter as tk
try:
root = tk.Tk(); root.withdraw()
except Exception:
pytest.skip("Tkinter init failed")
try:
bar = BallsBar(root, numbers=[1, 7, 14, 22, 35], bonus=3)
assert bar.winfo_exists()
finally:
root.destroy()
@pytest.mark.skipif(not _has_display(), reason="no display available")
def test_ballsbar_no_bonus():
import tkinter as tk
try:
root = tk.Tk(); root.withdraw()
except Exception:
pytest.skip("Tkinter init failed")
try:
bar = BallsBar(root, numbers=[5, 12, 30, 44, 66])
assert bar.winfo_exists()
assert int(bar.cget("width")) > 0
finally:
root.destroy()
@pytest.mark.skipif(not _has_display(), reason="no display available")
def test_ballsbar_with_highlights():
import tkinter as tk
try:
root = tk.Tk(); root.withdraw()
except Exception:
pytest.skip("Tkinter init failed")
try:
hi = {7: ("#27ae60", "#ffffff"), 14: ("#cccccc", "#888888")}
bar = BallsBar(root, numbers=[1, 7, 14, 22, 35], highlights=hi)
assert bar.winfo_exists()
finally:
root.destroy()
@pytest.mark.skipif(not _has_display(), reason="no display available")
def test_ballsbar_larger_radius():
import tkinter as tk
try:
root = tk.Tk(); root.withdraw()
except Exception:
pytest.skip("Tkinter init failed")
try:
bar_small = BallsBar(root, numbers=[1, 2, 3], radius=11)
bar_normal = BallsBar(root, numbers=[1, 2, 3], radius=14)
w_small = int(bar_small.cget("width"))
w_normal = int(bar_normal.cget("width"))
assert w_normal > w_small
finally:
root.destroy()