import unittest
from .backends import TaskWarrior
-from .task import Task, ReadOnlyDictView, TaskQuerySet
+from .task import Task, ReadOnlyDictView
from .lazy import LazyUUIDTask, LazyUUIDTaskSet
from .serializing import DATE_FORMAT, local_zone
'annotations',
)
-total_seconds_2_6 = lambda x: x.microseconds / 1e6 + x.seconds + x.days * 24 * 3600
+
+def total_seconds_2_6(x):
+ return x.microseconds / 1e6 + x.seconds + x.days * 24 * 3600
class TasklibTest(unittest.TestCase):
self.tw.tasks.all()[0].done()
self.assertEqual(len(self.tw.tasks.completed()), 1)
+ def test_deleted_empty(self):
+ Task(self.tw, description="test task").save()
+ self.assertEqual(len(self.tw.tasks.deleted()), 0)
+
+ def test_deleted_non_empty(self):
+ Task(self.tw, description="test task").save()
+ self.assertEqual(len(self.tw.tasks.deleted()), 0)
+ self.tw.tasks.all()[0].delete()
+ self.assertEqual(len(self.tw.tasks.deleted()), 1)
+
+ def test_waiting_empty(self):
+ Task(self.tw, description="test task").save()
+ self.assertEqual(len(self.tw.tasks.waiting()), 0)
+
+ def test_waiting_non_empty(self):
+ Task(self.tw, description="test task").save()
+ self.assertEqual(len(self.tw.tasks.waiting()), 0)
+
+ t = self.tw.tasks.all()[0]
+ t['wait'] = datetime.datetime.now() + datetime.timedelta(days=1)
+ t.save()
+
+ self.assertEqual(len(self.tw.tasks.waiting()), 1)
+
+ def test_recurring_empty(self):
+ Task(self.tw, description="test task").save()
+ self.assertEqual(len(self.tw.tasks.recurring()), 0)
+
+ def test_recurring_non_empty(self):
+ Task(self.tw, description="test task", recur="daily",
+ due=datetime.datetime.now()).save()
+ self.assertEqual(len(self.tw.tasks.recurring()), 1)
+
def test_filtering_by_attribute(self):
Task(self.tw, description="no priority task").save()
Task(self.tw, priority="H", description="high priority task").save()
# Assert that the correct tasks are returned
high_priority_task = self.tw.tasks.get(priority="H")
- self.assertEqual(high_priority_task['description'], "high priority task")
+ self.assertEqual(high_priority_task['description'],
+ "high priority task")
def test_filtering_by_empty_attribute(self):
Task(self.tw, description="no priority task").save()
def test_create_unsaved_task(self):
# Make sure a new task is not saved unless explicitly called for
- t = Task(self.tw, description="test task")
+ Task(self.tw, description="test task")
self.assertEqual(len(self.tw.tasks.all()), 0)
# TODO: once python 2.6 compatiblity is over, use context managers here
def test_add_multiple_completed_tasks(self):
t1 = Task(self.tw, description="test1", status="completed",
- end=datetime.datetime.now())
+ end=datetime.datetime.now())
t2 = Task(self.tw, description="test2", status="completed",
- end=datetime.datetime.now())
+ end=datetime.datetime.now())
t1.save()
t2.save()
def test_stopping_task(self):
t = Task(self.tw, description="test task")
- now = t.datetime_normalizer(datetime.datetime.now())
+ t.datetime_normalizer(datetime.datetime.now())
t.save()
t.start()
t.stop()
t2 = self.tw.tasks.get(uuid=t1['uuid'])
self.assertEqual(t1.__hash__(), t2.__hash__())
+ def test_hash_unequal_unsaved_tasks(self):
+ # Compare the hash of the task using two different objects
+ t1 = Task(self.tw, description="test task 1")
+ t2 = Task(self.tw, description="test task 2")
+
+ self.assertNotEqual(t1.__hash__(), t2.__hash__())
+
+ def test_hash_unequal_saved_tasks(self):
+ # Compare the hash of the task using two different objects
+ t1 = Task(self.tw, description="test task 1")
+ t2 = Task(self.tw, description="test task 2")
+
+ t1.save()
+ t2.save()
+
+ self.assertNotEqual(t1.__hash__(), t2.__hash__())
+
def test_adding_task_with_priority(self):
t = Task(self.tw, description="test task", priority="M")
t.save()
self.assertEqual(set(t._modified_fields), set())
# Get the task by using a filter by UUID
- t2 = self.tw.tasks.get(uuid=t['uuid'])
+ self.tw.tasks.get(uuid=t['uuid'])
# Reassigning the fields with the same values now should not produce
# modified fields
t = Task(self.tw)
for field in TASK_STANDARD_ATTRS:
- value = t[field]
+ t[field]
self.assertEqual(set(t._modified_fields), set())
def test_adding_tag_by_appending(self):
t = Task(self.tw, description="test task", tags=['test1'])
t.save()
- t['tags'].append('test2')
+ t['tags'].add('test2')
+ t.save()
+ self.assertEqual(t['tags'], set(['test1', 'test2']))
+
+ def test_adding_tag_twice(self):
+ t = Task(self.tw, description="test task", tags=['test1'])
+ t.save()
+ t['tags'].add('test2')
+ t['tags'].add('test2')
t.save()
- self.assertEqual(t['tags'], ['test1', 'test2'])
+ self.assertEqual(t['tags'], set(['test1', 'test2']))
def test_adding_tag_by_appending_empty(self):
t = Task(self.tw, description="test task")
t.save()
- t['tags'].append('test')
+ t['tags'].add('test')
t.save()
- self.assertEqual(t['tags'], ['test'])
+ self.assertEqual(t['tags'], set(['test']))
def test_serializers_returning_empty_string_for_none(self):
# Test that any serializer returns '' when passed None
# Test that any deserializer returns empty value when passed ''
t = Task(self.tw)
deserializers = [getattr(t, deserializer_name) for deserializer_name in
- filter(lambda x: x.startswith('deserialize_'), dir(t))]
+ filter(lambda x: x.startswith('deserialize_'), dir(t))]
for deserializer in deserializers:
self.assertTrue(deserializer('') in (None, [], set()))
t.save()
self.assertEqual(len(self.tw.tasks.pending()), 2)
+ def test_spawned_task_parent(self):
+ today = datetime.date.today()
+ t = Task(self.tw, description="brush teeth",
+ due=today, recur="daily")
+ t.save()
+
+ spawned = self.tw.tasks.pending().get(due=today)
+ assert spawned['parent'] == t
+
def test_modify_number_of_tasks_at_once(self):
for i in range(1, 100):
Task(self.tw, description="test task %d" % i, tags=['test']).save()
def test_return_all_from_failed_executed_command(self):
Task(self.tw, description="test task", tags=['test']).save()
out, err, rc = self.tw.execute_command(['countinvalid'],
- return_all=True, allow_failure=False)
+ return_all=True,
+ allow_failure=False)
self.assertNotEqual(rc, 0)
'"start":"20141119T152233Z",'
'"uuid":"a360fc44-315c-4366-b70c-ea7e7520b749"}')
- input_modify_data = six.StringIO(input_add_data.getvalue() + '\n' +
+ input_add_data_recurring = six.StringIO(
+ '{"description":"Mow the lawn",'
+ '"entry":"20160210T224304Z",'
+ '"parent":"62da6227-519c-42c2-915d-dccada926ad7",'
+ '"recur":"weekly",'
+ '"status":"pending",'
+ '"uuid":"81305335-0237-49ff-8e87-b3cdc2369cec"}')
+
+ input_modify_data = six.StringIO(
+ input_add_data.getvalue() + '\n' +
'{"description":"Buy some milk finally",'
'"entry":"20141118T050231Z",'
'"status":"completed",'
exported_raw_data = (
'{"project":"Home",'
- '"due":"20150101T232323Z",'
- '"description":"test task"}')
+ '"due":"20150101T232323Z",'
+ '"description":"test task"}')
def test_setting_up_from_add_hook_input(self):
t = Task.from_input(input_file=self.input_add_data, backend=self.tw)
self.assertEqual(t['description'], "Buy some milk")
self.assertEqual(t.pending, True)
+ def test_setting_up_from_add_hook_input_recurring(self):
+ t = Task.from_input(input_file=self.input_add_data_recurring,
+ backend=self.tw)
+ self.assertEqual(t['description'], "Mow the lawn")
+ self.assertEqual(t.pending, True)
+
def test_setting_up_from_modified_hook_input(self):
t = Task.from_input(input_file=self.input_modify_data, modify=True,
backend=self.tw)
def test_export_data(self):
t = Task(self.tw, description="test task",
- project="Home",
- due=pytz.utc.localize(datetime.datetime(2015,1,1,23,23,23)))
+ project="Home",
+ due=pytz.utc.localize(datetime.datetime(2015, 1, 1,
+ 23, 23, 23)))
# Check that the output is a permutation of:
# {"project":"Home","description":"test task","due":"20150101232323Z"}
self.assertTrue(any(t.export_data() == expected
for expected in allowed_output))
+
class TimezoneAwareDatetimeTest(TasklibTest):
def setUp(self):
super(TimezoneAwareDatetimeTest, self).setUp()
self.zone = local_zone
- self.localdate_naive = datetime.datetime(2015,2,2)
- self.localtime_naive = datetime.datetime(2015,2,2,0,0,0)
+ self.localdate_naive = datetime.datetime(2015, 2, 2)
+ self.localtime_naive = datetime.datetime(2015, 2, 2, 0, 0, 0)
self.localtime_aware = self.zone.localize(self.localtime_naive)
self.utctime_aware = self.localtime_aware.astimezone(pytz.utc)
self.assertEqual(json.loads(t.export_data())['due'],
self.utctime_aware.strftime(DATE_FORMAT))
+
class DatetimeStringTest(TasklibTest):
def test_simple_now_conversion(self):
now = local_zone.localize(datetime.datetime.now())
# Assert that both times are not more than 5 seconds apart
- if sys.version_info < (2,7):
+ if sys.version_info < (2, 7):
self.assertTrue(total_seconds_2_6(now - t['due']) < 5)
self.assertTrue(total_seconds_2_6(t['due'] - now) < 5)
else:
hour=23,
minute=59,
second=59
- )) - datetime.timedelta(0,4 * 30 * 86400)
+ )) - datetime.timedelta(0, 4 * 30 * 86400)
self.assertEqual(due_date, t['due'])
def test_filtering_with_string_datetime(self):
return
t = Task(self.tw, description="test task",
- due=datetime.datetime.now() - datetime.timedelta(0,2))
+ due=datetime.datetime.now() - datetime.timedelta(0, 2))
t.save()
self.assertEqual(len(self.tw.tasks.filter(due__before="now")), 1)
+
class AnnotationTest(TasklibTest):
def setUp(self):
self.assertEqual(len(task['annotations']), 0)
def test_annotation_after_modification(self):
- task = self.tw.tasks.get()
- task['project'] = 'test'
- task.add_annotation('I should really do this task')
- self.assertEqual(task['project'], 'test')
- task.save()
- self.assertEqual(task['project'], 'test')
+ task = self.tw.tasks.get()
+ task['project'] = 'test'
+ task.add_annotation('I should really do this task')
+ self.assertEqual(task['project'], 'test')
+ task.save()
+ self.assertEqual(task['project'], 'test')
def test_serialize_annotations(self):
# Test that serializing annotations is possible
Task(self.tw, description="test task").save()
self.tw.tasks.get()
+
class ReadOnlyDictViewTest(unittest.TestCase):
def setUp(self):
- self.sample = dict(l=[1,2,3], d={'k':'v'})
+ self.sample = dict(sample_list=[1, 2, 3], sample_dict={'key': 'value'})
self.original_sample = copy.deepcopy(self.sample)
self.view = ReadOnlyDictView(self.sample)
def test_readonlydictview_getitem(self):
- l = self.view['l']
- self.assertEqual(l, self.sample['l'])
+ sample_list = self.view['sample_list']
+ self.assertEqual(sample_list, self.sample['sample_list'])
# Assert that modification changed only copied value
- l.append(4)
- self.assertNotEqual(l, self.sample['l'])
+ sample_list.append(4)
+ self.assertNotEqual(sample_list, self.sample['sample_list'])
# Assert that viewed dict is not changed
self.assertEqual(self.sample, self.original_sample)
def test_readonlydictview_contains(self):
- self.assertEqual('l' in self.view, 'l' in self.sample)
- self.assertEqual('d' in self.view, 'd' in self.sample)
- self.assertEqual('k' in self.view, 'k' in self.sample)
+ self.assertEqual('sample_list' in self.view,
+ 'sample_list' in self.sample)
+ self.assertEqual('sample_dict' in self.view,
+ 'sample_dict' in self.sample)
+ self.assertEqual('key' in self.view, 'key' in self.sample)
# Assert that viewed dict is not changed
self.assertEqual(self.sample, self.original_sample)
def test_readonlydictview_iter(self):
- self.assertEqual(list(k for k in self.view),
- list(k for k in self.sample))
+ self.assertEqual(list(key for key in self.view),
+ list(key for key in self.sample))
# Assert the view is correct after modification
self.sample['new'] = 'value'
- self.assertEqual(list(k for k in self.view),
- list(k for k in self.sample))
+ self.assertEqual(list(key for key in self.view),
+ list(key for key in self.sample))
def test_readonlydictview_len(self):
self.assertEqual(len(self.view), len(self.sample))
self.assertEqual(len(self.view), len(self.sample))
def test_readonlydictview_get(self):
- l = self.view.get('l')
- self.assertEqual(l, self.sample.get('l'))
+ sample_list = self.view.get('sample_list')
+ self.assertEqual(sample_list, self.sample.get('sample_list'))
# Assert that modification changed only copied value
- l.append(4)
- self.assertNotEqual(l, self.sample.get('l'))
+ sample_list.append(4)
+ self.assertNotEqual(sample_list, self.sample.get('sample_list'))
# Assert that viewed dict is not changed
self.assertEqual(self.sample, self.original_sample)
def test_normal_to_lazy_equality(self):
assert self.stored == self.lazy
+ assert not self.stored != self.lazy
assert type(self.lazy) is LazyUUIDTask
def test_lazy_to_lazy_equality(self):
lazy2 = LazyUUIDTask(self.tw, self.stored['uuid'])
assert lazy1 == lazy2
+ assert not lazy1 != lazy2
+ assert type(lazy1) is LazyUUIDTask
+ assert type(lazy2) is LazyUUIDTask
+
+ def test_normal_to_lazy_inequality(self):
+ # Create a different UUID by changing the last letter
+ wrong_uuid = self.stored['uuid']
+ wrong_uuid = wrong_uuid[:-1] + ('a' if wrong_uuid[-1] != 'a' else 'b')
+
+ wrong_lazy = LazyUUIDTask(self.tw, wrong_uuid)
+
+ assert not self.stored == wrong_lazy
+ assert self.stored != wrong_lazy
+ assert type(wrong_lazy) is LazyUUIDTask
+
+ def test_lazy_to_lazy_inequality(self):
+ # Create a different UUID by changing the last letter
+ wrong_uuid = self.stored['uuid']
+ wrong_uuid = wrong_uuid[:-1] + ('a' if wrong_uuid[-1] != 'a' else 'b')
+
+ lazy1 = LazyUUIDTask(self.tw, self.stored['uuid'])
+ lazy2 = LazyUUIDTask(self.tw, wrong_uuid)
+
+ assert not lazy1 == lazy2
+ assert lazy1 != lazy2
assert type(lazy1) is LazyUUIDTask
assert type(lazy2) is LazyUUIDTask
assert taskset ^ lazyset == set([self.task1, self.task3])
assert lazyset ^ taskset == set([self.task1, self.task3])
- assert taskset.symmetric_difference(lazyset) == set([self.task1, self.task3])
- assert lazyset.symmetric_difference(taskset) == set([self.task1, self.task3])
+ assert taskset.symmetric_difference(lazyset) == set([self.task1,
+ self.task3])
+ assert lazyset.symmetric_difference(taskset) == set([self.task1,
+ self.task3])
lazyset ^= taskset
assert lazyset == set([self.task1, self.task3])
def test_config(self):
assert self.tw.config['nag'] == "You have more urgent tasks."
- assert self.tw.config['sugar'] == "yes"
+ assert self.tw.config['default.command'] == "next"
+ assert self.tw.config['dependency.indicator'] == "D"