Add files from the old svn, r101.
[matthijs/upstream/mobilegtd.git] / tests / specs / model / project_spec.py
1 import unittest
2 from mock import Mock
3 import model.project
4
5 from model.project import Project
6 from model import project
7 from model import action
8
9
10 class ProjectClassBehaviour(unittest.TestCase):
11     def setUp(self):
12         self.p_class = Project
13         self.observer = Mock()
14         self.p_class.observers.append(self.observer)
15     
16     def test_should_inform_listeners_of_project_creation(self):
17         p = Project(u'Test')
18         self.assertTrue(self.observer.notify.called)
19
20 class ProjectBehaviour(unittest.TestCase):
21
22     def setUp(self):
23         self.name = u'my project'
24         self.status = self.initial_status()
25         self.actions = self.initial_actions()
26         self.infos = self.initial_infos()
27         self.project = model.project.Project(self.name,self.status)
28         for a in self.actions:
29             self.project.add_action(a)
30         for i in self.infos:
31             self.project.add_info(i)
32         self.observer = Mock()
33         self.project.observers.append(self.observer)
34
35     def initial_actions(self):
36         return []
37
38     def create_action(self):
39         a = Mock()
40         a.status = self.action_status()
41         return a
42
43     def action_status(self):
44         return None
45
46     def initial_infos(self):
47         return []
48
49     def initial_status(self):
50         return project.inactive
51
52     def test_should_remember_its_name(self):
53         self.assertEqual(self.project.name,self.name)
54
55     def test_should_notify_observer_of_name_change(self):
56         self.project.name = 'new name'
57         self.assert_observed('name','new name',self.name)
58
59     def test_should_notify_observer_of_status_change(self):
60         old_status = self.project.status
61         self.project.status = project.done
62         self.assert_observed_status(project.done,old_status)
63
64     def create_action_with_status(self,status=action.inactive):
65         a = Mock()
66         a.status=status
67         return a    
68     def test_should_register_itself_as_project_for_added_actions(self):
69         a = self.create_action_with_status()
70         self.project.add_action(a)
71         self.assertEqual(a.project,self.project)
72     
73     def test_should_register_itself_as_observer_for_added_actions(self):
74         a = self.create_action()
75         self.project.add_action(a)
76         a.observers.append.assert_called_with(self.project)
77
78     def test_should_notify_observer_of_added_actions(self):
79         a = Mock()
80         a.status = action.done
81         self.project.add_action(a)
82         self.assert_observed('add_action', a)
83
84     def test_should_notify_observers_of_action_status_changes(self):
85         for a in self.project.actions:
86             self.project.action_changed_status(a, action.active)
87             self.assert_observed('changed_action', a, None)
88
89     def test_should_set_added_unprocessed_actions_to_active(self):
90         a = Mock()
91         a.status = action.unprocessed
92         self.project.add_action(a)
93         self.assertEqual(a.status,action.active)
94
95     def test_should_be_equal_if_name_and_status_are_identical(self):
96         other = Mock()
97         other.name = self.project.name
98         other.status = self.project.status
99         self.assertTrue(self.project == other)
100         self.assertFalse(self.project != other)
101         other.name = 'other name'
102         self.assertTrue(self.project != other)
103
104     def assert_observed(self,attribute,new=None,old=None):
105         calls = self.observer.notify.call_args_list
106         self.assertTrue(((self.project,attribute),{'new':new,'old':old}) in calls,
107                         'Expected notification from %s concerning the change of %s from %s to %s\n  Only got these calls:\n%s'%(repr(self.project),repr(attribute),repr(old),repr(new),repr(calls)))
108
109     def assert_observed_status(self,status,previous_status=None):
110         if not previous_status:
111             previous_status = self.status
112         self.assert_status(status)
113         self.assert_observed('status',status,previous_status)
114
115     def assert_status(self,status):
116         self.assertEqual(self.project.status,status)
117
118 class ActiveProjectBehaviour(ProjectBehaviour):
119
120     def initial_actions(self):
121         a = self.create_action_with_status(action.active)
122         return [a]
123     
124     def initial_status(self):
125         return project.active
126
127     def test_should_be_active(self):
128         self.assert_status(project.active)
129
130     def test_should_contain_active_actions(self):
131         self.assertTrue(self.project.has_active_actions())
132
133 #    def test_should_become_inactive_if_no_active_action_remains(self):
134 #        self.project.status = project.active
135 #        for a in self.project.actions_with_status(action.active):
136 #            self.project.remove_action(a)
137 #        self.assert_observed_status(project.inactive)
138 #
139 #    def test_should_become_inactive_when_active_actions_become_inactive(self):
140 #        self.project.status = project.active
141 #        for a in self.project.actions_with_status(action.active):
142 #            a.status = action.done
143 #            self.project.notify(a,'status',action.done)
144 #        self.assert_observed_status(project.inactive)
145
146     def test_should_deactivate_its_active_actions_on_deactivate(self):
147         active_actions = self.project.actions_with_status(action.active)
148         self.project.deactivate()
149         self.assertEqual(self.project.status,project.inactive)
150         for a in active_actions:
151             self.assertEqual(a.status,action.inactive)
152
153
154
155
156 class InactiveProjectBehaviour(ProjectBehaviour):
157     def initial_status(self):
158         return project.inactive
159     def test_should_be_inactive(self):
160         self.assert_status(project.inactive)
161
162 #    def test_should_become_active_if_active_actions_are_added(self):
163 #        a = Mock()
164 #        a.status = action.active
165 #        self.project.add_action(a)
166 #        self.assertEqual(self.project.status,project.active)
167
168     def test_should_activate_all_inactive_actions_when_activated_itself(self):
169         inactive_actions = self.project.actions_with_status(action.inactive)
170         for a in inactive_actions:
171             self.assertEqual(a.status,action.inactive)
172         self.project.activate()
173         for a in inactive_actions:
174             self.assertEqual(a.status,action.active)
175
176 class EmptyProjectBehaviour(InactiveProjectBehaviour):    
177
178     def test_should_return_an_empty_list_of_actions(self):
179         self.assertEqual(self.project.actions,[])
180         
181     def test_should_return_an_empty_list_of_infos(self):
182         self.assertEqual(self.project.infos,[])
183
184
185 class ProjectWithActionsBehaviour(ProjectBehaviour):
186     def setUp(self):
187         self.action = self.create_action()
188         super(ProjectWithActionsBehaviour,self).setUp()
189     
190     def initial_actions(self):
191         return [self.action]
192     
193     def test_should_contain_all_added_actions(self):
194         self.assertEqual(self.project.actions,self.actions)
195
196     def test_should_forget_removed_actions(self):
197         self.project.remove_action(self.actions[0])
198         self.assertFalse(self.actions[0] in self.project.actions)
199     
200     def test_should_remove_itself_as_observer_for_removed_actions(self):
201         self.project.remove_action(self.actions[0])
202         self.actions[0].observers.remove.assert_called_with(self.project)
203
204     def test_should_set_action_to_done_before_removing(self):
205         self.project.remove_action(self.actions[0])
206         self.assertEqual(self.actions[0].status,action.done)
207
208     def test_should_notify_observer_of_removed_actions(self):
209         self.project.remove_action(self.actions[0])
210         self.assert_observed('remove_action',self.actions[0],None)
211
212 def test_generator(field):
213     def test_should_notify_observer_of_changes_in_actions(self):
214         self.project.notify(self.actions[0], field, 'new %s'%field)
215         self.assert_observed('changed_action',self.actions[0])
216     return test_should_notify_observer_of_changes_in_actions
217
218 for field in ['description','info','context']:
219     no_change_on_action_becoming_active = 'test_should_notify_observer_of_changes_in_action_%s' % field
220     test = test_generator(field)
221     setattr(ProjectWithActionsBehaviour, no_change_on_action_becoming_active, test)
222         
223
224 class ProjectWithInactiveActionsBehaviour(ProjectWithActionsBehaviour):
225
226     def action_status(self):
227         return action.inactive
228
229 #    def test_should_become_active_when_inactive_actions_become_active(self):
230 #        self.actions[0].status = action.active
231 #        self.project.notify(self.actions[0],'status',action.active)
232 #        self.assert_observed_status(project.active)
233
234     def test_should_return_the_inactive_action(self):
235         self.assertEqual(self.project.actions_with_status(action.inactive),[self.actions[0]])
236
237     def test_should_return_no_active_action(self):
238         self.assertEqual(self.project.actions_with_status(action.active),[])
239
240
241
242 class InactiveProjectWithInactiveActionsBehaviour(ProjectWithInactiveActionsBehaviour,InactiveProjectBehaviour):
243     pass
244
245
246 class ProjectWithActiveActionsBehaviour(ProjectWithActionsBehaviour):
247     
248     def action_status(self):
249         return action.active
250
251     def test_should_return_the_active_action(self):
252         self.assertEqual(self.project.actions_with_status(action.active),[self.actions[0]])
253
254     def test_should_return_no_inactive_action(self):
255         self.assertEqual(self.project.actions_with_status(action.inactive),[])
256
257
258
259 #class ActiveProjectWithActiveActionsBehaviour(ProjectWithActiveActionsBehaviour,ActiveProjectBehaviour):
260     
261
262
263
264 class ProjectWithInfosBehaviour(ProjectBehaviour):
265     
266     def setUp(self):
267         super(ProjectWithInfosBehaviour,self).setUp()
268         self.info = Mock()
269         self.project.add_info(self.info)
270
271     def test_should_contain_all_added_infos(self):
272         self.assertEqual(self.project.infos,[self.info])
273
274     def test_should_really_forget_removed_infos(self):
275         self.project.remove_info(self.info)
276         self.assertFalse(self.info in self.project.infos)
277
278     def test_should_register_itself_as_observer_for_added_infos(self):
279         self.info.observers.append.assert_called_with(self.project)
280
281     def test_should_deregister_itself_as_observer_for_removed_infos(self):
282         self.project.remove_info(self.info)
283         self.info.observers.remove.assert_called_with(self.project)
284
285
286     def test_should_notify_observer_of_removed_infos(self):
287         self.project.remove_info(self.info)
288         self.assert_observed('remove_info',self.info)
289
290     def test_should_notify_observer_of_changes_in_infos(self):
291         self.project.notify(self.info, 'text', 'new text')
292         self.assert_observed('changed_info',self.info)
293
294
295
296
297 def generate_no_becoming_active_test(status):
298     def initial_status(self):
299         return status
300     def test_should_not_change_status_if_actions_become_active(self):
301         self.project.notify(self.actions[0], 'status', action.active)
302         self.assertEqual(status,self.project.status)
303     def test_should_not_change_status_if_active_actions_are_added(self):
304         a = Mock()
305         a.status = action.active
306         self.project.add_action(a)
307         self.assertEqual(status,self.project.status)
308     return (initial_status,test_should_not_change_status_if_actions_become_active,test_should_not_change_status_if_active_actions_are_added)
309 #
310 for status in ['someday','done','tickled']:
311     class_name = '%sProjectBehaviour'%status.capitalize()
312     my_class=type(class_name,(ProjectWithActiveActionsBehaviour,),{})
313     no_change_on_action_becoming_active = 'test_should_not_change_%s_status_if_actions_become_active' % status
314     no_change_on_active_action_added= 'test_should_not_change_%s_status_if_active_actions_are_added' % status
315     initial_status,no_change_on_action_becoming_active_test,no_change_on_active_action_added_test = generate_no_becoming_active_test(getattr(model.project,status))
316     
317     setattr(my_class, 'initial_status', initial_status)
318     setattr(my_class, no_change_on_action_becoming_active, no_change_on_action_becoming_active_test)
319     setattr(my_class, no_change_on_active_action_added, no_change_on_active_action_added_test)
320     globals()[class_name]=my_class
321
322
323            
324
325
326