]> git.madduck.net Git - etc/taskwarrior.git/blob - 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:

Tests: Add tests for modified fields
[etc/taskwarrior.git] / tasklib / tests.py
1 # coding=utf-8
2
3 import datetime
4 import shutil
5 import tempfile
6 import unittest
7
8 from .task import TaskWarrior, Task
9
10
11 class TasklibTest(unittest.TestCase):
12
13     def setUp(self):
14         self.tmp = tempfile.mkdtemp(dir='.')
15         self.tw = TaskWarrior(data_location=self.tmp)
16
17     def tearDown(self):
18         shutil.rmtree(self.tmp)
19
20
21 class TaskFilterTest(TasklibTest):
22
23     def test_all_empty(self):
24         self.assertEqual(len(self.tw.tasks.all()), 0)
25
26     def test_all_non_empty(self):
27         Task(self.tw, description="test task").save()
28         self.assertEqual(len(self.tw.tasks.all()), 1)
29         self.assertEqual(self.tw.tasks.all()[0]['description'], 'test task')
30         self.assertEqual(self.tw.tasks.all()[0]['status'], 'pending')
31
32     def test_pending_non_empty(self):
33         Task(self.tw, description="test task").save()
34         self.assertEqual(len(self.tw.tasks.pending()), 1)
35         self.assertEqual(self.tw.tasks.pending()[0]['description'],
36                          'test task')
37         self.assertEqual(self.tw.tasks.pending()[0]['status'], 'pending')
38
39     def test_completed_empty(self):
40         Task(self.tw, description="test task").save()
41         self.assertEqual(len(self.tw.tasks.completed()), 0)
42
43     def test_completed_non_empty(self):
44         Task(self.tw, description="test task").save()
45         self.assertEqual(len(self.tw.tasks.completed()), 0)
46         self.tw.tasks.all()[0].done()
47         self.assertEqual(len(self.tw.tasks.completed()), 1)
48
49     def test_filtering_by_attribute(self):
50         Task(self.tw, description="no priority task").save()
51         Task(self.tw, priority="H", description="high priority task").save()
52         self.assertEqual(len(self.tw.tasks.all()), 2)
53
54         # Assert that the correct number of tasks is returned
55         self.assertEqual(len(self.tw.tasks.filter(priority="H")), 1)
56
57         # Assert that the correct tasks are returned
58         high_priority_task = self.tw.tasks.get(priority="H")
59         self.assertEqual(high_priority_task['description'], "high priority task")
60
61     def test_filtering_by_empty_attribute(self):
62         Task(self.tw, description="no priority task").save()
63         Task(self.tw, priority="H", description="high priority task").save()
64         self.assertEqual(len(self.tw.tasks.all()), 2)
65
66         # Assert that the correct number of tasks is returned
67         self.assertEqual(len(self.tw.tasks.filter(priority=None)), 1)
68
69         # Assert that the correct tasks are returned
70         no_priority_task = self.tw.tasks.get(priority=None)
71         self.assertEqual(no_priority_task['description'], "no priority task")
72
73
74 class TaskTest(TasklibTest):
75
76     def test_create_unsaved_task(self):
77         # Make sure a new task is not saved unless explicitly called for
78         t = Task(self.tw, description="test task")
79         self.assertEqual(len(self.tw.tasks.all()), 0)
80
81     # TODO: once python 2.6 compatiblity is over, use context managers here
82     #       and in all subsequent tests for assertRaises
83
84     def test_delete_unsaved_task(self):
85         t = Task(self.tw, description="test task")
86         self.assertRaises(Task.NotSaved, t.delete)
87
88     def test_complete_unsaved_task(self):
89         t = Task(self.tw, description="test task")
90         self.assertRaises(Task.NotSaved, t.done)
91
92     def test_refresh_unsaved_task(self):
93         t = Task(self.tw, description="test task")
94         self.assertRaises(Task.NotSaved, t.refresh)
95
96     def test_delete_deleted_task(self):
97         t = Task(self.tw, description="test task")
98         t.save()
99         t.delete()
100
101         self.assertRaises(Task.DeletedTask, t.delete)
102
103     def test_complete_completed_task(self):
104         t = Task(self.tw, description="test task")
105         t.save()
106         t.done()
107
108         self.assertRaises(Task.CompletedTask, t.done)
109
110     def test_complete_deleted_task(self):
111         t = Task(self.tw, description="test task")
112         t.save()
113         t.delete()
114
115         self.assertRaises(Task.DeletedTask, t.done)
116
117     def test_empty_dependency_set_of_unsaved_task(self):
118         t = Task(self.tw, description="test task")
119         self.assertEqual(t['depends'], set())
120
121     def test_empty_dependency_set_of_saved_task(self):
122         t = Task(self.tw, description="test task")
123         t.save()
124         self.assertEqual(t['depends'], set())
125
126     def test_set_unsaved_task_as_dependency(self):
127         # Adds only one dependency to task with no dependencies
128         t = Task(self.tw, description="test task")
129         dependency = Task(self.tw, description="needs to be done first")
130
131         # We only save the parent task, dependency task is unsaved
132         t.save()
133
134         self.assertRaises(Task.NotSaved,
135                           t.__setitem__, 'depends', set([dependency]))
136
137     def test_set_simple_dependency_set(self):
138         # Adds only one dependency to task with no dependencies
139         t = Task(self.tw, description="test task")
140         dependency = Task(self.tw, description="needs to be done first")
141
142         t.save()
143         dependency.save()
144
145         t['depends'] = set([dependency])
146
147         self.assertEqual(t['depends'], set([dependency]))
148
149     def test_set_complex_dependency_set(self):
150         # Adds two dependencies to task with no dependencies
151         t = Task(self.tw, description="test task")
152         dependency1 = Task(self.tw, description="needs to be done first")
153         dependency2 = Task(self.tw, description="needs to be done second")
154
155         t.save()
156         dependency1.save()
157         dependency2.save()
158
159         t['depends'] = set([dependency1, dependency2])
160
161         self.assertEqual(t['depends'], set([dependency1, dependency2]))
162
163     def test_remove_from_dependency_set(self):
164         # Removes dependency from task with two dependencies
165         t = Task(self.tw, description="test task")
166         dependency1 = Task(self.tw, description="needs to be done first")
167         dependency2 = Task(self.tw, description="needs to be done second")
168
169         dependency1.save()
170         dependency2.save()
171
172         t['depends'] = set([dependency1, dependency2])
173         t.save()
174
175         t['depends'] = t['depends'] - set([dependency2])
176         t.save()
177
178         self.assertEqual(t['depends'], set([dependency1]))
179
180     def test_add_to_dependency_set(self):
181         # Adds dependency to task with one dependencies
182         t = Task(self.tw, description="test task")
183         dependency1 = Task(self.tw, description="needs to be done first")
184         dependency2 = Task(self.tw, description="needs to be done second")
185
186         dependency1.save()
187         dependency2.save()
188
189         t['depends'] = set([dependency1])
190         t.save()
191
192         t['depends'] = t['depends'] | set([dependency2])
193         t.save()
194
195         self.assertEqual(t['depends'], set([dependency1, dependency2]))
196
197     def test_simple_dependency_set_save_repeatedly(self):
198         # Adds only one dependency to task with no dependencies
199         t = Task(self.tw, description="test task")
200         dependency = Task(self.tw, description="needs to be done first")
201         dependency.save()
202
203         t['depends'] = set([dependency])
204         t.save()
205
206         # We taint the task, but keep depends intact
207         t['description'] = "test task modified"
208         t.save()
209
210         self.assertEqual(t['depends'], set([dependency]))
211
212         # We taint the task, but assign the same set to the depends
213         t['depends'] = set([dependency])
214         t['description'] = "test task modified again"
215         t.save()
216
217         self.assertEqual(t['depends'], set([dependency]))
218
219     def test_compare_different_tasks(self):
220         # Negative: compare two different tasks
221         t1 = Task(self.tw, description="test task")
222         t2 = Task(self.tw, description="test task")
223
224         t1.save()
225         t2.save()
226
227         self.assertEqual(t1 == t2, False)
228
229     def test_compare_same_task_object(self):
230         # Compare Task object wit itself
231         t = Task(self.tw, description="test task")
232         t.save()
233
234         self.assertEqual(t == t, True)
235
236     def test_compare_same_task(self):
237         # Compare the same task using two different objects
238         t1 = Task(self.tw, description="test task")
239         t1.save()
240
241         t2 = self.tw.tasks.get(uuid=t1['uuid'])
242         self.assertEqual(t1 == t2, True)
243
244     def test_compare_unsaved_tasks(self):
245         # t1 and t2 are unsaved tasks, considered to be unequal
246         # despite the content of data
247         t1 = Task(self.tw, description="test task")
248         t2 = Task(self.tw, description="test task")
249
250         self.assertEqual(t1 == t2, False)
251
252     def test_hash_unsaved_tasks(self):
253         # Considered equal, it's the same object
254         t1 = Task(self.tw, description="test task")
255         t2 = t1
256         self.assertEqual(hash(t1) == hash(t2), True)
257
258     def test_hash_same_task(self):
259         # Compare the hash of the task using two different objects
260         t1 = Task(self.tw, description="test task")
261         t1.save()
262
263         t2 = self.tw.tasks.get(uuid=t1['uuid'])
264         self.assertEqual(t1.__hash__(), t2.__hash__())
265
266     def test_adding_task_with_priority(self):
267         t = Task(self.tw, description="test task", priority="M")
268         t.save()
269
270     def test_removing_priority_with_none(self):
271         t = Task(self.tw, description="test task", priority="L")
272         t.save()
273
274         # Remove the priority mark
275         t['priority'] = None
276         t.save()
277
278         # Assert that priority is not there after saving
279         self.assertEqual(t['priority'], None)
280
281     def test_adding_task_with_due_time(self):
282         t = Task(self.tw, description="test task", due=datetime.datetime.now())
283         t.save()
284
285     def test_removing_due_time_with_none(self):
286         t = Task(self.tw, description="test task", due=datetime.datetime.now())
287         t.save()
288
289         # Remove the due timestamp
290         t['due'] = None
291         t.save()
292
293         # Assert that due timestamp is no longer there
294         self.assertEqual(t['due'], None)
295
296     def test_modified_fields_new_task(self):
297         t = Task(self.tw)
298
299         # This should be empty with new task
300         self.assertEqual(set(t._modified_fields), set())
301
302         # Modify the task
303         t['description'] = "test task"
304         self.assertEqual(set(t._modified_fields), set(['description']))
305
306         t['due'] = datetime.datetime(2014, 2, 14, 14, 14, 14)  # <3
307         self.assertEqual(set(t._modified_fields), set(['description', 'due']))
308
309         t['project'] = "test project"
310         self.assertEqual(set(t._modified_fields),
311                          set(['description', 'due', 'project']))
312
313         # List of modified fields should clear out when saved
314         t.save()
315         self.assertEqual(set(t._modified_fields), set())
316
317         # Reassigning the fields with the same values now should not produce
318         # modified fields
319         t['description'] = "test task"
320         t['due'] = datetime.datetime(2014, 2, 14, 14, 14, 14)  # <3
321         t['project'] = "test project"
322         self.assertEqual(set(t._modified_fields), set())
323
324     def test_modified_fields_loaded_task(self):
325         t = Task(self.tw)
326
327         # Modify the task
328         t['description'] = "test task"
329         t['due'] = datetime.datetime(2014, 2, 14, 14, 14, 14)  # <3
330         t['project'] = "test project"
331
332         dependency = Task(self.tw, description="dependency")
333         dependency.save()
334         t['depends'] = set([dependency])
335
336         # List of modified fields should clear out when saved
337         t.save()
338         self.assertEqual(set(t._modified_fields), set())
339
340         # Get the task by using a filter by UUID
341         t2 = self.tw.tasks.get(uuid=t['uuid'])
342
343         # Reassigning the fields with the same values now should not produce
344         # modified fields
345         t['description'] = "test task"
346         t['due'] = datetime.datetime(2014, 2, 14, 14, 14, 14)  # <3
347         t['project'] = "test project"
348         t['depends'] = set([dependency])
349         self.assertEqual(set(t._modified_fields), set())
350
351 class AnnotationTest(TasklibTest):
352
353     def setUp(self):
354         super(AnnotationTest, self).setUp()
355         Task(self.tw, description="test task").save()
356
357     def test_adding_annotation(self):
358         task = self.tw.tasks.get()
359         task.add_annotation('test annotation')
360         self.assertEqual(len(task['annotations']), 1)
361         ann = task['annotations'][0]
362         self.assertEqual(ann['description'], 'test annotation')
363
364     def test_removing_annotation(self):
365         task = self.tw.tasks.get()
366         task.add_annotation('test annotation')
367         ann = task['annotations'][0]
368         ann.remove()
369         self.assertEqual(len(task['annotations']), 0)
370
371     def test_removing_annotation_by_description(self):
372         task = self.tw.tasks.get()
373         task.add_annotation('test annotation')
374         task.remove_annotation('test annotation')
375         self.assertEqual(len(task['annotations']), 0)
376
377     def test_removing_annotation_by_obj(self):
378         task = self.tw.tasks.get()
379         task.add_annotation('test annotation')
380         ann = task['annotations'][0]
381         task.remove_annotation(ann)
382         self.assertEqual(len(task['annotations']), 0)
383
384
385 class UnicodeTest(TasklibTest):
386
387     def test_unicode_task(self):
388         Task(self.tw, description="†åßk").save()
389         self.tw.tasks.get()
390
391     def test_non_unicode_task(self):
392         Task(self.tw, description="test task").save()
393         self.tw.tasks.get()