1"""
2Test lldb-vscode setBreakpoints request
3"""
4
5
6import unittest2
7import vscode
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11import lldbvscode_testcase
12import os
13
14
15class TestVSCode_setBreakpoints(lldbvscode_testcase.VSCodeTestCaseBase):
16
17    mydir = TestBase.compute_mydir(__file__)
18
19    @skipIfWindows
20    @skipIfRemote
21    def test_set_and_clear(self):
22        '''Tests setting and clearing source file and line breakpoints.
23           This packet is a bit tricky on the debug adaptor side since there
24           is no "clearBreakpoints" packet. Source file and line breakpoints
25           are set by sending a "setBreakpoints" packet with a source file
26           specified and zero or more source lines. If breakpoints have been
27           set in the source file before, any exising breakpoints must remain
28           set, and any new breakpoints must be created, and any breakpoints
29           that were in previous requests and are not in the current request
30           must be removed. This function tests this setting and clearing
31           and makes sure things happen correctly. It doesn't test hitting
32           breakpoints and the functionality of each breakpoint, like
33           'conditions' and 'hitCondition' settings.'''
34        source_basename = 'main.cpp'
35        source_path = os.path.join(os.getcwd(), source_basename)
36        first_line = line_number('main.cpp', 'break 12')
37        second_line = line_number('main.cpp', 'break 13')
38        third_line = line_number('main.cpp', 'break 14')
39        lines = [first_line, second_line, third_line]
40
41        # Visual Studio Code Debug Adaptors have no way to specify the file
42        # without launching or attaching to a process, so we must start a
43        # process in order to be able to set breakpoints.
44        program = self.getBuildArtifact("a.out")
45        self.build_and_launch(program)
46
47        # Set 3 breakoints and verify that they got set correctly
48        response = self.vscode.request_setBreakpoints(source_path, lines)
49        line_to_id = {}
50        if response:
51            breakpoints = response['body']['breakpoints']
52            self.assertEquals(len(breakpoints), len(lines),
53                            "expect %u source breakpoints" % (len(lines)))
54            for breakpoint in breakpoints:
55                line = breakpoint['line']
56                # Store the "id" of the breakpoint that was set for later
57                line_to_id[line] = breakpoint['id']
58                self.assertTrue(line in lines, "line expected in lines array")
59                self.assertTrue(breakpoint['verified'],
60                                "expect breakpoint verified")
61
62        # There is no breakpoint delete packet, clients just send another
63        # setBreakpoints packet with the same source file with fewer lines.
64        # Below we remove the second line entry and call the setBreakpoints
65        # function again. We want to verify that any breakpoints that were set
66        # before still have the same "id". This means we didn't clear the
67        # breakpoint and set it again at the same location. We also need to
68        # verify that the second line location was actually removed.
69        lines.remove(second_line)
70        # Set 2 breakoints and verify that the previous breakoints that were
71        # set above are still set.
72        response = self.vscode.request_setBreakpoints(source_path, lines)
73        if response:
74            breakpoints = response['body']['breakpoints']
75            self.assertEquals(len(breakpoints), len(lines),
76                            "expect %u source breakpoints" % (len(lines)))
77            for breakpoint in breakpoints:
78                line = breakpoint['line']
79                # Verify the same breakpoints are still set within LLDB by
80                # making sure the breakpoint ID didn't change
81                self.assertEquals(line_to_id[line], breakpoint['id'],
82                                "verify previous breakpoints stayed the same")
83                self.assertTrue(line in lines, "line expected in lines array")
84                self.assertTrue(breakpoint['verified'],
85                                "expect breakpoint still verified")
86
87        # Now get the full list of breakpoints set in the target and verify
88        # we have only 2 breakpoints set. The response above could have told
89        # us about 2 breakpoints, but we want to make sure we don't have the
90        # third one still set in the target
91        response = self.vscode.request_testGetTargetBreakpoints()
92        if response:
93            breakpoints = response['body']['breakpoints']
94            self.assertEquals(len(breakpoints), len(lines),
95                            "expect %u source breakpoints" % (len(lines)))
96            for breakpoint in breakpoints:
97                line = breakpoint['line']
98                # Verify the same breakpoints are still set within LLDB by
99                # making sure the breakpoint ID didn't change
100                self.assertEquals(line_to_id[line], breakpoint['id'],
101                                "verify previous breakpoints stayed the same")
102                self.assertTrue(line in lines, "line expected in lines array")
103                self.assertTrue(breakpoint['verified'],
104                                "expect breakpoint still verified")
105
106        # Now clear all breakpoints for the source file by passing down an
107        # empty lines array
108        lines = []
109        response = self.vscode.request_setBreakpoints(source_path, lines)
110        if response:
111            breakpoints = response['body']['breakpoints']
112            self.assertEquals(len(breakpoints), len(lines),
113                            "expect %u source breakpoints" % (len(lines)))
114
115        # Verify with the target that all breakpoints have been cleared
116        response = self.vscode.request_testGetTargetBreakpoints()
117        if response:
118            breakpoints = response['body']['breakpoints']
119            self.assertEquals(len(breakpoints), len(lines),
120                            "expect %u source breakpoints" % (len(lines)))
121
122        # Now set a breakpoint again in the same source file and verify it
123        # was added.
124        lines = [second_line]
125        response = self.vscode.request_setBreakpoints(source_path, lines)
126        if response:
127            breakpoints = response['body']['breakpoints']
128            self.assertEquals(len(breakpoints), len(lines),
129                            "expect %u source breakpoints" % (len(lines)))
130            for breakpoint in breakpoints:
131                line = breakpoint['line']
132                self.assertTrue(line in lines, "line expected in lines array")
133                self.assertTrue(breakpoint['verified'],
134                                "expect breakpoint still verified")
135
136        # Now get the full list of breakpoints set in the target and verify
137        # we have only 2 breakpoints set. The response above could have told
138        # us about 2 breakpoints, but we want to make sure we don't have the
139        # third one still set in the target
140        response = self.vscode.request_testGetTargetBreakpoints()
141        if response:
142            breakpoints = response['body']['breakpoints']
143            self.assertEquals(len(breakpoints), len(lines),
144                            "expect %u source breakpoints" % (len(lines)))
145            for breakpoint in breakpoints:
146                line = breakpoint['line']
147                self.assertTrue(line in lines, "line expected in lines array")
148                self.assertTrue(breakpoint['verified'],
149                                "expect breakpoint still verified")
150
151    @skipIfWindows
152    @skipIfRemote
153    def test_functionality(self):
154        '''Tests hitting breakpoints and the functionality of a single
155           breakpoint, like 'conditions' and 'hitCondition' settings.'''
156        source_basename = 'main.cpp'
157        source_path = os.path.join(os.getcwd(), source_basename)
158        loop_line = line_number('main.cpp', '// break loop')
159
160        program = self.getBuildArtifact("a.out")
161        self.build_and_launch(program)
162        # Set a breakpoint at the loop line with no condition and no
163        # hitCondition
164        breakpoint_ids = self.set_source_breakpoints(source_path, [loop_line])
165        self.assertEquals(len(breakpoint_ids), 1, "expect one breakpoint")
166        self.vscode.request_continue()
167
168        # Verify we hit the breakpoint we just set
169        self.verify_breakpoint_hit(breakpoint_ids)
170
171        # Make sure i is zero at first breakpoint
172        i = int(self.vscode.get_local_variable_value('i'))
173        self.assertEquals(i, 0, 'i != 0 after hitting breakpoint')
174
175        # Update the condition on our breakpoint
176        new_breakpoint_ids = self.set_source_breakpoints(source_path,
177                                                         [loop_line],
178                                                         condition="i==4")
179        self.assertEquals(breakpoint_ids, new_breakpoint_ids,
180                        "existing breakpoint should have its condition "
181                        "updated")
182
183        self.continue_to_breakpoints(breakpoint_ids)
184        i = int(self.vscode.get_local_variable_value('i'))
185        self.assertEquals(i, 4,
186                        'i != 4 showing conditional works')
187
188        new_breakpoint_ids = self.set_source_breakpoints(source_path,
189                                                         [loop_line],
190                                                         hitCondition="2")
191
192        self.assertEquals(breakpoint_ids, new_breakpoint_ids,
193                        "existing breakpoint should have its condition "
194                        "updated")
195
196        # Continue with a hitContidtion of 2 and expect it to skip 1 value
197        self.continue_to_breakpoints(breakpoint_ids)
198        i = int(self.vscode.get_local_variable_value('i'))
199        self.assertEquals(i, 6,
200                        'i != 6 showing hitCondition works')
201
202        # continue after hitting our hitCondition and make sure it only goes
203        # up by 1
204        self.continue_to_breakpoints(breakpoint_ids)
205        i = int(self.vscode.get_local_variable_value('i'))
206        self.assertEquals(i, 7,
207                        'i != 7 showing post hitCondition hits every time')
208