Files
2026-09-09 17:49:01 +01:00

118 lines
3.7 KiB
Python

from datetime import date
from app import db as d
from app.config import get_settings
from app.services import compute_service_due
def _conn():
settings = get_settings()
settings.data_dir.mkdir(parents=True, exist_ok=True)
d.init_schema(settings.resolved_db_path)
return d.connect(settings.resolved_db_path)
def _mk_bike(conn, interval):
return d.create_bike(conn, "B", interval)
def _event(conn, bike_id, type, day, mileage, cost=None):
d.create_event(conn, bike_id, type, day, mileage, cost, "n")
def test_no_data_when_no_service():
conn = _conn()
bike_id = _mk_bike(conn, 5000)
_event(conn, bike_id, "tyre", date(2026, 1, 1), 10000)
due = compute_service_due(conn, d.get_bike(conn, bike_id))
assert due.status == "no-data"
conn.close()
def test_ok_when_under_interval():
conn = _conn()
bike_id = _mk_bike(conn, 5000)
_event(conn, bike_id, "service", date(2026, 1, 1), 10000)
_event(conn, bike_id, "tyre", date(2026, 6, 1), 12000)
due = compute_service_due(conn, d.get_bike(conn, bike_id))
assert due.status == "ok"
assert due.miles_since == 2000
assert due.miles_until_due == 3000
conn.close()
def test_overdue_when_over_interval():
conn = _conn()
bike_id = _mk_bike(conn, 5000)
_event(conn, bike_id, "service", date(2026, 1, 1), 10000)
_event(conn, bike_id, "other", date(2026, 6, 1), 16000)
due = compute_service_due(conn, d.get_bike(conn, bike_id))
assert due.status == "overdue"
assert due.miles_since == 6000
assert due.miles_until_due == -1000
conn.close()
def test_exactly_at_interval_is_due_soon():
conn = _conn()
bike_id = _mk_bike(conn, 5000)
_event(conn, bike_id, "service", date(2026, 1, 1), 10000)
_event(conn, bike_id, "other", date(2026, 6, 1), 15000)
due = compute_service_due(conn, d.get_bike(conn, bike_id))
assert due.status == "due-soon"
assert due.miles_until_due == 0
conn.close()
def test_within_lead_time_is_due_soon():
conn = _conn()
bike_id = _mk_bike(conn, 5000)
_event(conn, bike_id, "service", date(2026, 1, 1), 10000)
_event(conn, bike_id, "other", date(2026, 6, 1), 14900) # 100 mi left
due = compute_service_due(conn, d.get_bike(conn, bike_id))
assert due.status == "due-soon"
assert due.miles_until_due == 100
conn.close()
def test_just_outside_lead_time_is_ok():
conn = _conn()
bike_id = _mk_bike(conn, 5000)
_event(conn, bike_id, "service", date(2026, 1, 1), 10000)
_event(conn, bike_id, "other", date(2026, 6, 1), 14750) # 250 mi left
due = compute_service_due(conn, d.get_bike(conn, bike_id))
assert due.status == "ok"
assert due.miles_until_due == 250
conn.close()
def test_no_interval_set_is_no_data():
conn = _conn()
bike_id = _mk_bike(conn, None)
_event(conn, bike_id, "service", date(2026, 1, 1), 10000)
due = compute_service_due(conn, d.get_bike(conn, bike_id))
assert due.status == "no-data"
conn.close()
def test_latest_service_used_not_earliest():
conn = _conn()
bike_id = _mk_bike(conn, 5000)
_event(conn, bike_id, "service", date(2025, 1, 1), 8000)
_event(conn, bike_id, "service", date(2026, 1, 1), 10000) # most recent
_event(conn, bike_id, "other", date(2026, 6, 1), 14000)
due = compute_service_due(conn, d.get_bike(conn, bike_id))
assert due.status == "ok"
assert due.miles_since == 4000
conn.close()
def test_service_without_mileage_is_ignored():
conn = _conn()
bike_id = _mk_bike(conn, 5000)
_event(conn, bike_id, "service", date(2026, 1, 1), None) # no mileage
due = compute_service_due(conn, d.get_bike(conn, bike_id))
assert due.status == "no-data"
assert due.last_service is None
conn.close()