Add files from the old svn, r101.
[matthijs/upstream/mobilegtd.git] / tests / specs / model / project_spec.py
diff --git a/tests/specs/model/project_spec.py b/tests/specs/model/project_spec.py
new file mode 100644 (file)
index 0000000..12f6679
--- /dev/null
@@ -0,0 +1,326 @@
+import unittest
+from mock import Mock
+import model.project
+
+from model.project import Project
+from model import project
+from model import action
+
+
+class ProjectClassBehaviour(unittest.TestCase):
+    def setUp(self):
+        self.p_class = Project
+        self.observer = Mock()
+        self.p_class.observers.append(self.observer)
+    
+    def test_should_inform_listeners_of_project_creation(self):
+        p = Project(u'Test')
+        self.assertTrue(self.observer.notify.called)
+
+class ProjectBehaviour(unittest.TestCase):
+
+    def setUp(self):
+        self.name = u'my project'
+        self.status = self.initial_status()
+        self.actions = self.initial_actions()
+        self.infos = self.initial_infos()
+        self.project = model.project.Project(self.name,self.status)
+        for a in self.actions:
+            self.project.add_action(a)
+        for i in self.infos:
+            self.project.add_info(i)
+        self.observer = Mock()
+        self.project.observers.append(self.observer)
+
+    def initial_actions(self):
+        return []
+
+    def create_action(self):
+        a = Mock()
+        a.status = self.action_status()
+        return a
+
+    def action_status(self):
+        return None
+
+    def initial_infos(self):
+        return []
+
+    def initial_status(self):
+        return project.inactive
+
+    def test_should_remember_its_name(self):
+        self.assertEqual(self.project.name,self.name)
+
+    def test_should_notify_observer_of_name_change(self):
+        self.project.name = 'new name'
+        self.assert_observed('name','new name',self.name)
+
+    def test_should_notify_observer_of_status_change(self):
+        old_status = self.project.status
+        self.project.status = project.done
+        self.assert_observed_status(project.done,old_status)
+
+    def create_action_with_status(self,status=action.inactive):
+        a = Mock()
+        a.status=status
+        return a    
+    def test_should_register_itself_as_project_for_added_actions(self):
+        a = self.create_action_with_status()
+        self.project.add_action(a)
+        self.assertEqual(a.project,self.project)
+    
+    def test_should_register_itself_as_observer_for_added_actions(self):
+        a = self.create_action()
+        self.project.add_action(a)
+        a.observers.append.assert_called_with(self.project)
+
+    def test_should_notify_observer_of_added_actions(self):
+        a = Mock()
+        a.status = action.done
+        self.project.add_action(a)
+        self.assert_observed('add_action', a)
+
+    def test_should_notify_observers_of_action_status_changes(self):
+        for a in self.project.actions:
+            self.project.action_changed_status(a, action.active)
+            self.assert_observed('changed_action', a, None)
+
+    def test_should_set_added_unprocessed_actions_to_active(self):
+        a = Mock()
+        a.status = action.unprocessed
+        self.project.add_action(a)
+        self.assertEqual(a.status,action.active)
+
+    def test_should_be_equal_if_name_and_status_are_identical(self):
+        other = Mock()
+        other.name = self.project.name
+        other.status = self.project.status
+        self.assertTrue(self.project == other)
+        self.assertFalse(self.project != other)
+        other.name = 'other name'
+        self.assertTrue(self.project != other)
+
+    def assert_observed(self,attribute,new=None,old=None):
+        calls = self.observer.notify.call_args_list
+        self.assertTrue(((self.project,attribute),{'new':new,'old':old}) in calls,
+                        '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)))
+
+    def assert_observed_status(self,status,previous_status=None):
+        if not previous_status:
+            previous_status = self.status
+        self.assert_status(status)
+        self.assert_observed('status',status,previous_status)
+
+    def assert_status(self,status):
+        self.assertEqual(self.project.status,status)
+
+class ActiveProjectBehaviour(ProjectBehaviour):
+
+    def initial_actions(self):
+        a = self.create_action_with_status(action.active)
+        return [a]
+    
+    def initial_status(self):
+        return project.active
+
+    def test_should_be_active(self):
+        self.assert_status(project.active)
+
+    def test_should_contain_active_actions(self):
+        self.assertTrue(self.project.has_active_actions())
+
+#    def test_should_become_inactive_if_no_active_action_remains(self):
+#        self.project.status = project.active
+#        for a in self.project.actions_with_status(action.active):
+#            self.project.remove_action(a)
+#        self.assert_observed_status(project.inactive)
+#
+#    def test_should_become_inactive_when_active_actions_become_inactive(self):
+#        self.project.status = project.active
+#        for a in self.project.actions_with_status(action.active):
+#            a.status = action.done
+#            self.project.notify(a,'status',action.done)
+#        self.assert_observed_status(project.inactive)
+
+    def test_should_deactivate_its_active_actions_on_deactivate(self):
+        active_actions = self.project.actions_with_status(action.active)
+        self.project.deactivate()
+        self.assertEqual(self.project.status,project.inactive)
+        for a in active_actions:
+            self.assertEqual(a.status,action.inactive)
+
+
+
+
+class InactiveProjectBehaviour(ProjectBehaviour):
+    def initial_status(self):
+        return project.inactive
+    def test_should_be_inactive(self):
+        self.assert_status(project.inactive)
+
+#    def test_should_become_active_if_active_actions_are_added(self):
+#        a = Mock()
+#        a.status = action.active
+#        self.project.add_action(a)
+#        self.assertEqual(self.project.status,project.active)
+
+    def test_should_activate_all_inactive_actions_when_activated_itself(self):
+        inactive_actions = self.project.actions_with_status(action.inactive)
+        for a in inactive_actions:
+            self.assertEqual(a.status,action.inactive)
+        self.project.activate()
+        for a in inactive_actions:
+            self.assertEqual(a.status,action.active)
+
+class EmptyProjectBehaviour(InactiveProjectBehaviour):    
+
+    def test_should_return_an_empty_list_of_actions(self):
+        self.assertEqual(self.project.actions,[])
+        
+    def test_should_return_an_empty_list_of_infos(self):
+        self.assertEqual(self.project.infos,[])
+
+
+class ProjectWithActionsBehaviour(ProjectBehaviour):
+    def setUp(self):
+        self.action = self.create_action()
+        super(ProjectWithActionsBehaviour,self).setUp()
+    
+    def initial_actions(self):
+        return [self.action]
+    
+    def test_should_contain_all_added_actions(self):
+        self.assertEqual(self.project.actions,self.actions)
+
+    def test_should_forget_removed_actions(self):
+        self.project.remove_action(self.actions[0])
+        self.assertFalse(self.actions[0] in self.project.actions)
+    
+    def test_should_remove_itself_as_observer_for_removed_actions(self):
+        self.project.remove_action(self.actions[0])
+        self.actions[0].observers.remove.assert_called_with(self.project)
+
+    def test_should_set_action_to_done_before_removing(self):
+        self.project.remove_action(self.actions[0])
+        self.assertEqual(self.actions[0].status,action.done)
+
+    def test_should_notify_observer_of_removed_actions(self):
+        self.project.remove_action(self.actions[0])
+        self.assert_observed('remove_action',self.actions[0],None)
+
+def test_generator(field):
+    def test_should_notify_observer_of_changes_in_actions(self):
+        self.project.notify(self.actions[0], field, 'new %s'%field)
+        self.assert_observed('changed_action',self.actions[0])
+    return test_should_notify_observer_of_changes_in_actions
+
+for field in ['description','info','context']:
+    no_change_on_action_becoming_active = 'test_should_notify_observer_of_changes_in_action_%s' % field
+    test = test_generator(field)
+    setattr(ProjectWithActionsBehaviour, no_change_on_action_becoming_active, test)
+        
+
+class ProjectWithInactiveActionsBehaviour(ProjectWithActionsBehaviour):
+
+    def action_status(self):
+        return action.inactive
+
+#    def test_should_become_active_when_inactive_actions_become_active(self):
+#        self.actions[0].status = action.active
+#        self.project.notify(self.actions[0],'status',action.active)
+#        self.assert_observed_status(project.active)
+
+    def test_should_return_the_inactive_action(self):
+        self.assertEqual(self.project.actions_with_status(action.inactive),[self.actions[0]])
+
+    def test_should_return_no_active_action(self):
+        self.assertEqual(self.project.actions_with_status(action.active),[])
+
+
+
+class InactiveProjectWithInactiveActionsBehaviour(ProjectWithInactiveActionsBehaviour,InactiveProjectBehaviour):
+    pass
+
+
+class ProjectWithActiveActionsBehaviour(ProjectWithActionsBehaviour):
+    
+    def action_status(self):
+        return action.active
+
+    def test_should_return_the_active_action(self):
+        self.assertEqual(self.project.actions_with_status(action.active),[self.actions[0]])
+
+    def test_should_return_no_inactive_action(self):
+        self.assertEqual(self.project.actions_with_status(action.inactive),[])
+
+
+
+#class ActiveProjectWithActiveActionsBehaviour(ProjectWithActiveActionsBehaviour,ActiveProjectBehaviour):
+    
+
+
+
+class ProjectWithInfosBehaviour(ProjectBehaviour):
+    
+    def setUp(self):
+        super(ProjectWithInfosBehaviour,self).setUp()
+        self.info = Mock()
+        self.project.add_info(self.info)
+
+    def test_should_contain_all_added_infos(self):
+        self.assertEqual(self.project.infos,[self.info])
+
+    def test_should_really_forget_removed_infos(self):
+        self.project.remove_info(self.info)
+        self.assertFalse(self.info in self.project.infos)
+
+    def test_should_register_itself_as_observer_for_added_infos(self):
+        self.info.observers.append.assert_called_with(self.project)
+
+    def test_should_deregister_itself_as_observer_for_removed_infos(self):
+        self.project.remove_info(self.info)
+        self.info.observers.remove.assert_called_with(self.project)
+
+
+    def test_should_notify_observer_of_removed_infos(self):
+        self.project.remove_info(self.info)
+        self.assert_observed('remove_info',self.info)
+
+    def test_should_notify_observer_of_changes_in_infos(self):
+        self.project.notify(self.info, 'text', 'new text')
+        self.assert_observed('changed_info',self.info)
+
+
+
+
+def generate_no_becoming_active_test(status):
+    def initial_status(self):
+        return status
+    def test_should_not_change_status_if_actions_become_active(self):
+        self.project.notify(self.actions[0], 'status', action.active)
+        self.assertEqual(status,self.project.status)
+    def test_should_not_change_status_if_active_actions_are_added(self):
+        a = Mock()
+        a.status = action.active
+        self.project.add_action(a)
+        self.assertEqual(status,self.project.status)
+    return (initial_status,test_should_not_change_status_if_actions_become_active,test_should_not_change_status_if_active_actions_are_added)
+#
+for status in ['someday','done','tickled']:
+    class_name = '%sProjectBehaviour'%status.capitalize()
+    my_class=type(class_name,(ProjectWithActiveActionsBehaviour,),{})
+    no_change_on_action_becoming_active = 'test_should_not_change_%s_status_if_actions_become_active' % status
+    no_change_on_active_action_added= 'test_should_not_change_%s_status_if_active_actions_are_added' % status
+    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))
+    
+    setattr(my_class, 'initial_status', initial_status)
+    setattr(my_class, no_change_on_action_becoming_active, no_change_on_action_becoming_active_test)
+    setattr(my_class, no_change_on_active_action_added, no_change_on_active_action_added_test)
+    globals()[class_name]=my_class
+
+
+           
+
+
+