home · contact · privacy
Add Conditions for Todos/Processes to be met or undone by other Todos.
[plomtask] / tests / todos.py
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,
8                                  HandledException)
9
10
11 class TestsWithDB(TestCaseWithDB):
12     """Tests requiring DB, but not server setup."""
13
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)
28
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'), [])
42
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)
48         c1.save(self.db_conn)
49         assert c1.id_ is not None
50         c2 = Condition(None, True)
51         c2.save(self.db_conn)
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])
71
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)
79         c1.save(self.db_conn)
80         c2.save(self.db_conn)
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_])
87         todo.is_done = True
88         self.assertEqual(c1.is_active, True)
89         self.assertEqual(c2.is_active, False)
90         todo.is_done = False
91         self.assertEqual(c1.is_active, True)
92         self.assertEqual(c2.is_active, False)
93
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),
123                          [todo1])
124         self.assertEqual(Todo.enablers_for_at(self.db_conn, c1, day2.date),
125                          [])
126         self.assertEqual(Todo.disablers_for_at(self.db_conn, c1, day1.date),
127                          [])
128         self.assertEqual(Todo.disablers_for_at(self.db_conn, c1, day2.date),
129                          [])
130         self.assertEqual(Todo.enablers_for_at(self.db_conn, c2, day1.date),
131                          [todo2])
132         self.assertEqual(Todo.enablers_for_at(self.db_conn, c2, day2.date),
133                          [todo3])
134         self.assertEqual(Todo.disablers_for_at(self.db_conn, c2, day1.date),
135                          [todo1])
136         self.assertEqual(Todo.disablers_for_at(self.db_conn, c2, day2.date),
137                          [])
138
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)
158
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
182
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)
192         todo.is_done = True
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)
197
198
199 class TestsWithServer(TestCaseWithServer):
200     """Tests against our HTTP server/handler (and database)."""
201
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))
216         todo1 = todos[0]
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')
223         todo1 = todos[1]
224         self.assertEqual(todo1.id_, 2)
225         self.assertEqual(todo1.process.id_, process2.id_)
226         self.assertEqual(todo1.is_done, False)
227
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, '/')
239         form_data = {}
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)
251         form_data = {}
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)
273
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)