diff --git a/tests/test_recurrence.py b/tests/test_recurrence.py index bb89bfc..2a26aca 100644 --- a/tests/test_recurrence.py +++ b/tests/test_recurrence.py @@ -1,13 +1,23 @@ -"""Tests for task lifecycle timestamps and recurrence logic.""" +"""Tests for task lifecycle timestamps and recurrence logic. + +The note stand-ins come from `fake_note`, not a bare MagicMock. These four +predated that helper and broke the moment `update_note` started reading a +column they did not set (milestone 317): a fresh MagicMock is truthy on every +attribute, so `verify_with` read as "this record carries a check" and the +guard refused the write. That is note 2109's lesson, and the reason fake_note +exists — a stand-in has to be able to say NO. +""" from datetime import date, datetime, timezone from unittest.mock import AsyncMock, MagicMock, patch +from tests.helpers import fake_note, make_mock_session + # ── Timestamp side-effect tests ────────────────────────────────────────────── async def test_update_note_sets_started_at_on_in_progress(): """started_at is set when status transitions to in_progress.""" - mock_note = MagicMock() + mock_note = fake_note() mock_note.status = "in_progress" mock_note.started_at = None mock_note.recurrence_rule = None @@ -28,7 +38,7 @@ async def test_update_note_sets_started_at_on_in_progress(): async def test_update_note_sets_completed_at_on_done(): """completed_at is set when status transitions to done.""" - mock_note = MagicMock() + mock_note = fake_note() mock_note.status = "done" mock_note.started_at = datetime(2026, 3, 1, tzinfo=timezone.utc) mock_note.completed_at = None @@ -50,7 +60,7 @@ async def test_update_note_sets_completed_at_on_done(): async def test_update_note_clears_timestamps_on_todo(): """started_at and completed_at are cleared when status resets to todo.""" - mock_note = MagicMock() + mock_note = fake_note() mock_note.status = "todo" mock_note.started_at = datetime(2026, 3, 1, tzinfo=timezone.utc) mock_note.completed_at = datetime(2026, 3, 15, tzinfo=timezone.utc) @@ -74,7 +84,7 @@ async def test_update_note_clears_timestamps_on_todo(): async def test_update_note_preserves_started_at_if_already_set(): """started_at is not overwritten on a second transition to in_progress.""" original_start = datetime(2026, 3, 1, tzinfo=timezone.utc) - mock_note = MagicMock() + mock_note = fake_note() mock_note.status = "in_progress" mock_note.started_at = original_start mock_note.recurrence_rule = None @@ -96,7 +106,6 @@ async def test_update_note_preserves_started_at_if_already_set(): # ── Recurrence rule validation ──────────────────────────────────────────────── import pytest -from tests.helpers import make_mock_session def test_validate_interval_rule_valid():