good luck
Some checks failed
CI / Lint (push) Successful in 58s
CI / Test (push) Successful in 8s
CI / Build & Push (push) Failing after 1m33s

This commit is contained in:
2026-03-29 09:20:21 -04:00
parent b10736d43c
commit 3994943757
23 changed files with 579 additions and 161 deletions

0
tests/__init__.py Normal file
View File

Binary file not shown.

93
tests/conftest.py Normal file
View File

@@ -0,0 +1,93 @@
import json
import sqlite3
import pytest
def make_game(
game_state="LIVE",
home_name="Maple Leafs",
away_name="Bruins",
home_score=2,
away_score=1,
period=3,
seconds_remaining=300,
in_intermission=False,
start_time_utc="2024-04-10T23:00:00Z",
home_record="40-25-10",
away_record="38-27-09",
):
clock = {
"timeRemaining": f"{seconds_remaining // 60:02d}:{seconds_remaining % 60:02d}",
"secondsRemaining": seconds_remaining,
"running": game_state == "LIVE",
"inIntermission": in_intermission,
}
return {
"gameState": game_state,
"startTimeUTC": start_time_utc,
"periodDescriptor": {"number": period},
"clock": clock,
"homeTeam": {
"name": {"default": home_name},
"score": home_score,
"sog": 15,
"logo": "https://example.com/home.png",
"record": home_record,
},
"awayTeam": {
"name": {"default": away_name},
"score": away_score,
"sog": 12,
"logo": "https://example.com/away.png",
"record": away_record,
},
"gameOutcome": {"lastPeriodType": "REG"},
}
LIVE_GAME = make_game()
PRE_GAME = make_game(
game_state="FUT", home_score=0, away_score=0, period=0, seconds_remaining=1200
)
FINAL_GAME = make_game(game_state="OFF", period=3, seconds_remaining=0)
SAMPLE_SCOREBOARD = {"games": [LIVE_GAME, PRE_GAME, FINAL_GAME]}
@pytest.fixture()
def sample_scoreboard():
return SAMPLE_SCOREBOARD
@pytest.fixture()
def flask_client(tmp_path, monkeypatch):
data_dir = tmp_path / "data"
data_dir.mkdir()
# Write sample scoreboard JSON
scoreboard_file = data_dir / "scoreboard_data.json"
scoreboard_file.write_text(json.dumps(SAMPLE_SCOREBOARD))
# Create minimal SQLite DB so get_team_standings doesn't crash
db_path = data_dir / "nhl_standings.db"
conn = sqlite3.connect(str(db_path))
conn.execute(
"CREATE TABLE standings "
"(team_common_name TEXT, league_sequence INTEGER, league_l10_sequence INTEGER)"
)
conn.commit()
conn.close()
# Patch module-level path constants so no reloads are needed
import app.routes as routes
import app.scoreboard.process_data as process_data
monkeypatch.setattr(routes, "SCOREBOARD_DATA_FILE", str(scoreboard_file))
monkeypatch.setattr(process_data, "DB_PATH", str(db_path))
from app import app as flask_app
flask_app.config["TESTING"] = True
with flask_app.test_client() as client:
yield client

103
tests/test_process_data.py Normal file
View File

@@ -0,0 +1,103 @@
from tests.conftest import make_game
from app.scoreboard.process_data import (
convert_game_state,
get_game_outcome,
process_period,
process_record,
process_start_time,
process_time_remaining,
utc_to_est_time,
)
class TestConvertGameState:
def test_off_maps_to_final(self):
assert convert_game_state("OFF") == "FINAL"
def test_crit_maps_to_live(self):
assert convert_game_state("CRIT") == "LIVE"
def test_fut_maps_to_pre(self):
assert convert_game_state("FUT") == "PRE"
def test_unknown_state_passes_through(self):
assert convert_game_state("LIVE") == "LIVE"
class TestProcessRecord:
def test_na_returns_na(self):
assert process_record("N/A") == "N/A"
def test_pads_single_digit_parts(self):
assert process_record("5-3-1") == "05-03-01"
def test_already_padded_unchanged(self):
assert process_record("40-25-10") == "40-25-10"
class TestProcessPeriod:
def test_pre_game_returns_zero(self):
game = make_game(game_state="PRE")
assert process_period(game) == 0
def test_fut_game_returns_zero(self):
game = make_game(game_state="FUT")
assert process_period(game) == 0
def test_final_game_returns_na(self):
game = make_game(game_state="OFF")
assert process_period(game) == "N/A"
def test_live_game_returns_period_number(self):
game = make_game(game_state="LIVE", period=2)
assert process_period(game) == 2
class TestProcessTimeRemaining:
def test_pre_game_returns_2000(self):
game = make_game(game_state="FUT")
assert process_time_remaining(game) == "20:00"
def test_final_game_returns_0000(self):
game = make_game(game_state="OFF")
assert process_time_remaining(game) == "00:00"
def test_live_game_returns_clock(self):
game = make_game(game_state="LIVE", seconds_remaining=305)
assert process_time_remaining(game) == "05:05"
def test_live_game_at_zero_returns_end(self):
game = make_game(game_state="LIVE", seconds_remaining=0)
assert process_time_remaining(game) == "END"
class TestProcessStartTime:
def test_pre_game_returns_est_time(self):
game = make_game(game_state="FUT", start_time_utc="2024-04-10T23:00:00Z")
result = process_start_time(game)
assert result == "7:00 PM"
def test_pre_game_strips_leading_zero(self):
game = make_game(game_state="FUT", start_time_utc="2024-04-10T22:00:00Z")
result = process_start_time(game)
assert not result.startswith("0")
def test_live_game_returns_na(self):
game = make_game(game_state="LIVE")
assert process_start_time(game) == "N/A"
class TestGetGameOutcome:
def test_final_game_returns_last_period_type(self):
game = make_game(game_state="OFF")
assert get_game_outcome(game, "FINAL") == "REG"
def test_live_game_returns_na(self):
game = make_game(game_state="LIVE")
assert get_game_outcome(game, "LIVE") == "N/A"
class TestUtcToEstTime:
def test_converts_utc_to_est(self):
result = utc_to_est_time("2024-04-10T23:00:00Z")
assert result == "07:00 PM"

44
tests/test_routes.py Normal file
View File

@@ -0,0 +1,44 @@
import json
class TestIndexRoute:
def test_returns_200(self, flask_client):
response = flask_client.get("/")
assert response.status_code == 200
def test_returns_html(self, flask_client):
response = flask_client.get("/")
assert b"NHL Scoreboard" in response.data
class TestScoreboardRoute:
def test_returns_200(self, flask_client):
response = flask_client.get("/scoreboard")
assert response.status_code == 200
def test_returns_json_with_expected_keys(self, flask_client):
response = flask_client.get("/scoreboard")
data = json.loads(response.data)
assert "live_games" in data
assert "pre_games" in data
assert "final_games" in data
def test_live_games_have_required_fields(self, flask_client):
response = flask_client.get("/scoreboard")
data = json.loads(response.data)
if data["live_games"]:
game = data["live_games"][0]
assert "Home Team" in game
assert "Away Team" in game
assert "Home Score" in game
assert "Away Score" in game
assert "Game State" in game
assert game["Game State"] == "LIVE"
def test_missing_file_returns_error(self, flask_client, monkeypatch):
import app.routes as routes
monkeypatch.setattr(routes, "SCOREBOARD_DATA_FILE", "/nonexistent/path.json")
response = flask_client.get("/scoreboard")
data = json.loads(response.data)
assert "error" in data