125 lines
4.0 KiB
Python
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()
|