Commit f60572d2 authored by Bram Schoenmakers's avatar Bram Schoenmakers

Merge branch 'coverage'

Conflicts:
	topydo/lib/DCommand.py
parents 8dbbbbfb c547b850
[run]
source = topydo
[report]
exclude_lines =
pragma: no cover
def __repr__
raise AssertionError
raise NotImplementedError
if 0:
if __name__ == .__main__.:
omit =
topydo/lib/ExitCommand.py
topydo/lib/Version.py
...@@ -3,3 +3,4 @@ ...@@ -3,3 +3,4 @@
build build
dist dist
install install
.coverage
...@@ -211,6 +211,14 @@ class DepCommandTest(CommandTest): ...@@ -211,6 +211,14 @@ class DepCommandTest(CommandTest):
self.assertFalse(self.output) self.assertFalse(self.output)
self.assertEqual(self.errors, command.usage() + "\n") self.assertEqual(self.errors, command.usage() + "\n")
def test_ls7(self):
command = DepCommand(["ls", "top", "99"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.output, "")
self.assertEqual(self.errors, command.usage() + "\n")
def gc_helper(self, p_subcommand): def gc_helper(self, p_subcommand):
command = DepCommand([p_subcommand], self.todolist, self.out, self.error) command = DepCommand([p_subcommand], self.todolist, self.out, self.error)
command.execute() command.execute()
......
# Topydo - A todo.txt client written in Python.
# Copyright (C) 2015 Bram Schoenmakers <me@bramschoenmakers.nl>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from topydo.lib.JsonPrinter import JsonPrinter
from topydo.lib.Todo import Todo
from test.TopydoTest import TopydoTest
class JsonPrinterTest(TopydoTest):
"""
Tests the functionality of printing a single todo item. Printing a list is
already covered by the ListCommand tests.
"""
def test_json(self):
""" Print a single todo item. """
printer = JsonPrinter()
todo = Todo('2015-06-06 Foo due:2015-05-32')
result = printer.print_todo(todo)
self.assertEqual(result, '{"completed": false, "completion_date": null, "contexts": [], "creation_date": "2015-06-06", "priority": null, "projects": [], "source": "2015-06-06 Foo due:2015-05-32", "tags": [["due", "2015-05-32"]], "text": "Foo"}')
...@@ -224,7 +224,6 @@ class ListCommandUnicodeTest(CommandTest): ...@@ -224,7 +224,6 @@ class ListCommandUnicodeTest(CommandTest):
self.assertEqual(self.output, expected) self.assertEqual(self.output, expected)
class ListCommandJsonTest(CommandTest): class ListCommandJsonTest(CommandTest):
def test_json(self): def test_json(self):
todolist = load_file_to_todolist("test/data/ListCommandTest.txt") todolist = load_file_to_todolist("test/data/ListCommandTest.txt")
...@@ -265,11 +264,14 @@ def replace_ical_tags(p_text): ...@@ -265,11 +264,14 @@ def replace_ical_tags(p_text):
IS_PYTHON_32 = (sys.version_info.major, sys.version_info.minor) == (3, 2) IS_PYTHON_32 = (sys.version_info.major, sys.version_info.minor) == (3, 2)
class ListCommandIcalTest(CommandTest): class ListCommandIcalTest(CommandTest):
def setUp(self):
self.maxDiff = None
@unittest.skipIf(IS_PYTHON_32, "icalendar is not supported for Python 3.2") @unittest.skipIf(IS_PYTHON_32, "icalendar is not supported for Python 3.2")
def test_ical(self): def test_ical(self):
todolist = load_file_to_todolist("test/data/ListCommandTest.txt") todolist = load_file_to_todolist("test/data/ListCommandIcalTest.txt")
command = ListCommand(["-f", "ical"], todolist, self.out, self.error) command = ListCommand(["-x", "-f", "ical"], todolist, self.out, self.error)
command.execute() command.execute()
self.assertTrue(todolist.is_dirty()) self.assertTrue(todolist.is_dirty())
......
...@@ -24,6 +24,7 @@ from topydo.lib.Todo import Todo ...@@ -24,6 +24,7 @@ from topydo.lib.Todo import Todo
from topydo.lib.TodoFile import TodoFile from topydo.lib.TodoFile import TodoFile
from topydo.lib.TodoListBase import InvalidTodoException from topydo.lib.TodoListBase import InvalidTodoException
from topydo.lib.TodoList import TodoList from topydo.lib.TodoList import TodoList
from topydo.lib.TodoListBase import TodoListBase
from test.TopydoTest import TopydoTest from test.TopydoTest import TopydoTest
class TodoListTester(TopydoTest): class TodoListTester(TopydoTest):
...@@ -34,7 +35,7 @@ class TodoListTester(TopydoTest): ...@@ -34,7 +35,7 @@ class TodoListTester(TopydoTest):
lines = [line for line in self.todofile.read() \ lines = [line for line in self.todofile.read() \
if re.search(r'\S', line)] if re.search(r'\S', line)]
self.text = ''.join(lines) self.text = ''.join(lines)
self.todolist = TodoList(lines) self.todolist = TodoListBase(lines)
def test_contexts(self): def test_contexts(self):
self.assertEqual(set(['Context1', 'Context2']), \ self.assertEqual(set(['Context1', 'Context2']), \
...@@ -101,6 +102,16 @@ class TodoListTester(TopydoTest): ...@@ -101,6 +102,16 @@ class TodoListTester(TopydoTest):
self.assertTrue(self.todolist.is_dirty()) self.assertTrue(self.todolist.is_dirty())
self.assertRaises(InvalidTodoException, self.todolist.number, todo) self.assertRaises(InvalidTodoException, self.todolist.number, todo)
def test_delete2(self):
""" Try to remove a todo item that does not exist. """
count = self.todolist.count()
todo = Todo('Not in the list')
self.todolist.delete(todo)
self.assertEqual(self.todolist.count(), count)
self.assertFalse(self.todolist.is_dirty())
def test_append1(self): def test_append1(self):
todo = self.todolist.todo(3) todo = self.todolist.todo(3)
self.todolist.append(todo, "@Context3") self.todolist.append(todo, "@Context3")
...@@ -137,13 +148,6 @@ class TodoListTester(TopydoTest): ...@@ -137,13 +148,6 @@ class TodoListTester(TopydoTest):
""" Test that empty lines are not counted. """ """ Test that empty lines are not counted. """
self.assertEqual(self.todolist.count(), 5) self.assertEqual(self.todolist.count(), 5)
def test_todo_by_dep_id(self):
""" Tests that todos can be retrieved by their id tag. """
self.todolist.add("(C) Foo id:1")
self.assertTrue(self.todolist.todo_by_dep_id('1'))
self.assertFalse(self.todolist.todo_by_dep_id('2'))
def test_todo_number1(self): def test_todo_number1(self):
todo = Todo("No number") todo = Todo("No number")
self.todolist.add_todo(todo) self.todolist.add_todo(todo)
...@@ -349,6 +353,14 @@ class TodoListDependencyTester(TopydoTest): ...@@ -349,6 +353,14 @@ class TodoListDependencyTester(TopydoTest):
self.assertEqual(todo1.source(), 'Foo id:1') self.assertEqual(todo1.source(), 'Foo id:1')
self.assertEqual(todo2.source(), 'Bar p:1') self.assertEqual(todo2.source(), 'Bar p:1')
def test_todo_by_dep_id(self):
""" Tests that todos can be retrieved by their id tag. """
todolist = TodoList([])
todolist.add("(C) Foo id:1")
self.assertTrue(todolist.todo_by_dep_id('1'))
self.assertFalse(todolist.todo_by_dep_id('2'))
class TodoListCleanDependencyTester(TopydoTest): class TodoListCleanDependencyTester(TopydoTest):
def setUp(self): def setUp(self):
super(TodoListCleanDependencyTester, self).setUp() super(TodoListCleanDependencyTester, self).setUp()
......
(C) Foo @Context2 Not@Context +Project1 Not+Project
(D) Bar @Context1 +Project2 p:1 due:2015-06-06
(C) Baz @Context1 +Project1 key:value id:1
(C) 2015-06-06 Drink beer @ home
(G) 13 + 29 = 42
(C) Only a start date t:2015-06-06
x 2015-06-06 A completed item due:2015-05-05
This diff was suppressed by a .gitattributes entry.
...@@ -46,7 +46,7 @@ class ListCommand(ExpressionCommand): ...@@ -46,7 +46,7 @@ class ListCommand(ExpressionCommand):
""" """
try: try:
import icalendar as _ import icalendar as _
except ImportError: except ImportError: # pragma: no cover
self.error("icalendar package is not installed.") self.error("icalendar package is not installed.")
return False return False
...@@ -101,7 +101,7 @@ class ListCommand(ExpressionCommand): ...@@ -101,7 +101,7 @@ class ListCommand(ExpressionCommand):
try: try:
self._process_flags() self._process_flags()
except SyntaxError: except SyntaxError: # pragma: no cover
# importing icalendar failed, most likely due to Python 3.2 # importing icalendar failed, most likely due to Python 3.2
self.error("icalendar is not supported in this Python version.") self.error("icalendar is not supported in this Python version.")
return False return False
......
...@@ -84,8 +84,10 @@ class Command(object): ...@@ -84,8 +84,10 @@ class Command(object):
return result return result
def usage(self): def usage(self):
return "No usage text available for this command." """ Returns a one-line synopsis for this command. """
raise NotImplementedError
def help(self): def help(self):
return "No help text available for this command." """ Returns the help text for this command. """
raise NotImplementedError
...@@ -56,11 +56,10 @@ class DCommand(MultiCommand): ...@@ -56,11 +56,10 @@ class DCommand(MultiCommand):
self.out(printer.print_list(p_todos)) self.out(printer.print_list(p_todos))
def prompt_text(self): def prompt_text(self):
return "Yes or no? [y/N] " raise NotImplementedError
def prefix(self): def prefix(self):
""" Prefix to use when printing a todo. """ raise NotImplementedError
return ""
def _process_subtasks(self, p_todo): def _process_subtasks(self, p_todo):
children = self._uncompleted_children(p_todo) children = self._uncompleted_children(p_todo)
...@@ -101,17 +100,17 @@ class DCommand(MultiCommand): ...@@ -101,17 +100,17 @@ class DCommand(MultiCommand):
return True return True
def condition_failed_text(self): def condition_failed_text(self):
return "" raise NotImplementedError
def execute_specific(self, _): def execute_specific(self, _):
pass raise NotImplementedError
def execute_specific_core(self, p_todo): def execute_specific_core(self, p_todo):
""" """
The core operation on the todo itself. Also used to operate on The core operation on the todo itself. Also used to operate on
child/parent tasks. child/parent tasks.
""" """
pass raise NotImplementedError
def _execute_multi_specific(self): def _execute_multi_specific(self):
old_active = self._active_todos() old_active = self._active_todos()
......
...@@ -29,8 +29,7 @@ class Filter(object): ...@@ -29,8 +29,7 @@ class Filter(object):
return [t for t in p_todos if self.match(t)] return [t for t in p_todos if self.match(t)]
def match(self, _): def match(self, _):
""" Default match value. """ raise NotImplementedError
return True
class NegationFilter(Filter): class NegationFilter(Filter):
def __init__(self, p_filter): def __init__(self, p_filter):
......
...@@ -69,15 +69,12 @@ class IcalPrinter(Printer): ...@@ -69,15 +69,12 @@ class IcalPrinter(Printer):
try: try:
import icalendar import icalendar
self.icalendar = icalendar self.icalendar = icalendar
except (SyntaxError, ImportError): except (SyntaxError, ImportError): # pragma: no cover
# icalendar does not support Python 3.2 resulting in a SyntaxError. Since # icalendar does not support Python 3.2 resulting in a SyntaxError. Since
# this is an optional dependency, dropping Python 3.2 support altogether is # this is an optional dependency, dropping Python 3.2 support altogether is
# too much. Therefore just disable the iCalendar functionality # too much. Therefore just disable the iCalendar functionality
self.icalendar = None self.icalendar = None
def print_todo(self, p_todo):
return self._convert_todo(p_todo).to_ical() if self.icalendar else ""
def print_list(self, p_todos): def print_list(self, p_todos):
result = "" result = ""
......
...@@ -26,8 +26,7 @@ class Printer(object): ...@@ -26,8 +26,7 @@ class Printer(object):
Subclasses must at least implement the print_todo method. Subclasses must at least implement the print_todo method.
""" """
def print_todo(self, p_todo): def print_todo(self, p_todo):
""" Base implementation.""" raise NotImplementedError
return p_todo.source()
def print_list(self, p_todos): def print_list(self, p_todos):
""" """
......
...@@ -30,8 +30,10 @@ class PrettyPrinterFilter(object): ...@@ -30,8 +30,10 @@ class PrettyPrinterFilter(object):
""" """
def filter(self, p_todo_str, _): def filter(self, p_todo_str, _):
""" Default implementation returns an unmodified todo string. """ """
return p_todo_str Applies a filter to p_todo_str and returns a modified version of it.
"""
raise NotImplementedError
class PrettyPrinterColorFilter(PrettyPrinterFilter): class PrettyPrinterColorFilter(PrettyPrinterFilter):
""" """
......
...@@ -36,14 +36,11 @@ class TodoList(TodoListBase): ...@@ -36,14 +36,11 @@ class TodoList(TodoListBase):
Should be given a list of strings, each element a single todo string. Should be given a list of strings, each element a single todo string.
The string will be parsed. The string will be parsed.
""" """
self._todos = [] # initialize these first because the constructor calls add_list
self._tododict = {} # hash(todo) to todo lookup self._tododict = {} # hash(todo) to todo lookup
self._depgraph = DirectedGraph() self._depgraph = DirectedGraph()
self._todo_id_map = {}
self._id_todo_map = {}
self.add_list(p_todostrings) super(TodoList, self).__init__(p_todostrings)
self.dirty = False
def todo_by_dep_id(self, p_dep_id): def todo_by_dep_id(self, p_dep_id):
""" """
......
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