AbstractBase.py revision c21e523a1a7eb74d74d07990c5c12c16982ad1d9
1""" 2Abstract base class of basic types provides a generic type tester method. 3""" 4 5import os, time 6import re 7import lldb 8from lldbtest import * 9 10def Msg(var, val, using_frame_variable): 11 return "'%s %s' matches the output (from compiled code): %s" % ( 12 'frame variable -T' if using_frame_variable else 'expression' ,var, val) 13 14class GenericTester(TestBase): 15 16 # This is the pattern by design to match the " var = 'value'" output from 17 # printf() stmts (see basic_type.cpp). 18 pattern = re.compile(" (\*?a[^=]*) = '([^=]*)'$") 19 20 # Assert message. 21 DATA_TYPE_GROKKED = "Data type from expr parser output is parsed correctly" 22 23 def setUp(self): 24 # Call super's setUp(). 25 TestBase.setUp(self) 26 # We'll use the test method name as the exe_name. 27 # There are a bunch of test cases under test/types and we don't want the 28 # module cacheing subsystem to be confused with executable name "a.out" 29 # used for all the test cases. 30 self.exe_name = self.testMethodName 31 32 #==========================================================================# 33 # Functions build_and_run() and build_and_run_expr() are generic functions # 34 # which are called from the Test*Types*.py test cases. The API client is # 35 # responsible for supplying two mandatory arguments: the source file, e.g.,# 36 # 'int.cpp', and the atoms, e.g., set(['unsigned', 'long long']) to the # 37 # functions. There are also three optional keyword arguments of interest, # 38 # as follows: # 39 # # 40 # dsym -> build for dSYM (defaulted to True) # 41 # True: build dSYM file # 42 # False: build DWARF map # 43 # bc -> blockCaptured (defaulted to False) # 44 # True: testing vars of various basic types from isnide a block # 45 # False: testing vars of various basic types from a function # 46 # qd -> quotedDisplay (defaulted to False) # 47 # True: the output from 'frame var' or 'expr var' contains a pair # 48 # of single quotes around the value # 49 # False: no single quotes are to be found around the value of # 50 # variable # 51 #==========================================================================# 52 53 def build_and_run(self, source, atoms, dsym=True, bc=False, qd=False): 54 self.build_and_run_with_source_atoms_expr(source, atoms, expr=False, dsym=dsym, bc=bc, qd=qd) 55 56 def build_and_run_expr(self, source, atoms, dsym=True, bc=False, qd=False): 57 self.build_and_run_with_source_atoms_expr(source, atoms, expr=True, dsym=dsym, bc=bc, qd=qd) 58 59 def build_and_run_with_source_atoms_expr(self, source, atoms, expr, dsym=True, bc=False, qd=False): 60 # See also Makefile and basic_type.cpp:177. 61 if bc: 62 d = {'CXX_SOURCES': source, 'EXE': self.exe_name, 'CFLAGS_EXTRAS': '-DTEST_BLOCK_CAPTURED_VARS'} 63 else: 64 d = {'CXX_SOURCES': source, 'EXE': self.exe_name} 65 if dsym: 66 self.buildDsym(dictionary=d) 67 else: 68 self.buildDwarf(dictionary=d) 69 self.setTearDownCleanup(dictionary=d) 70 if expr: 71 self.generic_type_expr_tester(self.exe_name, atoms, blockCaptured=bc, quotedDisplay=qd) 72 else: 73 self.generic_type_tester(self.exe_name, atoms, blockCaptured=bc, quotedDisplay=qd) 74 75 def generic_type_tester(self, exe_name, atoms, quotedDisplay=False, blockCaptured=False): 76 """Test that variables with basic types are displayed correctly.""" 77 78 # First, capture the golden output emitted by the oracle, i.e., the 79 # series of printf statements. 80 go = system("./%s" % exe_name, sender=self)[0] 81 # This golden list contains a list of (variable, value) pairs extracted 82 # from the golden output. 83 gl = [] 84 85 # Scan the golden output line by line, looking for the pattern: 86 # 87 # variable = 'value' 88 # 89 for line in go.split(os.linesep): 90 # We'll ignore variables of array types from inside a block. 91 if blockCaptured and '[' in line: 92 continue 93 match = self.pattern.search(line) 94 if match: 95 var, val = match.group(1), match.group(2) 96 gl.append((var, val)) 97 #print "golden list:", gl 98 99 # Bring the program to the point where we can issue a series of 100 # 'frame variable -T' command. 101 self.runCmd("file %s" % exe_name, CURRENT_EXECUTABLE_SET) 102 if blockCaptured: 103 break_line = line_number ("basic_type.cpp", "// Break here to test block captured variables.") 104 else: 105 break_line = line_number ("basic_type.cpp", "// Here is the line we will break on to check variables.") 106 self.expect("breakpoint set -f basic_type.cpp -l %d" % break_line, 107 BREAKPOINT_CREATED, 108 startstr = "Breakpoint created: 1: file ='basic_type.cpp', line = %d, locations = 1" % 109 break_line) 110 111 self.runCmd("run", RUN_SUCCEEDED) 112 self.expect("process status", STOPPED_DUE_TO_BREAKPOINT, 113 substrs = [" at basic_type.cpp:%d" % break_line, 114 "stop reason = breakpoint"]) 115 116 #self.runCmd("frame variable -T") 117 118 # Now iterate through the golden list, comparing against the output from 119 # 'frame variable -T var'. 120 for var, val in gl: 121 self.runCmd("frame variable -T %s" % var) 122 output = self.res.GetOutput() 123 124 # The input type is in a canonical form as a set of named atoms. 125 # The display type string must conatin each and every element. 126 # 127 # Example: 128 # runCmd: frame variable -T a_array_bounded[0] 129 # output: (char) a_array_bounded[0] = 'a' 130 # 131 try: 132 dt = re.match("^\((.*)\)", output).group(1) 133 except: 134 self.fail(self.DATA_TYPE_GROKKED) 135 136 # Expect the display type string to contain each and every atoms. 137 self.expect(dt, 138 "Display type: '%s' must contain the type atoms: '%s'" % 139 (dt, atoms), 140 exe=False, 141 substrs = list(atoms)) 142 143 # The (var, val) pair must match, too. 144 nv = ("%s = '%s'" if quotedDisplay else "%s = %s") % (var, val) 145 self.expect(output, Msg(var, val, True), exe=False, 146 substrs = [nv]) 147 148 def generic_type_expr_tester(self, exe_name, atoms, quotedDisplay=False, blockCaptured=False): 149 """Test that variable expressions with basic types are evaluated correctly.""" 150 151 # First, capture the golden output emitted by the oracle, i.e., the 152 # series of printf statements. 153 go = system("./%s" % exe_name, sender=self)[0] 154 # This golden list contains a list of (variable, value) pairs extracted 155 # from the golden output. 156 gl = [] 157 158 # Scan the golden output line by line, looking for the pattern: 159 # 160 # variable = 'value' 161 # 162 for line in go.split(os.linesep): 163 # We'll ignore variables of array types from inside a block. 164 if blockCaptured and '[' in line: 165 continue 166 match = self.pattern.search(line) 167 if match: 168 var, val = match.group(1), match.group(2) 169 gl.append((var, val)) 170 #print "golden list:", gl 171 172 # Bring the program to the point where we can issue a series of 173 # 'expr' command. 174 self.runCmd("file %s" % exe_name, CURRENT_EXECUTABLE_SET) 175 if blockCaptured: 176 break_line = line_number ("basic_type.cpp", "// Break here to test block captured variables.") 177 else: 178 break_line = line_number ("basic_type.cpp", "// Here is the line we will break on to check variables.") 179 self.expect("breakpoint set -f basic_type.cpp -l %d" % break_line, 180 BREAKPOINT_CREATED, 181 startstr = "Breakpoint created: 1: file ='basic_type.cpp', line = %d, locations = 1" % 182 break_line) 183 self.runCmd("run", RUN_SUCCEEDED) 184 self.expect("process status", STOPPED_DUE_TO_BREAKPOINT, 185 substrs = [" at basic_type.cpp:%d" % break_line, 186 "stop reason = breakpoint"]) 187 188 #self.runCmd("frame variable -T") 189 190 # Now iterate through the golden list, comparing against the output from 191 # 'expr var'. 192 for var, val in gl: 193 # Don't overwhelm the expression mechanism. 194 # This slows down the test suite quite a bit, to enable it, define 195 # the environment variable LLDB_TYPES_EXPR_TIME_WAIT. For example: 196 # 197 # export LLDB_TYPES_EXPR_TIME_WAIT=0.5 198 # 199 # causes a 0.5 second delay between 'expression' commands. 200 if "LLDB_TYPES_EXPR_TIME_WAIT" in os.environ: 201 time.sleep(float(os.environ["LLDB_TYPES_EXPR_TIME_WAIT"])) 202 203 self.runCmd("expression %s" % var) 204 output = self.res.GetOutput() 205 206 # The input type is in a canonical form as a set of named atoms. 207 # The display type string must conatin each and every element. 208 # 209 # Example: 210 # runCmd: expr a 211 # output: (double) $0 = 1100.12 212 # 213 try: 214 dt = re.match("^\((.*)\) \$[0-9]+ = ", output).group(1) 215 except: 216 self.fail(self.DATA_TYPE_GROKKED) 217 218 # Expect the display type string to contain each and every atoms. 219 self.expect(dt, 220 "Display type: '%s' must contain the type atoms: '%s'" % 221 (dt, atoms), 222 exe=False, 223 substrs = list(atoms)) 224 225 # The val part must match, too. 226 valPart = ("'%s'" if quotedDisplay else "%s") % val 227 self.expect(output, Msg(var, val, False), exe=False, 228 substrs = [valPart]) 229