Add CI test-coverage gate at 80%, backfill remaining logic-module gaps
willemjan/glucose-dashboard/pipeline/head This commit looks good

pytest-cov + pyproject.toml [tool.coverage.*] measure reporting.py,
nightscout_client.py, data_processing.py, pdf_export.py, profile_data.py,
ui_common.py, and auth.py; app.py and pages/*.py are omitted (thin
Streamlit UI scripts, not meaningfully unit-testable without a running
Streamlit session — the handful of similarly UI-coupled functions left
in ui_common.py/auth.py are marked "# pragma: no cover" with the same
rationale, since the logic they call into is already fully tested).

The Gitea Actions test job now runs with --cov and fails the build
below 80%; the coverage XML is uploaded as a build artifact and fed
into the SonarQube scan (closing the gap flagged in
homelab-cicd-werkinstructie.md). Backfilled a few missing branches
(get_colors() theme fallback, secondary-y-axis overlay traces) to reach
98% on the measured modules — comfortable headroom above the 80% gate.

Builds on #29/#30/#31.
This commit is contained in:
2026-09-05 22:52:29 +02:00
parent f2c3f97b1f
commit 7f4377329a
10 changed files with 125 additions and 14 deletions
+47
View File
@@ -1,5 +1,8 @@
from types import SimpleNamespace
import pandas as pd
import plotly.graph_objects as go
import streamlit as st
from ui_common import (
PALETTE,
@@ -10,10 +13,26 @@ from ui_common import (
add_target_line_trace,
add_threshold_lines,
build_tir_stacked_bar_figure,
get_colors,
hex_to_rgba,
)
def test_get_colors_returns_dark_palette_when_theme_is_dark(monkeypatch):
monkeypatch.setattr(st, "context", SimpleNamespace(theme=SimpleNamespace(type="dark")))
assert get_colors() == PALETTE["dark"]
def test_get_colors_returns_light_palette_when_theme_is_light(monkeypatch):
monkeypatch.setattr(st, "context", SimpleNamespace(theme=SimpleNamespace(type="light")))
assert get_colors() == PALETTE["light"]
def test_get_colors_falls_back_to_light_when_theme_context_unavailable(monkeypatch):
monkeypatch.setattr(st, "context", SimpleNamespace()) # geen .theme-attribuut
assert get_colors() == PALETTE["light"]
def test_hex_to_rgba_converts_correctly():
assert hex_to_rgba("#2a78d6", 0.3) == "rgba(42,120,214,0.3)"
@@ -55,12 +74,34 @@ def test_add_basal_area_trace_adds_one_filled_step_trace():
assert fig.data[0].line.shape == "hv"
def test_add_basal_area_trace_supports_secondary_y_on_a_subplot_figure():
from plotly.subplots import make_subplots
basal = pd.DataFrame(
{"timestamp": pd.to_datetime(["2026-01-01 00:00", "2026-01-01 06:00"]), "rate": [0.8, 1.2]}
)
fig = make_subplots(specs=[[{"secondary_y": True}]])
add_basal_area_trace(fig, basal, PALETTE["light"], row=1, secondary_y=True)
assert len(fig.data) == 1
assert fig.data[0].yaxis == "y2"
def test_add_basal_area_trace_skips_empty_input():
fig = go.Figure()
add_basal_area_trace(fig, pd.DataFrame(columns=["timestamp", "rate"]), PALETTE["light"])
assert len(fig.data) == 0
def test_add_carb_bars_trace_supports_secondary_y_on_a_subplot_figure():
from plotly.subplots import make_subplots
carbs = pd.DataFrame({"timestamp": pd.to_datetime(["2026-01-01 08:00"]), "carbs": [40.0]})
fig = make_subplots(specs=[[{"secondary_y": True}]])
add_carb_bars_trace(fig, carbs, PALETTE["light"], row=1, secondary_y=True)
assert len(fig.data) == 1
assert fig.data[0].yaxis == "y2"
def test_add_carb_bars_trace_adds_one_bar_trace():
carbs = pd.DataFrame({"timestamp": pd.to_datetime(["2026-01-01 08:00"]), "carbs": [40.0]})
fig = go.Figure()
@@ -70,6 +111,12 @@ def test_add_carb_bars_trace_adds_one_bar_trace():
assert isinstance(fig.data[0], go.Bar)
def test_add_carb_bars_trace_skips_empty_input():
fig = go.Figure()
add_carb_bars_trace(fig, pd.DataFrame(columns=["timestamp", "carbs"]), PALETTE["light"])
assert len(fig.data) == 0
def test_add_bolus_marker_traces_adds_one_trace_per_category_present():
bolus = pd.DataFrame(
{