gump-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From leosim...@apache.org
Subject svn commit: r216018 - in /gump/branches/Gump3/pygump/python/gump: engine/verifier.py test/testEngineVerifier.py
Date Tue, 12 Jul 2005 21:11:01 GMT
Author: leosimons
Date: Tue Jul 12 14:11:00 2005
New Revision: 216018

URL: http://svn.apache.org/viewcvs?rev=216018&view=rev
Log:
100% coverage for the verifier and fix it to report on all cycles (fix for GUMP-94).

Modified:
    gump/branches/Gump3/pygump/python/gump/engine/verifier.py
    gump/branches/Gump3/pygump/python/gump/test/testEngineVerifier.py

Modified: gump/branches/Gump3/pygump/python/gump/engine/verifier.py
URL: http://svn.apache.org/viewcvs/gump/branches/Gump3/pygump/python/gump/engine/verifier.py?rev=216018&r1=216017&r2=216018&view=diff
==============================================================================
--- gump/branches/Gump3/pygump/python/gump/engine/verifier.py (original)
+++ gump/branches/Gump3/pygump/python/gump/engine/verifier.py Tue Jul 12 14:11:00 2005
@@ -44,15 +44,14 @@
     pass
 
 def print_cyclic_trace(cycles, handler):
-    for cycle in cycles: # isn't there a level of nesting too much here???
-        for chain in cycle:
-            msg = ""
-            indent = "  "
-            for project in chain:
-                msg += "%s%s -->\n" % (indent, project.name)
-                indent += "  "
-            msg = ansicolor.Bright_Red + msg[:-5] + ansicolor.Black
-            handler(msg)
+    for chain in cycles:
+        msg = ""
+        indent = "  "
+        for project in chain:
+            msg += "%s%s -->\n" % (indent, project.name)
+            indent += "  "
+        msg = ansicolor.Bright_Red + msg[:-5] + ansicolor.Black
+        handler(msg)
     
 class AbstractErrorHandler:
     """Base class for supporting configurable error recovery. Instead of
@@ -79,7 +78,7 @@
     def handleError(self):
         errorType = sys.exc_info()[0]
         if errorType is CyclicDependencyError:
-            errorValue = sys.exc_info()[1]
+            errorValue = sys.exc_info()[1][0]
             self.log.error("The following cyclic dependencies were found:")
             print_cyclic_trace(errorValue, self.log.error)
             self.log.error("The projects involved will not be built!")
@@ -96,6 +95,8 @@
     def __init__(self, walker, errorHandler=AbstractErrorHandler()):
         assert hasattr(walker, "walk")
         assert callable(walker.walk)
+        assert hasattr(errorHandler, "_handleError")
+        assert callable(errorHandler._handleError)
         
         self.walker = walker
         self.errorHandler = errorHandler
@@ -160,10 +161,12 @@
             stack.append(dependency)
             if dependency == needle: # cycle involving needle!
                 cycles.append(stack[:])
-                visited.append(dependency)
+                # no need for this, its already in there visited.append(dependency)
             else:
                 if not dependency in visited:
-                    self._visit(dependency,visited,stack,needle,cycles)
+                    # note we duplicate the visited[] array here. There may be
+                    # multiple cycles involving this project. We want them all.
+                    self._visit(dependency,visited[:],stack,needle,cycles)
 
             stack.pop() # get rid of this dependency, we'll be looking
                         # at the next dependency in the next iteration of

Modified: gump/branches/Gump3/pygump/python/gump/test/testEngineVerifier.py
URL: http://svn.apache.org/viewcvs/gump/branches/Gump3/pygump/python/gump/test/testEngineVerifier.py?rev=216018&r1=216017&r2=216018&view=diff
==============================================================================
--- gump/branches/Gump3/pygump/python/gump/test/testEngineVerifier.py (original)
+++ gump/branches/Gump3/pygump/python/gump/test/testEngineVerifier.py Tue Jul 12 14:11:00
2005
@@ -22,12 +22,249 @@
 import unittest
 from pmock import *
 
-from gump.engine.verifier import *
+from gump.engine.verifier import VerificationError
+from gump.engine.verifier import CyclicDependencyError
+from gump.engine.verifier import print_cyclic_trace
+from gump.engine.verifier import AbstractErrorHandler
+from gump.engine.verifier import LoggingErrorHandler
+from gump.engine.verifier import Verifier
+
+class Project:
+    def __init__(self, name):
+        self.name = name
+        self.dependencies = []
+    
+    def __str__(self):
+        return "project:%s" % self.name
+
+class Relationship:
+    def __init__(self, project):
+        self.dependency = project
+
+    def __rel__(self):
+        return "relationship:dependency=%s" % self.dependency
+
+class MyError(Exception):
+    pass
+    
+counter = 0
+def p():
+    global counter
+    counter = counter + 1
+    return Project("project_%s" % counter)
+        
+def r(p):
+    return Relationship(p)
 
 class EngineVerifierTestCase(MockTestCase):
     def setUp(self):
-        pass
+        self.walker = self.mock()
+        self.walker.stubs().method("walk")
+        self.handler = self.mock()
+        self.handler.stubs().method("_handleError")
     
-    def test_something(self):
-        # TODO replace with something useful
-        pass
+    def test_VerificationError(self):
+        e = VerificationError()
+        
+    def test_CyclicDependencyError(self):
+        e = CyclicDependencyError()
+        
+    def test_print_cyclic_trace(self):
+        def handler(msg):
+            pass
+        
+        cycles = []
+        p1 = p()
+        p2 = p()
+        cycles.append([p1, p(), p(), p1])
+        cycles.append([p2, p(), p(), p(), p(), p(), p2])
+        print_cyclic_trace(cycles, handler)
+        
+        
+    def test_AbstractErrorHandler(self):
+        called = []
+        def handleError(called=called):
+            called.append(1)
+        
+        e = AbstractErrorHandler()
+        e.handleError = handleError
+        e._handleError()
+        self.failUnless(len(called) == 1)
+        
+        e = AbstractErrorHandler()
+        try:
+            raise MyError, "problem"
+        except:
+            try:
+                e._handleError()
+                self.fail("Exception swallowed")
+            except MyError:
+                pass
+
+            
+    def test_LoggingErrorHandler(self):
+        log = self.mock()
+        log.expects(at_least_once()).method("error")
+        
+        e = LoggingErrorHandler(log)
+        cycles = []
+        cycle = []
+        cycle.append(Project("a"))
+        cycle.append(Project("b"))
+        cycles.append(cycle)
+        
+        try:
+            raise CyclicDependencyError, cycles
+        except:
+            e._handleError()
+
+        try:
+            raise MyError, "problem"
+        except:
+            try:
+                e._handleError()
+                self.fail("Exception swallowed")
+            except MyError:
+                pass
+
+    def test_Verifier__init__(self):
+        v = Verifier(self.walker, self.handler)
+        self.assertEqual(self.walker, v.walker)
+        self.assertEqual(self.handler, v.errorHandler)
+        self.assertRaises(AssertionError, Verifier, None, self.handler)
+        self.assertRaises(AssertionError, Verifier, self.walker, None)
+        
+    def test_Verifier_verify(self):
+        v = Verifier(self.walker, self.handler)
+        
+        p1 = p()
+        p2 = p()
+        p3 = p()
+        p4 = p()
+        p5 = p()
+        p6 = p()
+        p7 = p()
+        p8 = p()
+        p9 = p()
+        p10 = p()
+
+        p1.dependencies.append(r(p2))
+        p1.dependencies.append(r(p3))
+        #p1.dependencies.append(r(p4))
+        p1.dependencies.append(r(p5))
+        p1.dependencies.append(r(p6))
+
+        #p2.dependencies.append(r(p3))
+        #p2.dependencies.append(r(p4))
+        p2.dependencies.append(r(p5))
+        p2.dependencies.append(r(p6))
+
+        #p3.dependencies.append(r(p3))
+        p3.dependencies.append(r(p4))
+        p3.dependencies.append(r(p5))
+        p3.dependencies.append(r(p6))
+        #p3.dependencies.append(r(p7))
+        p3.dependencies.append(r(p8))
+        p3.dependencies.append(r(p9))
+        #p3.dependencies.append(r(p10))
+
+        p4.dependencies.append(r(p5))
+        p4.dependencies.append(r(p6))
+        p4.dependencies.append(r(p7))
+        p4.dependencies.append(r(p8))
+        p4.dependencies.append(r(p9))
+        #p4.dependencies.append(r(p10))
+
+        p7.dependencies.append(r(p8))
+        p7.dependencies.append(r(p9))
+        p7.dependencies.append(r(p10))
+
+        visited = []
+        project = p1
+        stack = [p1]
+        needle = p1
+        cycles = []
+        
+        # first we test the internal _visit()
+        v._visit(project,visited,stack,needle,cycles)
+        self.assertEqual(len(cycles), 0)
+        
+        # introduce a cycle
+        p10.dependencies.append(r(p1))
+        visited = []
+        project = p1
+        stack = [p1]
+        needle = p1
+        cycles = []
+        
+        v._visit(project,visited,stack,needle,cycles)
+        self.assertEqual(len(cycles), 1)
+        cycle = cycles[0]
+        self.assertEqual(p1,cycle[0])
+        self.assertEqual(p3,cycle[1])
+        self.assertEqual(p4,cycle[2])
+        self.assertEqual(p7,cycle[3])
+        self.assertEqual(p10,cycle[4])
+        self.assertEqual(p1,cycle[5])
+
+        # introduce more cycles, and more complex ones
+        p2.dependencies.append(r(p1))
+        p3.dependencies.append(r(p1))
+        p2.dependencies.append(r(p3))
+        visited = []
+        project = p1
+        stack = [p1]
+        needle = p1
+        cycles = []
+        
+        v._visit(project,visited,stack,needle,cycles)
+        self.assertEqual(len(cycles), 5)
+
+        # now test _find_cycles method
+        projects = [p1, p2, p3, p4, p7, p10]
+        
+        # behaviour manually verified as being correct on Jul 12
+        #def handler(msg):
+            #print msg
+        #print_cyclic_trace(v._find_cycles(projects), handler)
+        self.assertEqual(len(v._find_cycles(projects)), 18)
+        
+        # finally, the sugared up verify...
+        walker = self.mock()
+        # (visited_repositories, visited_modules, visited_projects) = self.walker.walk(workspace,
visitor)
+        walker.expects(at_least_once()).method("walk").will(return_value((None, None, [p5,
p6, p8, p9])))
+        
+        handler = self.mock()
+        handler.expects(once()).method("_handleError").will(raise_exception(CyclicDependencyError))
+        
+        class Workspace:
+            projects = {"p1": p1,
+                        "p2": p2,
+                        "p3": p3,
+                        "p4": p4,
+                        "p5": p5,
+                        "p6": p6,
+                        "p7": p7,
+                        "p8": p8,
+                        "p9": p9,
+                        "p10": p10}
+            cycles = []
+            unvisited = []
+        
+        w = Workspace()
+        
+        v = Verifier(walker, handler)
+        self.assertRaises(CyclicDependencyError, v.verify, w)
+        self.assertEqual(len(w.cycles), 18)
+        self.assertEqual(len(w.unvisited), 6)
+        self.assertEqual(len(w.unvisited), 6)
+        
+        v = Verifier(walker, self.handler)
+        w = Workspace()
+        w.projects = {"p5": p5,
+                        "p6": p6,
+                        "p8": p8,
+                        "p9": p9}
+        v.verify(w)
+        self.assertEqual(len(w.cycles), 0)
+        self.assertEqual(len(w.unvisited), 0)



Mime
View raw message