Ejemplo n.º 1
0
    def get_tags_tree(self,req):
        '''This create a liblarch tree suitable for tags,
        including the all_tags_tag and notag_tag.
        '''
        tagtree = Tree()
        
        ### building the initial tags
        # Build the "all tasks tag"
        alltag = Tag(CoreConfig.ALLTASKS_TAG, req=req)
        alltag.set_attribute("special","all")
        alltag.set_attribute("label","<span weight='bold'>%s</span>"\
                                             % _("All tasks"))
        alltag.set_attribute("icon","gtg-tags-all")
        alltag.set_attribute("order",0)
        tagtree.add_node(alltag)
        p = {'transparent':True}
        self.tasktree.add_filter(CoreConfig.ALLTASKS_TAG,\
                                    self.alltag,parameters=p)
        # Build the "without tag tag"
        notag_tag = Tag(CoreConfig.NOTAG_TAG,req=req)
        notag_tag.set_attribute("special","notag")
        notag_tag.set_attribute("label","<span weight='bold'>%s</span>"\
                                             % _("Tasks with no tags"))
        notag_tag.set_attribute("icon","gtg-tags-none")
        notag_tag.set_attribute("order",1)
        tagtree.add_node(notag_tag)
        p = {'transparent':True}
        self.tasktree.add_filter(CoreConfig.NOTAG_TAG,\
                                    self.notag,parameters=p)
        # Build the separator
        sep_tag = Tag(CoreConfig.SEP_TAG,req=req)
        sep_tag.set_attribute("special","sep")
        sep_tag.set_attribute("order",2)
        tagtree.add_node(sep_tag)
        
        
        #### Filters 
        tagtree.add_filter('activetag',self.actively_used_tag)
        tagtree.add_filter('usedtag',self.used_tag)
        
        activeview = tagtree.get_viewtree(name='activetags',refresh=False)
        activeview.apply_filter('activetag')
        
        #This view doesn't seem to be used. So it's not useful to build it now
#        usedview = tagtree.get_viewtree(name='usedtags',refresh=False)
#        usedview.apply_filter('usedtag')
        
        self.tagtree = tagtree
        self.tagtree_loaded = True
        return tagtree
class TestLibLarch(unittest.TestCase):
    """Tests for `Tree`."""


    def caller_name(self):
        '''
        Returns the filename and the line of the calling function.
        Precisely, it returns the calling calling function (because
        you're calling this one).
        '''
        frame=inspect.currentframe()
        frame=frame.f_back.f_back
        code=frame.f_code
        return code.co_filename, code.co_firstlineno    

    def assertSignal(self, generator, signal_name, function, \
                     how_many_signals = 1):
        def new(how_many_signals, error_code, *args, **kws):
            with SignalCatcher(self, generator, signal_name,\
                               how_many_signals = how_many_signals,
                               error_code = error_code)\
                    as [signal_catched_event, signal_arguments]:
                function(*args, **kws)
                signal_catched_event.wait()
                self.recorded_signals[signal_name] += signal_arguments
            return None
        return functools.partial(new, how_many_signals, self.caller_name())

    def test_assertSignal(self):
        class FakeGobject(gobject.GObject):
            __gsignals__ = {'node-added-inview': (gobject.SIGNAL_RUN_FIRST,
                                    gobject.TYPE_NONE, [])}
            def emit_n_signals(self, n):
                while n:
                    n -= 1
                    gobject.idle_add(self.emit, 'node-added-inview')
        fake_gobject = FakeGobject() 
        self.assertSignal(fake_gobject, \
                          'node-added-inview', \
                          fake_gobject.emit_n_signals, 33)(33)

    def setUp(self):
        """Set up a dummy tree with filters and nodes.

        Construct a Tree for testing, with some filters for testing, including
        filters with parameters 'flat' and 'transparent'.  Create a collection of
        nodes with some of the properties these filters filter on.
        """
        i = 0
        #node numbers, used to check
        self.red_nodes = 0
        self.blue_nodes = 0
        self.green_nodes = 0
        #Larch, is the tree. Learn to recognize it.
        self.tree = Tree()
        self.view = self.tree.get_viewtree()
        self.tester = TreeTester(self.view)
        self.mainview = self.tree.get_main_view()
        self.tree.add_filter('blue',self.is_blue)
        self.tree.add_filter('green',self.is_green)
        self.tree.add_filter('red',self.is_red)
        self.tree.add_filter('leaf',self.is_leaf)
        param = {}
        param['flat'] = True
        self.tree.add_filter('flatgreen',self.is_green,parameters=param)
        self.tree.add_filter('flatleaves',self.is_leaf,parameters=param)
        param = {}
        param['transparent'] = True
        self.tree.add_filter('transblue',self.is_blue,parameters=param)
        self.tree.add_filter('transgreen',self.is_green,parameters=param)
        #first, we add some red nodes at the root
        while i < 5:
            node = DummyNode(str(i))
            node.add_color('red')
            self.tree.add_node(node)
            i += 1
            self.red_nodes += 1
        #then, we add some blue nodes also at the root
        while i < 10:
            node = DummyNode(str(i))
            node.add_color('blue')
            self.tree.add_node(node)
            i+=1
            self.blue_nodes += 1
        #finally, we add some green nodes as children of the last nodes
        # (stairs-like configuration)
        while i < 15:
            node = DummyNode(str(i))
            node.add_color('green')
            self.tree.add_node(node,parent_id=str(i-1))
            i+=1
            self.green_nodes += 1
        self.total = self.red_nodes + self.blue_nodes + self.green_nodes
        ################now testing the GTK treeview ##################
        #The columns description:
        desc = {}
        col = {}
        col['title'] = "Node name"
        render_text = gtk.CellRendererText()
        col['renderer'] = ['markup',render_text]
        def get_node_name(node):
            return node.get_id()
        col['value'] = [str,get_node_name]
        desc['titles'] = col
        treeview = TreeView(self.view,desc)
        #initalize gobject signaling system
        self.gobject_signal_manager = GobjectSignalsManager()
        self.gobject_signal_manager.init_signals()
        self.recorded_signals = {'node-added-inview': [],
                                 'node-modified-inview': [],
                                 'node-deleted-inview': []}
        self.assertNodeAddedInview = functools.partial ( \
            self.assertSignal, self.view, 'node-added-inview')
        self.assertNodeModifiedInview = functools.partial ( \
            self.assertSignal, self.view, 'node-modified-inview')
        self.assertNodeDeletedInview = functools.partial ( \
            self.assertSignal, self.view, 'node-deleted-inview')

    def tearDown(self):
        try:
            self.tester.test_validity()
        finally:
            #stopping gobject main loop
            self.gobject_signal_manager.terminate_signals()
        
    ####Filters
    def is_blue(self,node,parameters=None):
        return node.has_color('blue')
    def is_green(self,node,parameters=None):
        return node.has_color('green')
    def is_red(self,node,parameters=None):
        return node.has_color('red')
    def is_leaf(self,node,parameters=None):
        return not node.has_child()
        
    #### Testing nodes movements in the tree
    #### We test by counting nodes that meet some criterias
    
    def test_get_node(self):
        """Test that one node can be retrieved from the tree
        """
        #we test that get node works for the last node
        node = self.tree.get_node(str(self.total-1))
        self.assert_(node != None)
        self.assertEqual(str(self.total-1),node.get_id())
        #and not for an non-existing node
        self.assertRaises(ValueError,self.tree.get_node,str(self.total))

    def test_add_remove_node(self):
        """ Test the adding and removal of nodes """
        view = self.tree.get_viewtree(refresh=True)
        node = DummyNode('temp')
        node.add_color('blue')

        self.assertSignal(self.view, \
                            'node-modified-inview', \
                            self.assertSignal(self.view, \
                                              'node-added-inview', \
                                          self.tree.add_node))(node, parent_id = '0')
        self.assert_(('temp',(0, 0)) in self.recorded_signals['node-added-inview'])
        self.assert_(('0',(0, )) in \
                     self.recorded_signals['node-modified-inview'])
        shouldbe = self.blue_nodes + 1
        total = self.red_nodes + self.blue_nodes + self.green_nodes
        #Testing that the blue node count has increased
        self.assertEqual(total+1,view.get_n_nodes())
        self.assertEqual(shouldbe,view.get_n_nodes(withfilters=['blue']))
        #also comparing with another view
        self.assertEqual(total+1,self.view.get_n_nodes())
        self.assertEqual(shouldbe,self.view.get_n_nodes(withfilters=['blue']))
        self.tree.del_node('temp')
        #Testing that it goes back to normal
        self.assertEqual(total,view.get_n_nodes())
        self.assertEqual(self.blue_nodes,view.get_n_nodes(withfilters=['blue']))
        #also comparing with another view
        self.assertEqual(total,self.view.get_n_nodes())
        self.assertEqual(self.blue_nodes,self.view.get_n_nodes(withfilters=['blue']))
        self.tester.test_validity()
        
    def test_modifying_node(self):
        """ Modifying a node and see if the change is reflected in filters """
        viewblue = self.tree.get_viewtree(refresh=False)
        testblue = TreeTester(viewblue)
        viewblue.apply_filter('blue')
        viewred = self.tree.get_viewtree(refresh=False)
        testred = TreeTester(viewred)
        viewred.apply_filter('red')
        node = DummyNode('temp')
        node.add_color('blue')
        #Do you see : we are modifying a child
        self.assertSignal(self.view, \
                          'node-modified-inview', \
                          self.tree.add_node, 1)(node,parent_id='0')
        self.assert_(('0',(0, )) in self.recorded_signals['node-modified-inview'])
        #Node is blue
        self.assert_(viewblue.is_displayed('temp'))
        self.failIf(viewred.is_displayed('temp'))
        #node is blue and red
        node.add_color('red')
        self.assert_(viewblue.is_displayed('temp'))
        self.assert_(viewred.is_displayed('temp'))
        #node is red only
        node.remove_color('blue')
        self.failIf(viewblue.is_displayed('temp'))
        self.assert_(viewred.is_displayed('temp'))
        testred.test_validity()
        testblue.test_validity()

    def test_removing_parent(self):
        """Test behavior of node when its parent goes away.

        When you remove a parent, the child nodes should be added to
        the root if they don't have any other parents.
        """
        view = self.tree.get_viewtree(refresh=True)
        node = DummyNode('temp')
        node.add_color('blue')
        self.tree.add_node(node,parent_id='0')
        all_nodes = self.view.get_all_nodes()
        self.assert_('0' in all_nodes)
        self.assert_('temp' in all_nodes)
        self.assertSignal(self.view, \
                          'node-deleted-inview', \
                          self.tree.del_node, 1)('0')
#        self.assert_(('0',(0, )) in self.recorded_signals['node-deleted-inview'])
        all_nodes = self.view.get_all_nodes()
        self.failIf('0' in all_nodes)
        self.assert_('temp' in all_nodes)
        
    def test_adding_to_late_parent(self):
        '''Add a node to a parent not yet in the tree
        then add the parent later'''
        view = self.tree.get_viewtree(refresh=True)
        node = DummyNode('child')
        self.tree.add_node(node,parent_id='futur')
        all_nodes = view.get_all_nodes()
        self.assert_('child' in all_nodes)
        self.failIf('futur' in all_nodes)
        self.assertEqual(len(view.node_parents('child')),0)
        #now inserting the parent
        node2 = DummyNode('futur')
        self.tree.add_node(node2)
        all_nodes = view.get_all_nodes()
        self.assert_('child' in all_nodes)
        self.assert_('futur' in all_nodes)
        self.assert_('futur' in view.node_parents('child'))
        #TODO the same test but with filters
        
    def test_adding_to_late_parent2(self):
        '''Another tricky case with late parent. This was
        a very rare but existing crash'''
        view = self.tree.get_viewtree(refresh=True)
        node = DummyNode('child')
        self.tree.add_node(node)
        node2 = DummyNode('futur')
        node.add_parent('futur')
        node.modified()
        self.assertEqual(len(view.node_parents('child')),0)
        self.assertNotEqual(view.get_paths_for_node('child'),[(0,0)])
        self.tree.add_node(node2)
        self.assert_('futur' in view.node_parents('child'))
        
    def test_adding_to_late_parent3(self):
        '''Another tricky case with late parent. This was
        a very rare but existing crash'''
        view = self.tree.get_viewtree(refresh=True)
        view.apply_filter('red')
        node = DummyNode('child')
        node.add_color('red')
        self.tree.add_node(node)
        node2 = view.get_node('0')
        node2.remove_color('red')
        node.add_parent('0')
        node.modified()
        self.assertEqual(len(view.node_parents('child')),0)
        self.assertNotEqual(view.get_paths_for_node('child'),[(0,0)])
#        view.print_tree()
        node2.add_color('red')
#        view.print_tree()
        self.assert_('0' in view.node_parents('child'))
        
    def test_multiple_children(self):
        '''We test a node with two children.'''
        view = self.tree.get_viewtree(refresh=True)
        node = DummyNode('child')
        node2 = DummyNode('child2')
        self.tree.add_node(node,parent_id='0')
        self.tree.add_node(node2,parent_id='0')
        #We first test that the childrens are both there.
        self.assertEqual(view.node_n_children('0'),2)
        self.assertEqual(view.next_node('child'),'child2')
        #We build a list of children paths
        paths = []
        paths += view.get_paths_for_node('child')
        paths += view.get_paths_for_node('child2')
        #take the paths of the parent - let's call it (X,) "
        roots = view.get_paths_for_node('0')
        #Then, (X,0) and (X,1) should be both in paths of children
        for r in roots:
            p = r + (0,)
            self.assert_(p in paths)
            p = r + (1,)
            self.assert_(p in paths)
            
    def test_clean_multiple_parents(self):
        view = self.tree.get_viewtree(refresh=True)
        node = DummyNode('child')
        node2 = DummyNode('child2')
        self.tree.add_node(node,parent_id='0')
        self.tree.add_node(node2,parent_id='child')
        node.add_parent('1')
        node2.add_parent('1')
        self.assertEqual(len(view.node_parents('child')),2)
        view.apply_filter('blue')
        
    def test_adding_to_late_parent_with_leaf_filter(self):
        '''Add a node to a parent not yet in the tree
        then add the parent later'''
        view = self.tree.get_viewtree(refresh=True)
        node = DummyNode('child')
        self.tree.add_node(node,parent_id='futur')
        all_nodes = view.get_all_nodes()
        self.assert_('child' in all_nodes)
        self.failIf('futur' in all_nodes)
        self.assertEqual(len(view.node_parents('child')),0)
        #now inserting the parent
        view.apply_filter('leaf')
        node2 = DummyNode('futur')
        self.tree.add_node(node2)
        all_nodes = view.get_all_nodes()
        self.assert_('child' in all_nodes)
        self.failIf('futur' in all_nodes)
        self.failIf('futur' in view.node_parents('child'))
        view.reset_filters()
        self.assert_(view.is_displayed('futur'))
        self.assert_('futur' in view.node_parents('child'))
        
    def test_updating_parent(self):
        node = DummyNode('child')
        node.add_color('red')
        self.tree.add_node(node,parent_id='0')
        view = self.tree.get_viewtree(refresh=False)
        view.apply_filter('red')
        self.assertEqual(view.node_parents('child'),['0'])
        path0 = view.get_paths_for_node('0')[0]
        pathchild = path0 + (0,)
        self.assertEqual(view.get_paths_for_node('child'),[pathchild])
        node0 = view.get_node('0')
        node0.add_color('blue')
        self.assertEqual(view.node_parents('child'),['0'])
        self.assertEqual(view.get_paths_for_node('child'),[pathchild])
        node0.remove_color('red')
        self.assertEqual(view.node_parents('child'),[])
        self.assertEqual(len(view.get_paths_for_node('child')[0]),1)
        node0.add_color('red')
        path0 = view.get_paths_for_node('0')[0]
        pathchild = path0 + (0,)
        self.assertEqual(view.node_parents('child'),['0'])
        self.assertEqual(view.get_paths_for_node('child'),[pathchild])
        
    def test_addchild_with_late_parent(self):
        '''Add a child to a node which is not yet in the tree. 
        We also check with a callback that the path sent is well
        corresponding to the nid received.
        '''
        def check_path(nid,path,state_id):
            realnode = view.get_node_for_path(path)
#            self.assertEqual(nid,realnode)
        def printtree(tid,paths=None,state_id=None):
            treestr = ' '
            #The printtree method returns an error when the printed tree
            #is not logical. Thus, by connecting a print tree to signals,
            #the test will fail if there's any inconsistencies.
            view.print_tree(string=True)
        view = self.tree.get_viewtree(refresh=True)
        view.register_cllbck('node-modified-inview',check_path)
        view.register_cllbck('node-deleted-inview',printtree)
        node = DummyNode('child')
        node2 = DummyNode('futur')
        node3 = DummyNode('child2')
        node2.add_child('child')
        node2.add_child('child2')
        self.tree.add_node(node)
        self.tree.add_node(node3)
        all_nodes = view.get_all_nodes()
        self.assert_('child' in all_nodes)
        self.assert_('child2' in all_nodes)
        self.failIf('futur' in all_nodes)
        self.assertEqual(len(view.node_parents('child')),0)
        self.assertEqual(len(view.node_parents('child2')),0)
        #now inserting the parent
        view.apply_filter('leaf')
        self.tree.add_node(node2)
        all_nodes = view.get_all_nodes()
        self.assert_('child' in all_nodes)
        self.assert_('child2' in all_nodes)
        self.failIf('futur' in all_nodes)
        self.failIf('futur' in view.node_parents('child'))
        self.failIf('futur' in view.node_parents('child2'))
        view.reset_filters()
        self.assert_(view.is_displayed('futur'))
        self.assert_('futur' in view.node_parents('child'))
        self.assert_('futur' in view.node_parents('child2'))
        
    def test_addparent_with_late_child(self):
        '''Add a child not yet in the tree to a node'''
        view = self.tree.get_viewtree(refresh=True)
        node = DummyNode('parent')
        node2 = DummyNode('futur')
        node.add_child('futur')
        self.tree.add_node(node)
        all_nodes = view.get_all_nodes()
        self.assert_('parent' in all_nodes)
        self.failIf('futur' in all_nodes)
        self.assertEqual(view.node_n_children('parent'),0)
        #now inserting the parent
        view.apply_filter('leaf')
        self.tree.add_node(node2)
        all_nodes = view.get_all_nodes()
        self.assert_('futur' in all_nodes)
        self.failIf('parent' in all_nodes)
        self.failIf('parent' in view.node_parents('futur'))
        view.reset_filters()
        self.assert_(view.is_displayed('parent'))
        self.assert_('futur' in view.node_all_children('parent'))
        
    def test_more_late_child(self):
        '''This one is trickier. We add a node with some children.
        Then, we add later a new child between the existing children.
        '''
        view = self.tree.get_viewtree(refresh=True)
        node = DummyNode('parent')
        node1 = DummyNode('futur1')
        node2 = DummyNode('futur2')
        node3 = DummyNode('futur3')
        node4 = DummyNode('futur4')
        node.add_child('futur1')
        node.add_child('futur2')
        node.add_child('futur3')
        node.add_child('futur4')
        self.tree.add_node(node)
        self.tree.add_node(node1)
        #look, we miss the node 2 !
        self.tree.add_node(node3)
        self.tree.add_node(node4)
        self.assertEqual(view.node_n_children('parent'),3)
        self.tree.add_node(node2)
        self.assertEqual(view.node_n_children('parent'),4)
        
    def test_late_first_child(self):
        '''Futur2 is the child of parent
           Futur1 is both the child of parent and futur2
           Futur1 will be added later, forcing a reorganization.
        '''
        view = self.tree.get_viewtree(refresh=True)
        node = DummyNode('parent')
        node1 = DummyNode('futur1')
        node2 = DummyNode('futur2')
        node.add_child('futur1')
        node.add_child('futur2')
        node2.add_child('futur1')
        self.tree.add_node(node)
        self.tree.add_node(node2)
        #Look, we didn't add futur1
        self.assertEqual(view.node_n_children('parent'),1)
        self.assertEqual(view.node_n_children('futur2'),0)
        self.assertFalse(view.is_displayed('futur1'))
        #Now we add it !
        self.tree.add_node(node1)
        self.assertEqual(view.node_n_children('parent'),2)
        self.assertEqual(view.node_n_children('futur2'),1)
        self.assert_(view.is_displayed('futur1'))
        
    def test_move_node_to_a_multiple_parent(self):
        view = self.tree.get_viewtree(refresh=True)
        node = self.tree.get_node('13')
        node3 = self.tree.get_node('3')
        node.add_parent('9')
        node.add_parent('10')
#        self.mainview.print_tree(string=False)
        self.tree.del_node('3')
        self.failIf(self.tree.has_node('3'))
#        self.mainview.print_tree(string=False)
        self.tree.add_node(node3,parent_id='13')
        self.assertEqual(len(view.get_paths_for_node('3')),3)
        self.tree.del_node('3')
        self.tree.move_node('4','13')
        self.assertEqual(len(view.get_paths_for_node('4')),3)
        
        
    def test_recursive_removing_parent(self):
        """Test behavior of node when its parent goes away.

        When you remove a parent recursively, all the children
        are also removed !
        """
        view = self.tree.get_viewtree(refresh=True)
        node = DummyNode('temp')
        node.add_color('blue')
        self.tree.add_node(node,parent_id='0')
        all_nodes = self.view.get_all_nodes()
        self.assert_('0' in all_nodes)
        self.assert_('temp' in all_nodes)
#        print "nothing before the deletion", self.recorded_signals['node-deleted-inview']
        self.assertSignal(self.view, \
                          'node-deleted-inview', \
                          self.tree.del_node, 1)('0', recursive = True)
#        print "A lot of deleted signals", self.recorded_signals['node-deleted-inview']
        self.assert_(('temp',(0, 0)) in self.recorded_signals['node-deleted-inview'])
        #FIXME : the deleted path is not necesarly the one given
#        self.assert_(('0',(0,)) in self.recorded_signals['node-deleted-inview'])
        all_nodes = self.view.get_all_nodes()
        self.failIf('0' in all_nodes)
        self.failIf('temp' in all_nodes)

    def test_move_node(self):
        """Test node movement from parents.

        Check that node can be moved from one node to another,
        and to root.  When moved to root, verify it has no parents.
        """
        view = self.tree.get_viewtree(refresh=True)
        node = DummyNode('temp')
        node.add_color('blue')
        self.tree.add_node(node,parent_id='0')
        #Testing initial situation
        self.assert_(view.node_has_child('0'))
        self.assert_('temp' in view.node_all_children('0'))
        self.assert_('temp' not in view.node_all_children('1'))
        #Moving node
        self.assertSignal(self.view, \
                          'node-modified-inview', \
                          self.tree.move_node, 2)('temp','1')
#        self.assert_(('0',(0,)) in self.recorded_signals['node-modified-inview'])
        self.assert_(('1',(1,)) in self.recorded_signals['node-modified-inview'])
        self.assert_(view.node_has_child('1'))
        self.assert_('temp' in view.node_all_children('1'))
        self.assert_('temp' not in view.node_all_children('0'))
        #Now moving to root
        self.tree.move_node('temp')
        self.assert_('temp' not in view.node_all_children('1'))
        self.assert_('temp' not in view.node_all_children('0'))
        #temp still exist and doesn't have any parents
        all_nodes = self.mainview.get_all_nodes()
        self.assert_('temp' in all_nodes)
        self.assertEqual(0,len(self.mainview.node_parents('temp')))

    def test_add_parent(self):
        """Test that a node can have two parents.

        Verify that when a node with a parent gets a second parent, 
        the node can be found in both parent nodes.
        """
        view = self.tree.get_viewtree(refresh = True)
        node = DummyNode('temp')
        node.add_color('blue')
        self.assertSignal(self.view, \
                          'node-modified-inview', \
                          self.tree.add_node, 1)(node, parent_id = '0')
        #Not checking temp. Indeed, it has been added, so there should not 
        #be any modified signal
        self.assert_(('0',(0,)) in self.recorded_signals['node-modified-inview'])
        #Testing initial situation
        self.assert_(view.node_has_child('0'))
        self.assert_('temp' in view.node_all_children('0'))
        self.assert_('temp' not in view.node_all_children('1'))
        #Adding another parent
        self.assertSignal(self.view, \
                          'node-modified-inview', \
                          self.tree.add_parent, 1)('temp','1')
        self.assert_(('1',(1,)) in self.recorded_signals['node-modified-inview'])
        self.assert_(view.node_has_child('1'))
        self.assert_('temp' in view.node_all_children('1'))
        self.assert_('temp' in view.node_all_children('0'))
    
    #we try to add a task as a child of one of its grand-children.
    #Nothing should happen

    def test_cyclic_paradox(self):
        """Try to add a node as a child of one of its grand-children."""
        node = DummyNode('temp')
        node.add_color('blue')
        self.tree.add_node(node,parent_id='0')
        self.tree.add_parent('0','1')
        self.assert_('1' in self.mainview.node_parents('0'))
        self.assert_('0' in self.mainview.node_parents('temp'))
        #direct circular relationship
        self.assertRaises(Exception,self.tree.add_parent,'0','temp')
        #More complex circular relationship
        self.assertRaises(Exception,self.tree.add_parent,'1','temp')
        
    def test_mainview(self):
        """Verify mainview behavior

        Test that mainview is always up-to-date and raise exception when
        trying to add filters on it
        """
        self.assertRaises(Exception,self.mainview.apply_filter,'blue')
        
    #### Testing each method of the ViewTree
    
    ### Testing each method of the TreeView
    def test_viewtree_get_n_nodes(self):
        """ Test get_n_nodes() method of TreeView

        Check that retrieving counts of nodes with various filters returns
        the expected collections.
        """
        total = self.red_nodes + self.blue_nodes + self.green_nodes
        self.assertEqual(total,self.view.get_n_nodes())
        self.assertEqual(self.green_nodes,self.view.get_n_nodes(withfilters=['green']))
        self.assertEqual(total,self.mainview.get_n_nodes())
        
    def test_viewtree_get_n_nodes_with_cache(self):
        '''Testing the cache of the get_n_nodes'''
        nbr = self.green_nodes
        self.assertEqual(nbr,self.mainview.get_n_nodes(\
                            withfilters=['green'],include_transparent=False))
        node = self.tree.get_node('0')
        node.add_color('green')
        
        self.assertEqual(nbr+1,self.mainview.get_n_nodes(\
                            withfilters=['green'],include_transparent=False))
        node.remove_color('green')
        self.assertEqual(nbr,self.mainview.get_n_nodes(\
                            withfilters=['green'],include_transparent=False))
    
    def test_viewtree_get_all_nodes(self):
        all_nodes = self.view.get_all_nodes()
        all_nodes2 = self.mainview.get_all_nodes()
        self.assertEqual(True,'0' in all_nodes)
        self.assertEqual(False,'tmp' in all_nodes)
        self.assertEqual(self.total,len(all_nodes))
        #Mainview
        self.assertEqual(True,'0' in all_nodes2)
        self.assertEqual(False,'tmp' in all_nodes2)
        self.assertEqual(self.total,len(all_nodes2))
        #adding a node
        node = DummyNode('temp')
        node.add_color('blue')
        self.tree.add_node(node,parent_id=str(0))
        all_nodes = self.view.get_all_nodes()
        all_nodes2 = self.mainview.get_all_nodes()
        self.assert_('0' in all_nodes)
        self.assert_('temp' in all_nodes)
        self.assertEqual(self.total+1,len(all_nodes))
        #Mainview
        self.assert_('0' in all_nodes2)
        self.assert_('temp' in all_nodes2)
        self.assertEqual(self.total+1,len(all_nodes2))
        #Removing the node
        self.tree.del_node('1')
        all_nodes = self.view.get_all_nodes()
        all_nodes2 = self.mainview.get_all_nodes()
        self.failIf('1' in all_nodes)
        self.assert_('temp' in all_nodes)
        self.assertEqual(self.total,len(all_nodes))
        #mainview
        self.failIf('1' in all_nodes2)
        self.assert_('temp' in all_nodes2)
        self.assertEqual(self.total,len(all_nodes2))
        
        
    def test_viewtree_get_node_for_path(self):
        view = self.tree.get_viewtree(refresh=True)
        #nid1 and nid2 are not always the same
        nid1 = view.get_node_for_path((0,))
        nid2 = self.mainview.get_node_for_path((0,))
        self.assert_(nid1 != None)
        self.assert_(nid2 != None)
        #Thus we do a mix of test.
        nid1b = view.next_node(nid1)
        path1b = view.get_paths_for_node(nid1b)
        self.assertEqual([(1,)],path1b)
        #same for mainview
        nid2b = self.mainview.next_node(nid2)
        path2b = self.mainview.get_paths_for_node(nid2b)
        self.assertEqual([(1,)],path2b)
        #with children
        node = DummyNode('temp')
        node.add_color('blue')
        self.tree.add_node(node,parent_id=nid1)
        self.tree.add_parent('temp',nid2)
        self. assertEqual('temp',view.get_node_for_path((0,0)))
        self. assertEqual('temp',self.mainview.get_node_for_path((0,0)))
        #Adding a child to the child
        node2 = DummyNode('temp2')
        node2.add_color('blue')
        self.tree.add_node(node2,parent_id=nid1)
        node = DummyNode('temp_child')
        node.add_color('blue')
        self.tree.add_node(node,parent_id='temp2')
        self.assertEqual('temp_child',view.get_node_for_path((0,1,0)))
        self.tree.add_parent('temp2',nid2)
        self.assertEqual('temp_child',self.mainview.get_node_for_path((0,1,0)))
        #with filters
        view.apply_filter('blue')
        pl = view.get_paths_for_node('temp2')
        for p in pl:
            pp = p + (0,)
            self.assertEqual('temp_child',view.get_node_for_path(pp))
        
    def test_viewtree_get_paths_for_node(self):
        view = self.tree.get_viewtree(refresh=True)
        #testing the root path
        self.assertEqual([()],view.get_paths_for_node())
        self.assertEqual([()],self.mainview.get_paths_for_node())
        #with children
        #the first blue node is:
        firstgreen = self.red_nodes + self.blue_nodes - 1
        pp = view.get_paths_for_node(str(firstgreen))[0]
        i = 0
        #Testing all the green nodes (that are in stairs)
        while i < self.green_nodes:
            returned = view.get_paths_for_node(str(firstgreen+i))[0]
            self.assertEqual(pp,returned)
            i+=1
            pp += (0,)
        #with filters
        view.apply_filter('green')
        pp = view.get_paths_for_node(str(firstgreen+1))[0]
        i = 1
        #Testing all the green nodes (that are in stairs)
        while i < self.green_nodes:
            returned = view.get_paths_for_node(str(firstgreen+i))[0]
            self.assertEqual(pp,returned)
            i+=1
            pp += (0,)
        
    def test_viewtree_next_node(self):
        view = self.tree.get_viewtree(refresh=True)
        """Test next_node() for TreeView.

        Add two nodes to a parent, then verify various ways of looking
        at the next node in the parent's list.
        """
        node = DummyNode('temp')
        node.add_color('blue')
        node.add_color('green')
        self.tree.add_node(node,parent_id='0')
        view = self.tree.get_viewtree(refresh=True)
        node = DummyNode('temp2')
        node.add_color('red')
        self.tree.add_node(node,parent_id='0')
        #we give the pid
        self.assertEqual('temp2',view.next_node('temp',pid='0'))
        self.assertEqual('temp2',self.mainview.next_node('temp',pid='0'))
        #or we give not (should be the same here because only one parent)
        self.assertEqual('temp2',view.next_node('temp'))
        self.assertEqual('temp2',self.mainview.next_node('temp'))
        #next node for last node.
        self.assertEqual(None,view.next_node('temp2'))
        self.assertEqual(None,self.mainview.next_node('temp2'))
        #with filters, temp should not have any next node
        view.apply_filter('blue',refresh=False)
        view.apply_filter('green')
        self.assertEqual(None,view.next_node('temp'))

    def test_viewtree_node_has_child(self):
        view = self.tree.get_viewtree(refresh=True)
        """Test node_has_child() for TreeView

        Verify that TreeView's node_n_children()'s return changes after
        a node is added to an empty TreeView instance.
        """
        node = DummyNode('temp')
        node.add_color('blue')
        self.failIf(view.node_has_child('0'))
        self.failIf(self.mainview.node_has_child('0'))
        #Adding the node to the tree
        self.tree.add_node(node,parent_id='0')
        self.assert_(view.node_has_child('0'))
        self.assert_(self.mainview.node_has_child('0'))
    
    def test_viewtree_node_all_children(self):
        view = self.tree.get_viewtree(refresh=True)
        self.assertEqual(0,len(view.node_all_children('0')))
        """Test node_all_children() for TreeView.

        We also test node_n_children here. Nearly the same method.
        """
        #checking that 0 and 1 are in root
        self.assert_('0' in view.node_all_children())
        self.assert_('1' in view.node_all_children())
        self.assert_('0' in self.mainview.node_all_children())
        self.assert_('1' in self.mainview.node_all_children())
        node = DummyNode('temp')
        node.add_color('blue')
        #adding a new children
        self.tree.add_node(node,parent_id='0')
        self.assertEqual(1,view.node_n_children('0'))
        self.assert_('temp' in view.node_all_children('0'))
        self.assertEqual(1,self.mainview.node_n_children('0'))
        self.assert_('temp' in self.mainview.node_all_children('0'))
        #Testing with a filter
        view.apply_filter('red')
        self.failIf('temp' in view.node_all_children('0'))
        view.unapply_filter('red')
        #moving an existing children
        self.tree.move_node('1','0')
        self.assertEqual(2,view.node_n_children('0'))
        self.assert_('1' in view.node_all_children('0'))
        self.failIf('1' in view.node_all_children())
        self.assertEqual(2,self.mainview.node_n_children('0'))
        self.assert_('1' in self.mainview.node_all_children('0'))
        self.failIf('1' in self.mainview.node_all_children())
        #removing a node
        self.tree.del_node('temp')
        self.assertEqual(1,view.node_n_children('0'))
        self.failIf('temp' in view.node_all_children('0'))
        self.assertEqual(1,self.mainview.node_n_children('0'))
        self.failIf('temp' in self.mainview.node_all_children('0'))
        #moving a node elsewhere
        self.tree.move_node('1')
        self.assertEqual(0,view.node_n_children('0'))
        self.failIf('1' in view.node_all_children('0'))
        self.assertEqual(0,self.mainview.node_n_children('0'))
        self.failIf('1' in self.mainview.node_all_children('0'))
        #checking that '1' is back in root
        self.assert_('1' in view.node_all_children())
        self.assert_('1' in self.mainview.node_all_children())
        
    def test_viewtree_node_nth_child(self):
        """Test node_nth_child() for TreeView.

        Verify that when retrieving a given child node, that it is
        returned, except when requesting a node not in the tree or that
        is not present due being filtered out.
        """
        view = self.tree.get_viewtree(refresh=True)
        node = DummyNode('temp')
        node.add_color('blue')
        #Asking for a child that doesn't exist should raise an exception
        self.assertRaises(ValueError,view.node_nth_child,'0',0)
        self.assertRaises(ValueError,self.mainview.node_nth_child,'0',0)
        #Adding the node to the tree
        self.tree.add_node(node,parent_id='0')
        self.assertEqual('temp',view.node_nth_child('0',0))
        self.assertEqual('temp',self.mainview.node_nth_child('0',0))
        #Now with a filter
        view.apply_filter('red')
        self.assertRaises(ValueError,view.node_nth_child,'0',0)
        
        
    def test_viewtree_node_parents(self):
        view = self.tree.get_viewtree(refresh=True)
        """Test node_parents() for TreeView.

        Verify that a node's parents can be retrieved, if it has any.
        Check that if a node has multiple parents, that both parents are
        returned.
        """
        #Checking that a node at the root has no parents
        self.assertEqual([],view.node_parents('0'))
        self.assertEqual([],self.mainview.node_parents('0'))
        #Adding a child
        node = DummyNode('temp')
        node.add_color('blue')
        self.tree.add_node(node,parent_id='0')
        self.assertEqual(['0'],view.node_parents('temp'))
        self.assertEqual(['0'],self.mainview.node_parents('temp'))
        #adding a second node.add_child('0')parent
        self.tree.add_parent('temp','1')
        self.assertEqual(['0','1'],view.node_parents('temp'))
        self.assertEqual(['0','1'],self.mainview.node_parents('temp'))
        #now with a filter
        view.apply_filter('blue')
        self.assertEqual([],view.node_parents('temp'))
        #if the node is not displayed, asking for parents will raise an error
        view.unapply_filter('blue')
        view.apply_filter('red')
        self.assertRaises(IndexError,view.node_parents,'temp')
        

    def test_viewtree_is_displayed(self):
        view = self.tree.get_viewtree(refresh=True)
        """Test is_displayed() for TreeView.

        Verify that a node is shown as displayed once it's been added
        to the tree, but not if an active filter should be hiding it.
        """
        node = DummyNode('temp')
        node.add_color('blue')
        self.failIf(view.is_displayed('temp'))
        self.failIf(self.mainview.is_displayed('temp'))
        #Adding the node to the tree
        self.tree.add_node(node,parent_id='0')
        self.assert_(view.is_displayed('temp'))
        self.assert_(self.mainview.is_displayed('temp'))
        view.apply_filter('blue')
        self.assert_(view.is_displayed('temp'))
        view.apply_filter('red')
        self.failIf(view.is_displayed('temp'))





############ Filters

    def test_simple_filter(self):
        view = self.tree.get_viewtree(refresh=False)
        test = TreeTester(view)
        """Test use of filters to restrict nodes shown.

        When the 'red' filter is applied, only nodes with the 'red' color
        should be returned.  Applying the 'blue' filter on top of that should
        result in no nodes, since there are no nodes with both 'red' and 'blue'.

        When two filters are applied, and the second one is removed, the
        result should be the same as if only the first one had been applied.

        When a node gains a color, check that it is filtered appropriately.

        When a displayed node is added to a non-displayed parent, it
        should still be displayed.
        """
        view.apply_filter('red')
        test.test_validity()
        self.assertEqual(self.red_nodes,view.get_n_nodes())
        self.assertEqual(self.red_nodes,view.get_n_nodes(withfilters=['red']))
        self.assertEqual(0,view.get_n_nodes(withfilters=['blue']))
        #Red nodes are all at the root
        self.assertEqual(self.red_nodes,view.node_n_children())
        #applying another filter
        view.apply_filter('green')
        test.test_validity()
        self.assertEqual(0,view.get_n_nodes())
        #unapplying the first filter
        view.unapply_filter('red')
        test.test_validity()
        self.assertEqual(self.green_nodes,view.get_n_nodes())
        self.assertEqual(self.green_nodes,view.get_n_nodes(withfilters=['green']))
        self.assertEqual(0,view.get_n_nodes(withfilters=['red']))
        #There's only one green node at the root
        self.assertEqual(1,view.node_n_children())
        #Modifying a node to make it red and green
        self.failIf(view.is_displayed('0'))
        node = view.get_node('0')
        node.add_color('green')
        #It should now be in the view
        self.assert_(view.is_displayed('0'))
        self.assertEqual(1,view.get_n_nodes(withfilters=['red']))
        self.assertEqual(2,view.node_n_children())
        #Now, we add a new node
        node = DummyNode('temp')
        node.add_color('green')
        self.tree.add_node(node)
        test.test_validity()
        #It should now be in the view
        self.assert_(view.is_displayed('temp'))
        self.assertEqual(3,view.node_n_children())
        #We remove it
        self.tree.del_node('temp')
        test.test_validity()
        self.failIf(view.is_displayed('temp'))
        self.assertEqual(2,view.node_n_children())
        #We add it again as a children of a non-displayed node
        self.tree.add_node(node,parent_id='1')
        test.test_validity()
        self.assert_(view.is_displayed('temp'))
        self.assertEqual(3,view.node_n_children())
        #It should not have parent
        self.assertEqual(0,len(view.node_parents('temp')))

    def test_leaf_filter(self):
        view = self.tree.get_viewtree(refresh=False)
        test = TreeTester(view)
        """Test filtering to show only the leaf nodes.

        When the 'leaf' filter is applied and a child added to a node,
        the parent node should not be present in the results.
        """
        view.apply_filter('leaf')
        total = self.red_nodes + self.blue_nodes
        self.assertEqual(total,view.get_n_nodes())
        view.apply_filter('green')
        self.assertEqual(1,view.get_n_nodes())
        nid = view.get_node_for_path((0,))
        #Now, we add a new node
        node = DummyNode('temp')
        node.add_color('green')
        self.tree.add_node(node,parent_id=nid)
        self.assertEqual(1,view.get_n_nodes())
        nid = view.get_node_for_path((0,))
        self.assertEqual('temp',nid)
        test.test_validity()

    #we copy/paste the test
    def test_flatleaves_filters(self):
        """We apply a leaves + flat filter and the result
        should be the same as a simple leaf filter.
        """
        view = self.tree.get_viewtree(refresh=False)
        test = TreeTester(view)
        view.apply_filter('flatleaves')
        total = self.red_nodes + self.blue_nodes
        self.assertEqual(total,view.get_n_nodes())
        view.apply_filter('green')
        self.assertEqual(1,view.get_n_nodes())
        nid = view.get_node_for_path((0,))
        #Now, we add a new node
        node = DummyNode('temp')
        node.add_color('green')
        self.tree.add_node(node,parent_id=nid)
        self.assertEqual(1,view.get_n_nodes())
        nid = view.get_node_for_path((0,))
        self.assertEqual('temp',nid)
        test.test_validity()
        
    #green are stairs
    #the flat filter should make them flat
    def test_flat_filters(self):
        """Test a flat filter.
        
        Green nodes are in "stairs" (each one being the child of another)
        By applying a filter with the flat properties, we test that
        all the nodes are now seen "flately".
        """
        view = self.tree.get_viewtree(refresh=False)
        test = TreeTester(view)
        view.apply_filter('flatgreen')
        #all green nodes should be visibles
        self.assertEqual(self.green_nodes,view.get_n_nodes())
        i = 0
        nodes = []
        #we check that the paths are on the root
        while i < self.green_nodes:
            nid = view.get_node_for_path((i,))
            nodes.append(nid)
            self.failIf(nid == None)
            #let see if a node has parent
            self.failIf(view.node_has_parent(nid))
            #and, of course, it cannot have children
            self.failIf(view.node_has_child(nid))
            i += 1
        #we check that we have seen all the nodes
        i = 1
        while i <= self.green_nodes :
            self.assert_(str(self.total-i) in nodes)
            i += 1
        test.test_validity()
        
    def test_transparent_filters(self):
        view = self.tree.get_viewtree(refresh=False)
        test = TreeTester(view)
        """Test excluding transparent filters

        Filters marked with the 'transparent' property should apply in get_n_nodes()
        normally, but can be turned off via the include_transparent parameter.
        """
        view.apply_filter('transgreen')
        self.assertEqual(self.green_nodes,view.get_n_nodes())
        self.assertEqual(self.total,view.get_n_nodes(include_transparent=False))
        #Now with filters in the counting
        count1 = view.get_n_nodes(withfilters=['transblue'])
        count2 = view.get_n_nodes(withfilters=['transblue'],\
                                                    include_transparent=False)
        self.assertEqual(0,count1)
        self.assertEqual(self.blue_nodes,count2)
        test.test_validity()

    def test_view_signals(self):
        view = self.tree.get_viewtree(refresh = True)
        
    def test_update_callback(self):
        '''We test the update callbacks and we check that the path
            received is well corresponding to the nid received'''
        def check_path(nid,path,state_id):
            self.assertEqual(view.get_node_for_path(path),nid)
            self.assert_(path in view.get_paths_for_node(nid))
        view = self.tree.get_viewtree(refresh=False)
        test = TreeTester(view)
        view.register_cllbck('node-modified-inview',check_path)
        view.register_cllbck('node-added-inview',check_path)
        view.apply_filter('leaf')
        view.unapply_filter('leaf')
        test.test_validity()
        
    def test_torture(self):
        '''This is a torture test, where we will do whatever
        we want in random order.
        '''
        view = self.tree.get_viewtree(refresh = False)
        test = TreeTester(view)
        view.reset_filters(refresh=True)
        node = DummyNode('parent')
        node.add_child('1')
        node.add_child('3')
        node.add_child('5')
        node.add_child('7')
        node.add_child('9')
        node.add_child('11')
        self.assertFalse(view.is_displayed('parent'))
        print "################"
        self.tree.add_node(node)
        print "#$$$$$$$$$$$$$$"
        test.test_validity()
        self.assertEqual(view.node_n_children('parent'),6)
        view.apply_filter('blue')
        test.test_validity()
        self.assertFalse(view.is_displayed('parent'))
#        print view.print_tree(string=True)
        node.add_color('blue')
        test.test_validity()
        self.assertEqual(view.node_n_children('parent'),3)
        
    def test_copypasting_child(self):
        view = self.tree.get_viewtree(refresh = False)
        test = TreeTester(view)
        view.apply_filter('green')
        node = DummyNode('child')
        node.add_color('green')
        node1 = DummyNode('child2')
        node1.add_color('green')
        node2 = DummyNode('parent')
        node2.add_color('green')
        self.tree.add_node(node2)
        self.tree.add_node(node,parent_id='10')
        self.tree.add_node(node1,parent_id='10')
        #We copy paste 'child' into 'parent'
        node2.add_child('child')
        test.test_validity()

    def test_speed(self):
        '''
        Performance tests. Patches that reduce performance too much are not
        acceptable
        '''
        self.tester.quit()
        BIG_NUMBER = 100 #FIXME: deleting 200 nodes takes too long
        view = self.tree.get_viewtree(refresh = False)
        nodes_id = []
        start = time.time()
        for index in xrange(BIG_NUMBER):
            node = DummyNode("stress" + str(index))
            nodes_id.append(node.get_id())
            self.tree.add_node(node)
        end = time.time()
        print "\nADDING %d NODES: %f" % (BIG_NUMBER, end - start)

        start = time.time()
        for node_id in nodes_id:
            self.tree.refresh_node(node_id)
        end = time.time()
        print "\nUPDATING %d NODES: %f" % (BIG_NUMBER, end - start)

        start = time.time()
        for node_id in nodes_id:
            self.tree.del_node(node_id)
        end = time.time()
        print "\nDELETING %d NODES: %f" % (BIG_NUMBER, end - start)