xref: /llvm-project/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py (revision fa6377119c0624773cb698935692d46843e9f6ec)
1"""
2Test lldb-dap setBreakpoints request
3"""
4
5
6import dap_server
7from lldbsuite.test.decorators import *
8from lldbsuite.test.lldbtest import *
9from lldbsuite.test import lldbutil
10import lldbdap_testcase
11
12
13class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase):
14    @skipIfWindows
15    def test_set_and_clear(self):
16        """Tests setting and clearing function breakpoints.
17        This packet is a bit tricky on the debug adaptor side since there
18        is no "clearFunction Breakpoints" packet. Function breakpoints
19        are set by sending a "setFunctionBreakpoints" packet with zero or
20        more function names. If function breakpoints have been set before,
21        any existing breakpoints must remain set, and any new breakpoints
22        must be created, and any breakpoints that were in previous requests
23        and are not in the current request must be removed. This function
24        tests this setting and clearing and makes sure things happen
25        correctly. It doesn't test hitting breakpoints and the functionality
26        of each breakpoint, like 'conditions' and 'hitCondition' settings.
27        """
28        # Visual Studio Code Debug Adaptors have no way to specify the file
29        # without launching or attaching to a process, so we must start a
30        # process in order to be able to set breakpoints.
31        program = self.getBuildArtifact("a.out")
32        self.build_and_launch(program)
33        bp_id_12 = None
34        functions = ["twelve"]
35        # Set a function breakpoint at 'twelve'
36        response = self.dap_server.request_setFunctionBreakpoints(functions)
37        if response:
38            breakpoints = response["body"]["breakpoints"]
39            self.assertEqual(
40                len(breakpoints),
41                len(functions),
42                "expect %u source breakpoints" % (len(functions)),
43            )
44            for breakpoint in breakpoints:
45                bp_id_12 = breakpoint["id"]
46                self.assertTrue(breakpoint["verified"], "expect breakpoint verified")
47
48        # Add an extra name and make sure we have two breakpoints after this
49        functions.append("thirteen")
50        response = self.dap_server.request_setFunctionBreakpoints(functions)
51        if response:
52            breakpoints = response["body"]["breakpoints"]
53            self.assertEqual(
54                len(breakpoints),
55                len(functions),
56                "expect %u source breakpoints" % (len(functions)),
57            )
58            for breakpoint in breakpoints:
59                self.assertTrue(breakpoint["verified"], "expect breakpoint verified")
60
61        # There is no breakpoint delete packet, clients just send another
62        # setFunctionBreakpoints packet with the different function names.
63        functions.remove("thirteen")
64        response = self.dap_server.request_setFunctionBreakpoints(functions)
65        if response:
66            breakpoints = response["body"]["breakpoints"]
67            self.assertEqual(
68                len(breakpoints),
69                len(functions),
70                "expect %u source breakpoints" % (len(functions)),
71            )
72            for breakpoint in breakpoints:
73                bp_id = breakpoint["id"]
74                self.assertEqual(
75                    bp_id, bp_id_12, 'verify "twelve" breakpoint ID is same'
76                )
77                self.assertTrue(
78                    breakpoint["verified"], "expect breakpoint still verified"
79                )
80
81        # Now get the full list of breakpoints set in the target and verify
82        # we have only 1 breakpoints set. The response above could have told
83        # us about 1 breakpoints, but we want to make sure we don't have the
84        # second one still set in the target
85        response = self.dap_server.request_testGetTargetBreakpoints()
86        if response:
87            breakpoints = response["body"]["breakpoints"]
88            self.assertEqual(
89                len(breakpoints),
90                len(functions),
91                "expect %u source breakpoints" % (len(functions)),
92            )
93            for breakpoint in breakpoints:
94                bp_id = breakpoint["id"]
95                self.assertEqual(
96                    bp_id, bp_id_12, 'verify "twelve" breakpoint ID is same'
97                )
98                self.assertTrue(
99                    breakpoint["verified"], "expect breakpoint still verified"
100                )
101
102        # Now clear all breakpoints for the source file by passing down an
103        # empty lines array
104        functions = []
105        response = self.dap_server.request_setFunctionBreakpoints(functions)
106        if response:
107            breakpoints = response["body"]["breakpoints"]
108            self.assertEqual(
109                len(breakpoints),
110                len(functions),
111                "expect %u source breakpoints" % (len(functions)),
112            )
113
114        # Verify with the target that all breakpoints have been cleared
115        response = self.dap_server.request_testGetTargetBreakpoints()
116        if response:
117            breakpoints = response["body"]["breakpoints"]
118            self.assertEqual(
119                len(breakpoints),
120                len(functions),
121                "expect %u source breakpoints" % (len(functions)),
122            )
123
124    @skipIfWindows
125    def test_functionality(self):
126        """Tests hitting breakpoints and the functionality of a single
127        breakpoint, like 'conditions' and 'hitCondition' settings."""
128
129        program = self.getBuildArtifact("a.out")
130        self.build_and_launch(program)
131        # Set a breakpoint on "twelve" with no condition and no hitCondition
132        functions = ["twelve"]
133        breakpoint_ids = self.set_function_breakpoints(functions)
134
135        self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint")
136
137        # Verify we hit the breakpoint we just set
138        self.continue_to_breakpoints(breakpoint_ids)
139
140        # Make sure i is zero at first breakpoint
141        i = int(self.dap_server.get_local_variable_value("i"))
142        self.assertEqual(i, 0, "i != 0 after hitting breakpoint")
143
144        # Update the condition on our breakpoint
145        new_breakpoint_ids = self.set_function_breakpoints(functions, condition="i==4")
146        self.assertEqual(
147            breakpoint_ids,
148            new_breakpoint_ids,
149            "existing breakpoint should have its condition " "updated",
150        )
151
152        self.continue_to_breakpoints(breakpoint_ids)
153        i = int(self.dap_server.get_local_variable_value("i"))
154        self.assertEqual(i, 4, "i != 4 showing conditional works")
155        new_breakpoint_ids = self.set_function_breakpoints(functions, hitCondition="2")
156
157        self.assertEqual(
158            breakpoint_ids,
159            new_breakpoint_ids,
160            "existing breakpoint should have its condition " "updated",
161        )
162
163        # Continue with a hitCondition of 2 and expect it to skip 1 value
164        self.continue_to_breakpoints(breakpoint_ids)
165        i = int(self.dap_server.get_local_variable_value("i"))
166        self.assertEqual(i, 6, "i != 6 showing hitCondition works")
167
168        # continue after hitting our hitCondition and make sure it only goes
169        # up by 1
170        self.continue_to_breakpoints(breakpoint_ids)
171        i = int(self.dap_server.get_local_variable_value("i"))
172        self.assertEqual(i, 7, "i != 7 showing post hitCondition hits every time")
173