Two milestones: a note can carry its own check (317), and a rule keeps what it used to say (323) #135
@@ -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 datetime import date, datetime, timezone
|
||||||
from unittest.mock import AsyncMock, MagicMock, patch
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||||||
|
|
||||||
|
from tests.helpers import fake_note, make_mock_session
|
||||||
|
|
||||||
|
|
||||||
# ── Timestamp side-effect tests ──────────────────────────────────────────────
|
# ── Timestamp side-effect tests ──────────────────────────────────────────────
|
||||||
|
|
||||||
async def test_update_note_sets_started_at_on_in_progress():
|
async def test_update_note_sets_started_at_on_in_progress():
|
||||||
"""started_at is set when status transitions to 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.status = "in_progress"
|
||||||
mock_note.started_at = None
|
mock_note.started_at = None
|
||||||
mock_note.recurrence_rule = 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():
|
async def test_update_note_sets_completed_at_on_done():
|
||||||
"""completed_at is set when status transitions to done."""
|
"""completed_at is set when status transitions to done."""
|
||||||
mock_note = MagicMock()
|
mock_note = fake_note()
|
||||||
mock_note.status = "done"
|
mock_note.status = "done"
|
||||||
mock_note.started_at = datetime(2026, 3, 1, tzinfo=timezone.utc)
|
mock_note.started_at = datetime(2026, 3, 1, tzinfo=timezone.utc)
|
||||||
mock_note.completed_at = None
|
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():
|
async def test_update_note_clears_timestamps_on_todo():
|
||||||
"""started_at and completed_at are cleared when status resets to 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.status = "todo"
|
||||||
mock_note.started_at = datetime(2026, 3, 1, tzinfo=timezone.utc)
|
mock_note.started_at = datetime(2026, 3, 1, tzinfo=timezone.utc)
|
||||||
mock_note.completed_at = datetime(2026, 3, 15, 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():
|
async def test_update_note_preserves_started_at_if_already_set():
|
||||||
"""started_at is not overwritten on a second transition to in_progress."""
|
"""started_at is not overwritten on a second transition to in_progress."""
|
||||||
original_start = datetime(2026, 3, 1, tzinfo=timezone.utc)
|
original_start = datetime(2026, 3, 1, tzinfo=timezone.utc)
|
||||||
mock_note = MagicMock()
|
mock_note = fake_note()
|
||||||
mock_note.status = "in_progress"
|
mock_note.status = "in_progress"
|
||||||
mock_note.started_at = original_start
|
mock_note.started_at = original_start
|
||||||
mock_note.recurrence_rule = None
|
mock_note.recurrence_rule = None
|
||||||
@@ -96,7 +106,6 @@ async def test_update_note_preserves_started_at_if_already_set():
|
|||||||
# ── Recurrence rule validation ────────────────────────────────────────────────
|
# ── Recurrence rule validation ────────────────────────────────────────────────
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from tests.helpers import make_mock_session
|
|
||||||
|
|
||||||
|
|
||||||
def test_validate_interval_rule_valid():
|
def test_validate_interval_rule_valid():
|
||||||
|
|||||||
Reference in New Issue
Block a user