1 """Test Todos module."""
2 from tests.utils import TestCaseWithDB, TestCaseWithServer
3 from plomtask.todos import Todo
4 from plomtask.days import Day
5 from plomtask.processes import Process
6 from plomtask.conditions import Condition
7 from plomtask.exceptions import (NotFoundException, BadFormatException,
11 class TestsWithDB(TestCaseWithDB):
12 """Tests requiring DB, but not server setup."""
14 def test_Todo_by_id(self) -> None:
15 """Test creation and findability of Todos."""
16 day = Day('2024-01-01')
17 process = Process(None)
18 todo = Todo(None, process, False, day)
19 with self.assertRaises(NotFoundException):
20 todo.save(self.db_conn)
21 process.save_without_steps(self.db_conn)
22 todo.save(self.db_conn)
23 self.assertEqual(Todo.by_id(self.db_conn, 1), todo)
24 with self.assertRaises(NotFoundException):
25 self.assertEqual(Todo.by_id(self.db_conn, 0), todo)
26 with self.assertRaises(NotFoundException):
27 self.assertEqual(Todo.by_id(self.db_conn, 2), todo)
29 def test_Todo_by_date(self) -> None:
30 """Test findability of Todos by date."""
31 day1 = Day('2024-01-01')
32 day2 = Day('2024-01-02')
33 process = Process(None)
34 process.save_without_steps(self.db_conn)
35 todo1 = Todo(None, process, False, day1)
36 todo1.save(self.db_conn)
37 todo2 = Todo(None, process, False, day1)
38 todo2.save(self.db_conn)
39 self.assertEqual(Todo.by_date(self.db_conn, day1.date), [todo1, todo2])
40 self.assertEqual(Todo.by_date(self.db_conn, day2.date), [])
41 self.assertEqual(Todo.by_date(self.db_conn, 'foo'), [])
43 def test_Todo_from_process(self) -> None:
44 """Test spawning of Todo attributes from Process."""
45 day = Day('2024-01-01')
46 process = Process(None)
47 c1 = Condition(None, False)
49 assert c1.id_ is not None
50 c2 = Condition(None, True)
52 assert c2.id_ is not None
53 process.set_conditions(self.db_conn, [c1.id_])
54 todo = Todo(None, process, False, day)
55 self.assertEqual(todo.conditions, [c1])
56 todo.set_conditions(self.db_conn, [c2.id_])
57 self.assertEqual(todo.conditions, [c2])
58 self.assertEqual(process.conditions, [c1])
59 process.set_fulfills(self.db_conn, [c1.id_])
60 todo = Todo(None, process, False, day)
61 self.assertEqual(todo.fulfills, [c1])
62 todo.set_fulfills(self.db_conn, [c2.id_])
63 self.assertEqual(todo.fulfills, [c2])
64 self.assertEqual(process.fulfills, [c1])
65 process.set_undoes(self.db_conn, [c1.id_])
66 todo = Todo(None, process, False, day)
67 self.assertEqual(todo.undoes, [c1])
68 todo.set_undoes(self.db_conn, [c2.id_])
69 self.assertEqual(todo.undoes, [c2])
70 self.assertEqual(process.undoes, [c1])
72 def test_Todo_on_conditions(self) -> None:
73 """Test effect of Todos on Conditions."""
74 day = Day('2024-01-01')
75 process = Process(None)
76 process.save_without_steps(self.db_conn)
77 c1 = Condition(None, False)
78 c2 = Condition(None, True)
81 assert c1.id_ is not None
82 assert c2.id_ is not None
83 todo = Todo(None, process, False, day)
84 todo.save(self.db_conn)
85 todo.set_fulfills(self.db_conn, [c1.id_])
86 todo.set_undoes(self.db_conn, [c2.id_])
88 self.assertEqual(c1.is_active, True)
89 self.assertEqual(c2.is_active, False)
91 self.assertEqual(c1.is_active, True)
92 self.assertEqual(c2.is_active, False)
94 def test_Todo_enablers_disablers(self) -> None:
95 """Test Todo.enablers_for_at/disablers_for_at."""
96 day1 = Day('2024-01-01')
97 day2 = Day('2024-01-02')
98 process = Process(None)
99 process.save_without_steps(self.db_conn)
100 c1 = Condition(None, False)
101 c2 = Condition(None, True)
102 c1.save(self.db_conn)
103 c2.save(self.db_conn)
104 todo1 = Todo(None, process, False, day1)
105 todo1.save(self.db_conn)
106 assert c1.id_ is not None
107 assert c2.id_ is not None
108 todo1.set_fulfills(self.db_conn, [c1.id_])
109 todo1.set_undoes(self.db_conn, [c2.id_])
110 todo1.save(self.db_conn)
111 assert todo1.id_ is not None
112 todo2 = Todo(None, process, False, day1)
113 todo2.save(self.db_conn)
114 assert todo2.id_ is not None
115 todo2.set_fulfills(self.db_conn, [c2.id_])
116 todo2.save(self.db_conn)
117 todo3 = Todo(None, process, False, day2)
118 todo3.save(self.db_conn)
119 assert todo3.id_ is not None
120 todo3.set_fulfills(self.db_conn, [c2.id_])
121 todo3.save(self.db_conn)
122 self.assertEqual(Todo.enablers_for_at(self.db_conn, c1, day1.date),
124 self.assertEqual(Todo.enablers_for_at(self.db_conn, c1, day2.date),
126 self.assertEqual(Todo.disablers_for_at(self.db_conn, c1, day1.date),
128 self.assertEqual(Todo.disablers_for_at(self.db_conn, c1, day2.date),
130 self.assertEqual(Todo.enablers_for_at(self.db_conn, c2, day1.date),
132 self.assertEqual(Todo.enablers_for_at(self.db_conn, c2, day2.date),
134 self.assertEqual(Todo.disablers_for_at(self.db_conn, c2, day1.date),
136 self.assertEqual(Todo.disablers_for_at(self.db_conn, c2, day2.date),
139 def test_Todo_children(self) -> None:
140 """Test Todo.children relations."""
141 day = Day('2024-01-01')
142 process = Process(None)
143 process.save_without_steps(self.db_conn)
144 todo_1 = Todo(None, process, False, day)
145 todo_2 = Todo(None, process, False, day)
146 with self.assertRaises(HandledException):
147 todo_1.add_child(todo_2)
148 todo_1.save(self.db_conn)
149 with self.assertRaises(HandledException):
150 todo_1.add_child(todo_2)
151 todo_2.save(self.db_conn)
152 todo_1.add_child(todo_2)
153 todo_1.save(self.db_conn)
154 todo_retrieved = Todo.by_id(self.db_conn, todo_1.id_)
155 self.assertEqual(todo_retrieved.children, [todo_2])
156 with self.assertRaises(BadFormatException):
157 todo_2.add_child(todo_1)
159 def test_Todo_conditioning(self) -> None:
160 """Test Todo.doability conditions."""
161 day = Day('2024-01-01')
162 process = Process(None)
163 process.save_without_steps(self.db_conn)
164 todo_1 = Todo(None, process, False, day)
165 todo_1.save(self.db_conn)
166 todo_2 = Todo(None, process, False, day)
167 todo_2.save(self.db_conn)
168 todo_2.add_child(todo_1)
169 with self.assertRaises(BadFormatException):
170 todo_2.is_done = True
171 todo_1.is_done = True
172 todo_2.is_done = True
173 todo_2.is_done = False
174 condition = Condition(None)
175 condition.save(self.db_conn)
176 assert condition.id_ is not None
177 todo_2.set_conditions(self.db_conn, [condition.id_])
178 with self.assertRaises(BadFormatException):
179 todo_2.is_done = True
180 condition.is_active = True
181 todo_2.is_done = True
183 def test_Todo_singularity(self) -> None:
184 """Test pointers made for single object keep pointing to it."""
185 day = Day('2024-01-01')
186 day.save(self.db_conn)
187 process = Process(None)
188 process.save_without_steps(self.db_conn)
189 todo = Todo(None, process, False, day)
190 todo.save(self.db_conn)
191 retrieved_todo = Todo.by_id(self.db_conn, 1)
193 self.assertEqual(retrieved_todo.is_done, True)
194 retrieved_todo = Todo.by_date(self.db_conn, '2024-01-01')[0]
195 retrieved_todo.is_done = False
196 self.assertEqual(todo.is_done, False)
199 class TestsWithServer(TestCaseWithServer):
200 """Tests against our HTTP server/handler (and database)."""
202 def test_do_POST_day(self) -> None:
203 """Test Todo posting of POST /day."""
204 form_data = {'title': '', 'description': '', 'effort': 1}
205 self.check_post(form_data, '/process?id=', 302, '/')
206 self.check_post(form_data, '/process?id=', 302, '/')
207 process1 = Process.by_id(self.db_conn, 1)
208 process2 = Process.by_id(self.db_conn, 2)
209 form_data = {'comment': ''}
210 self.check_post(form_data, '/day?date=2024-01-01', 302, '/')
211 self.assertEqual(Todo.by_date(self.db_conn, '2024-01-01'), [])
212 form_data['new_todo'] = str(process1.id_)
213 self.check_post(form_data, '/day?date=2024-01-01', 302, '/')
214 todos = Todo.by_date(self.db_conn, '2024-01-01')
215 self.assertEqual(1, len(todos))
217 self.assertEqual(todo1.id_, 1)
218 self.assertEqual(todo1.process.id_, process1.id_)
219 self.assertEqual(todo1.is_done, False)
220 form_data['new_todo'] = str(process2.id_)
221 self.check_post(form_data, '/day?date=2024-01-01', 302, '/')
222 todos = Todo.by_date(self.db_conn, '2024-01-01')
224 self.assertEqual(todo1.id_, 2)
225 self.assertEqual(todo1.process.id_, process2.id_)
226 self.assertEqual(todo1.is_done, False)
228 def test_do_POST_todo(self) -> None:
229 """Test POST /todo."""
230 def post_and_reload(form_data: dict[str, object],
231 status: int = 302) -> Todo:
232 self.check_post(form_data, '/todo?id=1', status, '/')
233 self.db_conn.cached_todos = {}
234 return Todo.by_date(self.db_conn, '2024-01-01')[0]
235 form_data = {'title': '', 'description': '', 'effort': 1}
236 self.check_post(form_data, '/process', 302, '/')
237 form_data = {'comment': '', 'new_todo': 1}
238 self.check_post(form_data, '/day?date=2024-01-01', 302, '/')
240 self.check_post(form_data, '/todo=', 404)
241 self.check_post(form_data, '/todo?id=', 404)
242 self.check_post(form_data, '/todo?id=FOO', 400)
243 self.check_post(form_data, '/todo?id=0', 404)
244 todo1 = post_and_reload(form_data)
245 self.assertEqual(todo1.children, [])
246 self.assertEqual(todo1.parents, [])
247 self.assertEqual(todo1.is_done, False)
248 form_data = {'done': ''}
249 todo1 = post_and_reload(form_data)
250 self.assertEqual(todo1.is_done, True)
252 todo1 = post_and_reload(form_data)
253 self.assertEqual(todo1.is_done, False)
254 form_data = {'adopt': 'foo'}
255 self.check_post(form_data, '/todo?id=1', 400)
256 form_data = {'adopt': 1}
257 self.check_post(form_data, '/todo?id=1', 400)
258 form_data = {'adopt': 2}
259 self.check_post(form_data, '/todo?id=1', 404)
260 form_data = {'comment': '', 'new_todo': 1}
261 self.check_post(form_data, '/day?date=2024-01-01', 302, '/')
262 form_data = {'adopt': 2}
263 todo1 = post_and_reload(form_data)
264 todo2 = Todo.by_date(self.db_conn, '2024-01-01')[1]
265 self.assertEqual(todo1.children, [todo2])
266 self.assertEqual(todo1.parents, [])
267 self.assertEqual(todo2.children, [])
268 self.assertEqual(todo2.parents, [todo1])
269 self.check_post(form_data, '/todo?id=1', 400, '/')
270 form_data = {'done': ''}
271 todo1 = post_and_reload(form_data, 400)
272 self.assertEqual(todo1.is_done, False)
274 def test_do_GET_todo(self) -> None:
275 """Test GET /todo response codes."""
276 form_data = {'title': '', 'description': '', 'effort': 1}
277 self.check_post(form_data, '/process?id=', 302, '/')
278 form_data = {'comment': '', 'new_todo': 1}
279 self.check_post(form_data, '/day?date=2024-01-01', 302, '/')
280 self.check_get('/todo', 404)
281 self.check_get('/todo?id=', 404)
282 self.check_get('/todo?id=foo', 400)
283 self.check_get('/todo?id=0', 404)
284 self.check_get('/todo?id=1', 200)