from claude_matrix_bot.reset_watcher.diff import Alert, WindowSnapshot
from claude_matrix_bot.reset_watcher.format import (
_format_delta,
_progress_bar,
format_alert,
format_armed,
)
def test_delta_under_minute_shows_seconds() -> None:
assert _format_delta(45) == "+45s"
assert _format_delta(-30) == "-30s"
assert _format_delta(0) == "+0s"
def test_delta_under_hour_shows_minutes() -> None:
assert _format_delta(60) == "+1 min"
assert _format_delta(720) == "+12 min"
assert _format_delta(-300) == "-5 min"
def test_delta_at_or_above_hour_shows_hours_and_minutes() -> None:
assert _format_delta(3_600) == "+1h"
assert _format_delta(3_660) == "+1h 1m"
assert _format_delta(12_000) == "+3h 20m"
assert _format_delta(-7_200) == "-2h"
def test_reset_shift_alert_renders_with_seconds_when_small() -> None:
alert = Alert(
kind="reset_shift",
window="five_hour",
detail={
"old_resets_at": 1_700_000_000,
"new_resets_at": 1_700_000_045,
"delta_seconds": 45,
},
)
plain, html = format_alert(alert)
assert "+45s" in plain
assert "+45s" in html
# Should never display "0 min" for a sub-minute delta.
assert "0 min" not in plain
# Aligned visual frame with armed message
assert "
" in html
assert "" in html
assert "5-hour session" in html
def test_threshold_alert_renders_emoji_and_percent() -> None:
alert = Alert(
kind="threshold_crossed",
window="seven_day",
detail={"threshold": 80, "utilization_pct": 82.5, "resets_at": 1_700_000_000},
)
plain, html = format_alert(alert)
assert "🔥" in plain
assert "82.5%" in plain
assert "weekly (all)" in html
# Aligned visual frame with armed message
assert "" in html
assert "" in html
assert "" in html
assert "weekly (all)" in html
assert "#c0392b" in html # 82.5% -> red severity
def test_threshold_50_uses_warn_emoji_not_fire() -> None:
"""50% threshold gets the warning emoji; only 80%+ uses the fire emoji."""
alert = Alert(
kind="threshold_crossed",
window="seven_day_sonnet",
detail={"threshold": 50, "utilization_pct": 51.0, "resets_at": 1_700_000_000},
)
plain, html = format_alert(alert)
assert "⚠️" in plain
assert "🔥" not in plain
def test_progress_bar_proportional() -> None:
assert _progress_bar(0, width=10) == "░░░░░░░░░░"
assert _progress_bar(50, width=10) == "█████░░░░░"
assert _progress_bar(100, width=10) == "██████████"
# Out-of-range stays clamped (defensive, not expected in practice)
assert _progress_bar(120, width=10) == "██████████"
assert _progress_bar(-5, width=10) == "░░░░░░░░░░"
def test_reset_shift_uses_blockquote_and_table() -> None:
alert = Alert(
kind="reset_shift",
window="five_hour",
detail={
"old_resets_at": 1_700_000_000,
"new_resets_at": 1_700_000_300,
"delta_seconds": 300,
},
)
plain, html = format_alert(alert)
assert "" in html
assert "" in html
assert "5-hour session" in html
# delta in plain still uses the arrow form for narrow display
assert "→" in plain
assert "+5 min" in plain
# delta colored amber for <30min shifts
assert "#d68910" in html
def test_armed_message_renders_blockquote_table() -> None:
fresh = {
"five_hour": WindowSnapshot(utilization=0.06, resets_at=1_700_000_000),
"seven_day": WindowSnapshot(utilization=0.55, resets_at=1_700_500_000),
"seven_day_opus": WindowSnapshot(utilization=0.10, resets_at=1_700_500_000),
"seven_day_sonnet": WindowSnapshot(utilization=0.62, resets_at=1_700_500_000),
}
plain, html = format_armed(fresh)
assert "🤖" in plain
assert "reset-watcher armed" in plain
# Each window appears in both plain and html
for label in ("5-hour session", "weekly (all)", "weekly Opus", "weekly Sonnet"):
assert label in plain
assert label in html
# New visual frame: blockquote, italic title, code subtitle, table layout
assert "" in html
assert "armed" in html
assert "baseline captured" in html
assert "" in html
assert "resets" in html
# No progress bars anymore
assert "█" not in plain
assert "█" not in html
# Severity colors applied per row (matches user's mockup palette)
assert "#27ae60" in html # 6% -> green
assert "#d68910" in html # 62% -> amber (50-80% band)