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