More refactorings to migrate logic from TestBase to its parent class.


git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@136641 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/lldbtest.py b/test/lldbtest.py
index fc1b994..4b073c5 100644
--- a/test/lldbtest.py
+++ b/test/lldbtest.py
@@ -380,6 +380,10 @@
     # Keep track of the old current working directory.
     oldcwd = None
 
+    def TraceOn(self):
+        """Returns True if we are in trace mode (tracing detailed test execution)."""
+        return traceAlways
+
     @classmethod
     def setUpClass(cls):
         """
@@ -440,7 +444,10 @@
             return True
 
     def setUp(self):
-        """Works with the test driver to conditionally skip tests."""
+        """Fixture for unittest test case setup.
+
+        It works with the test driver to conditionally skip tests and does other
+        initializations."""
         #import traceback
         #traceback.print_stack()
 
@@ -470,6 +477,255 @@
         except AttributeError:
             pass
 
+        # These are for customized teardown cleanup.
+        self.dict = None
+        self.doTearDownCleanup = False
+        # And in rare cases where there are multiple teardown cleanups.
+        self.dicts = []
+        self.doTearDownCleanups = False
+
+        # Create a string buffer to record the session info, to be dumped into a
+        # test case specific file if test failure is encountered.
+        self.session = StringIO.StringIO()
+
+        # Optimistically set __errored__, __failed__, __expected__ to False
+        # initially.  If the test errored/failed, the session info
+        # (self.session) is then dumped into a session specific file for
+        # diagnosis.
+        self.__errored__    = False
+        self.__failed__     = False
+        self.__expected__   = False
+        # We are also interested in unexpected success.
+        self.__unexpected__ = False
+
+        # See addTearDownHook(self, hook) which allows the client to add a hook
+        # function to be run during tearDown() time.
+        self.hooks = []
+
+        # See HideStdout(self).
+        self.sys_stdout_hidden = False
+
+    def HideStdout(self):
+        """Hide output to stdout from the user.
+
+        During test execution, there might be cases where we don't want to show the
+        standard output to the user.  For example,
+
+            self.runCmd(r'''sc print "\n\n\tHello!\n"''')
+
+        tests whether command abbreviation for 'script' works or not.  There is no
+        need to show the 'Hello' output to the user as long as the 'script' command
+        succeeds and we are not in TraceOn() mode (see the '-t' option).
+
+        In this case, the test method calls self.HideStdout(self) to redirect the
+        sys.stdout to a null device, and restores the sys.stdout upon teardown.
+
+        Note that you should only call this method at most once during a test case
+        execution.  Any subsequent call has no effect at all."""
+        if self.sys_stdout_hidden:
+            return
+
+        self.sys_stdout_hidden = True
+        old_stdout = sys.stdout
+        sys.stdout = open(os.devnull, 'w')
+        def restore_stdout():
+            sys.stdout = old_stdout
+        self.addTearDownHook(restore_stdout)
+
+    # =======================================================================
+    # Methods for customized teardown cleanups as well as execution of hooks.
+    # =======================================================================
+
+    def setTearDownCleanup(self, dictionary=None):
+        """Register a cleanup action at tearDown() time with a dictinary"""
+        self.dict = dictionary
+        self.doTearDownCleanup = True
+
+    def addTearDownCleanup(self, dictionary):
+        """Add a cleanup action at tearDown() time with a dictinary"""
+        self.dicts.append(dictionary)
+        self.doTearDownCleanups = True
+
+    def addTearDownHook(self, hook):
+        """
+        Add a function to be run during tearDown() time.
+
+        Hooks are executed in a first come first serve manner.
+        """
+        if callable(hook):
+            with recording(self, traceAlways) as sbuf:
+                print >> sbuf, "Adding tearDown hook:", getsource_if_available(hook)
+            self.hooks.append(hook)
+
+    def tearDown(self):
+        """Fixture for unittest test case teardown."""
+        #import traceback
+        #traceback.print_stack()
+
+        # Check and run any hook functions.
+        for hook in reversed(self.hooks):
+            with recording(self, traceAlways) as sbuf:
+                print >> sbuf, "Executing tearDown hook:", getsource_if_available(hook)
+            hook()
+
+        del self.hooks
+
+        # Perform registered teardown cleanup.
+        if doCleanup and self.doTearDownCleanup:
+            module = builder_module()
+            if not module.cleanup(self, dictionary=self.dict):
+                raise Exception("Don't know how to do cleanup with dictionary: " + self.dict)
+
+        # In rare cases where there are multiple teardown cleanups added.
+        if doCleanup and self.doTearDownCleanups:
+            module = builder_module()
+            if self.dicts:
+                for dict in reversed(self.dicts):
+                    if not module.cleanup(self, dictionary=dict):
+                        raise Exception("Don't know how to do cleanup with dictionary: " + dict)
+
+        # Decide whether to dump the session info.
+        self.dumpSessionInfo()
+
+    # =========================================================
+    # Various callbacks to allow introspection of test progress
+    # =========================================================
+
+    def markError(self):
+        """Callback invoked when an error (unexpected exception) errored."""
+        self.__errored__ = True
+        with recording(self, False) as sbuf:
+            # False because there's no need to write "ERROR" to the stderr twice.
+            # Once by the Python unittest framework, and a second time by us.
+            print >> sbuf, "ERROR"
+
+    def markFailure(self):
+        """Callback invoked when a failure (test assertion failure) occurred."""
+        self.__failed__ = True
+        with recording(self, False) as sbuf:
+            # False because there's no need to write "FAIL" to the stderr twice.
+            # Once by the Python unittest framework, and a second time by us.
+            print >> sbuf, "FAIL"
+
+    def markExpectedFailure(self):
+        """Callback invoked when an expected failure/error occurred."""
+        self.__expected__ = True
+        with recording(self, False) as sbuf:
+            # False because there's no need to write "expected failure" to the
+            # stderr twice.
+            # Once by the Python unittest framework, and a second time by us.
+            print >> sbuf, "expected failure"
+
+    def markUnexpectedSuccess(self):
+        """Callback invoked when an unexpected success occurred."""
+        self.__unexpected__ = True
+        with recording(self, False) as sbuf:
+            # False because there's no need to write "unexpected success" to the
+            # stderr twice.
+            # Once by the Python unittest framework, and a second time by us.
+            print >> sbuf, "unexpected success"
+
+    def dumpSessionInfo(self):
+        """
+        Dump the debugger interactions leading to a test error/failure.  This
+        allows for more convenient postmortem analysis.
+
+        See also LLDBTestResult (dotest.py) which is a singlton class derived
+        from TextTestResult and overwrites addError, addFailure, and
+        addExpectedFailure methods to allow us to to mark the test instance as
+        such.
+        """
+
+        # We are here because self.tearDown() detected that this test instance
+        # either errored or failed.  The lldb.test_result singleton contains
+        # two lists (erros and failures) which get populated by the unittest
+        # framework.  Look over there for stack trace information.
+        #
+        # The lists contain 2-tuples of TestCase instances and strings holding
+        # formatted tracebacks.
+        #
+        # See http://docs.python.org/library/unittest.html#unittest.TestResult.
+        if self.__errored__:
+            pairs = lldb.test_result.errors
+            prefix = 'Error'
+        elif self.__failed__:
+            pairs = lldb.test_result.failures
+            prefix = 'Failure'
+        elif self.__expected__:
+            pairs = lldb.test_result.expectedFailures
+            prefix = 'ExpectedFailure'
+        elif self.__unexpected__:
+            prefix = "UnexpectedSuccess"
+        else:
+            # Simply return, there's no session info to dump!
+            return
+
+        if not self.__unexpected__:
+            for test, traceback in pairs:
+                if test is self:
+                    print >> self.session, traceback
+
+        dname = os.path.join(os.environ["LLDB_TEST"],
+                             os.environ["LLDB_SESSION_DIRNAME"])
+        if not os.path.isdir(dname):
+            os.mkdir(dname)
+        fname = os.path.join(dname, "%s-%s.log" % (prefix, self.id()))
+        with open(fname, "w") as f:
+            import datetime
+            print >> f, "Session info generated @", datetime.datetime.now().ctime()
+            print >> f, self.session.getvalue()
+            print >> f, "To rerun this test, issue the following command from the 'test' directory:\n"
+            print >> f, "./dotest.py %s -v -t -f %s.%s" % (self.getRunOptions(),
+                                                           self.__class__.__name__,
+                                                           self._testMethodName)
+
+    # ====================================================
+    # Config. methods supported through a plugin interface
+    # (enables reading of the current test configuration)
+    # ====================================================
+
+    def getArchitecture(self):
+        """Returns the architecture in effect the test suite is running with."""
+        module = builder_module()
+        return module.getArchitecture()
+
+    def getCompiler(self):
+        """Returns the compiler in effect the test suite is running with."""
+        module = builder_module()
+        return module.getCompiler()
+
+    def getRunOptions(self):
+        """Command line option for -A and -C to run this test again, called from
+        self.dumpSessionInfo()."""
+        arch = self.getArchitecture()
+        comp = self.getCompiler()
+        if not arch and not comp:
+            return ""
+        else:
+            return "%s %s" % ("-A "+arch if arch else "",
+                              "-C "+comp if comp else "")
+
+    # ==================================================
+    # Build methods supported through a plugin interface
+    # ==================================================
+
+    def buildDefault(self, architecture=None, compiler=None, dictionary=None):
+        """Platform specific way to build the default binaries."""
+        module = builder_module()
+        if not module.buildDefault(self, architecture, compiler, dictionary):
+            raise Exception("Don't know how to build default binary")
+
+    def buildDsym(self, architecture=None, compiler=None, dictionary=None):
+        """Platform specific way to build binaries with dsym info."""
+        module = builder_module()
+        if not module.buildDsym(self, architecture, compiler, dictionary):
+            raise Exception("Don't know how to build binary with dsym")
+
+    def buildDwarf(self, architecture=None, compiler=None, dictionary=None):
+        """Platform specific way to build binaries with dwarf maps."""
+        module = builder_module()
+        if not module.buildDwarf(self, architecture, compiler, dictionary):
+            raise Exception("Don't know how to build binary with dwarf")
 
 
 class TestBase(Base):
@@ -608,152 +864,11 @@
         # And the result object.
         self.res = lldb.SBCommandReturnObject()
 
-        # These are for customized teardown cleanup.
-        self.dict = None
-        self.doTearDownCleanup = False
-        # And in rare cases where there are multiple teardown cleanups.
-        self.dicts = []
-        self.doTearDownCleanups = False
-
-        # Create a string buffer to record the session info, to be dumped into a
-        # test case specific file if test failure is encountered.
-        self.session = StringIO.StringIO()
-
-        # Optimistically set __errored__, __failed__, __expected__ to False
-        # initially.  If the test errored/failed, the session info
-        # (self.session) is then dumped into a session specific file for
-        # diagnosis.
-        self.__errored__    = False
-        self.__failed__     = False
-        self.__expected__   = False
-        # We are also interested in unexpected success.
-        self.__unexpected__ = False
-
-        # See addTearDownHook(self, hook) which allows the client to add a hook
-        # function to be run during tearDown() time.
-        self.hooks = []
-
-        # See HideStdout(self).
-        self.sys_stdout_hidden = False
-
-    def markError(self):
-        """Callback invoked when an error (unexpected exception) errored."""
-        self.__errored__ = True
-        with recording(self, False) as sbuf:
-            # False because there's no need to write "ERROR" to the stderr twice.
-            # Once by the Python unittest framework, and a second time by us.
-            print >> sbuf, "ERROR"
-
-    def markFailure(self):
-        """Callback invoked when a failure (test assertion failure) occurred."""
-        self.__failed__ = True
-        with recording(self, False) as sbuf:
-            # False because there's no need to write "FAIL" to the stderr twice.
-            # Once by the Python unittest framework, and a second time by us.
-            print >> sbuf, "FAIL"
-
-    def markExpectedFailure(self):
-        """Callback invoked when an expected failure/error occurred."""
-        self.__expected__ = True
-        with recording(self, False) as sbuf:
-            # False because there's no need to write "expected failure" to the
-            # stderr twice.
-            # Once by the Python unittest framework, and a second time by us.
-            print >> sbuf, "expected failure"
-
-    def markUnexpectedSuccess(self):
-        """Callback invoked when an unexpected success occurred."""
-        self.__unexpected__ = True
-        with recording(self, False) as sbuf:
-            # False because there's no need to write "unexpected success" to the
-            # stderr twice.
-            # Once by the Python unittest framework, and a second time by us.
-            print >> sbuf, "unexpected success"
-
-    def dumpSessionInfo(self):
-        """
-        Dump the debugger interactions leading to a test error/failure.  This
-        allows for more convenient postmortem analysis.
-
-        See also LLDBTestResult (dotest.py) which is a singlton class derived
-        from TextTestResult and overwrites addError, addFailure, and
-        addExpectedFailure methods to allow us to to mark the test instance as
-        such.
-        """
-
-        # We are here because self.tearDown() detected that this test instance
-        # either errored or failed.  The lldb.test_result singleton contains
-        # two lists (erros and failures) which get populated by the unittest
-        # framework.  Look over there for stack trace information.
-        #
-        # The lists contain 2-tuples of TestCase instances and strings holding
-        # formatted tracebacks.
-        #
-        # See http://docs.python.org/library/unittest.html#unittest.TestResult.
-        if self.__errored__:
-            pairs = lldb.test_result.errors
-            prefix = 'Error'
-        elif self.__failed__:
-            pairs = lldb.test_result.failures
-            prefix = 'Failure'
-        elif self.__expected__:
-            pairs = lldb.test_result.expectedFailures
-            prefix = 'ExpectedFailure'
-        elif self.__unexpected__:
-            prefix = "UnexpectedSuccess"
-        else:
-            # Simply return, there's no session info to dump!
-            return
-
-        if not self.__unexpected__:
-            for test, traceback in pairs:
-                if test is self:
-                    print >> self.session, traceback
-
-        dname = os.path.join(os.environ["LLDB_TEST"],
-                             os.environ["LLDB_SESSION_DIRNAME"])
-        if not os.path.isdir(dname):
-            os.mkdir(dname)
-        fname = os.path.join(dname, "%s-%s.log" % (prefix, self.id()))
-        with open(fname, "w") as f:
-            import datetime
-            print >> f, "Session info generated @", datetime.datetime.now().ctime()
-            print >> f, self.session.getvalue()
-            print >> f, "To rerun this test, issue the following command from the 'test' directory:\n"
-            print >> f, "./dotest.py %s -v -t -f %s.%s" % (self.getRunOptions(),
-                                                           self.__class__.__name__,
-                                                           self._testMethodName)
-
-    def setTearDownCleanup(self, dictionary=None):
-        """Register a cleanup action at tearDown() time with a dictinary"""
-        self.dict = dictionary
-        self.doTearDownCleanup = True
-
-    def addTearDownCleanup(self, dictionary):
-        """Add a cleanup action at tearDown() time with a dictinary"""
-        self.dicts.append(dictionary)
-        self.doTearDownCleanups = True
-
-    def addTearDownHook(self, hook):
-        """
-        Add a function to be run during tearDown() time.
-
-        Hooks are executed in a first come first serve manner.
-        """
-        if callable(hook):
-            with recording(self, traceAlways) as sbuf:
-                print >> sbuf, "Adding tearDown hook:", getsource_if_available(hook)
-            self.hooks.append(hook)
-
     def tearDown(self):
         #import traceback
         #traceback.print_stack()
 
-        # Check and run any hook functions.
-        for hook in reversed(self.hooks):
-            with recording(self, traceAlways) as sbuf:
-                print >> sbuf, "Executing tearDown hook:", getsource_if_available(hook)
-            hook()
+        Base.tearDown(self)
 
         # This is for the case of directly spawning 'lldb' and interacting with it
         # using pexpect.
@@ -786,24 +901,6 @@
             self.dbg.DeleteTarget(target)
 
         del self.dbg
-        del self.hooks
-
-        # Perform registered teardown cleanup.
-        if doCleanup and self.doTearDownCleanup:
-            module = builder_module()
-            if not module.cleanup(self, dictionary=self.dict):
-                raise Exception("Don't know how to do cleanup with dictionary: " + self.dict)
-
-        # In rare cases where there are multiple teardown cleanups added.
-        if doCleanup and self.doTearDownCleanups:
-            module = builder_module()
-            if self.dicts:
-                for dict in reversed(self.dicts):
-                    if not module.cleanup(self, dictionary=dict):
-                        raise Exception("Don't know how to do cleanup with dictionary: " + dict)
-
-        # Decide whether to dump the session info.
-        self.dumpSessionInfo()
 
     def runCmd(self, cmd, msg=None, check=True, trace=False):
         """
@@ -940,54 +1037,6 @@
             print >> sbuf, str(method) + ":",  result
         return result
 
-    # ====================================================
-    # Config. methods supported through a plugin interface
-    # (enables reading of the current test configuration)
-    # ====================================================
-
-    def getArchitecture(self):
-        """Returns the architecture in effect the test suite is running with."""
-        module = builder_module()
-        return module.getArchitecture()
-
-    def getCompiler(self):
-        """Returns the compiler in effect the test suite is running with."""
-        module = builder_module()
-        return module.getCompiler()
-
-    def getRunOptions(self):
-        """Command line option for -A and -C to run this test again, called from
-        self.dumpSessionInfo()."""
-        arch = self.getArchitecture()
-        comp = self.getCompiler()
-        if not arch and not comp:
-            return ""
-        else:
-            return "%s %s" % ("-A "+arch if arch else "",
-                              "-C "+comp if comp else "")
-
-    # ==================================================
-    # Build methods supported through a plugin interface
-    # ==================================================
-
-    def buildDefault(self, architecture=None, compiler=None, dictionary=None):
-        """Platform specific way to build the default binaries."""
-        module = builder_module()
-        if not module.buildDefault(self, architecture, compiler, dictionary):
-            raise Exception("Don't know how to build default binary")
-
-    def buildDsym(self, architecture=None, compiler=None, dictionary=None):
-        """Platform specific way to build binaries with dsym info."""
-        module = builder_module()
-        if not module.buildDsym(self, architecture, compiler, dictionary):
-            raise Exception("Don't know how to build binary with dsym")
-
-    def buildDwarf(self, architecture=None, compiler=None, dictionary=None):
-        """Platform specific way to build binaries with dwarf maps."""
-        module = builder_module()
-        if not module.buildDwarf(self, architecture, compiler, dictionary):
-            raise Exception("Don't know how to build binary with dwarf")
-
     # =================================================
     # Misc. helper methods for debugging test execution
     # =================================================
@@ -1016,34 +1065,3 @@
             return
 
         print child
-
-    def TraceOn(self):
-        """Returns True if we are in trace mode (i.e., tracing lldb command execution)."""
-        return traceAlways
-
-    def HideStdout(self):
-        """Hide output to stdout from the user.
-
-        During test execution, there might be cases where we don't want to show the
-        standard output to the user.  For example,
-
-            self.runCmd(r'''sc print "\n\n\tHello!\n"''')
-
-        tests whether command abbreviation for 'script' works or not.  There is no
-        need to show the 'Hello' output to the user as long as the 'script' command
-        succeeds and we are not in TraceOn() mode (see the '-t' option).
-
-        In this case, the test method calls self.HideStdout(self) to redirect the
-        sys.stdout to a null device, and restores the sys.stdout upon teardown.
-
-        Note that you should only call this method at most once during a test case
-        execution.  Any subsequent call has no effect at all."""
-        if self.sys_stdout_hidden:
-            return
-
-        self.sys_stdout_hidden = True
-        old_stdout = sys.stdout
-        sys.stdout = open(os.devnull, 'w')
-        def restore_stdout():
-            sys.stdout = old_stdout
-        self.addTearDownHook(restore_stdout)