xref: /openbsd-src/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbinline.py (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1061da546Spatrickfrom __future__ import print_function
2061da546Spatrickfrom __future__ import absolute_import
3061da546Spatrick
4061da546Spatrick# System modules
5061da546Spatrickimport os
6*f6aab3d8Srobertimport textwrap
7061da546Spatrick
8061da546Spatrick# Third-party modules
9061da546Spatrickimport io
10061da546Spatrick
11061da546Spatrick# LLDB modules
12061da546Spatrickimport lldb
13061da546Spatrickfrom .lldbtest import *
14061da546Spatrickfrom . import configuration
15061da546Spatrickfrom . import lldbutil
16061da546Spatrickfrom .decorators import *
17061da546Spatrick
18061da546Spatrickdef source_type(filename):
19061da546Spatrick    _, extension = os.path.splitext(filename)
20061da546Spatrick    return {
21061da546Spatrick        '.c': 'C_SOURCES',
22061da546Spatrick        '.cpp': 'CXX_SOURCES',
23061da546Spatrick        '.cxx': 'CXX_SOURCES',
24061da546Spatrick        '.cc': 'CXX_SOURCES',
25061da546Spatrick        '.m': 'OBJC_SOURCES',
26061da546Spatrick        '.mm': 'OBJCXX_SOURCES'
27061da546Spatrick    }.get(extension, None)
28061da546Spatrick
29061da546Spatrick
30061da546Spatrickclass CommandParser:
31061da546Spatrick
32061da546Spatrick    def __init__(self):
33061da546Spatrick        self.breakpoints = []
34061da546Spatrick
35061da546Spatrick    def parse_one_command(self, line):
36061da546Spatrick        parts = line.split('//%')
37061da546Spatrick
38061da546Spatrick        command = None
39061da546Spatrick        new_breakpoint = True
40061da546Spatrick
41061da546Spatrick        if len(parts) == 2:
42*f6aab3d8Srobert            command = parts[1].rstrip()
43061da546Spatrick            new_breakpoint = parts[0].strip() != ""
44061da546Spatrick
45061da546Spatrick        return (command, new_breakpoint)
46061da546Spatrick
47061da546Spatrick    def parse_source_files(self, source_files):
48061da546Spatrick        for source_file in source_files:
49061da546Spatrick            file_handle = io.open(source_file, encoding='utf-8')
50061da546Spatrick            lines = file_handle.readlines()
51061da546Spatrick            line_number = 0
52061da546Spatrick            # non-NULL means we're looking through whitespace to find
53061da546Spatrick            # additional commands
54061da546Spatrick            current_breakpoint = None
55061da546Spatrick            for line in lines:
56061da546Spatrick                line_number = line_number + 1  # 1-based, so we do this first
57061da546Spatrick                (command, new_breakpoint) = self.parse_one_command(line)
58061da546Spatrick
59061da546Spatrick                if new_breakpoint:
60061da546Spatrick                    current_breakpoint = None
61061da546Spatrick
62061da546Spatrick                if command is not None:
63061da546Spatrick                    if current_breakpoint is None:
64061da546Spatrick                        current_breakpoint = {}
65061da546Spatrick                        current_breakpoint['file_name'] = source_file
66061da546Spatrick                        current_breakpoint['line_number'] = line_number
67061da546Spatrick                        current_breakpoint['command'] = command
68061da546Spatrick                        self.breakpoints.append(current_breakpoint)
69061da546Spatrick                    else:
70061da546Spatrick                        current_breakpoint['command'] = current_breakpoint[
71061da546Spatrick                            'command'] + "\n" + command
72*f6aab3d8Srobert        for bkpt in self.breakpoints:
73*f6aab3d8Srobert            bkpt['command'] = textwrap.dedent(bkpt['command'])
74061da546Spatrick
75061da546Spatrick    def set_breakpoints(self, target):
76061da546Spatrick        for breakpoint in self.breakpoints:
77061da546Spatrick            breakpoint['breakpoint'] = target.BreakpointCreateByLocation(
78061da546Spatrick                breakpoint['file_name'], breakpoint['line_number'])
79061da546Spatrick
80061da546Spatrick    def handle_breakpoint(self, test, breakpoint_id):
81061da546Spatrick        for breakpoint in self.breakpoints:
82061da546Spatrick            if breakpoint['breakpoint'].GetID() == breakpoint_id:
83061da546Spatrick                test.execute_user_command(breakpoint['command'])
84061da546Spatrick                return
85061da546Spatrick
86061da546Spatrick
87061da546Spatrickclass InlineTest(TestBase):
88dda28197Spatrick
89dda28197Spatrick    def getBuildDirBasename(self):
90dda28197Spatrick        return self.__class__.__name__ + "." + self.testMethodName
91061da546Spatrick
92061da546Spatrick    def BuildMakefile(self):
93061da546Spatrick        makefilePath = self.getBuildArtifact("Makefile")
94061da546Spatrick        if os.path.exists(makefilePath):
95061da546Spatrick            return
96061da546Spatrick
97061da546Spatrick        categories = {}
98061da546Spatrick        for f in os.listdir(self.getSourceDir()):
99061da546Spatrick            t = source_type(f)
100061da546Spatrick            if t:
101061da546Spatrick                if t in list(categories.keys()):
102061da546Spatrick                    categories[t].append(f)
103061da546Spatrick                else:
104061da546Spatrick                    categories[t] = [f]
105061da546Spatrick
106dda28197Spatrick        with open(makefilePath, 'w+') as makefile:
107061da546Spatrick            for t in list(categories.keys()):
108061da546Spatrick                line = t + " := " + " ".join(categories[t])
109061da546Spatrick                makefile.write(line + "\n")
110061da546Spatrick
111dda28197Spatrick            if ('OBJCXX_SOURCES' in list(categories.keys())) or \
112dda28197Spatrick               ('OBJC_SOURCES' in list(categories.keys())):
113061da546Spatrick                makefile.write(
114061da546Spatrick                    "LDFLAGS = $(CFLAGS) -lobjc -framework Foundation\n")
115061da546Spatrick
116061da546Spatrick            if ('CXX_SOURCES' in list(categories.keys())):
117061da546Spatrick                makefile.write("CXXFLAGS += -std=c++11\n")
118061da546Spatrick
119061da546Spatrick            makefile.write("include Makefile.rules\n")
120061da546Spatrick
121061da546Spatrick    def _test(self):
122061da546Spatrick        self.BuildMakefile()
123dda28197Spatrick        self.build(dictionary=self._build_dict)
124061da546Spatrick        self.do_test()
125061da546Spatrick
126061da546Spatrick    def execute_user_command(self, __command):
127061da546Spatrick        exec(__command, globals(), locals())
128061da546Spatrick
129dda28197Spatrick    def _get_breakpoint_ids(self, thread):
130dda28197Spatrick        ids = set()
131dda28197Spatrick        for i in range(0, thread.GetStopReasonDataCount(), 2):
132dda28197Spatrick            ids.add(thread.GetStopReasonDataAtIndex(i))
133dda28197Spatrick        self.assertGreater(len(ids), 0)
134dda28197Spatrick        return sorted(ids)
135dda28197Spatrick
136061da546Spatrick    def do_test(self):
137061da546Spatrick        exe = self.getBuildArtifact("a.out")
138061da546Spatrick        source_files = [f for f in os.listdir(self.getSourceDir())
139061da546Spatrick                        if source_type(f)]
140061da546Spatrick        target = self.dbg.CreateTarget(exe)
141061da546Spatrick
142061da546Spatrick        parser = CommandParser()
143061da546Spatrick        parser.parse_source_files(source_files)
144061da546Spatrick        parser.set_breakpoints(target)
145061da546Spatrick
146061da546Spatrick        process = target.LaunchSimple(None, None, self.get_process_working_directory())
147dda28197Spatrick        self.assertIsNotNone(process, PROCESS_IS_VALID)
148dda28197Spatrick
149061da546Spatrick        hit_breakpoints = 0
150061da546Spatrick
151061da546Spatrick        while lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint):
152061da546Spatrick            hit_breakpoints += 1
153061da546Spatrick            thread = lldbutil.get_stopped_thread(
154061da546Spatrick                process, lldb.eStopReasonBreakpoint)
155dda28197Spatrick            for bp_id in self._get_breakpoint_ids(thread):
156dda28197Spatrick                parser.handle_breakpoint(self, bp_id)
157061da546Spatrick            process.Continue()
158061da546Spatrick
159061da546Spatrick        self.assertTrue(hit_breakpoints > 0,
160061da546Spatrick                        "inline test did not hit a single breakpoint")
161061da546Spatrick        # Either the process exited or the stepping plan is complete.
162061da546Spatrick        self.assertTrue(process.GetState() in [lldb.eStateStopped,
163061da546Spatrick                                               lldb.eStateExited],
164061da546Spatrick                        PROCESS_EXITED)
165061da546Spatrick
166061da546Spatrick    def check_expression(self, expression, expected_result, use_summary=True):
167061da546Spatrick        value = self.frame().EvaluateExpression(expression)
168061da546Spatrick        self.assertTrue(value.IsValid(), expression + "returned a valid value")
169061da546Spatrick        if self.TraceOn():
170061da546Spatrick            print(value.GetSummary())
171061da546Spatrick            print(value.GetValue())
172061da546Spatrick        if use_summary:
173061da546Spatrick            answer = value.GetSummary()
174061da546Spatrick        else:
175061da546Spatrick            answer = value.GetValue()
176061da546Spatrick        report_str = "%s expected: %s got: %s" % (
177061da546Spatrick            expression, expected_result, answer)
178061da546Spatrick        self.assertTrue(answer == expected_result, report_str)
179061da546Spatrick
180061da546Spatrick
181061da546Spatrickdef ApplyDecoratorsToFunction(func, decorators):
182061da546Spatrick    tmp = func
183061da546Spatrick    if isinstance(decorators, list):
184061da546Spatrick        for decorator in decorators:
185061da546Spatrick            tmp = decorator(tmp)
186061da546Spatrick    elif hasattr(decorators, '__call__'):
187061da546Spatrick        tmp = decorators(tmp)
188061da546Spatrick    return tmp
189061da546Spatrick
190061da546Spatrick
191dda28197Spatrickdef MakeInlineTest(__file, __globals, decorators=None, name=None,
192dda28197Spatrick        build_dict=None):
193061da546Spatrick    # Adjust the filename if it ends in .pyc.  We want filenames to
194061da546Spatrick    # reflect the source python file, not the compiled variant.
195061da546Spatrick    if __file is not None and __file.endswith(".pyc"):
196061da546Spatrick        # Strip the trailing "c"
197061da546Spatrick        __file = __file[0:-1]
198061da546Spatrick
199dda28197Spatrick    if name is None:
200061da546Spatrick        # Derive the test name from the current file name
201061da546Spatrick        file_basename = os.path.basename(__file)
202dda28197Spatrick        name, _ = os.path.splitext(file_basename)
203061da546Spatrick
204061da546Spatrick    test_func = ApplyDecoratorsToFunction(InlineTest._test, decorators)
205061da546Spatrick    # Build the test case
206dda28197Spatrick    test_class = type(name, (InlineTest,), dict(test=test_func,
207dda28197Spatrick        name=name, _build_dict=build_dict))
208061da546Spatrick
209061da546Spatrick    # Add the test case to the globals, and hide InlineTest
210dda28197Spatrick    __globals.update({name: test_class})
211061da546Spatrick
212061da546Spatrick    # Keep track of the original test filename so we report it
213061da546Spatrick    # correctly in test results.
214061da546Spatrick    test_class.test_filename = __file
215061da546Spatrick    test_class.mydir = TestBase.compute_mydir(__file)
216061da546Spatrick    return test_class
217