1""" 2Test lldb-vscode setBreakpoints request 3""" 4 5 6import unittest2 7import vscode 8import shutil 9from lldbsuite.test.decorators import * 10from lldbsuite.test.lldbtest import * 11from lldbsuite.test import lldbutil 12import lldbvscode_testcase 13import os 14 15 16class TestVSCode_setBreakpoints(lldbvscode_testcase.VSCodeTestCaseBase): 17 18 mydir = TestBase.compute_mydir(__file__) 19 20 def setUp(self): 21 lldbvscode_testcase.VSCodeTestCaseBase.setUp(self) 22 23 self.main_basename = 'main-copy.cpp' 24 self.main_path = os.path.realpath(self.getBuildArtifact(self.main_basename)) 25 26 @skipIfWindows 27 @skipIfRemote 28 def test_source_map(self): 29 self.build_and_create_debug_adaptor() 30 31 other_basename = 'other-copy.c' 32 other_path = self.getBuildArtifact(other_basename) 33 34 source_folder = os.path.dirname(self.main_path) 35 36 new_main_folder = os.path.join(source_folder, 'moved_main') 37 new_other_folder = os.path.join(source_folder, 'moved_other') 38 39 new_main_path = os.path.join(new_main_folder, self.main_basename) 40 new_other_path = os.path.join(new_other_folder, other_basename) 41 42 # move the sources 43 os.mkdir(new_main_folder) 44 os.mkdir(new_other_folder) 45 shutil.move(self.main_path, new_main_path) 46 shutil.move(other_path, new_other_path) 47 48 main_line = line_number('main.cpp', 'break 12') 49 other_line = line_number('other.c', 'break other') 50 51 program = self.getBuildArtifact("a.out") 52 source_map = [ 53 [source_folder, new_main_folder], 54 [source_folder, new_other_folder], 55 ] 56 self.launch(program, sourceMap=source_map) 57 58 # breakpoint in main.cpp 59 response = self.vscode.request_setBreakpoints(new_main_path, [main_line]) 60 breakpoints = response['body']['breakpoints'] 61 self.assertEquals(len(breakpoints), 1) 62 breakpoint = breakpoints[0] 63 self.assertEqual(breakpoint['line'], main_line) 64 self.assertTrue(breakpoint['verified']) 65 self.assertEqual(self.main_basename, breakpoint['source']['name']) 66 self.assertEqual(new_main_path, breakpoint['source']['path']) 67 68 # 2nd breakpoint, which is from a dynamically loaded library 69 response = self.vscode.request_setBreakpoints(new_other_path, [other_line]) 70 breakpoints = response['body']['breakpoints'] 71 breakpoint = breakpoints[0] 72 self.assertEqual(breakpoint['line'], other_line) 73 self.assertFalse(breakpoint['verified']) 74 self.assertEqual(other_basename, breakpoint['source']['name']) 75 self.assertEqual(new_other_path, breakpoint['source']['path']) 76 other_breakpoint_id = breakpoint['id'] 77 78 self.vscode.request_continue() 79 self.verify_breakpoint_hit([other_breakpoint_id]) 80 81 # 2nd breakpoint again, which should be valid at this point 82 response = self.vscode.request_setBreakpoints(new_other_path, [other_line]) 83 breakpoints = response['body']['breakpoints'] 84 breakpoint = breakpoints[0] 85 self.assertEqual(breakpoint['line'], other_line) 86 self.assertTrue(breakpoint['verified']) 87 self.assertEqual(other_basename, breakpoint['source']['name']) 88 self.assertEqual(new_other_path, breakpoint['source']['path']) 89 90 @skipIfWindows 91 @skipIfRemote 92 def test_set_and_clear(self): 93 '''Tests setting and clearing source file and line breakpoints. 94 This packet is a bit tricky on the debug adaptor side since there 95 is no "clearBreakpoints" packet. Source file and line breakpoints 96 are set by sending a "setBreakpoints" packet with a source file 97 specified and zero or more source lines. If breakpoints have been 98 set in the source file before, any existing breakpoints must remain 99 set, and any new breakpoints must be created, and any breakpoints 100 that were in previous requests and are not in the current request 101 must be removed. This function tests this setting and clearing 102 and makes sure things happen correctly. It doesn't test hitting 103 breakpoints and the functionality of each breakpoint, like 104 'conditions' and 'hitCondition' settings.''' 105 first_line = line_number('main.cpp', 'break 12') 106 second_line = line_number('main.cpp', 'break 13') 107 third_line = line_number('main.cpp', 'break 14') 108 lines = [first_line, third_line, second_line] 109 110 # Visual Studio Code Debug Adaptors have no way to specify the file 111 # without launching or attaching to a process, so we must start a 112 # process in order to be able to set breakpoints. 113 program = self.getBuildArtifact("a.out") 114 self.build_and_launch(program) 115 116 # Set 3 breakpoints and verify that they got set correctly 117 response = self.vscode.request_setBreakpoints(self.main_path, lines) 118 line_to_id = {} 119 if response: 120 breakpoints = response['body']['breakpoints'] 121 self.assertEquals(len(breakpoints), len(lines), 122 "expect %u source breakpoints" % (len(lines))) 123 for (breakpoint, index) in zip(breakpoints, range(len(lines))): 124 line = breakpoint['line'] 125 self.assertTrue(line, lines[index]) 126 # Store the "id" of the breakpoint that was set for later 127 line_to_id[line] = breakpoint['id'] 128 self.assertIn(line, lines, "line expected in lines array") 129 self.assertTrue(breakpoint['verified'], 130 "expect breakpoint verified") 131 132 # There is no breakpoint delete packet, clients just send another 133 # setBreakpoints packet with the same source file with fewer lines. 134 # Below we remove the second line entry and call the setBreakpoints 135 # function again. We want to verify that any breakpoints that were set 136 # before still have the same "id". This means we didn't clear the 137 # breakpoint and set it again at the same location. We also need to 138 # verify that the second line location was actually removed. 139 lines.remove(second_line) 140 # Set 2 breakpoints and verify that the previous breakpoints that were 141 # set above are still set. 142 response = self.vscode.request_setBreakpoints(self.main_path, lines) 143 if response: 144 breakpoints = response['body']['breakpoints'] 145 self.assertEquals(len(breakpoints), len(lines), 146 "expect %u source breakpoints" % (len(lines))) 147 for (breakpoint, index) in zip(breakpoints, range(len(lines))): 148 line = breakpoint['line'] 149 self.assertTrue(line, lines[index]) 150 # Verify the same breakpoints are still set within LLDB by 151 # making sure the breakpoint ID didn't change 152 self.assertEquals(line_to_id[line], breakpoint['id'], 153 "verify previous breakpoints stayed the same") 154 self.assertIn(line, lines, "line expected in lines array") 155 self.assertTrue(breakpoint['verified'], 156 "expect breakpoint still verified") 157 158 # Now get the full list of breakpoints set in the target and verify 159 # we have only 2 breakpoints set. The response above could have told 160 # us about 2 breakpoints, but we want to make sure we don't have the 161 # third one still set in the target 162 response = self.vscode.request_testGetTargetBreakpoints() 163 if response: 164 breakpoints = response['body']['breakpoints'] 165 self.assertEquals(len(breakpoints), len(lines), 166 "expect %u source breakpoints" % (len(lines))) 167 for breakpoint in breakpoints: 168 line = breakpoint['line'] 169 # Verify the same breakpoints are still set within LLDB by 170 # making sure the breakpoint ID didn't change 171 self.assertEquals(line_to_id[line], breakpoint['id'], 172 "verify previous breakpoints stayed the same") 173 self.assertIn(line, lines, "line expected in lines array") 174 self.assertTrue(breakpoint['verified'], 175 "expect breakpoint still verified") 176 177 # Now clear all breakpoints for the source file by passing down an 178 # empty lines array 179 lines = [] 180 response = self.vscode.request_setBreakpoints(self.main_path, lines) 181 if response: 182 breakpoints = response['body']['breakpoints'] 183 self.assertEquals(len(breakpoints), len(lines), 184 "expect %u source breakpoints" % (len(lines))) 185 186 # Verify with the target that all breakpoints have been cleared 187 response = self.vscode.request_testGetTargetBreakpoints() 188 if response: 189 breakpoints = response['body']['breakpoints'] 190 self.assertEquals(len(breakpoints), len(lines), 191 "expect %u source breakpoints" % (len(lines))) 192 193 # Now set a breakpoint again in the same source file and verify it 194 # was added. 195 lines = [second_line] 196 response = self.vscode.request_setBreakpoints(self.main_path, lines) 197 if response: 198 breakpoints = response['body']['breakpoints'] 199 self.assertEquals(len(breakpoints), len(lines), 200 "expect %u source breakpoints" % (len(lines))) 201 for breakpoint in breakpoints: 202 line = breakpoint['line'] 203 self.assertIn(line, lines, "line expected in lines array") 204 self.assertTrue(breakpoint['verified'], 205 "expect breakpoint still verified") 206 207 # Now get the full list of breakpoints set in the target and verify 208 # we have only 2 breakpoints set. The response above could have told 209 # us about 2 breakpoints, but we want to make sure we don't have the 210 # third one still set in the target 211 response = self.vscode.request_testGetTargetBreakpoints() 212 if response: 213 breakpoints = response['body']['breakpoints'] 214 self.assertEquals(len(breakpoints), len(lines), 215 "expect %u source breakpoints" % (len(lines))) 216 for breakpoint in breakpoints: 217 line = breakpoint['line'] 218 self.assertIn(line, lines, "line expected in lines array") 219 self.assertTrue(breakpoint['verified'], 220 "expect breakpoint still verified") 221 222 @skipIfWindows 223 @skipIfRemote 224 def test_clear_breakpoints_unset_breakpoints(self): 225 '''Test clearing breakpoints like test_set_and_clear, but clear 226 breakpoints by omitting the breakpoints array instead of sending an 227 empty one.''' 228 lines = [line_number('main.cpp', 'break 12'), 229 line_number('main.cpp', 'break 13')] 230 231 # Visual Studio Code Debug Adaptors have no way to specify the file 232 # without launching or attaching to a process, so we must start a 233 # process in order to be able to set breakpoints. 234 program = self.getBuildArtifact("a.out") 235 self.build_and_launch(program) 236 237 # Set one breakpoint and verify that it got set correctly. 238 response = self.vscode.request_setBreakpoints(self.main_path, lines) 239 line_to_id = {} 240 breakpoints = response['body']['breakpoints'] 241 self.assertEquals(len(breakpoints), len(lines), 242 "expect %u source breakpoints" % (len(lines))) 243 for (breakpoint, index) in zip(breakpoints, range(len(lines))): 244 line = breakpoint['line'] 245 self.assertTrue(line, lines[index]) 246 # Store the "id" of the breakpoint that was set for later 247 line_to_id[line] = breakpoint['id'] 248 self.assertIn(line, lines, "line expected in lines array") 249 self.assertTrue(breakpoint['verified'], 250 "expect breakpoint verified") 251 252 # Now clear all breakpoints for the source file by not setting the 253 # lines array. 254 lines = None 255 response = self.vscode.request_setBreakpoints(self.main_path, lines) 256 breakpoints = response['body']['breakpoints'] 257 self.assertEquals(len(breakpoints), 0, "expect no source breakpoints") 258 259 # Verify with the target that all breakpoints have been cleared. 260 response = self.vscode.request_testGetTargetBreakpoints() 261 breakpoints = response['body']['breakpoints'] 262 self.assertEquals(len(breakpoints), 0, "expect no source breakpoints") 263 264 @skipIfWindows 265 @skipIfRemote 266 def test_functionality(self): 267 '''Tests hitting breakpoints and the functionality of a single 268 breakpoint, like 'conditions' and 'hitCondition' settings.''' 269 loop_line = line_number('main.cpp', '// break loop') 270 271 program = self.getBuildArtifact("a.out") 272 self.build_and_launch(program) 273 # Set a breakpoint at the loop line with no condition and no 274 # hitCondition 275 breakpoint_ids = self.set_source_breakpoints(self.main_path, [loop_line]) 276 self.assertEquals(len(breakpoint_ids), 1, "expect one breakpoint") 277 self.vscode.request_continue() 278 279 # Verify we hit the breakpoint we just set 280 self.verify_breakpoint_hit(breakpoint_ids) 281 282 # Make sure i is zero at first breakpoint 283 i = int(self.vscode.get_local_variable_value('i')) 284 self.assertEquals(i, 0, 'i != 0 after hitting breakpoint') 285 286 # Update the condition on our breakpoint 287 new_breakpoint_ids = self.set_source_breakpoints(self.main_path, 288 [loop_line], 289 condition="i==4") 290 self.assertEquals(breakpoint_ids, new_breakpoint_ids, 291 "existing breakpoint should have its condition " 292 "updated") 293 294 self.continue_to_breakpoints(breakpoint_ids) 295 i = int(self.vscode.get_local_variable_value('i')) 296 self.assertEquals(i, 4, 297 'i != 4 showing conditional works') 298 299 new_breakpoint_ids = self.set_source_breakpoints(self.main_path, 300 [loop_line], 301 hitCondition="2") 302 303 self.assertEquals(breakpoint_ids, new_breakpoint_ids, 304 "existing breakpoint should have its condition " 305 "updated") 306 307 # Continue with a hitCondition of 2 and expect it to skip 1 value 308 self.continue_to_breakpoints(breakpoint_ids) 309 i = int(self.vscode.get_local_variable_value('i')) 310 self.assertEquals(i, 6, 311 'i != 6 showing hitCondition works') 312 313 # continue after hitting our hitCondition and make sure it only goes 314 # up by 1 315 self.continue_to_breakpoints(breakpoint_ids) 316 i = int(self.vscode.get_local_variable_value('i')) 317 self.assertEquals(i, 7, 318 'i != 7 showing post hitCondition hits every time') 319