home · contact · privacy
Add InputsParser.get_float_or_none.
authorChristian Heller <c.heller@plomlompom.de>
Sun, 14 Jul 2024 20:15:11 +0000 (22:15 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Sun, 14 Jul 2024 20:15:11 +0000 (22:15 +0200)
plomtask/http.py
tests/misc.py
tests/todos.py

index 875260035f79cd77e38b26a990f22692e4ae825e..0d58af30d6370477f8247300b49f6ad49eff23c4 100644 (file)
@@ -123,6 +123,17 @@ class InputsParser:
             msg = f'cannot float form field value for key {key}: {val}'
             raise BadFormatException(msg) from e
 
+    def get_float_or_none(self, key: str) -> float | None:
+        """Retrieve float value of key from self.postvars, None if empty."""
+        val = self.get_str(key)
+        if '' == val:
+            return None
+        try:
+            return float(val)
+        except ValueError as e:
+            msg = f'cannot float form field value for key {key}: {val}'
+            raise BadFormatException(msg) from e
+
     def get_all_str(self, key: str) -> list[str]:
         """Retrieve list of string values at key."""
         if key not in self.inputs.keys():
@@ -565,7 +576,7 @@ class TaskHandler(BaseHTTPRequestHandler):
             day_comment = self._form_data.get_str('day_comment')
             make_type = self._form_data.get_str('make_type')
         except NotFoundException as e:
-            raise BadFormatException(e) from e
+            raise BadFormatException(e)
         old_todos = self._form_data.get_all_int('todo_id')
         new_todos = self._form_data.get_all_int('new_todo')
         comments = self._form_data.get_all_str('comment')
@@ -601,11 +612,17 @@ class TaskHandler(BaseHTTPRequestHandler):
     def do_POST_todo(self, todo: Todo) -> str:
         """Update Todo and its children."""
         # pylint: disable=too-many-locals
+        # pylint: disable=too-many-branches
+        # pylint: disable=too-many-branches
         adopted_child_ids = self._form_data.get_all_int('adopt')
         processes_to_make_full = self._form_data.get_all_int('make_full')
         processes_to_make_empty = self._form_data.get_all_int('make_empty')
         fill_fors = self._form_data.get_first_strings_starting('fill_for_')
-        effort = self._form_data.get_str('effort', ignore_strict=True)
+        with_effort_post = True
+        try:
+            effort = self._form_data.get_float_or_none('effort')
+        except NotFoundException:
+            with_effort_post = False
         conditions = self._form_data.get_all_int('conditions')
         disables = self._form_data.get_all_int('disables')
         blockers = self._form_data.get_all_int('blockers')
@@ -641,7 +658,8 @@ class TaskHandler(BaseHTTPRequestHandler):
         for process_id in processes_to_make_full:
             made = Todo.create_with_children(self.conn, process_id, todo.date)
             todo.add_child(made)
-        todo.effort = float(effort) if effort else None
+        if with_effort_post:
+            todo.effort = effort
         todo.set_conditions(self.conn, conditions)
         todo.set_blockers(self.conn, blockers)
         todo.set_enables(self.conn, enables)
index e72c6d73ee637ae85b75ac1831f06d6aa11a63b7..1713432576e779d72d7f47a35f120ce05e4d47ed 100644 (file)
@@ -120,6 +120,31 @@ class TestsSansServer(TestCase):
             with self.assertRaises(BadFormatException):
                 InputsParser({'foo': []}, strictness).get_float('foo')
 
+    def test_InputsParser_get_float_or_none(self) -> None:
+        """Test InputsParser.get_float_or_none on strict and non-strict."""
+        for strictness in (False, True):
+            with self.assertRaises(BadFormatException):
+                InputsParser({'foo': ['bar']}, strictness).\
+                        get_float_or_none('foo')
+            parser = InputsParser({'foo': ['']}, strictness)
+            self.assertEqual(None, parser.get_float_or_none('foo'))
+            parser = InputsParser({'foo': ['0']}, strictness)
+            self.assertEqual(0, parser.get_float_or_none('foo'))
+            parser = InputsParser({'foo': ['0.1']}, strictness)
+            self.assertEqual(0.1, parser.get_float_or_none('foo'))
+            parser = InputsParser({'foo': ['1.23', '456']}, strictness)
+            self.assertEqual(1.23, parser.get_float_or_none('foo'))
+        if strictness:
+            with self.assertRaises(NotFoundException):
+                InputsParser({}, strictness).get_float_or_none('foo')
+            with self.assertRaises(NotFoundException):
+                InputsParser({'foo': []}, strictness).get_float_or_none('foo')
+        else:
+            parser = InputsParser({}, strictness)
+            self.assertEqual(None, parser.get_float_or_none('foo'))
+            parser = InputsParser({'foo': []}, strictness)
+            self.assertEqual(None, parser.get_float_or_none('foo'))
+
     def test_InputsParser_get_all_str(self) -> None:
         """Test InputsParser.get_all_str on strict and non-strict."""
         for strictness in (False, True):
index dcd485622886c76077736a6a250a6ec3a9e7d9ff..c5c29d49bc875921593ddeb5cf2053a49bb598a6 100644 (file)
@@ -236,9 +236,29 @@ class TestsWithDB(TestCaseWithDB, TestCaseSansDB):
 class TestsWithServer(TestCaseWithServer):
     """Tests against our HTTP server/handler (and database)."""
 
+    def setUp(self) -> None:
+        super().setUp()
+        self._proc1_form_data = self.post_process(1)
+
+    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', 404)
+        self.check_post({}, '/todo?id=FOO', 400)
+        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')
+        for name in ['adopt', 'effort', 'make_full', 'make_empty',
+                     'conditions', 'disables', 'blockers', 'enables']:
+            self.check_post({name: 'x'}, '/todo?id=1', 400, '/todo')
+        # test we cannot POST adoption of self or non-existing Todo
+        self.check_post({'adopt': 1}, '/todo?id=1', 400)
+        self.check_post({'adopt': 2}, '/todo?id=1', 404)
+
     def test_do_POST_day(self) -> None:
         """Test Todo posting of POST /day."""
-        self.post_process()
         self.post_process(2)
         proc = Process.by_id(self.db_conn, 1)
         proc2 = Process.by_id(self.db_conn, 2)
@@ -273,16 +293,9 @@ class TestsWithServer(TestCaseWithServer):
                             redir_url: str = '/todo?id=1') -> Todo:
             self.check_post(form_data, '/todo?id=1', status, redir_url)
             return Todo.by_date(self.db_conn, '2024-01-01')[0]
-        # test minimum
-        self.post_process()
         self.check_post({'day_comment': '', 'new_todo': 1,
                          'make_type': 'full'},
                         '/day?date=2024-01-01&make_type=full', 302)
-        # test posting to bad URLs
-        self.check_post({}, '/todo=', 404)
-        self.check_post({}, '/todo?id=', 404)
-        self.check_post({}, '/todo?id=FOO', 400)
-        self.check_post({}, '/todo?id=0', 404)
         # test posting naked entity
         todo1 = post_and_reload({})
         self.assertEqual(todo1.children, [])
@@ -294,10 +307,6 @@ class TestsWithServer(TestCaseWithServer):
         # test implicitly posting non-doneness
         todo1 = post_and_reload({})
         self.assertEqual(todo1.is_done, False)
-        # test malformed adoptions
-        self.check_post({'adopt': 'foo'}, '/todo?id=1', 400)
-        self.check_post({'adopt': 1}, '/todo?id=1', 400)
-        self.check_post({'adopt': 2}, '/todo?id=1', 404)
         # test posting second todo of same process
         self.check_post({'day_comment': '', 'new_todo': 1,
                          'make_type': 'full'},
@@ -324,8 +333,8 @@ class TestsWithServer(TestCaseWithServer):
 
     def test_do_POST_day_todo_adoption(self) -> None:
         """Test Todos posted to Day view may adopt existing Todos."""
-        form_data = self.post_process()
-        form_data = self.post_process(2, form_data | {'new_top_step': 1})
+        form_data = self.post_process(
+                2, self._proc1_form_data | {'new_top_step': 1})
         form_data = {'day_comment': '', 'new_todo': 1, 'make_type': 'full'}
         self.check_post(form_data, '/day?date=2024-01-01&make_type=full', 302)
         form_data['new_todo'] = 2
@@ -339,7 +348,7 @@ class TestsWithServer(TestCaseWithServer):
 
     def test_do_POST_day_todo_multiple(self) -> None:
         """Test multiple Todos can be posted to Day view."""
-        form_data = self.post_process()
+        form_data = self.post_process()
         form_data = self.post_process(2)
         form_data = {'day_comment': '', 'new_todo': [1, 2],
                      'make_type': 'full'}
@@ -393,8 +402,7 @@ class TestsWithServer(TestCaseWithServer):
             self.assertEqual(todo3.children, [])
             self.assertEqual(sorted(todo3.parents), sorted([todo2, todo1]))
 
-        form_data = self.post_process()
-        form_data = self.post_process(2, form_data | {'new_top_step': 1})
+        self.post_process(2, self._proc1_form_data | {'new_top_step': 1})
         check_adoption('2024-01-01', [1, 2])
         check_adoption('2024-01-02', [2, 1])
         check_nesting_adoption(3, '2024-01-03', [1, 2])
@@ -402,7 +410,6 @@ class TestsWithServer(TestCaseWithServer):
 
     def test_do_POST_day_todo_doneness(self) -> None:
         """Test Todo doneness can be posted to Day view."""
-        self.post_process()
         form_data = {'day_comment': '', 'new_todo': [1], 'make_type': 'full'}
         self.check_post(form_data, '/day?date=2024-01-01&make_type=full', 302)
         todo = Todo.by_date(self.db_conn, '2024-01-01')[0]
@@ -419,7 +426,6 @@ class TestsWithServer(TestCaseWithServer):
 
     def test_do_GET_todo(self) -> None:
         """Test GET /todo response codes."""
-        self.post_process()
         form_data = {'day_comment': '', 'new_todo': 1, 'make_type': 'full'}
         self.check_post(form_data, '/day?date=2024-01-01&make_type=full', 302)
         self.check_get('/todo', 404)
@@ -427,3 +433,4 @@ class TestsWithServer(TestCaseWithServer):
         self.check_get('/todo?id=foo', 400)
         self.check_get('/todo?id=0', 404)
         self.check_get('/todo?id=1', 200)
+        self.check_get('/todo?id=2', 404)