Commit cb465863 authored by Bram Schoenmakers's avatar Bram Schoenmakers

Handle absence or invalid recurrence patterns more gracefully.

When completing a command, show a warning when a 'rec' tag has an
invalid recurrence pattern.

Fixes issue #6.
parent 503d876a
...@@ -38,6 +38,7 @@ class DoCommandTest(CommandTest.CommandTest): ...@@ -38,6 +38,7 @@ class DoCommandTest(CommandTest.CommandTest):
"Inactive t:2030-12-31 id:2", "Inactive t:2030-12-31 id:2",
"Subtodo of inactive p:2", "Subtodo of inactive p:2",
"Strict due:2014-01-01 rec:1d", "Strict due:2014-01-01 rec:1d",
"Invalid rec:1",
] ]
self.todolist = TodoList(todos) self.todolist = TodoList(todos)
...@@ -120,7 +121,7 @@ class DoCommandTest(CommandTest.CommandTest): ...@@ -120,7 +121,7 @@ class DoCommandTest(CommandTest.CommandTest):
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertEquals(self.errors, "") self.assertEquals(self.errors, "")
self.assertEquals(self.todolist.count(), 9) self.assertEquals(self.todolist.count(), 10)
def test_recurrence(self): def test_recurrence(self):
self.assertFalse(self.todolist.todo(4).has_tag('due')) self.assertFalse(self.todolist.todo(4).has_tag('due'))
...@@ -128,22 +129,22 @@ class DoCommandTest(CommandTest.CommandTest): ...@@ -128,22 +129,22 @@ class DoCommandTest(CommandTest.CommandTest):
self._recurrence_helper(["4"]) self._recurrence_helper(["4"])
self.assertTrue(self.todolist.todo(4).is_completed()) self.assertTrue(self.todolist.todo(4).is_completed())
result = "| 9| {today} Recurring! rec:1d due:{tomorrow}\nCompleted: x {today} Recurring! rec:1d\n".format(today=self.today, tomorrow=self.tomorrow) result = "| 10| {today} Recurring! rec:1d due:{tomorrow}\nCompleted: x {today} Recurring! rec:1d\n".format(today=self.today, tomorrow=self.tomorrow)
self.assertEquals(self.output, result) self.assertEquals(self.output, result)
todo = self.todolist.todo(8) todo = self.todolist.todo(10)
self.assertFalse(todo.is_completed()) self.assertFalse(todo.is_completed())
self.assertTrue(todo.has_tag('due')) self.assertTrue(todo.has_tag('due'))
def test_strict_recurrence1(self): def test_strict_recurrence1(self):
self._recurrence_helper(["-s", "8"]) self._recurrence_helper(["-s", "8"])
result = "| 9| {today} Strict due:2014-01-02 rec:1d\nCompleted: x {today} Strict due:2014-01-01 rec:1d\n".format(today=self.today) result = "| 10| {today} Strict due:2014-01-02 rec:1d\nCompleted: x {today} Strict due:2014-01-01 rec:1d\n".format(today=self.today)
self.assertEquals(self.output, result) self.assertEquals(self.output, result)
def test_strict_recurrence2(self): def test_strict_recurrence2(self):
self._recurrence_helper(["--strict", "8"]) self._recurrence_helper(["--strict", "8"])
result = "| 9| {today} Strict due:2014-01-02 rec:1d\nCompleted: x {today} Strict due:2014-01-01 rec:1d\n".format(today=self.today) result = "| 10| {today} Strict due:2014-01-02 rec:1d\nCompleted: x {today} Strict due:2014-01-01 rec:1d\n".format(today=self.today)
self.assertEquals(self.output, result) self.assertEquals(self.output, result)
def test_invalid1(self): def test_invalid1(self):
...@@ -251,7 +252,7 @@ class DoCommandTest(CommandTest.CommandTest): ...@@ -251,7 +252,7 @@ class DoCommandTest(CommandTest.CommandTest):
command.execute() command.execute()
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertEquals(self.output, "| 9| {today} Recurring! rec:1d due:{today}\nCompleted: x {yesterday} Recurring! rec:1d\n".format(today=self.today, yesterday=self.yesterday)) self.assertEquals(self.output, "| 10| {today} Recurring! rec:1d due:{today}\nCompleted: x {yesterday} Recurring! rec:1d\n".format(today=self.today, yesterday=self.yesterday))
self.assertEquals(self.errors, "") self.assertEquals(self.errors, "")
def test_do_custom_date6(self): def test_do_custom_date6(self):
...@@ -264,7 +265,7 @@ class DoCommandTest(CommandTest.CommandTest): ...@@ -264,7 +265,7 @@ class DoCommandTest(CommandTest.CommandTest):
command.execute() command.execute()
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertEquals(self.output, "| 9| {today} Recurring! rec:1d due:{today}\nCompleted: x {yesterday} Recurring! rec:1d\n".format(today=self.today, yesterday=self.yesterday)) self.assertEquals(self.output, "| 10| {today} Recurring! rec:1d due:{today}\nCompleted: x {yesterday} Recurring! rec:1d\n".format(today=self.today, yesterday=self.yesterday))
self.assertEquals(self.errors, "") self.assertEquals(self.errors, "")
def test_do_custom_date7(self): def test_do_custom_date7(self):
...@@ -276,7 +277,7 @@ class DoCommandTest(CommandTest.CommandTest): ...@@ -276,7 +277,7 @@ class DoCommandTest(CommandTest.CommandTest):
command.execute() command.execute()
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertEquals(self.output, "| 9| {today} Strict due:2014-01-02 rec:1d\nCompleted: x {yesterday} Strict due:2014-01-01 rec:1d\n".format(today=self.today, yesterday=self.yesterday)) self.assertEquals(self.output, "| 10| {today} Strict due:2014-01-02 rec:1d\nCompleted: x {yesterday} Strict due:2014-01-01 rec:1d\n".format(today=self.today, yesterday=self.yesterday))
self.assertEquals(self.errors, "") self.assertEquals(self.errors, "")
def test_multi_do1(self): def test_multi_do1(self):
...@@ -319,11 +320,19 @@ class DoCommandTest(CommandTest.CommandTest): ...@@ -319,11 +320,19 @@ class DoCommandTest(CommandTest.CommandTest):
When a todo item was generated by a recurring todo item, make sure When a todo item was generated by a recurring todo item, make sure
it cannot be completed in the same invocation. it cannot be completed in the same invocation.
""" """
command = DoCommand(["4", "9"], self.todolist, self.out, self.error, _no_prompt) command = DoCommand(["4", "10"], self.todolist, self.out, self.error, _no_prompt)
command.execute() command.execute()
self.assertTrue(self.todolist.todo(4).is_completed()) self.assertTrue(self.todolist.todo(4).is_completed())
self.assertFalse(self.todolist.todo(9).is_completed()) self.assertFalse(self.todolist.todo(10).is_completed())
def test_invalid_recurrence(self):
""" Show error message when an item has an invalid recurrence pattern. """
command = DoCommand(["9"], self.todolist, self.out, self.error, _no_prompt)
command.execute()
self.assertEquals(self.output, "Completed: x {} Invalid rec:1\n".format(self.today))
self.assertEquals(self.errors, "Warning: todo item has an invalid recurrence pattern.\n")
def test_empty(self): def test_empty(self):
command = DoCommand([], self.todolist, self.out, self.error) command = DoCommand([], self.todolist, self.out, self.error)
......
...@@ -136,7 +136,12 @@ class RecurrenceTest(TopydoTest): ...@@ -136,7 +136,12 @@ class RecurrenceTest(TopydoTest):
def test_no_recurrence(self): def test_no_recurrence(self):
self.todo.remove_tag('rec') self.todo.remove_tag('rec')
self.assertRaises(NoRecurrenceException,advance_recurring_todo,self.todo) self.assertRaises(NoRecurrenceException, advance_recurring_todo, self.todo)
def test_invalid_recurrence(self):
""" Throw exception when 'rec' tag has an invalid value. """
self.todo.set_tag('rec', '1')
self.assertRaises(NoRecurrenceException, advance_recurring_todo, self.todo)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -18,7 +18,7 @@ from datetime import date ...@@ -18,7 +18,7 @@ from datetime import date
from topydo.lib.DCommand import DCommand from topydo.lib.DCommand import DCommand
from topydo.lib.PrettyPrinter import pretty_print from topydo.lib.PrettyPrinter import pretty_print
from topydo.lib.Recurrence import advance_recurring_todo, strict_advance_recurring_todo from topydo.lib.Recurrence import advance_recurring_todo, strict_advance_recurring_todo, NoRecurrenceException
from topydo.lib.Utils import date_string_to_date from topydo.lib.Utils import date_string_to_date
class DoCommand(DCommand): class DoCommand(DCommand):
...@@ -48,6 +48,7 @@ class DoCommand(DCommand): ...@@ -48,6 +48,7 @@ class DoCommand(DCommand):
def _handle_recurrence(self, p_todo): def _handle_recurrence(self, p_todo):
if p_todo.has_tag('rec'): if p_todo.has_tag('rec'):
try:
if self.strict_recurrence: if self.strict_recurrence:
new_todo = strict_advance_recurring_todo(p_todo, new_todo = strict_advance_recurring_todo(p_todo,
self.completion_date) self.completion_date)
...@@ -57,6 +58,8 @@ class DoCommand(DCommand): ...@@ -57,6 +58,8 @@ class DoCommand(DCommand):
self.todolist.add_todo(new_todo) self.todolist.add_todo(new_todo)
self.out(pretty_print(new_todo, [self.todolist.pp_number()])) self.out(pretty_print(new_todo, [self.todolist.pp_number()]))
except NoRecurrenceException:
self.error("Warning: todo item has an invalid recurrence pattern.")
def prompt_text(self): def prompt_text(self):
return "Also mark subtasks as done? [y/N] " return "Also mark subtasks as done? [y/N] "
......
...@@ -42,8 +42,11 @@ def _advance_recurring_todo_helper(p_todo, p_offset): ...@@ -42,8 +42,11 @@ def _advance_recurring_todo_helper(p_todo, p_offset):
raise NoRecurrenceException() raise NoRecurrenceException()
length = todo.length() length = todo.length()
new_due = relative_date_to_date(pattern, p_offset) new_due = relative_date_to_date(pattern, p_offset)
if not new_due:
raise NoRecurrenceException()
todo.set_tag(config().tag_due(), new_due.isoformat()) todo.set_tag(config().tag_due(), new_due.isoformat())
if todo.start_date(): if todo.start_date():
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment