brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.2 KiB · ae38ab9 Raw
214 lines · python
1# System modules2import os3import textwrap4 5# Third-party modules6import io7 8# LLDB modules9import lldb10from .lldbtest import *11from . import configuration12from . import lldbutil13from .decorators import *14 15 16def source_type(filename):17    _, extension = os.path.splitext(filename)18    return {19        ".c": "C_SOURCES",20        ".cpp": "CXX_SOURCES",21        ".cxx": "CXX_SOURCES",22        ".cc": "CXX_SOURCES",23        ".m": "OBJC_SOURCES",24        ".mm": "OBJCXX_SOURCES",25    }.get(extension, None)26 27 28class CommandParser:29    def __init__(self):30        self.breakpoints = []31 32    def parse_one_command(self, line):33        parts = line.split("//%")34 35        command = None36        new_breakpoint = True37 38        if len(parts) == 2:39            command = parts[1].rstrip()40            new_breakpoint = parts[0].strip() != ""41 42        return (command, new_breakpoint)43 44    def parse_source_files(self, source_files):45        for source_file in source_files:46            file_handle = io.open(source_file, encoding="utf-8")47            lines = file_handle.readlines()48            line_number = 049            # non-NULL means we're looking through whitespace to find50            # additional commands51            current_breakpoint = None52            for line in lines:53                line_number = line_number + 1  # 1-based, so we do this first54                (command, new_breakpoint) = self.parse_one_command(line)55 56                if new_breakpoint:57                    current_breakpoint = None58 59                if command is not None:60                    if current_breakpoint is None:61                        current_breakpoint = {}62                        current_breakpoint["file_name"] = source_file63                        current_breakpoint["line_number"] = line_number64                        current_breakpoint["command"] = command65                        self.breakpoints.append(current_breakpoint)66                    else:67                        current_breakpoint["command"] = (68                            current_breakpoint["command"] + "\n" + command69                        )70        for bkpt in self.breakpoints:71            bkpt["command"] = textwrap.dedent(bkpt["command"])72 73    def set_breakpoints(self, target):74        for breakpoint in self.breakpoints:75            breakpoint["breakpoint"] = target.BreakpointCreateByLocation(76                breakpoint["file_name"], breakpoint["line_number"]77            )78 79    def handle_breakpoint(self, test, breakpoint_id):80        for breakpoint in self.breakpoints:81            if breakpoint["breakpoint"].GetID() == breakpoint_id:82                test.execute_user_command(breakpoint["command"])83                return84 85 86class InlineTest(TestBase):87    def getBuildDirBasename(self):88        return self.__class__.__name__ + "." + self.testMethodName89 90    def BuildMakefile(self):91        makefilePath = self.getBuildArtifact("Makefile")92        if os.path.exists(makefilePath):93            return94 95        categories = {}96        for f in os.listdir(self.getSourceDir()):97            t = source_type(f)98            if t:99                if t in list(categories.keys()):100                    categories[t].append(f)101                else:102                    categories[t] = [f]103 104        with open(makefilePath, "w+") as makefile:105            for t in list(categories.keys()):106                line = t + " := " + " ".join(categories[t])107                makefile.write(line + "\n")108 109            if ("OBJCXX_SOURCES" in list(categories.keys())) or (110                "OBJC_SOURCES" in list(categories.keys())111            ):112                makefile.write("LDFLAGS = $(CFLAGS) -lobjc -framework Foundation\n")113 114            if "CXX_SOURCES" in list(categories.keys()):115                makefile.write("CXXFLAGS += -std=c++11\n")116 117            makefile.write("include Makefile.rules\n")118 119    def _test(self):120        self.BuildMakefile()121        self.build(dictionary=self._build_dict)122        self.do_test()123 124    def execute_user_command(self, __command):125        exec(__command, globals(), locals())126 127    def _get_breakpoint_ids(self, thread):128        ids = set()129        for i in range(0, thread.GetStopReasonDataCount(), 2):130            ids.add(thread.GetStopReasonDataAtIndex(i))131        self.assertGreater(len(ids), 0)132        return sorted(ids)133 134    def do_test(self):135        exe = self.getBuildArtifact("a.out")136        source_files = [f for f in os.listdir(self.getSourceDir()) if source_type(f)]137        target = self.dbg.CreateTarget(exe)138 139        parser = CommandParser()140        parser.parse_source_files(source_files)141        parser.set_breakpoints(target)142 143        process = target.LaunchSimple(None, None, self.get_process_working_directory())144        self.assertIsNotNone(process, PROCESS_IS_VALID)145 146        hit_breakpoints = 0147 148        while lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint):149            hit_breakpoints += 1150            thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)151            for bp_id in self._get_breakpoint_ids(thread):152                parser.handle_breakpoint(self, bp_id)153            process.Continue()154 155        self.assertTrue(156            hit_breakpoints > 0, "inline test did not hit a single breakpoint"157        )158        # Either the process exited or the stepping plan is complete.159        self.assertTrue(160            process.GetState() in [lldb.eStateStopped, lldb.eStateExited],161            PROCESS_EXITED,162        )163 164    def check_expression(self, expression, expected_result, use_summary=True):165        value = self.frame().EvaluateExpression(expression)166        self.assertTrue(value.IsValid(), expression + "returned a valid value")167        if self.TraceOn():168            print(value.GetSummary())169            print(value.GetValue())170        if use_summary:171            answer = value.GetSummary()172        else:173            answer = value.GetValue()174        report_str = "%s expected: %s got: %s" % (expression, expected_result, answer)175        self.assertTrue(answer == expected_result, report_str)176 177 178def ApplyDecoratorsToFunction(func, decorators):179    tmp = func180    if isinstance(decorators, list):181        for decorator in decorators:182            tmp = decorator(tmp)183    elif hasattr(decorators, "__call__"):184        tmp = decorators(tmp)185    return tmp186 187 188def MakeInlineTest(__file, __globals, decorators=None, name=None, build_dict=None):189    # Adjust the filename if it ends in .pyc.  We want filenames to190    # reflect the source python file, not the compiled variant.191    if __file is not None and __file.endswith(".pyc"):192        # Strip the trailing "c"193        __file = __file[0:-1]194 195    if name is None:196        # Derive the test name from the current file name197        file_basename = os.path.basename(__file)198        name, _ = os.path.splitext(file_basename)199 200    test_func = ApplyDecoratorsToFunction(InlineTest._test, decorators)201    # Build the test case202    test_class = type(203        name, (InlineTest,), dict(test=test_func, name=name, _build_dict=build_dict)204    )205 206    # Add the test case to the globals, and hide InlineTest207    __globals.update({name: test_class})208 209    # Keep track of the original test filename so we report it210    # correctly in test results.211    test_class.test_filename = __file212    test_class.mydir = TestBase.compute_mydir(__file)213    return test_class214