signal-bot/tests/test_day_log.py
Krzysztof kuhy Rudnicki 77795ee6f8
Some checks are pending
CI / check (push) Waiting to run
CI / web (push) Waiting to run
Today's food and workout logs, read from where diet_guard and screen_locker keep them
Two commands, food_today and workout_today, each printing the current
Warsaw day out of a log another program owns: every meal with its time,
calories and source plus the day's total and macros; every workout with
every field it carries. Three workout fields are withheld (a reservation
phone number, a screenshot path, the sync record id), and the food budget
is never printed -- diet_guard keeps that number on the machine on purpose.

The spellings the group uses carry a surname, so they are custom aliases in
the state directory; aliases.json ships only plain words. The suite points
both logs at absent temp files so it can never read the operator's own,
and the e2e run writes one invented entry of each under today's date.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-04 22:07:46 +02:00

73 lines
2.6 KiB
Python

# Copyright (c) 2026 Krzysztof Rudnicki. MIT licence.
"""Reading one day out of a log another program keeps."""
from __future__ import annotations
import json
from pathlib import Path
import pytest
from signal_bot.day_log import DayLogError, path_from_env, read_day
DAY = "2026-09-04"
def _write(path: Path, document: object) -> Path:
path.write_text(json.dumps(document), encoding="utf-8")
return path
def test_the_days_entries_come_back_in_file_order(tmp_path: Path) -> None:
log = _write(
tmp_path / "log.json",
{DAY: [{"desc": "a"}, {"desc": "b"}], "2026-09-03": [{"desc": "old"}]},
)
assert read_day(log, DAY) == [{"desc": "a"}, {"desc": "b"}]
def test_a_day_the_log_has_not_reached_is_empty_not_an_error(tmp_path: Path) -> None:
"""Before breakfast the day has no key yet; that is the normal case."""
assert read_day(_write(tmp_path / "log.json", {"2026-09-03": [{}]}), DAY) == []
assert read_day(_write(tmp_path / "log.json", {}), DAY) == []
def test_entries_that_are_not_objects_are_dropped(tmp_path: Path) -> None:
log = _write(tmp_path / "log.json", {DAY: [{"desc": "a"}, "junk", 3, None]})
assert read_day(log, DAY) == [{"desc": "a"}]
def test_a_missing_file_is_an_error_because_nothing_today_would_be_a_lie(
tmp_path: Path,
) -> None:
with pytest.raises(DayLogError, match="cannot be read"):
read_day(tmp_path / "absent.json", DAY)
def test_a_file_that_is_not_json_is_an_error(tmp_path: Path) -> None:
broken = tmp_path / "log.json"
broken.write_text("{not json", encoding="utf-8")
with pytest.raises(DayLogError, match="cannot be read"):
read_day(broken, DAY)
def test_a_document_that_is_not_an_object_of_days_is_an_error(tmp_path: Path) -> None:
with pytest.raises(DayLogError, match="not an object of days"):
read_day(_write(tmp_path / "log.json", [1, 2]), DAY)
def test_a_day_that_is_not_a_list_is_an_error(tmp_path: Path) -> None:
with pytest.raises(DayLogError, match="not a list of entries"):
read_day(_write(tmp_path / "log.json", {DAY: {"desc": "a"}}), DAY)
def test_the_path_comes_from_the_environment_or_the_programs_default(
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
) -> None:
monkeypatch.delenv("SOME_LOG", raising=False)
assert path_from_env("SOME_LOG", "~/x/log.json") == Path.home() / "x/log.json"
monkeypatch.setenv("SOME_LOG", f" {tmp_path / 'mine.json'} ")
assert path_from_env("SOME_LOG", "~/x/log.json") == tmp_path / "mine.json"
monkeypatch.setenv("SOME_LOG", " ")
assert path_from_env("SOME_LOG", "~/x/log.json") == Path.home() / "x/log.json"