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