]> git.madduck.net Git - etc/taskwarrior.git/blobdiff - tasklib/tests.py

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Setup: Add tzlocal to required packages
[etc/taskwarrior.git] / tasklib / tests.py
index cba3271cf7c2090dfd6a9fd7cba5d0892828d857..f7b9a2724614ba2004fdd4b6a2b4c492956eb530 100644 (file)
@@ -2,13 +2,38 @@
 
 import datetime
 import itertools
 
 import datetime
 import itertools
+import json
+import pytz
 import six
 import shutil
 import tempfile
 import unittest
 
 import six
 import shutil
 import tempfile
 import unittest
 
-from .task import TaskWarrior, Task
-
+from .task import TaskWarrior, Task, local_zone, DATE_FORMAT
+
+# http://taskwarrior.org/docs/design/task.html , Section: The Attributes
+TASK_STANDARD_ATTRS = (
+    'status',
+    'uuid',
+    'entry',
+    'description',
+    'start',
+    'end',
+    'due',
+    'until',
+    'wait',
+    'modified',
+    'scheduled',
+    'recur',
+    'mask',
+    'imask',
+    'parent',
+    'project',
+    'priority',
+    'depends',
+    'tags',
+    'annotations',
+)
 
 class TasklibTest(unittest.TestCase):
 
 
 class TasklibTest(unittest.TestCase):
 
@@ -413,6 +438,14 @@ class TaskTest(TasklibTest):
         t['depends'] = set([dependency])
         self.assertEqual(set(t._modified_fields), set())
 
         t['depends'] = set([dependency])
         self.assertEqual(set(t._modified_fields), set())
 
+    def test_modified_fields_not_affected_by_reading(self):
+        t = Task(self.tw)
+
+        for field in TASK_STANDARD_ATTRS:
+            value = t[field]
+
+        self.assertEqual(set(t._modified_fields), set())
+
     def test_setting_read_only_attrs_through_init(self):
         # Test that we are unable to set readonly attrs through __init__
         for readonly_key in Task.read_only_fields:
     def test_setting_read_only_attrs_through_init(self):
         # Test that we are unable to set readonly attrs through __init__
         for readonly_key in Task.read_only_fields:
@@ -446,6 +479,30 @@ class TaskTest(TasklibTest):
         t.save()
         self.assertEqual(t['tags'], ['test'])
 
         t.save()
         self.assertEqual(t['tags'], ['test'])
 
+    def test_serializers_returning_empty_string_for_none(self):
+        # Test that any serializer returns '' when passed None
+        t = Task(self.tw)
+        serializers = [getattr(t, serializer_name) for serializer_name in
+                       filter(lambda x: x.startswith('serialize_'), dir(t))]
+        for serializer in serializers:
+            self.assertEqual(serializer(None), '')
+
+    def test_deserializer_returning_empty_value_for_empty_string(self):
+        # 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))]
+        for deserializer in deserializers:
+            self.assertTrue(deserializer('') in (None, [], set()))
+
+    def test_normalizers_returning_empty_string_for_none(self):
+        # Test that any normalizer can handle None as a valid value
+        t = Task(self.tw)
+        normalizers = [getattr(t, normalizer_name) for normalizer_name in
+                       filter(lambda x: x.startswith('normalize_'), dir(t))]
+        for normalizer in normalizers:
+            normalizer(None)
+
 
 class TaskFromHookTest(TasklibTest):
 
 
 class TaskFromHookTest(TasklibTest):
 
@@ -484,7 +541,8 @@ class TaskFromHookTest(TasklibTest):
 
     def test_export_data(self):
         t = Task(self.tw, description="test task",
 
     def test_export_data(self):
         t = Task(self.tw, description="test task",
-            project="Home", due=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"}
 
         # Check that the output is a permutation of:
         # {"project":"Home","description":"test task","due":"20150101232323Z"}
@@ -497,6 +555,75 @@ class TaskFromHookTest(TasklibTest):
         self.assertTrue(any(t.export_data() == expected
                             for expected in allowed_output))
 
         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.localtime_aware = self.zone.localize(self.localtime_naive)
+        self.utctime_aware = self.localtime_aware.astimezone(pytz.utc)
+
+    def test_timezone_naive_datetime_setitem(self):
+        t = Task(self.tw, description="test task")
+        t['due'] = self.localtime_naive
+        self.assertEqual(t['due'], self.localtime_aware)
+
+    def test_timezone_naive_datetime_using_init(self):
+        t = Task(self.tw, description="test task", due=self.localtime_naive)
+        self.assertEqual(t['due'], self.localtime_aware)
+
+    def test_filter_by_naive_datetime(self):
+        t = Task(self.tw, description="task1", due=self.localtime_naive)
+        t.save()
+        matching_tasks = self.tw.tasks.filter(due=self.localtime_naive)
+        self.assertEqual(len(matching_tasks), 1)
+
+    def test_serialize_naive_datetime(self):
+        t = Task(self.tw, description="task1", due=self.localtime_naive)
+        self.assertEqual(json.loads(t.export_data())['due'], 
+                         self.utctime_aware.strftime(DATE_FORMAT))
+
+    def test_timezone_naive_date_setitem(self):
+        t = Task(self.tw, description="test task")
+        t['due'] = self.localdate_naive
+        self.assertEqual(t['due'], self.localtime_aware)
+
+    def test_timezone_naive_date_using_init(self):
+        t = Task(self.tw, description="test task", due=self.localdate_naive)
+        self.assertEqual(t['due'], self.localtime_aware)
+
+    def test_filter_by_naive_date(self):
+        t = Task(self.tw, description="task1", due=self.localdate_naive)
+        t.save()
+        matching_tasks = self.tw.tasks.filter(due=self.localdate_naive)
+        self.assertEqual(len(matching_tasks), 1)
+
+    def test_serialize_naive_date(self):
+        t = Task(self.tw, description="task1", due=self.localdate_naive)
+        self.assertEqual(json.loads(t.export_data())['due'], 
+                         self.utctime_aware.strftime(DATE_FORMAT))
+
+    def test_timezone_aware_datetime_setitem(self):
+        t = Task(self.tw, description="test task")
+        t['due'] = self.localtime_aware
+        self.assertEqual(t['due'], self.localtime_aware)
+
+    def test_timezone_aware_datetime_using_init(self):
+        t = Task(self.tw, description="test task", due=self.localtime_aware)
+        self.assertEqual(t['due'], self.localtime_aware)
+
+    def test_filter_by_aware_datetime(self):
+        t = Task(self.tw, description="task1", due=self.localtime_aware)
+        t.save()
+        matching_tasks = self.tw.tasks.filter(due=self.localtime_aware)
+        self.assertEqual(len(matching_tasks), 1)
+
+    def test_serialize_aware_datetime(self):
+        t = Task(self.tw, description="task1", due=self.localtime_aware)
+        self.assertEqual(json.loads(t.export_data())['due'], 
+                         self.utctime_aware.strftime(DATE_FORMAT))
 
 class AnnotationTest(TasklibTest):
 
 
 class AnnotationTest(TasklibTest):
 
@@ -539,6 +666,23 @@ class AnnotationTest(TasklibTest):
          task.save()
          self.assertEqual(task['project'], 'test')
 
          task.save()
          self.assertEqual(task['project'], 'test')
 
+    def test_serialize_annotations(self):
+        # Test that serializing annotations is possible
+        t = Task(self.tw, description="test")
+        t.save()
+
+        t.add_annotation("annotation1")
+        t.add_annotation("annotation2")
+
+        data = t._serialize('annotations', t._data['annotations'])
+
+        self.assertEqual(len(data), 2)
+        self.assertEqual(type(data[0]), dict)
+        self.assertEqual(type(data[1]), dict)
+
+        self.assertEqual(data[0]['description'], "annotation1")
+        self.assertEqual(data[1]['description'], "annotation2")
+
 
 class UnicodeTest(TasklibTest):
 
 
 class UnicodeTest(TasklibTest):