Johnny Chen | bf6ffa3 | 2010-07-03 03:41:59 +0000 | [diff] [blame] | 1 | """ |
| 2 | LLDB module which provides the abstract base class of lldb test case. |
| 3 | |
| 4 | The concrete subclass can override lldbtest.TesBase in order to inherit the |
| 5 | common behavior for unitest.TestCase.setUp/tearDown implemented in this file. |
| 6 | |
| 7 | The subclass should override the attribute mydir in order for the python runtime |
| 8 | to locate the individual test cases when running as part of a large test suite |
| 9 | or when running each test case as a separate python invocation. |
| 10 | |
| 11 | ./dotest.py provides a test driver which sets up the environment to run the |
| 12 | entire test suite. Users who want to run a test case on its own can specify the |
| 13 | LLDB_TEST and PYTHONPATH environment variables, for example: |
| 14 | |
| 15 | $ export LLDB_TEST=$PWD |
| 16 | $ export PYTHONPATH=/Volumes/data/lldb/svn/trunk/build/Debug/LLDB.framework/Resources/Python:$LLDB_TEST |
| 17 | $ echo $LLDB_TEST |
| 18 | /Volumes/data/lldb/svn/trunk/test |
| 19 | $ echo $PYTHONPATH |
| 20 | /Volumes/data/lldb/svn/trunk/build/Debug/LLDB.framework/Resources/Python:/Volumes/data/lldb/svn/trunk/test |
| 21 | $ python function_types/TestFunctionTypes.py |
| 22 | . |
| 23 | ---------------------------------------------------------------------- |
| 24 | Ran 1 test in 0.363s |
| 25 | |
| 26 | OK |
| 27 | $ |
| 28 | """ |
| 29 | |
| 30 | import os |
Johnny Chen | ff3d01d | 2010-08-20 21:03:09 +0000 | [diff] [blame] | 31 | import sys |
Johnny Chen | 7325883 | 2010-08-05 23:42:46 +0000 | [diff] [blame] | 32 | import unittest2 |
Johnny Chen | bf6ffa3 | 2010-07-03 03:41:59 +0000 | [diff] [blame] | 33 | import lldb |
| 34 | |
Johnny Chen | 0077809 | 2010-08-09 22:01:17 +0000 | [diff] [blame] | 35 | # |
| 36 | # Some commonly used assert messages. |
| 37 | # |
| 38 | |
| 39 | CURRENT_EXECUTABLE_SET = "Current executable set successfully" |
| 40 | |
Johnny Chen | ff3d01d | 2010-08-20 21:03:09 +0000 | [diff] [blame] | 41 | RUN_STOPPED = "Process is launched and then stopped successfully" |
Johnny Chen | 0077809 | 2010-08-09 22:01:17 +0000 | [diff] [blame] | 42 | |
Johnny Chen | 1794184 | 2010-08-09 23:44:24 +0000 | [diff] [blame] | 43 | RUN_COMPLETED = "Process exited successfully" |
Johnny Chen | 0077809 | 2010-08-09 22:01:17 +0000 | [diff] [blame] | 44 | |
Johnny Chen | 1794184 | 2010-08-09 23:44:24 +0000 | [diff] [blame] | 45 | BREAKPOINT_CREATED = "Breakpoint created successfully" |
| 46 | |
Johnny Chen | e76896c | 2010-08-17 21:33:31 +0000 | [diff] [blame] | 47 | BREAKPOINT_PENDING_CREATED = "Pending breakpoint created successfully" |
| 48 | |
Johnny Chen | 1794184 | 2010-08-09 23:44:24 +0000 | [diff] [blame] | 49 | BREAKPOINT_HIT_ONCE = "Breakpoint resolved with hit cout = 1" |
Johnny Chen | 0077809 | 2010-08-09 22:01:17 +0000 | [diff] [blame] | 50 | |
| 51 | STOPPED_DUE_TO_BREAKPOINT = "Process state is stopped due to breakpoint" |
| 52 | |
| 53 | STOPPED_DUE_TO_STEP_IN = "Process state is stopped due to step in" |
| 54 | |
| 55 | VARIABLES_DISPLAYED_CORRECTLY = "Show specified variable(s) correctly" |
| 56 | |
Johnny Chen | 1794184 | 2010-08-09 23:44:24 +0000 | [diff] [blame] | 57 | # |
| 58 | # And a generic "Command '%s' returns successfully" message generator. |
| 59 | # |
| 60 | def CMD_MSG(command): |
| 61 | return "Command '%s' returns successfully" % (command) |
| 62 | |
| 63 | |
Johnny Chen | 7325883 | 2010-08-05 23:42:46 +0000 | [diff] [blame] | 64 | class TestBase(unittest2.TestCase): |
Johnny Chen | bf6ffa3 | 2010-07-03 03:41:59 +0000 | [diff] [blame] | 65 | """This LLDB abstract base class is meant to be subclassed.""" |
| 66 | |
| 67 | # The concrete subclass should override this attribute. |
Johnny Chen | f02ec12 | 2010-07-03 20:41:42 +0000 | [diff] [blame] | 68 | mydir = None |
Johnny Chen | bf6ffa3 | 2010-07-03 03:41:59 +0000 | [diff] [blame] | 69 | |
Johnny Chen | 6ca006c | 2010-08-16 21:28:10 +0000 | [diff] [blame] | 70 | # State pertaining to the inferior process, if any. |
| 71 | runStarted = False |
| 72 | |
Johnny Chen | bf6ffa3 | 2010-07-03 03:41:59 +0000 | [diff] [blame] | 73 | def setUp(self): |
Johnny Chen | 9289a65 | 2010-08-07 01:13:18 +0000 | [diff] [blame] | 74 | #import traceback |
Johnny Chen | a212495 | 2010-08-05 21:23:45 +0000 | [diff] [blame] | 75 | #traceback.print_stack() |
| 76 | |
Johnny Chen | f02ec12 | 2010-07-03 20:41:42 +0000 | [diff] [blame] | 77 | # Fail fast if 'mydir' attribute is not overridden. |
| 78 | if not self.mydir or len(self.mydir) == 0: |
| 79 | raise Exception("Subclasses must override the 'mydir' attribute.") |
Johnny Chen | bf6ffa3 | 2010-07-03 03:41:59 +0000 | [diff] [blame] | 80 | # Save old working directory. |
| 81 | self.oldcwd = os.getcwd() |
| 82 | |
| 83 | # Change current working directory if ${LLDB_TEST} is defined. |
| 84 | # See also dotest.py which sets up ${LLDB_TEST}. |
| 85 | if ("LLDB_TEST" in os.environ): |
| 86 | os.chdir(os.path.join(os.environ["LLDB_TEST"], self.mydir)); |
| 87 | |
| 88 | # Create the debugger instance if necessary. |
| 89 | try: |
| 90 | self.dbg = lldb.DBG |
Johnny Chen | bf6ffa3 | 2010-07-03 03:41:59 +0000 | [diff] [blame] | 91 | except AttributeError: |
| 92 | self.dbg = lldb.SBDebugger.Create() |
Johnny Chen | f02ec12 | 2010-07-03 20:41:42 +0000 | [diff] [blame] | 93 | |
Johnny Chen | bf6ffa3 | 2010-07-03 03:41:59 +0000 | [diff] [blame] | 94 | if not self.dbg.IsValid(): |
| 95 | raise Exception('Invalid debugger instance') |
| 96 | |
| 97 | # We want our debugger to be synchronous. |
| 98 | self.dbg.SetAsync(False) |
| 99 | |
| 100 | # Retrieve the associated command interpreter instance. |
| 101 | self.ci = self.dbg.GetCommandInterpreter() |
| 102 | if not self.ci: |
| 103 | raise Exception('Could not get the command interpreter') |
| 104 | |
| 105 | # And the result object. |
| 106 | self.res = lldb.SBCommandReturnObject() |
| 107 | |
Johnny Chen | bf6ffa3 | 2010-07-03 03:41:59 +0000 | [diff] [blame] | 108 | def tearDown(self): |
Johnny Chen | 6ca006c | 2010-08-16 21:28:10 +0000 | [diff] [blame] | 109 | # Finish the inferior process, if it was "run" previously. |
| 110 | if self.runStarted: |
| 111 | self.ci.HandleCommand("continue", self.res) |
| 112 | |
Johnny Chen | bf6ffa3 | 2010-07-03 03:41:59 +0000 | [diff] [blame] | 113 | del self.dbg |
| 114 | |
| 115 | # Restore old working directory. |
| 116 | os.chdir(self.oldcwd) |
Johnny Chen | 27f212d | 2010-08-19 23:26:59 +0000 | [diff] [blame] | 117 | |
Johnny Chen | 5bbb88f | 2010-08-20 17:57:32 +0000 | [diff] [blame] | 118 | def runCmd(self, cmd, msg=None, check=True, verbose=False): |
Johnny Chen | 27f212d | 2010-08-19 23:26:59 +0000 | [diff] [blame] | 119 | """ |
| 120 | Ask the command interpreter to handle the command and then check its |
| 121 | return status. |
| 122 | """ |
| 123 | # Fail fast if 'cmd' is not meaningful. |
| 124 | if not cmd or len(cmd) == 0: |
| 125 | raise Exception("Bad 'cmd' parameter encountered") |
Johnny Chen | 5bbb88f | 2010-08-20 17:57:32 +0000 | [diff] [blame] | 126 | |
| 127 | if verbose: |
Johnny Chen | ff3d01d | 2010-08-20 21:03:09 +0000 | [diff] [blame] | 128 | print >> sys.stderr, "runCmd:", cmd |
Johnny Chen | 5bbb88f | 2010-08-20 17:57:32 +0000 | [diff] [blame] | 129 | |
Johnny Chen | 27f212d | 2010-08-19 23:26:59 +0000 | [diff] [blame] | 130 | self.ci.HandleCommand(cmd, self.res) |
Johnny Chen | 5bbb88f | 2010-08-20 17:57:32 +0000 | [diff] [blame] | 131 | |
Johnny Chen | a6480c1 | 2010-08-19 23:53:55 +0000 | [diff] [blame] | 132 | if cmd.startswith("run"): |
Johnny Chen | 27f212d | 2010-08-19 23:26:59 +0000 | [diff] [blame] | 133 | self.runStarted = True |
Johnny Chen | 5bbb88f | 2010-08-20 17:57:32 +0000 | [diff] [blame] | 134 | |
Johnny Chen | 5bbb88f | 2010-08-20 17:57:32 +0000 | [diff] [blame] | 135 | if verbose: |
Johnny Chen | ff3d01d | 2010-08-20 21:03:09 +0000 | [diff] [blame] | 136 | if self.res.Succeeded(): |
| 137 | print >> sys.stderr, "output:", self.res.GetOutput() |
| 138 | else: |
| 139 | print >> sys.stderr, self.res.GetError() |
Johnny Chen | 5bbb88f | 2010-08-20 17:57:32 +0000 | [diff] [blame] | 140 | |
Johnny Chen | 27f212d | 2010-08-19 23:26:59 +0000 | [diff] [blame] | 141 | if check: |
| 142 | self.assertTrue(self.res.Succeeded(), |
| 143 | msg if msg else CMD_MSG(cmd)) |
| 144 | |
Johnny Chen | 74f26b8 | 2010-08-20 19:17:39 +0000 | [diff] [blame] | 145 | def expect(self, cmd, msg=None, startstr=None, substrs=None, verbose=False): |
Johnny Chen | 27f212d | 2010-08-19 23:26:59 +0000 | [diff] [blame] | 146 | """ |
| 147 | Similar to runCmd; with additional expect style output matching ability. |
| 148 | |
| 149 | Ask the command interpreter to handle the command and then check its |
| 150 | return status. The 'msg' parameter specifies an informational assert |
| 151 | message. We expect the output from running the command to start with |
| 152 | 'startstr' and matches the substrings contained in 'substrs'. |
| 153 | """ |
Johnny Chen | 74f26b8 | 2010-08-20 19:17:39 +0000 | [diff] [blame] | 154 | |
| 155 | # First run the command. |
Johnny Chen | 5bbb88f | 2010-08-20 17:57:32 +0000 | [diff] [blame] | 156 | self.runCmd(cmd, verbose = (True if verbose else False)) |
Johnny Chen | 27f212d | 2010-08-19 23:26:59 +0000 | [diff] [blame] | 157 | |
Johnny Chen | 74f26b8 | 2010-08-20 19:17:39 +0000 | [diff] [blame] | 158 | # Then compare the output against expected strings. |
Johnny Chen | 27f212d | 2010-08-19 23:26:59 +0000 | [diff] [blame] | 159 | output = self.res.GetOutput() |
| 160 | matched = output.startswith(startstr) if startstr else True |
Johnny Chen | b145bba | 2010-08-20 18:25:15 +0000 | [diff] [blame] | 161 | |
| 162 | if not matched and startstr and verbose: |
Johnny Chen | ff3d01d | 2010-08-20 21:03:09 +0000 | [diff] [blame] | 163 | print >> sys.stderr, "Startstr not matched:", startstr |
Johnny Chen | b145bba | 2010-08-20 18:25:15 +0000 | [diff] [blame] | 164 | |
Johnny Chen | 27f212d | 2010-08-19 23:26:59 +0000 | [diff] [blame] | 165 | if substrs: |
| 166 | for str in substrs: |
| 167 | matched = output.find(str) > 0 |
| 168 | if not matched: |
Johnny Chen | b145bba | 2010-08-20 18:25:15 +0000 | [diff] [blame] | 169 | if verbose: |
Johnny Chen | ff3d01d | 2010-08-20 21:03:09 +0000 | [diff] [blame] | 170 | print >> sys.stderr, "Substring not matched:", str |
Johnny Chen | 27f212d | 2010-08-19 23:26:59 +0000 | [diff] [blame] | 171 | break |
| 172 | |
Johnny Chen | 74f26b8 | 2010-08-20 19:17:39 +0000 | [diff] [blame] | 173 | self.assertTrue(matched, msg if msg else CMD_MSG(cmd)) |
Johnny Chen | 27f212d | 2010-08-19 23:26:59 +0000 | [diff] [blame] | 174 | |