def setUp(self) -> None:
super().setUp()
self._proc1_form_data: Any = self.post_process(1)
+ self._date = '2024-01-01'
@classmethod
def GET_todo_dict(cls,
target_id: int,
todos: list[dict[str, object]],
- processes: list[dict[str, object]]
+ processes: list[dict[str, object]],
+ process_steps: list[dict[str, object]] | None = None,
) -> dict[str, object]:
"""Return JSON of GET /todo to expect."""
library = {'Todo': cls.as_refs(todos),
'Process': cls.as_refs(processes)}
+ if process_steps:
+ library['ProcessStep'] = cls.as_refs(process_steps)
return {'todo': target_id,
'steps_todo_to_process': [],
'adoption_candidates_for': {},
'condition_candidates': [],
'_library': library}
+ @staticmethod
+ def _step_as_dict(node_id: int,
+ children: list[dict[str, object]],
+ process: int | None = None,
+ todo: int | None = None,
+ fillable: bool = False,
+ ) -> dict[str, object]:
+ return {'node_id': node_id,
+ 'children': children,
+ 'process': process,
+ 'fillable': fillable,
+ 'todo': todo}
+
+ def _make_todo_via_day_post(self, proc_id: int) -> None:
+ payload = {'day_comment': '',
+ 'new_todo': proc_id,
+ 'make_type': 'empty'}
+ self.check_post(payload, f'/day?date={self._date}&make_type=empty')
+
def test_basic_fail_POST_todo(self) -> None:
"""Test basic malformed/illegal POST /todo requests."""
# test we cannot just POST into non-existing Todo
self.check_post({}, '/todo?id=0', 404)
self.check_post({}, '/todo?id=1', 404)
# test malformed values on existing Todo
- day_post = {'day_comment': '', 'new_todo': 1, 'make_type': 'full'}
- self.check_post(day_post, '/day?date=2024-01-01&make_type=full')
+ self._make_todo_via_day_post(1)
for name in ['adopt', 'effort', 'make_full', 'make_empty',
'conditions', 'disables', 'blockers', 'enables']:
self.check_post({name: 'x'}, '/todo?id=1', 400, '/todo')
'/todo?id=1', 400, '/todo')
def test_basic_POST_todo(self) -> None:
- """Test POST /todo."""
- date = '2024-01-01'
- day_post = {'day_comment': '', 'new_todo': 1, 'make_type': 'full'}
- self.check_post(day_post, f'/day?date={date}&make_type=full')
+ """Test basic POST /todo manipulations."""
+ self._make_todo_via_day_post(1)
# test posting naked entity at first changes nothing
- todo_dict = self.todo_as_dict(1, process_id=1, date=date)
+ todo_dict = self.todo_as_dict(1, 1, self._date)
proc_dict = self.proc_as_dict(**self._proc1_form_data)
expected = self.GET_todo_dict(1, [todo_dict], [proc_dict])
self.check_json_get('/todo?id=1', expected)
todo_post = {'done': '', 'calendarize': '', 'comment': 'foo',
'effort': 2.3}
todo_dict = self.todo_as_dict(
- 1, process_id=1, date=date, is_done=True, calendarize=True,
+ 1, 1, self._date, is_done=True, calendarize=True,
comment='foo', effort=2.3)
expected = self.GET_todo_dict(1, [todo_dict], [proc_dict])
self.check_post(todo_post, '/todo?id=1')
self.check_json_get('/todo?id=1', expected)
# test implicitly un-setting all of those except effort by empty post
self.check_post({}, '/todo?id=1')
- todo_dict = self.todo_as_dict(1, process_id=1, date=date, effort=2.3)
+ todo_dict = self.todo_as_dict(1, 1, date=self._date, effort=2.3)
expected = self.GET_todo_dict(1, [todo_dict], [proc_dict])
self.check_json_get('/todo?id=1', expected)
# test empty effort post can be explicitly unset by "" post
self.check_post({'effort': ''}, '/todo?id=1')
todo_dict['effort'] = None
self.check_json_get('/todo?id=1', expected)
+
+ def test_POST_todo_deletion(self) -> None:
+ """Test deletions via POST /todo."""
+ self._make_todo_via_day_post(1)
+ todo_dict = self.todo_as_dict(1, process_id=1, date=self._date)
+ proc_dict = self.proc_as_dict(**self._proc1_form_data)
+ expected = self.GET_todo_dict(1, [todo_dict], [proc_dict])
# test failure of deletion on non-existing Todo
self.check_post({'delete': ''}, '/todo?id=2', 404, '/')
# test deletion of existing Todo
self.check_post({'delete': ''}, '/todo?id=1', 302, '/')
self.check_get('/todo?id=1', 404)
# test deletion of adopted Todo
- self.check_post(day_post, f'/day?date={date}&make_type=full')
- self.check_post(day_post, f'/day?date={date}&make_type=full')
+ self._make_todo_via_day_post(1)
+ self._make_todo_via_day_post(1)
self.check_post({'adopt': 2}, '/todo?id=1')
self.check_post({'delete': ''}, '/todo?id=2', 302, '/')
self.check_json_get('/todo?id=1', expected)
# test deletion of adopting Todo
- self.check_post(day_post, f'/day?date={date}&make_type=full')
+ self._make_todo_via_day_post(1)
self.check_post({'adopt': 2}, '/todo?id=1')
self.check_post({'delete': ''}, '/todo?id=1', 302, '/')
todo_dict['id'] = 2
self.check_json_get('/todo?id=2', expected)
def test_POST_todo_adoption(self) -> None:
- """Test POST /todo."""
- date = '2024-01-01'
+ """Test adoption via POST /todo with "adopt"."""
# post two Todos to Day, have first adopt second
+ self._make_todo_via_day_post(1)
+ self._make_todo_via_day_post(1)
proc_dict = self.proc_as_dict(**self._proc1_form_data)
- day_post = {'day_comment': '', 'new_todo': 1, 'make_type': 'full'}
- self.check_post(day_post, f'/day?date={date}&make_type=full')
- self.check_post(day_post, f'/day?date={date}&make_type=full')
- todo1_dict = self.todo_as_dict(1, process_id=1, date=date)
+ todo1_dict = self.todo_as_dict(1, process_id=1, date=self._date)
todo1_dict['children'] = [2]
- todo2_dict = self.todo_as_dict(2, process_id=1, date=date)
+ todo2_dict = self.todo_as_dict(2, process_id=1, date=self._date)
todo2_dict['parents'] = [1]
expected = self.GET_todo_dict(1, [todo1_dict, todo2_dict], [proc_dict])
expected['todo_candidates'] = [2]
- expected['steps_todo_to_process'] = [{
- 'children': [], 'fillable': False,
- 'node_id': 1, 'process': None, 'todo': 2}]
+ expected['steps_todo_to_process'] = [self._step_as_dict(1, [], todo=2)]
self.check_post({'adopt': 2}, '/todo?id=1')
self.check_json_get('/todo?id=1', expected)
# test Todo cannot be set done with adopted Todo not done yet
self.check_post({'adopt': 1}, '/todo?id=2')
self.check_post({'adopt': 2}, '/todo?id=1', 400)
# test cannot do 2-step circular adoption
- day_post = {'day_comment': '', 'new_todo': 1, 'make_type': 'full'}
- self.check_post(day_post, f'/day?date={date}&make_type=full')
+ self._make_todo_via_day_post(1)
self.check_post({'adopt': 2}, '/todo?id=3')
self.check_post({'adopt': 3}, '/todo?id=1', 400)
+ def test_POST_todo_make_full(self) -> None:
+ """Test creation and adoption via POST /todo with "make_full"."""
+ # pylint: disable=too-many-locals
+ # create chain of Processes
+ proc_post = {'title': '', 'description': '', 'effort': 0.9}
+ self.post_process(2, proc_post | {'new_top_step': 1})
+ self.post_process(3, proc_post | {'new_top_step': 2})
+ self.post_process(4, proc_post | {'new_top_step': 3})
+ proc1_dict = self.proc_as_dict(**self._proc1_form_data)
+ proc2_dict = self.proc_as_dict(2, '', '', 0.9)
+ proc2_dict['explicit_steps'] = [1]
+ proc3_dict = self.proc_as_dict(3, '', '', 0.9)
+ proc3_dict['explicit_steps'] = [2]
+ proc4_dict = self.proc_as_dict(4, '', '', 0.9)
+ proc4_dict['explicit_steps'] = [3]
+ proc_dicts = [proc1_dict, proc2_dict, proc3_dict, proc4_dict]
+ procstep_dicts = [self.procstep_as_dict(1, 2, 1),
+ self.procstep_as_dict(2, 3, 2),
+ self.procstep_as_dict(3, 4, 3)]
+ # post (childless) Todo of chain end, then make_full on next in line
+ self._make_todo_via_day_post(4)
+ todo1_dict = self.todo_as_dict(1, 4, self._date)
+ todo1_dict['children'] = [2]
+ todo2_dict = self.todo_as_dict(2, 3, self._date)
+ todo2_dict['parents'] = [1]
+ todo2_dict['children'] = [3]
+ todo3_dict = self.todo_as_dict(3, 2, self._date)
+ todo3_dict['parents'] = [2]
+ todo3_dict['children'] = [4]
+ todo4_dict = self.todo_as_dict(4, 1, self._date)
+ todo4_dict['parents'] = [3]
+ todo_dicts = [todo1_dict, todo2_dict, todo3_dict, todo4_dict]
+ expected = self.GET_todo_dict(
+ 1, todo_dicts, proc_dicts, procstep_dicts)
+ step_proc1 = self._step_as_dict(3, [], 1, 4, True)
+ step_proc2 = self._step_as_dict(2, [step_proc1], 2, 3, True)
+ step_proc3 = self._step_as_dict(1, [step_proc2], 3, 2, True)
+ expected['steps_todo_to_process'] = [step_proc3]
+ expected['process_candidates'] = [4, 3, 2, 1]
+ expected['todo_candidates'] = [2, 3, 4]
+ self.check_post({'fill_for_3': 'make_full_3'}, '/todo?id=1')
+ self.check_json_get('/todo?id=1', expected)
+
def test_do_GET_todo(self) -> None:
"""Test GET /todo response codes."""
- date = '2024-01-01'
- day_post = {'day_comment': '', 'new_todo': 1, 'make_type': 'full'}
- self.check_post(day_post, f'/day?date={date}&make_type=full')
+ self._make_todo_via_day_post(1)
# test malformed or illegal parameter values
self.check_get('/todo', 404)
self.check_get('/todo?id=', 404)
self.check_get('/todo?id=0', 404)
self.check_get('/todo?id=2', 404)
# test all existing Processes are shown as available
- p2_post: Any = {'title': 'bar', 'description': 'baz', 'effort': 0.9}
- self.post_process(2, p2_post)
- todo1_dict = self.todo_as_dict(1, process_id=1, date=date)
+ proc_post = {'title': '', 'description': '', 'effort': 0.9}
+ self.post_process(2, proc_post)
+ todo1_dict = self.todo_as_dict(1, process_id=1, date=self._date)
proc1_dict = self.proc_as_dict(1, **self._proc1_form_data)
- proc2_dict = self.proc_as_dict(2, **p2_post)
- expected = self.GET_todo_dict(1, [todo1_dict], [proc1_dict,
- proc2_dict])
+ proc2_dict = self.proc_as_dict(2, '', '', 0.9)
+ proc_dicts = [proc1_dict, proc2_dict]
+ expected = self.GET_todo_dict(1, [todo1_dict], proc_dicts)
+ self.check_json_get('/todo?id=1', expected)
+ # test chain of Processes shown as potential step nodes
+ self.post_process(2, proc_post)
+ self.post_process(3, proc_post)
+ self.post_process(4, proc_post)
+ self.post_process(1, self._proc1_form_data | {'new_top_step': 2})
+ self.post_process(2, proc_post | {'new_top_step': 3, 'step_of': [1]})
+ self.post_process(3, proc_post | {'new_top_step': 4, 'step_of': [2]})
+ proc1_dict['explicit_steps'] = [1]
+ proc2_dict['explicit_steps'] = [2]
+ proc3_dict = self.proc_as_dict(3, '', '', 0.9, explicit_steps=[3])
+ proc4_dict = self.proc_as_dict(4, '', '', 0.9)
+ proc_dicts = [proc1_dict, proc2_dict, proc3_dict, proc4_dict]
+ procstep_dicts = [self.procstep_as_dict(1, 1, 2, None),
+ self.procstep_as_dict(2, 2, 3, None),
+ self.procstep_as_dict(3, 3, 4, None)]
+ expected = self.GET_todo_dict(
+ 1, [todo1_dict], proc_dicts, procstep_dicts)
+ step_proc4 = self._step_as_dict(3, [], 4)
+ step_proc3 = self._step_as_dict(2, [step_proc4], 3)
+ step_proc2 = self._step_as_dict(1, [step_proc3], 2, fillable=True)
+ expected['steps_todo_to_process'] = [step_proc2]
+ expected['adoption_candidates_for'] = {'2': [], '3': [], '4': []}
+ self.check_json_get('/todo?id=1', expected)
+ # test display of parallel chains
+ steps_d = {'new_top_step': 4, 'keep_step': [1],
+ 'step_1_process_id': 2, 'steps': [1, 4]}
+ self.post_process(1, self._proc1_form_data | steps_d)
+ proc1_dict['explicit_steps'] = [1, 4]
+ step2_proc4 = self._step_as_dict(4, [], 4, fillable=True)
+ procstep_dicts += [self.procstep_as_dict(4, 1, 4, None)]
+ expected = self.GET_todo_dict(
+ 1, [todo1_dict], proc_dicts, procstep_dicts)
+ expected['steps_todo_to_process'] = [step_proc2, step2_proc4]
+ expected['adoption_candidates_for'] = {'2': [], '3': [], '4': []}
self.check_json_get('/todo?id=1', expected)
def test_do_POST_day(self) -> None: