home · contact · privacy
Add Conditions for Todos/Processes to be met or undone by other Todos.
[plomtask] / tests / todos.py
index 93b34d197f33aebbd5b096619c3804ca0b8f75ce..98c2aaf8da3e158f2709a4ef1f3251d63f7b9068 100644 (file)
@@ -3,37 +3,203 @@ from tests.utils import TestCaseWithDB, TestCaseWithServer
 from plomtask.todos import Todo
 from plomtask.days import Day
 from plomtask.processes import Process
-from plomtask.exceptions import NotFoundException
+from plomtask.conditions import Condition
+from plomtask.exceptions import (NotFoundException, BadFormatException,
+                                 HandledException)
 
 
 class TestsWithDB(TestCaseWithDB):
-    """Tests not requiring DB setup."""
+    """Tests requiring DB, but not server setup."""
 
-    def test_Todo_by_date(self) -> None:
+    def test_Todo_by_id(self) -> None:
         """Test creation and findability of Todos."""
+        day = Day('2024-01-01')
+        process = Process(None)
+        todo = Todo(None, process, False, day)
+        with self.assertRaises(NotFoundException):
+            todo.save(self.db_conn)
+        process.save_without_steps(self.db_conn)
+        todo.save(self.db_conn)
+        self.assertEqual(Todo.by_id(self.db_conn, 1), todo)
+        with self.assertRaises(NotFoundException):
+            self.assertEqual(Todo.by_id(self.db_conn, 0), todo)
+        with self.assertRaises(NotFoundException):
+            self.assertEqual(Todo.by_id(self.db_conn, 2), todo)
+
+    def test_Todo_by_date(self) -> None:
+        """Test findability of Todos by date."""
         day1 = Day('2024-01-01')
         day2 = Day('2024-01-02')
-        process1 = Process(None)
-        todo1 = Todo(None, process1, False, day1)
-        with self.assertRaises(NotFoundException):
-            todo1.save(self.db_conn)
-        process1.save_without_steps(self.db_conn)
+        process = Process(None)
+        process.save_without_steps(self.db_conn)
+        todo1 = Todo(None, process, False, day1)
         todo1.save(self.db_conn)
-        todo2 = Todo(None, process1, False, day1)
+        todo2 = Todo(None, process, False, day1)
         todo2.save(self.db_conn)
-        with self.assertRaises(NotFoundException):
-            Todo.by_date(self.db_conn, day1.date),
-        day1.save(self.db_conn)
-        day2.save(self.db_conn)
         self.assertEqual(Todo.by_date(self.db_conn, day1.date), [todo1, todo2])
         self.assertEqual(Todo.by_date(self.db_conn, day2.date), [])
         self.assertEqual(Todo.by_date(self.db_conn, 'foo'), [])
 
+    def test_Todo_from_process(self) -> None:
+        """Test spawning of Todo attributes from Process."""
+        day = Day('2024-01-01')
+        process = Process(None)
+        c1 = Condition(None, False)
+        c1.save(self.db_conn)
+        assert c1.id_ is not None
+        c2 = Condition(None, True)
+        c2.save(self.db_conn)
+        assert c2.id_ is not None
+        process.set_conditions(self.db_conn, [c1.id_])
+        todo = Todo(None, process, False, day)
+        self.assertEqual(todo.conditions, [c1])
+        todo.set_conditions(self.db_conn, [c2.id_])
+        self.assertEqual(todo.conditions, [c2])
+        self.assertEqual(process.conditions, [c1])
+        process.set_fulfills(self.db_conn, [c1.id_])
+        todo = Todo(None, process, False, day)
+        self.assertEqual(todo.fulfills, [c1])
+        todo.set_fulfills(self.db_conn, [c2.id_])
+        self.assertEqual(todo.fulfills, [c2])
+        self.assertEqual(process.fulfills, [c1])
+        process.set_undoes(self.db_conn, [c1.id_])
+        todo = Todo(None, process, False, day)
+        self.assertEqual(todo.undoes, [c1])
+        todo.set_undoes(self.db_conn, [c2.id_])
+        self.assertEqual(todo.undoes, [c2])
+        self.assertEqual(process.undoes, [c1])
+
+    def test_Todo_on_conditions(self) -> None:
+        """Test effect of Todos on Conditions."""
+        day = Day('2024-01-01')
+        process = Process(None)
+        process.save_without_steps(self.db_conn)
+        c1 = Condition(None, False)
+        c2 = Condition(None, True)
+        c1.save(self.db_conn)
+        c2.save(self.db_conn)
+        assert c1.id_ is not None
+        assert c2.id_ is not None
+        todo = Todo(None, process, False, day)
+        todo.save(self.db_conn)
+        todo.set_fulfills(self.db_conn, [c1.id_])
+        todo.set_undoes(self.db_conn, [c2.id_])
+        todo.is_done = True
+        self.assertEqual(c1.is_active, True)
+        self.assertEqual(c2.is_active, False)
+        todo.is_done = False
+        self.assertEqual(c1.is_active, True)
+        self.assertEqual(c2.is_active, False)
+
+    def test_Todo_enablers_disablers(self) -> None:
+        """Test Todo.enablers_for_at/disablers_for_at."""
+        day1 = Day('2024-01-01')
+        day2 = Day('2024-01-02')
+        process = Process(None)
+        process.save_without_steps(self.db_conn)
+        c1 = Condition(None, False)
+        c2 = Condition(None, True)
+        c1.save(self.db_conn)
+        c2.save(self.db_conn)
+        todo1 = Todo(None, process, False, day1)
+        todo1.save(self.db_conn)
+        assert c1.id_ is not None
+        assert c2.id_ is not None
+        todo1.set_fulfills(self.db_conn, [c1.id_])
+        todo1.set_undoes(self.db_conn, [c2.id_])
+        todo1.save(self.db_conn)
+        assert todo1.id_ is not None
+        todo2 = Todo(None, process, False, day1)
+        todo2.save(self.db_conn)
+        assert todo2.id_ is not None
+        todo2.set_fulfills(self.db_conn, [c2.id_])
+        todo2.save(self.db_conn)
+        todo3 = Todo(None, process, False, day2)
+        todo3.save(self.db_conn)
+        assert todo3.id_ is not None
+        todo3.set_fulfills(self.db_conn, [c2.id_])
+        todo3.save(self.db_conn)
+        self.assertEqual(Todo.enablers_for_at(self.db_conn, c1, day1.date),
+                         [todo1])
+        self.assertEqual(Todo.enablers_for_at(self.db_conn, c1, day2.date),
+                         [])
+        self.assertEqual(Todo.disablers_for_at(self.db_conn, c1, day1.date),
+                         [])
+        self.assertEqual(Todo.disablers_for_at(self.db_conn, c1, day2.date),
+                         [])
+        self.assertEqual(Todo.enablers_for_at(self.db_conn, c2, day1.date),
+                         [todo2])
+        self.assertEqual(Todo.enablers_for_at(self.db_conn, c2, day2.date),
+                         [todo3])
+        self.assertEqual(Todo.disablers_for_at(self.db_conn, c2, day1.date),
+                         [todo1])
+        self.assertEqual(Todo.disablers_for_at(self.db_conn, c2, day2.date),
+                         [])
+
+    def test_Todo_children(self) -> None:
+        """Test Todo.children relations."""
+        day = Day('2024-01-01')
+        process = Process(None)
+        process.save_without_steps(self.db_conn)
+        todo_1 = Todo(None, process, False, day)
+        todo_2 = Todo(None, process, False, day)
+        with self.assertRaises(HandledException):
+            todo_1.add_child(todo_2)
+        todo_1.save(self.db_conn)
+        with self.assertRaises(HandledException):
+            todo_1.add_child(todo_2)
+        todo_2.save(self.db_conn)
+        todo_1.add_child(todo_2)
+        todo_1.save(self.db_conn)
+        todo_retrieved = Todo.by_id(self.db_conn, todo_1.id_)
+        self.assertEqual(todo_retrieved.children, [todo_2])
+        with self.assertRaises(BadFormatException):
+            todo_2.add_child(todo_1)
+
+    def test_Todo_conditioning(self) -> None:
+        """Test Todo.doability conditions."""
+        day = Day('2024-01-01')
+        process = Process(None)
+        process.save_without_steps(self.db_conn)
+        todo_1 = Todo(None, process, False, day)
+        todo_1.save(self.db_conn)
+        todo_2 = Todo(None, process, False, day)
+        todo_2.save(self.db_conn)
+        todo_2.add_child(todo_1)
+        with self.assertRaises(BadFormatException):
+            todo_2.is_done = True
+        todo_1.is_done = True
+        todo_2.is_done = True
+        todo_2.is_done = False
+        condition = Condition(None)
+        condition.save(self.db_conn)
+        assert condition.id_ is not None
+        todo_2.set_conditions(self.db_conn, [condition.id_])
+        with self.assertRaises(BadFormatException):
+            todo_2.is_done = True
+        condition.is_active = True
+        todo_2.is_done = True
+
+    def test_Todo_singularity(self) -> None:
+        """Test pointers made for single object keep pointing to it."""
+        day = Day('2024-01-01')
+        day.save(self.db_conn)
+        process = Process(None)
+        process.save_without_steps(self.db_conn)
+        todo = Todo(None, process, False, day)
+        todo.save(self.db_conn)
+        retrieved_todo = Todo.by_id(self.db_conn, 1)
+        todo.is_done = True
+        self.assertEqual(retrieved_todo.is_done, True)
+        retrieved_todo = Todo.by_date(self.db_conn, '2024-01-01')[0]
+        retrieved_todo.is_done = False
+        self.assertEqual(todo.is_done, False)
+
 
 class TestsWithServer(TestCaseWithServer):
     """Tests against our HTTP server/handler (and database)."""
 
-    def test_do_POST_todo(self) -> None:
+    def test_do_POST_day(self) -> None:
         """Test Todo posting of POST /day."""
         form_data = {'title': '', 'description': '', 'effort': 1}
         self.check_post(form_data, '/process?id=', 302, '/')
@@ -58,3 +224,61 @@ class TestsWithServer(TestCaseWithServer):
         self.assertEqual(todo1.id_, 2)
         self.assertEqual(todo1.process.id_, process2.id_)
         self.assertEqual(todo1.is_done, False)
+
+    def test_do_POST_todo(self) -> None:
+        """Test POST /todo."""
+        def post_and_reload(form_data: dict[str, object],
+                            status: int = 302) -> Todo:
+            self.check_post(form_data, '/todo?id=1', status, '/')
+            self.db_conn.cached_todos = {}
+            return Todo.by_date(self.db_conn, '2024-01-01')[0]
+        form_data = {'title': '', 'description': '', 'effort': 1}
+        self.check_post(form_data, '/process', 302, '/')
+        form_data = {'comment': '', 'new_todo': 1}
+        self.check_post(form_data, '/day?date=2024-01-01', 302, '/')
+        form_data = {}
+        self.check_post(form_data, '/todo=', 404)
+        self.check_post(form_data, '/todo?id=', 404)
+        self.check_post(form_data, '/todo?id=FOO', 400)
+        self.check_post(form_data, '/todo?id=0', 404)
+        todo1 = post_and_reload(form_data)
+        self.assertEqual(todo1.children, [])
+        self.assertEqual(todo1.parents, [])
+        self.assertEqual(todo1.is_done, False)
+        form_data = {'done': ''}
+        todo1 = post_and_reload(form_data)
+        self.assertEqual(todo1.is_done, True)
+        form_data = {}
+        todo1 = post_and_reload(form_data)
+        self.assertEqual(todo1.is_done, False)
+        form_data = {'adopt': 'foo'}
+        self.check_post(form_data, '/todo?id=1', 400)
+        form_data = {'adopt': 1}
+        self.check_post(form_data, '/todo?id=1', 400)
+        form_data = {'adopt': 2}
+        self.check_post(form_data, '/todo?id=1', 404)
+        form_data = {'comment': '', 'new_todo': 1}
+        self.check_post(form_data, '/day?date=2024-01-01', 302, '/')
+        form_data = {'adopt': 2}
+        todo1 = post_and_reload(form_data)
+        todo2 = Todo.by_date(self.db_conn, '2024-01-01')[1]
+        self.assertEqual(todo1.children, [todo2])
+        self.assertEqual(todo1.parents, [])
+        self.assertEqual(todo2.children, [])
+        self.assertEqual(todo2.parents, [todo1])
+        self.check_post(form_data, '/todo?id=1', 400, '/')
+        form_data = {'done': ''}
+        todo1 = post_and_reload(form_data, 400)
+        self.assertEqual(todo1.is_done, False)
+
+    def test_do_GET_todo(self) -> None:
+        """Test GET /todo response codes."""
+        form_data = {'title': '', 'description': '', 'effort': 1}
+        self.check_post(form_data, '/process?id=', 302, '/')
+        form_data = {'comment': '', 'new_todo': 1}
+        self.check_post(form_data, '/day?date=2024-01-01', 302, '/')
+        self.check_get('/todo', 404)
+        self.check_get('/todo?id=', 404)
+        self.check_get('/todo?id=foo', 400)
+        self.check_get('/todo?id=0', 404)
+        self.check_get('/todo?id=1', 200)