# Copyright (c) 2026 Krzysztof Rudnicki. MIT licence. """Rendering a period, and the on-demand answers.""" from __future__ import annotations from signal_bot.stats import periods from signal_bot.stats.events import Person from signal_bot.stats.queries_day import DayRow from signal_bot.stats.queries_period import Trend from signal_bot.stats.records import DayRecord, Silence from signal_bot.stats.render_extra import ( ME_TITLE, render_crown, render_me, render_records, render_weekdays, ) from signal_bot.stats.render_period import MAX_ROWS, bar, render_period, trend_line WEEK = periods.week_of("2026-09-01") def rows(spec: list[tuple[str, int]]) -> list[DayRow]: """Build period rows from (name, messages) pairs.""" return [ DayRow(f"u{i}", name, messages, 0, 0, messages * 10) for i, (name, messages) in enumerate(spec) ] def test_a_period_with_nobody_in_it() -> None: rendered = render_period(WEEK, [], Trend(0, 0)) assert "Nikt nic nie napisał." in rendered def test_the_bar_fills_with_the_share() -> None: assert bar(0) == "░" * 10 assert bar(100) == "█" * 10 assert bar(50) == "█████░░░░░" def test_trend_says_first_rather_than_no_change() -> None: """Zero percent and "nothing to compare against" are different claims.""" assert "pierwszy taki okres" in trend_line(Trend(now=10, before=0), "poprzednio") assert "dokładnie tyle samo" in trend_line(Trend(now=10, before=10), "poprzednio") assert "↑ 50% więcej" in trend_line(Trend(now=15, before=10), "poprzednio") assert "↓ 50% mniej" in trend_line(Trend(now=5, before=10), "poprzednio") def test_a_long_period_is_truncated_with_its_total() -> None: many = rows([(f"Osoba {i:02d}", 20 - i) for i in range(MAX_ROWS + 4)]) rendered = render_period(WEEK, many, Trend(100, 90)) assert "…i 4 osoby więcej" in rendered assert len([line for line in rendered.split("\n") if line.startswith(("1.", "2."))]) >= 1 def test_medals_only_appear_on_a_podium() -> None: three = rows([("A", 3), ("B", 2), ("C", 1)]) assert "🥇" in render_period(WEEK, three, Trend(6, 5), podium=True) assert "🥇" not in render_period(WEEK, three, Trend(6, 5)) def test_an_empty_command_still_says_what_it_is_for() -> None: """A bare "za mało danych" tells nobody what they asked for. Reported by the group within minutes of 0.1.0: somebody typed !korona, got only that line, and learned neither what the command does nor when it would work. """ for rendered in ( render_records({}, None, None, [], "2026-08-30"), render_crown({}, [], "2026-08-30"), render_weekdays({}, 0, "2026-08-30"), ): assert "Jeszcze za mało danych." in rendered assert "Pokażę:" in rendered assert "Liczę od 30 sierpnia." in rendered def test_an_empty_command_without_a_start_date_omits_it() -> None: assert "Liczę od" not in render_crown({}, []) def test_records_reports_each_kind_it_has() -> None: rendered = render_records( {"2026-09-01": 10, "2026-09-03": 2}, DayRecord("2026-09-01", 4), Silence("2026-09-04", "2026-09-06", 3), [("Ala", DayRecord("2026-09-01", 9))], ) assert "Najwięcej w jeden dzień: 10" in rendered assert "Najciszej (ale ktoś pisał): 2" in rendered assert "Najwięcej zdjęć" in rendered assert "Najdłuższa cisza: 3 dni" in rendered assert "Ala — 9" in rendered def test_the_crown_reports_now_longest_and_totals() -> None: winners = { "2026-09-01": [("u1", "Ala")], "2026-09-02": [("u1", "Ala")], "2026-09-03": [("u2", "kuhy")], } people = [Person("u1", "Ala", ""), Person("u2", "kuhy", "")] rendered = render_crown(winners, people) assert "Teraz: kuhy — 1 dzień z rzędu" in rendered assert "Najdłuższa seria: Ala — 2 dni" in rendered assert "Ala — 2 dni" in rendered def test_weekdays_skips_days_never_recorded() -> None: rendered = render_weekdays({0: [10, 20], 4: [5]}, 4) assert "poniedziałki: średnio 15" in rendered assert "piątki: średnio 5" in rendered assert "← dziś" in rendered assert "wtorki" not in rendered def test_me_omits_what_it_does_not_know() -> None: """No record, no favourite hour, no streak: three clauses that vanish.""" rendered = render_me("kuhy", 3, None, 10, None, 0) assert rendered == f"{ME_TITLE}\n\nkuhy — 3 wiadomości w historii\nUdział w rozmowie: 10%" def test_me_reports_everything_it_does_know() -> None: rendered = render_me("kuhy", 30, DayRecord("2026-09-01", 12), 40, 23, 2) assert "Rekord życiowy: 12 (1 września)" in rendered assert "Najczęściej piszesz między 23:00 a 00:00" in rendered assert "Korona: 2 dni z rzędu" in rendered def test_funny_counts_are_marked_wherever_a_count_is_printed() -> None: """The number carries its marker in a row, a record and the me block alike. Shares are left alone: the 69% here is the rounding of 2137 / 3106, not something anybody did. """ period = render_period(WEEK, rows([("Ala", 2137), ("kuhy", 969)]), Trend(0, 0)) assert "Ala — 2137 🙏 " in period assert "3106 wiadomości" in period assert "69%" in period assert "69 (nice)%" not in period records = render_records( {"2026-09-01": 420}, None, None, [("Ala", DayRecord("2026-09-01", 1410))] ) assert "Najwięcej w jeden dzień: 420 🌿 wiadomości" in records assert "Ala — 1410 ⚔️ (1 września)" in records me = render_me("kuhy", 1916, DayRecord("2026-09-01", 314), 40, None, 67) assert "kuhy — 1916 🇵🇱 wiadomości w historii" in me assert "Rekord życiowy: 314 🥧 (1 września)" in me assert "Korona: 67 🤷 dni z rzędu" in me