1"""
2Test setting a breakpoint by line and column.
3"""
4
5import re
6import lldb
7from lldbsuite.test.decorators import *
8from lldbsuite.test.lldbtest import *
9from lldbsuite.test import lldbutil
10
11
12class BreakpointByLineAndColumnTestCase(TestBase):
13    ## Skip gcc version less 7.1 since it doesn't support -gcolumn-info
14    @skipIf(compiler="gcc", compiler_version=["<", "7.1"])
15    def testBreakpointByLineAndColumn(self):
16        self.build()
17        src_file = lldb.SBFileSpec("main.cpp")
18        line = (
19            line_number("main.cpp", "At the beginning of a function name (col:50)") + 1
20        )  # Next line after comment
21        _, _, _, breakpoint = lldbutil.run_to_line_breakpoint(self, src_file, line, 50)
22        self.expect("fr v did_call", substrs=["1"])
23        in_then = False
24        for i in range(breakpoint.GetNumLocations()):
25            b_loc = breakpoint.GetLocationAtIndex(i).GetAddress().GetLineEntry()
26            self.assertEqual(b_loc.GetLine(), line)
27            in_then |= b_loc.GetColumn() == 50
28        self.assertTrue(in_then)
29
30    ## Skip gcc version less 7.1 since it doesn't support -gcolumn-info
31    @skipIf(compiler="gcc", compiler_version=["<", "7.1"])
32    def testBreakpointByLine(self):
33        self.build()
34        src_file = lldb.SBFileSpec("main.cpp")
35        line = (
36            line_number("main.cpp", "At the beginning of a function name (col:50)") + 1
37        )  # Next line after comment
38        _, _, _, breakpoint = lldbutil.run_to_line_breakpoint(self, src_file, line)
39        self.expect("fr v did_call", substrs=["0"])
40        in_condition = False
41        for i in range(breakpoint.GetNumLocations()):
42            b_loc = breakpoint.GetLocationAtIndex(i).GetAddress().GetLineEntry()
43            self.assertEqual(b_loc.GetLine(), line)
44            in_condition |= b_loc.GetColumn() < 30
45        self.assertTrue(in_condition)
46
47    @skipIfWindows
48    ## Skip gcc version less 7.1 since it doesn't support -gcolumn-info
49    @skipIf(compiler="gcc", compiler_version=["<", "7.1"])
50    def testBreakpointByLineAndColumnNearestCode(self):
51        self.build()
52
53        patterns = [
54            "In the middle of a function name (col:42)",
55            "In the middle of the lambda declaration argument (col:23)",
56            "Inside the lambda (col:26)",
57        ]
58
59        source_loc = []
60
61        for pattern in patterns:
62            line = line_number("main.cpp", pattern) + 1
63            column = int(re.search("\(col:([0-9]+)\)", pattern).group(1))
64            source_loc.append({"line": line, "column": column})
65
66        target = self.createTestTarget()
67
68        for loc in source_loc:
69            src_file = lldb.SBFileSpec("main.cpp")
70            line = loc["line"]
71            column = loc["column"]
72            indent = 0
73            module_list = lldb.SBFileSpecList()
74
75            valid_bpkt = target.BreakpointCreateByLocation(
76                src_file, line, column, indent, module_list, True
77            )
78            self.assertTrue(valid_bpkt, VALID_BREAKPOINT)
79            self.assertEqual(valid_bpkt.GetNumLocations(), 1)
80
81        process = target.LaunchSimple(None, None, self.get_process_working_directory())
82        self.assertTrue(process, PROCESS_IS_VALID)
83
84        nearest_column = [7, 17, 26]
85
86        for idx, loc in enumerate(source_loc):
87            bpkt = target.GetBreakpointAtIndex(idx)
88            bpkt_loc = bpkt.GetLocationAtIndex(0)
89            self.assertEqual(bpkt_loc.GetHitCount(), 1)
90            self.assertSuccess(process.Continue())
91            bpkt_loc_desc = lldb.SBStream()
92            self.assertTrue(
93                bpkt_loc.GetDescription(bpkt_loc_desc, lldb.eDescriptionLevelVerbose)
94            )
95            self.assertIn(
96                "main.cpp:{}:{}".format(loc["line"], nearest_column[idx]),
97                bpkt_loc_desc.GetData(),
98            )
99            bpkt_loc_addr = bpkt_loc.GetAddress()
100            self.assertTrue(bpkt_loc_addr)
101
102            list = target.FindCompileUnits(lldb.SBFileSpec("main.cpp", False))
103            # Executable has been built just from one source file 'main.cpp',
104            # so we may check only the first element of list.
105            compile_unit = list[0].GetCompileUnit()
106
107            found = False
108            for line_entry in compile_unit:
109                if line_entry.GetStartAddress() == bpkt_loc_addr:
110                    self.assertEqual(line_entry.GetFileSpec().GetFilename(), "main.cpp")
111                    self.assertEqual(line_entry.GetLine(), loc["line"])
112                    self.assertEqual(line_entry.GetColumn(), nearest_column[idx])
113                    found = True
114                    break
115
116            self.assertTrue(found)
117
118        line = line_number("main.cpp", "// This is a random comment.")
119        column = len("// This is a random comment.")
120        indent = 2
121        invalid_bpkt = target.BreakpointCreateByLocation(
122            src_file, line, column, indent, module_list, False
123        )
124        self.assertTrue(invalid_bpkt, VALID_BREAKPOINT)
125        self.assertEqual(invalid_bpkt.GetNumLocations(), 0)
126