AbstractBase.py revision 99323d8797f5a75dcbf64937422fbc685cf132b6
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    def generic_type_tester(self, exe_name, atoms, quotedDisplay=False):
33        """Test that variables with basic types are displayed correctly."""
34
35        # First, capture the golden output emitted by the oracle, i.e., the
36        # series of printf statements.
37        go = system("./%s" % exe_name, sender=self)[0]
38        # This golden list contains a list of (variable, value) pairs extracted
39        # from the golden output.
40        gl = []
41
42        # Scan the golden output line by line, looking for the pattern:
43        #
44        #     variable = 'value'
45        #
46        for line in go.split(os.linesep):
47            match = self.pattern.search(line)
48            if match:
49                var, val = match.group(1), match.group(2)
50                gl.append((var, val))
51        #print "golden list:", gl
52
53        # Bring the program to the point where we can issue a series of
54        # 'frame variable -T' command.
55        self.runCmd("file %s" % exe_name, CURRENT_EXECUTABLE_SET)
56        puts_line = line_number ("basic_type.cpp", "// Here is the line we will break on to check variables")
57        self.expect("breakpoint set -f basic_type.cpp -l %d" % puts_line,
58                    BREAKPOINT_CREATED,
59            startstr = "Breakpoint created: 1: file ='basic_type.cpp', line = %d, locations = 1" %
60                        puts_line)
61
62        self.runCmd("run", RUN_SUCCEEDED)
63        self.expect("process status", STOPPED_DUE_TO_BREAKPOINT,
64            substrs = [" at basic_type.cpp:%d" % puts_line,
65                       "stop reason = breakpoint"])
66
67        #self.runCmd("frame variable -T")
68
69        # Now iterate through the golden list, comparing against the output from
70        # 'frame variable -T var'.
71        for var, val in gl:
72            self.runCmd("frame variable -T %s" % var)
73            output = self.res.GetOutput()
74
75            # The input type is in a canonical form as a set of named atoms.
76            # The display type string must conatin each and every element.
77            #
78            # Example:
79            #     runCmd: frame variable -T a_array_bounded[0]
80            #     output: (char) a_array_bounded[0] = 'a'
81            #
82            try:
83                dt = re.match("^\((.*)\)", output).group(1)
84            except:
85                self.fail(self.DATA_TYPE_GROKKED)
86
87            # Expect the display type string to contain each and every atoms.
88            self.expect(dt,
89                        "Display type: '%s' must contain the type atoms: '%s'" %
90                        (dt, atoms),
91                        exe=False,
92                substrs = list(atoms))
93
94            # The (var, val) pair must match, too.
95            nv = ("%s = '%s'" if quotedDisplay else "%s = %s") % (var, val)
96            self.expect(output, Msg(var, val, True), exe=False,
97                substrs = [nv])
98
99    def generic_type_expr_tester(self, exe_name, atoms, quotedDisplay=False):
100        """Test that variable expressions with basic types are evaluated correctly."""
101
102        # First, capture the golden output emitted by the oracle, i.e., the
103        # series of printf statements.
104        go = system("./%s" % exe_name, sender=self)[0]
105        # This golden list contains a list of (variable, value) pairs extracted
106        # from the golden output.
107        gl = []
108
109        # Scan the golden output line by line, looking for the pattern:
110        #
111        #     variable = 'value'
112        #
113        for line in go.split(os.linesep):
114            match = self.pattern.search(line)
115            if match:
116                var, val = match.group(1), match.group(2)
117                gl.append((var, val))
118        #print "golden list:", gl
119
120        # Bring the program to the point where we can issue a series of
121        # 'expr' command.
122        self.runCmd("file %s" % exe_name, CURRENT_EXECUTABLE_SET)
123        puts_line = line_number ("basic_type.cpp", "// Here is the line we will break on to check variables.")
124        self.expect("breakpoint set -f basic_type.cpp -l %d" % puts_line,
125                    BREAKPOINT_CREATED,
126            startstr = "Breakpoint created: 1: file ='basic_type.cpp', line = %d, locations = 1" %
127                        puts_line)
128        self.runCmd("run", RUN_SUCCEEDED)
129        self.expect("process status", STOPPED_DUE_TO_BREAKPOINT,
130            substrs = [" at basic_type.cpp:%d" % puts_line,
131                       "stop reason = breakpoint"])
132
133        #self.runCmd("frame variable -T")
134
135        # Now iterate through the golden list, comparing against the output from
136        # 'expr var'.
137        for var, val in gl:
138            # Don't overwhelm the expression mechanism.
139            # This slows down the test suite quite a bit, to enable it, define
140            # the environment variable LLDB_TYPES_EXPR_TIME_WAIT.  For example:
141            #
142            #     export LLDB_TYPES_EXPR_TIME_WAIT=0.5
143            #
144            # causes a 0.5 second delay between 'expression' commands.
145            if "LLDB_TYPES_EXPR_TIME_WAIT" in os.environ:
146                time.sleep(float(os.environ["LLDB_TYPES_EXPR_TIME_WAIT"]))
147
148            self.runCmd("expression %s" % var)
149            output = self.res.GetOutput()
150
151            # The input type is in a canonical form as a set of named atoms.
152            # The display type string must conatin each and every element.
153            #
154            # Example:
155            #     runCmd: expr a
156            #     output: (double) $0 = 1100.12
157            #
158            try:
159                dt = re.match("^\((.*)\) \$[0-9]+ = ", output).group(1)
160            except:
161                self.fail(self.DATA_TYPE_GROKKED)
162
163            # Expect the display type string to contain each and every atoms.
164            self.expect(dt,
165                        "Display type: '%s' must contain the type atoms: '%s'" %
166                        (dt, atoms),
167                        exe=False,
168                substrs = list(atoms))
169
170            # The val part must match, too.
171            valPart = ("'%s'" if quotedDisplay else "%s") % val
172            self.expect(output, Msg(var, val, False), exe=False,
173                substrs = [valPart])
174