test_project_query.py 3.69 KB
"""v_project_list tests: c_project_list/c_project_get/c_project_update
(2026-08-03), real sqlite (no mocking needed).

Run: python3 -m unittest src.test_project_query -v
"""

import unittest

from src import project_query, schema


class ProjectQueryTestBase(unittest.TestCase):
    def setUp(self):
        self.conn = schema.connect(":memory:")
        schema.create_schema(self.conn)

    def tearDown(self):
        self.conn.close()

    def _insert_project(self, project_id, name="P", target_folder_path=None, status="active"):
        self.conn.execute(
            "INSERT INTO project (project_id, name, target_folder_path, has_git_repo, status) "
            "VALUES (?, ?, ?, 1, ?)",
            (project_id, name, target_folder_path or ("/tmp/" + project_id), status),
        )
        self.conn.commit()


class ListProjectsTest(ProjectQueryTestBase):
    def test_lists_all_projects_with_goal_count(self):
        self._insert_project("proj-1")
        self._insert_project("proj-2")
        self.conn.execute(
            "INSERT INTO task (task_id, project_id, goal_text, task_type, status, assigned_org_node) "
            "VALUES ('task-1', 'proj-1', 'goal', 'goal', 'queued', 'planner')"
        )
        self.conn.commit()

        result = project_query.list_projects(self.conn)
        by_id = {p["project_id"]: p for p in result}
        self.assertEqual(by_id["proj-1"]["goal_count"], 1)
        self.assertEqual(by_id["proj-2"]["goal_count"], 0)

    def test_includes_archived_projects(self):
        self._insert_project("proj-1", status="archived")
        result = project_query.list_projects(self.conn)
        self.assertEqual(result[0]["status"], "archived")


class GetProjectTest(ProjectQueryTestBase):
    def test_returns_project_detail(self):
        self._insert_project("proj-1", name="My Project", target_folder_path="/tmp/my-project")
        result = project_query.get_project(self.conn, "proj-1")
        self.assertEqual(result["name"], "My Project")
        self.assertEqual(result["target_folder_path"], "/tmp/my-project")
        self.assertEqual(result["goal_count"], 0)

    def test_nonexistent_project_raises_not_found(self):
        with self.assertRaises(project_query.ProjectNotFoundError):
            project_query.get_project(self.conn, "no-such-project")


class UpdateProjectTest(ProjectQueryTestBase):
    def test_renames_project(self):
        self._insert_project("proj-1", name="old name")
        result = project_query.update_project(self.conn, "proj-1", name="new name")
        self.assertEqual(result["name"], "new name")

    def test_archives_project(self):
        self._insert_project("proj-1", status="active")
        result = project_query.update_project(self.conn, "proj-1", status="archived")
        self.assertEqual(result["status"], "archived")

    def test_reactivates_archived_project(self):
        self._insert_project("proj-1", status="archived")
        result = project_query.update_project(self.conn, "proj-1", status="active")
        self.assertEqual(result["status"], "active")

    def test_invalid_status_rejected(self):
        self._insert_project("proj-1")
        with self.assertRaises(project_query.InvalidParamError):
            project_query.update_project(self.conn, "proj-1", status="deleted")

    def test_blank_name_rejected(self):
        self._insert_project("proj-1")
        with self.assertRaises(project_query.InvalidParamError):
            project_query.update_project(self.conn, "proj-1", name="   ")

    def test_nonexistent_project_raises_not_found(self):
        with self.assertRaises(project_query.ProjectNotFoundError):
            project_query.update_project(self.conn, "no-such-project", name="x")


if __name__ == "__main__":
    unittest.main()