# Acceptance test for time-to-green task T07 (written for the 2026-10-30 bench). # FROZEN COPY for the time-to-green bench: acceptance test t07: add-tests-to-a-legacy-script-with-an-agent_test.py with the case-sensitivity pin replaced by the case-insensitive expectation; every other test as shipped. # Edits to tasks/ are denied to the agent. """Characterization tests for the legacy logreport script. These tests pin what the script DOES today, including its quirks and one latent bug, following Michael Feathers' method: write the test, run it, paste the actual output in as the expectation, then name the test after what you learned. Run: python -m unittest add-tests-to-a-legacy-script-with-an-agent_test.py Python 3.13, standard library only. """ from __future__ import annotations import importlib.util import io import os import unittest HERE = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # frozen copy in tasks/: modules live in the repo root _spec = importlib.util.spec_from_file_location( "logreport", os.path.join(HERE, "add-tests-to-a-legacy-script-with-an-agent.py")) logreport = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(logreport) LINES = [ "2026-09-05 14:03:11 ERROR auth: token expired user=42\n", "2026-09-05 14:03:12 INFO auth: refreshed user=42\n", "garbage line without a timestamp\n", "2026-09-05 14:04:00 INFO web: GET /health 200\n", "2026-09-05 14:05:30 WARN db: slow query 1.2s\n", ] def run(lines): out = io.StringIO() logreport.run(lines, out) return out.getvalue() class ReportCharacterization(unittest.TestCase): def test_report_for_five_lines_is_exactly_this(self): # Pasted from the first run; every character is intentional. self.assertEqual(run(LINES), "WARN skipping line 3: 'garbage line without a timestamp'\n" "lines: 5 (skipped 1)\n" " INFO 2\n" " ERROR 1\n" " WARN 1\n" "first: 05/09/26 14:03:11\n" "last: 05/09/26 14:05:30\n") def test_empty_input_prints_only_the_line_count(self): self.assertEqual(run([]), "lines: 0 (skipped 0)\n") def test_levels_sort_by_count_then_name(self): out = run(["2026-01-01 00:00:00 B x\n", "2026-01-01 00:00:00 A x\n", "2026-01-01 00:00:00 A x\n", "2026-01-01 00:00:00 C x\n"]) self.assertEqual(out.splitlines()[1:4], [" A 2", " B 1", " C 1"]) def test_level_match_is_case_insensitive_and_printed_upper_case(self): # Corrected expectation (time-to-green T07): levels counted case-insensitively, printed upper-cased. out = run(["2026-01-01 00:00:00 error x\n", "2026-01-01 00:00:00 ERROR x\n", "2026-01-01 00:00:00 Error x\n"]) self.assertIn(" ERROR 3\n", out) self.assertNotIn(" error", out) self.assertNotIn(" Error", out) def test_short_or_malformed_stamps_are_skipped_with_a_warning(self): cases = { "2026-9-5 14:03:11 INFO x\n": "WARN skipping line 1: '2026-9-5 14:03:11 INFO x'", "2026-09-05 14:03 INFO x\n": "WARN skipping line 1: '2026-09-05 14:03 INFO x'", "2026-09-05 14:03:11 INFO\n": "WARN skipping line 1: '2026-09-05 14:03:11 INFO'", } for line, expected in cases.items(): with self.subTest(line=line): self.assertEqual(run([line]).splitlines()[0], expected) def test_run_resets_state_between_calls(self): run(LINES) self.assertEqual(run([]), "lines: 0 (skipped 0)\n") class DateQuirks(unittest.TestCase): def test_dates_are_reformatted_to_dd_mm_yy(self): for iso, expected in {"2026-09-05": "05/09/26", "1999-12-31": "31/12/99", "2000-01-01": "01/01/00"}.items(): with self.subTest(iso=iso): self.assertEqual(logreport.fmt_date(iso), expected) def test_last_seen_is_wrong_across_a_month_boundary_documented_bug(self): # 1 September sorts before 31 August once both are DD/MM/YY strings. out = run(["2026-08-31 23:59:59 INFO x\n", "2026-09-01 00:00:01 INFO y\n"]) self.assertIn("first: 01/09/26 00:00:01\n", out) # wrong, pinned on purpose self.assertIn("last: 31/08/26 23:59:59\n", out) # wrong, pinned on purpose if __name__ == "__main__": unittest.main()