Revert "[LoongArch] Eliminate the redundant sign extension of division (#107971)"
[llvm-project.git] / lldb / test / API / types / AbstractBase.py
blob043a5510c62f2dfc77e339c6d60a9645b3f4d795
1 """
2 Abstract base class of basic types provides a generic type tester method.
3 """
5 import os
6 import re
7 import lldb
8 from lldbsuite.test.lldbtest import *
9 import lldbsuite.test.lldbutil as lldbutil
12 def Msg(var, val, using_frame_variable):
13 return "'%s %s' matches the output (from compiled code): %s" % (
14 "frame variable --show-types" if using_frame_variable else "expression",
15 var,
16 val,
20 class GenericTester(TestBase):
21 # This is the pattern by design to match the " var = 'value'" output from
22 # printf() stmts (see basic_type.cpp).
23 pattern = re.compile(" (\*?a[^=]*) = '([^=]*)'$")
25 # Assert message.
26 DATA_TYPE_GROKKED = "Data type from expr parser output is parsed correctly"
28 def setUp(self):
29 # Call super's setUp().
30 TestBase.setUp(self)
31 # We'll use the test method name as the exe_name.
32 # There are a bunch of test cases under test/types and we don't want the
33 # module cacheing subsystem to be confused with executable name "a.out"
34 # used for all the test cases.
35 self.exe_name = self.testMethodName
36 golden = "{}-golden-output.txt".format(self.testMethodName)
37 self.golden_filename = self.getBuildArtifact(golden)
39 def tearDown(self):
40 """Cleanup the test byproducts."""
41 if os.path.exists(self.golden_filename):
42 os.remove(self.golden_filename)
43 TestBase.tearDown(self)
45 # ==========================================================================#
46 # Functions build_and_run() and build_and_run_expr() are generic functions #
47 # which are called from the Test*Types*.py test cases. The API client is #
48 # responsible for supplying two mandatory arguments: the source file, e.g.,#
49 # 'int.cpp', and the atoms, e.g., set(['unsigned', 'long long']) to the #
50 # functions. There are also three optional keyword arguments of interest, #
51 # as follows: #
52 # #
53 # bc -> blockCaptured (defaulted to False) #
54 # True: testing vars of various basic types from inside a block #
55 # False: testing vars of various basic types from a function #
56 # qd -> quotedDisplay (defaulted to False) #
57 # True: the output from 'frame var' or 'expr var' contains a pair #
58 # of single quotes around the value #
59 # False: no single quotes are to be found around the value of #
60 # variable #
61 # ==========================================================================#
63 def build_and_run(self, source, atoms, bc=False, qd=False):
64 self.build_and_run_with_source_atoms_expr(
65 source, atoms, expr=False, bc=bc, qd=qd
68 def build_and_run_expr(self, source, atoms, bc=False, qd=False):
69 self.build_and_run_with_source_atoms_expr(
70 source, atoms, expr=True, bc=bc, qd=qd
73 def build_and_run_with_source_atoms_expr(
74 self, source, atoms, expr, bc=False, qd=False
76 # See also Makefile and basic_type.cpp:177.
77 if bc:
78 d = {
79 "CXX_SOURCES": source,
80 "EXE": self.exe_name,
81 "CFLAGS_EXTRAS": "-DTEST_BLOCK_CAPTURED_VARS",
83 else:
84 d = {"CXX_SOURCES": source, "EXE": self.exe_name}
85 self.build(dictionary=d)
86 self.setTearDownCleanup(dictionary=d)
87 if expr:
88 self.generic_type_expr_tester(
89 self.exe_name, atoms, blockCaptured=bc, quotedDisplay=qd
91 else:
92 self.generic_type_tester(
93 self.exe_name, atoms, blockCaptured=bc, quotedDisplay=qd
96 def process_launch_o(self):
97 # process launch command output redirect always goes to host the
98 # process is running on
99 if lldb.remote_platform:
100 # process launch -o requires a path that is valid on the target
101 self.assertIsNotNone(lldb.remote_platform.GetWorkingDirectory())
102 remote_path = lldbutil.append_to_process_working_directory(
103 self, "lldb-stdout-redirect.txt"
105 self.runCmd("process launch -- {remote}".format(remote=remote_path))
106 # copy remote_path to local host
107 self.runCmd(
108 'platform get-file {remote} "{local}"'.format(
109 remote=remote_path, local=self.golden_filename
112 else:
113 self.runCmd(
114 'process launch -o "{local}"'.format(local=self.golden_filename)
117 def get_golden_list(self, blockCaptured=False):
118 with open(self.golden_filename, "r") as f:
119 go = f.read()
121 golden_list = []
122 # Scan the golden output line by line, looking for the pattern:
124 # variable = 'value'
126 for line in go.split(os.linesep):
127 # We'll ignore variables of array types from inside a block.
128 if blockCaptured and "[" in line:
129 continue
130 match = self.pattern.search(line)
131 if match:
132 var, val = match.group(1), match.group(2)
133 golden_list.append((var, val))
134 return golden_list
136 def generic_type_tester(
137 self, exe_name, atoms, quotedDisplay=False, blockCaptured=False
139 """Test that variables with basic types are displayed correctly."""
140 self.runCmd("file %s" % self.getBuildArtifact(exe_name), CURRENT_EXECUTABLE_SET)
142 # First, capture the golden output emitted by the oracle, i.e., the
143 # series of printf statements.
144 self.process_launch_o()
146 # This golden list contains a list of (variable, value) pairs extracted
147 # from the golden output.
148 gl = self.get_golden_list(blockCaptured)
150 # This test uses a #include of "basic_type.cpp" so we need to enable
151 # always setting inlined breakpoints.
152 self.runCmd("settings set target.inline-breakpoint-strategy always")
154 # Inherit TCC permissions. We can leave this set.
155 self.runCmd("settings set target.inherit-tcc true")
157 # Kill rather than detach from the inferior if something goes wrong.
158 self.runCmd("settings set target.detach-on-error false")
160 # And add hooks to restore the settings during tearDown().
161 self.addTearDownHook(
162 lambda: self.runCmd(
163 "settings set target.inline-breakpoint-strategy headers"
167 # Bring the program to the point where we can issue a series of
168 # 'frame variable --show-types' command.
169 if blockCaptured:
170 break_line = line_number(
171 "basic_type.cpp", "// Break here to test block captured variables."
173 else:
174 break_line = line_number(
175 "basic_type.cpp",
176 "// Here is the line we will break on to check variables.",
178 lldbutil.run_break_set_by_file_and_line(
179 self, "basic_type.cpp", break_line, num_expected_locations=1, loc_exact=True
182 self.runCmd("run", RUN_SUCCEEDED)
183 self.expect(
184 "process status",
185 STOPPED_DUE_TO_BREAKPOINT,
186 substrs=[
187 "stop reason = breakpoint",
188 " at basic_type.cpp:%d" % break_line,
192 # self.runCmd("frame variable --show-types")
194 # Now iterate through the golden list, comparing against the output from
195 # 'frame variable --show-types var'.
196 for var, val in gl:
197 self.runCmd("frame variable --show-types %s" % var)
198 output = self.res.GetOutput()
200 # The input type is in a canonical form as a set of named atoms.
201 # The display type string must contain each and every element.
203 # Example:
204 # runCmd: frame variable --show-types a_array_bounded[0]
205 # output: (char) a_array_bounded[0] = 'a'
207 try:
208 dt = re.match("^\((.*)\)", output).group(1)
209 except:
210 self.fail(self.DATA_TYPE_GROKKED)
212 # Expect the display type string to contain each and every atoms.
213 self.expect(
215 "Display type: '%s' must contain the type atoms: '%s'" % (dt, atoms),
216 exe=False,
217 substrs=list(atoms),
220 # The (var, val) pair must match, too.
221 nv = ("%s = '%s'" if quotedDisplay else "%s = %s") % (var, val)
222 self.expect(output, Msg(var, val, True), exe=False, substrs=[nv])
224 def generic_type_expr_tester(
225 self, exe_name, atoms, quotedDisplay=False, blockCaptured=False
227 """Test that variable expressions with basic types are evaluated correctly."""
229 self.runCmd("file %s" % self.getBuildArtifact(exe_name), CURRENT_EXECUTABLE_SET)
231 # First, capture the golden output emitted by the oracle, i.e., the
232 # series of printf statements.
233 self.process_launch_o()
235 # This golden list contains a list of (variable, value) pairs extracted
236 # from the golden output.
237 gl = self.get_golden_list(blockCaptured)
239 # This test uses a #include of "basic_type.cpp" so we need to enable
240 # always setting inlined breakpoints.
241 self.runCmd("settings set target.inline-breakpoint-strategy always")
242 # And add hooks to restore the settings during tearDown().
243 self.addTearDownHook(
244 lambda: self.runCmd(
245 "settings set target.inline-breakpoint-strategy headers"
249 # Bring the program to the point where we can issue a series of
250 # 'expr' command.
251 if blockCaptured:
252 break_line = line_number(
253 "basic_type.cpp", "// Break here to test block captured variables."
255 else:
256 break_line = line_number(
257 "basic_type.cpp",
258 "// Here is the line we will break on to check variables.",
260 lldbutil.run_break_set_by_file_and_line(
261 self, "basic_type.cpp", break_line, num_expected_locations=1, loc_exact=True
264 self.runCmd("run", RUN_SUCCEEDED)
265 self.expect(
266 "process status",
267 STOPPED_DUE_TO_BREAKPOINT,
268 substrs=["stop reason = breakpoint", " at basic_type.cpp:%d" % break_line],
271 # self.runCmd("frame variable --show-types")
273 # Now iterate through the golden list, comparing against the output from
274 # 'expr var'.
275 for var, val in gl:
276 self.runCmd("expression %s" % var)
277 output = self.res.GetOutput()
279 # The input type is in a canonical form as a set of named atoms.
280 # The display type string must contain each and every element.
282 # Example:
283 # runCmd: expr a
284 # output: (double) $0 = 1100.12
286 try:
287 dt = re.match("^\((.*)\) \$[0-9]+ = ", output).group(1)
288 except:
289 self.fail(self.DATA_TYPE_GROKKED)
291 # Expect the display type string to contain each and every atoms.
292 self.expect(
294 "Display type: '%s' must contain the type atoms: '%s'" % (dt, atoms),
295 exe=False,
296 substrs=list(atoms),
299 # The val part must match, too.
300 valPart = ("'%s'" if quotedDisplay else "%s") % val
301 self.expect(output, Msg(var, val, False), exe=False, substrs=[valPart])