From 7d9ffb46ac336772159bef854eefeedba9ef1578 Mon Sep 17 00:00:00 2001 From: Deevdeep Parida Date: Sat, 5 Sep 2026 22:01:09 +0530 Subject: [PATCH] Fix task bugs and add search filter --- app/service.py | 19 ++++++----- tests/test_tasks.py | 82 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 tests/test_tasks.py diff --git a/app/service.py b/app/service.py index 8022b93..a666c65 100644 --- a/app/service.py +++ b/app/service.py @@ -10,15 +10,18 @@ def list_tasks(status: str | None = None, q: str | None = None) -> list[dict[str """Return task records, optionally filtered by status and search text.""" tasks = load_tasks() filtered: list[dict[str, Any]] = [] + query = q.lower() if q else None for task in tasks: - # Instructor note: intentional bug for the lab. - # This uses the literal string "status" instead of the query parameter value. - if status and task["status"] != "status": + if status and task["status"] != status: continue - # Instructor note: partial feature for the lab. - # The route already accepts `q`, but search is not implemented yet. + if query: + title = str(task.get("title", "")).lower() + description = str(task.get("description", "")).lower() + if query not in title and query not in description: + continue + filtered.append(task) return filtered @@ -51,14 +54,14 @@ def complete_task(task_id: int) -> dict[str, Any] | None: """Mark a task as completed.""" tasks = load_tasks() - for task in tasks: + for index, task in enumerate(tasks): if task["id"] == task_id: updated_task = dict(task) updated_task["status"] = "done" updated_task["completed_at"] = datetime.now(timezone.utc).isoformat() - # Instructor note: intentional bug for the lab. - # The updated task is returned, but the stored list is never updated or saved. + tasks[index] = updated_task + save_tasks(tasks) return updated_task return None diff --git a/tests/test_tasks.py b/tests/test_tasks.py new file mode 100644 index 0000000..6dfb5f2 --- /dev/null +++ b/tests/test_tasks.py @@ -0,0 +1,82 @@ +import json +import tempfile +import unittest +from pathlib import Path +from unittest.mock import patch + +from app import service, store + + +class TaskServiceTests(unittest.TestCase): + def setUp(self): + self.tempdir = tempfile.TemporaryDirectory() + self.data_path = Path(self.tempdir.name) / "tasks.json" + self.data_path.write_text( + json.dumps( + [ + { + "id": 1, + "title": "Write launch recap", + "description": "Draft a short internal summary of the product launch.", + "status": "open", + "priority": "high", + "created_at": "2026-02-25T16:00:00Z", + "completed_at": None, + }, + { + "id": 2, + "title": "Fix login redirect", + "description": "Resolve the redirect loop after the OAuth callback.", + "status": "done", + "priority": "high", + "created_at": "2026-02-20T14:30:00Z", + "completed_at": "2026-02-21T09:15:00Z", + }, + { + "id": 3, + "title": "Plan workshop agenda", + "description": "Outline topics for the partner onboarding session.", + "status": "open", + "priority": "medium", + "created_at": "2026-02-27T11:45:00Z", + "completed_at": None, + }, + ] + ), + encoding="utf-8", + ) + self.patcher = patch.object(store, "DATA_FILE", self.data_path) + self.patcher.start() + + def tearDown(self): + self.patcher.stop() + self.tempdir.cleanup() + + def test_list_tasks_filters_by_status(self): + tasks = service.list_tasks(status="open") + self.assertEqual([task["id"] for task in tasks], [1, 3]) + + def test_list_tasks_filters_by_q_case_insensitive_across_title_and_description(self): + tasks = service.list_tasks(q="launch") + self.assertEqual([task["id"] for task in tasks], [1]) + + tasks = service.list_tasks(q="OAUTH") + self.assertEqual([task["id"] for task in tasks], [2]) + + def test_list_tasks_filters_by_status_and_q(self): + tasks = service.list_tasks(status="open", q="plan") + self.assertEqual([task["id"] for task in tasks], [3]) + + def test_complete_task_persists_status_and_timestamp(self): + updated = service.complete_task(1) + + self.assertEqual(updated["status"], "done") + self.assertIsNotNone(updated["completed_at"]) + + persisted = store.load_tasks() + self.assertEqual(persisted[0]["status"], "done") + self.assertIsNotNone(persisted[0]["completed_at"]) + + +if __name__ == "__main__": + unittest.main()