# Copyright (c) 2026 Krzysztof Rudnicki. MIT licence. """The nightly block: exact text, and the line budget.""" from __future__ import annotations from signal_bot.stats.queries_day import DayRow, day_totals, with_silent from signal_bot.stats.render_day import MAX_LINES, DayView, render_day, summary_line # The real group, so the rendered example is a case that can actually occur. GROUP = [ ("Ala", 76, 12), ("Tomasz Nowak", 42, 3), ("kuhy", 38, 0), ("Basia", 33, 1), ("Franciszek Kowalczyk", 16, 0), ("Cezary Wiśniewski", 15, 0), ] def rows(spec: list[tuple[str, int, int]], *, commands: int = 0) -> list[DayRow]: """Build day rows from (name, messages, media) triples.""" return [ DayRow( uuid=f"u{i}", display_name=name, messages=messages, media=media, commands=commands if i == 0 else 0, chars=messages * 47, ) for i, (name, messages, media) in enumerate(spec) ] def test_the_nightly_block_for_a_real_day() -> None: """Pinned exactly: this is the only assertion that proves the rendering.""" day_rows_ = with_silent(rows(GROUP), [("u9", "Celina")]) rendered = render_day( "2026-09-01", day_rows_, day_totals(day_rows_), DayView(since="2026-08-30", highlights=("🏆 Ala 76 — rekord życiowy (poprzedni 71)",)), ) assert rendered == ( "📊 Wtorek, 1 września — 220 wiadomości (16 📷)\n" "👑 Ala — 76 (12 📷)\n" "2. Tomasz Nowak — 42 (3 📷)\n" "3. kuhy — 38\n" "4. Basia — 33 (1 📷)\n" "5. Franciszek Kowalczyk — 16\n" "6. Cezary Wiśniewski — 15\n" "🏆 Ala 76 — rekord życiowy (poprzedni 71)\n" "Cisza: Celina\n" "Średnio 47 znaków na wiadomość.\n" "(liczymy od 30 sierpnia)" ) assert len(rendered.split("\n")) <= MAX_LINES def test_a_day_with_no_media_shows_no_camera() -> None: day = rows([("kuhy", 3, 0)]) rendered = render_day("2026-09-01", day, day_totals(day)) assert "📷" not in rendered assert rendered.startswith("📊 Wtorek, 1 września — 3 wiadomości\n👑 kuhy — 3") def test_commands_are_broken_out() -> None: day = rows([("kuhy", 10, 0)], commands=4) assert summary_line(day_totals(day)) == "Z tego 4 komendy, średnio 47 znaków na wiadomość." def test_an_approximate_day_claims_no_average_length() -> None: """The backfilled day has counts but no lengths; 0 would be a lie.""" day = rows([("kuhy", 10, 0)]) assert summary_line(day_totals(day), approximate=True) == "" with_commands = rows([("kuhy", 10, 0)], commands=4) assert summary_line(day_totals(with_commands), approximate=True) == "Z tego 4 komendy." def test_summary_is_empty_on_a_day_nobody_spoke() -> None: assert summary_line(day_totals([])) == "" assert day_totals([]).average_length == 0 def test_unnamed_members_are_counted_never_named() -> None: """Their only spellings are a uuid or a phone number; both would leak.""" day = with_silent(rows([("kuhy", 3, 0)]), [("u9", "Celina")]) rendered = render_day("2026-09-01", day, day_totals(day), DayView(unnamed=2)) assert "Cisza: Celina, i 2 osoby bez ani jednej wiadomości tutaj" in rendered def test_a_big_group_is_truncated_and_still_fits() -> None: """The rule the current group size cannot reach, fixed before it can.""" big = rows([(f"Osoba {i:02d}", 30 - i, 0) for i in range(20)]) rendered = render_day( "2026-09-01", big, day_totals(big), DayView(since="2026-08-30", highlights=("🏆 rekord", "👑 korona", "📅 wtorki")), ) lines = rendered.split("\n") assert len(lines) <= MAX_LINES assert any(line.startswith("…i ") for line in lines) # The reserved highlight slot survives the truncation. assert "🏆 rekord" in rendered def test_the_hidden_tail_reports_its_own_total() -> None: day = rows([("A", 10, 0), ("B", 5, 0), ("C", 3, 0), ("D", 2, 0)]) rendered = render_day( "2026-09-01", day, day_totals(day), DayView(since="2026-08-30", highlights=("h1", "h2", "h3")), ) assert len(rendered.split("\n")) <= MAX_LINES def test_a_custom_heading_replaces_the_date() -> None: day = rows([("kuhy", 1, 0)]) rendered = render_day("2026-09-01", day, day_totals(day), DayView(heading="Dziś, na razie")) assert rendered.startswith("Dziś, na razie\n")