"""Tests for the status-terminal consolidation trigger in update_note.""" from unittest.mock import AsyncMock, MagicMock, patch def _mock_session_for_update(mock_note): mock_session = AsyncMock() mock_result = MagicMock() mock_result.scalars.return_value.first.return_value = mock_note mock_session.execute = AsyncMock(return_value=mock_result) mock_session.commit = AsyncMock() mock_session.refresh = AsyncMock() mock_session.__aenter__ = AsyncMock(return_value=mock_session) mock_session.__aexit__ = AsyncMock(return_value=False) return mock_session async def test_update_note_to_done_triggers_consolidation(): """status: in_progress → done should fire maybe_consolidate(task_closed).""" mock_note = MagicMock() mock_note.id = 42 mock_note.status = "in_progress" # pre-update state mock_note.body = "" mock_note.title = "" mock_note.tags = [] mock_note.started_at = None mock_note.completed_at = None mock_note.recurrence_rule = None mock_note.project_id = None with patch( "fabledassistant.services.notes.async_session", return_value=_mock_session_for_update(mock_note), ), patch( "fabledassistant.services.consolidation.maybe_consolidate", new=AsyncMock(), ) as mock_mc: from fabledassistant.services.notes import update_note await update_note(1, 42, status="done") mock_mc.assert_awaited_once_with(1, 42, reason="task_closed") async def test_update_note_to_cancelled_triggers_consolidation(): mock_note = MagicMock() mock_note.id = 42 mock_note.status = "in_progress" mock_note.body = "" mock_note.title = "" mock_note.tags = [] mock_note.started_at = None mock_note.completed_at = None mock_note.recurrence_rule = None mock_note.project_id = None with patch( "fabledassistant.services.notes.async_session", return_value=_mock_session_for_update(mock_note), ), patch( "fabledassistant.services.consolidation.maybe_consolidate", new=AsyncMock(), ) as mock_mc: from fabledassistant.services.notes import update_note await update_note(1, 42, status="cancelled") mock_mc.assert_awaited_once_with(1, 42, reason="task_closed") async def test_update_note_to_in_progress_does_not_trigger_consolidation(): """Non-terminal status changes don't fire the trigger.""" mock_note = MagicMock() mock_note.id = 42 mock_note.status = "todo" mock_note.body = "" mock_note.title = "" mock_note.tags = [] mock_note.started_at = None mock_note.completed_at = None mock_note.recurrence_rule = None mock_note.project_id = None with patch( "fabledassistant.services.notes.async_session", return_value=_mock_session_for_update(mock_note), ), patch( "fabledassistant.services.consolidation.maybe_consolidate", new=AsyncMock(), ) as mock_mc: from fabledassistant.services.notes import update_note await update_note(1, 42, status="in_progress") mock_mc.assert_not_awaited() async def test_update_note_already_done_does_not_retrigger(): """If the status was already 'done' and update_note(status='done') runs again, no fresh trigger fires — only transitions count.""" mock_note = MagicMock() mock_note.id = 42 mock_note.status = "done" mock_note.body = "" mock_note.title = "" mock_note.tags = [] mock_note.started_at = None mock_note.completed_at = None mock_note.recurrence_rule = None mock_note.project_id = None with patch( "fabledassistant.services.notes.async_session", return_value=_mock_session_for_update(mock_note), ), patch( "fabledassistant.services.consolidation.maybe_consolidate", new=AsyncMock(), ) as mock_mc: from fabledassistant.services.notes import update_note await update_note(1, 42, status="done") mock_mc.assert_not_awaited()