"""
Test lldb-dap setBreakpoints request
"""
import dap_server
import shutil
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
import lldbdap_testcase
import os
class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase):
def setUp(self):
lldbdap_testcase.DAPTestCaseBase.setUp(self)
self.main_basename = "main-copy.cpp"
self.main_path = os.path.realpath(self.getBuildArtifact(self.main_basename))
@skipIfWindows
def test_source_map(self):
"""
This test simulates building two files in a folder, and then moving
each source to a different folder. Then, the debug session is started
with the corresponding source maps to have breakpoints and frames
working.
"""
self.build_and_create_debug_adaptor()
other_basename = "other-copy.c"
other_path = self.getBuildArtifact(other_basename)
source_folder = os.path.dirname(self.main_path)
new_main_folder = os.path.join(source_folder, "moved_main")
new_other_folder = os.path.join(source_folder, "moved_other")
new_main_path = os.path.join(new_main_folder, self.main_basename)
new_other_path = os.path.join(new_other_folder, other_basename)
os.mkdir(new_main_folder)
os.mkdir(new_other_folder)
shutil.move(self.main_path, new_main_path)
shutil.move(other_path, new_other_path)
main_line = line_number("main.cpp", "break 12")
other_line = line_number("other.c", "break other")
program = self.getBuildArtifact("a.out")
source_map = [
[source_folder, new_main_folder],
[source_folder, new_other_folder],
]
self.launch(program, sourceMap=source_map)
response = self.dap_server.request_setBreakpoints(new_main_path, [main_line])
breakpoints = response["body"]["breakpoints"]
self.assertEqual(len(breakpoints), 1)
breakpoint = breakpoints[0]
self.assertEqual(breakpoint["line"], main_line)
self.assertTrue(breakpoint["verified"])
self.assertEqual(self.main_basename, breakpoint["source"]["name"])
self.assertEqual(new_main_path, breakpoint["source"]["path"])
response = self.dap_server.request_setBreakpoints(new_other_path, [other_line])
breakpoints = response["body"]["breakpoints"]
breakpoint = breakpoints[0]
self.assertEqual(breakpoint["line"], other_line)
self.assertFalse(breakpoint["verified"])
self.assertEqual(other_basename, breakpoint["source"]["name"])
self.assertEqual(new_other_path, breakpoint["source"]["path"])
other_breakpoint_id = breakpoint["id"]
self.dap_server.request_continue()
self.verify_breakpoint_hit([other_breakpoint_id])
response = self.dap_server.request_setBreakpoints(new_other_path, [other_line])
breakpoints = response["body"]["breakpoints"]
breakpoint = breakpoints[0]
self.assertEqual(breakpoint["line"], other_line)
self.assertTrue(breakpoint["verified"])
self.assertEqual(other_basename, breakpoint["source"]["name"])
self.assertEqual(new_other_path, breakpoint["source"]["path"])
frames = self.dap_server.request_stackTrace()["body"]["stackFrames"]
self.assertEqual(frames[0]["source"]["name"], other_basename)
self.assertEqual(frames[0]["source"]["path"], new_other_path)
self.assertEqual(frames[1]["source"]["name"], self.main_basename)
self.assertEqual(frames[1]["source"]["path"], new_main_path)
@skipIfWindows
def test_set_and_clear(self):
"""Tests setting and clearing source file and line breakpoints.
This packet is a bit tricky on the debug adaptor side since there
is no "clearBreakpoints" packet. Source file and line breakpoints
are set by sending a "setBreakpoints" packet with a source file
specified and zero or more source lines. If breakpoints have been
set in the source file before, any existing breakpoints must remain
set, and any new breakpoints must be created, and any breakpoints
that were in previous requests and are not in the current request
must be removed. This function tests this setting and clearing
and makes sure things happen correctly. It doesn't test hitting
breakpoints and the functionality of each breakpoint, like
'conditions' and 'hitCondition' settings."""
first_line = line_number("main.cpp", "break 12")
second_line = line_number("main.cpp", "break 13")
third_line = line_number("main.cpp", "break 14")
lines = [first_line, third_line, second_line]
program = self.getBuildArtifact("a.out")
self.build_and_launch(program)
response = self.dap_server.request_setBreakpoints(self.main_path, lines)
line_to_id = {}
if response:
breakpoints = response["body"]["breakpoints"]
self.assertEqual(
len(breakpoints),
len(lines),
"expect %u source breakpoints" % (len(lines)),
)
for breakpoint, index in zip(breakpoints, range(len(lines))):
line = breakpoint["line"]
self.assertTrue(line, lines[index])
line_to_id[line] = breakpoint["id"]
self.assertIn(line, lines, "line expected in lines array")
self.assertTrue(breakpoint["verified"], "expect breakpoint verified")
lines.remove(second_line)
response = self.dap_server.request_setBreakpoints(self.main_path, lines)
if response:
breakpoints = response["body"]["breakpoints"]
self.assertEqual(
len(breakpoints),
len(lines),
"expect %u source breakpoints" % (len(lines)),
)
for breakpoint, index in zip(breakpoints, range(len(lines))):
line = breakpoint["line"]
self.assertTrue(line, lines[index])
self.assertEqual(
line_to_id[line],
breakpoint["id"],
"verify previous breakpoints stayed the same",
)
self.assertIn(line, lines, "line expected in lines array")
self.assertTrue(
breakpoint["verified"], "expect breakpoint still verified"
)
response = self.dap_server.request_testGetTargetBreakpoints()
if response:
breakpoints = response["body"]["breakpoints"]
self.assertEqual(
len(breakpoints),
len(lines),
"expect %u source breakpoints" % (len(lines)),
)
for breakpoint in breakpoints:
line = breakpoint["line"]
self.assertEqual(
line_to_id[line],
breakpoint["id"],
"verify previous breakpoints stayed the same",
)
self.assertIn(line, lines, "line expected in lines array")
self.assertTrue(
breakpoint["verified"], "expect breakpoint still verified"
)
lines = []
response = self.dap_server.request_setBreakpoints(self.main_path, lines)
if response:
breakpoints = response["body"]["breakpoints"]
self.assertEqual(
len(breakpoints),
len(lines),
"expect %u source breakpoints" % (len(lines)),
)
response = self.dap_server.request_testGetTargetBreakpoints()
if response:
breakpoints = response["body"]["breakpoints"]
self.assertEqual(
len(breakpoints),
len(lines),
"expect %u source breakpoints" % (len(lines)),
)
lines = [second_line]
response = self.dap_server.request_setBreakpoints(self.main_path, lines)
if response:
breakpoints = response["body"]["breakpoints"]
self.assertEqual(
len(breakpoints),
len(lines),
"expect %u source breakpoints" % (len(lines)),
)
for breakpoint in breakpoints:
line = breakpoint["line"]
self.assertIn(line, lines, "line expected in lines array")
self.assertTrue(
breakpoint["verified"], "expect breakpoint still verified"
)
response = self.dap_server.request_testGetTargetBreakpoints()
if response:
breakpoints = response["body"]["breakpoints"]
self.assertEqual(
len(breakpoints),
len(lines),
"expect %u source breakpoints" % (len(lines)),
)
for breakpoint in breakpoints:
line = breakpoint["line"]
self.assertIn(line, lines, "line expected in lines array")
self.assertTrue(
breakpoint["verified"], "expect breakpoint still verified"
)
@skipIfWindows
def test_clear_breakpoints_unset_breakpoints(self):
"""Test clearing breakpoints like test_set_and_clear, but clear
breakpoints by omitting the breakpoints array instead of sending an
empty one."""
lines = [
line_number("main.cpp", "break 12"),
line_number("main.cpp", "break 13"),
]
program = self.getBuildArtifact("a.out")
self.build_and_launch(program)
response = self.dap_server.request_setBreakpoints(self.main_path, lines)
line_to_id = {}
breakpoints = response["body"]["breakpoints"]
self.assertEqual(
len(breakpoints), len(lines), "expect %u source breakpoints" % (len(lines))
)
for breakpoint, index in zip(breakpoints, range(len(lines))):
line = breakpoint["line"]
self.assertTrue(line, lines[index])
line_to_id[line] = breakpoint["id"]
self.assertIn(line, lines, "line expected in lines array")
self.assertTrue(breakpoint["verified"], "expect breakpoint verified")
lines = None
response = self.dap_server.request_setBreakpoints(self.main_path, lines)
breakpoints = response["body"]["breakpoints"]
self.assertEqual(len(breakpoints), 0, "expect no source breakpoints")
response = self.dap_server.request_testGetTargetBreakpoints()
breakpoints = response["body"]["breakpoints"]
self.assertEqual(len(breakpoints), 0, "expect no source breakpoints")
@skipIfWindows
def test_functionality(self):
"""Tests hitting breakpoints and the functionality of a single
breakpoint, like 'conditions' and 'hitCondition' settings."""
loop_line = line_number("main.cpp", "// break loop")
program = self.getBuildArtifact("a.out")
self.build_and_launch(program)
breakpoint_ids = self.set_source_breakpoints(self.main_path, [loop_line])
self.assertEqual(len(breakpoint_ids), 1, "expect one breakpoint")
self.dap_server.request_continue()
self.verify_breakpoint_hit(breakpoint_ids)
i = int(self.dap_server.get_local_variable_value("i"))
self.assertEqual(i, 0, "i != 0 after hitting breakpoint")
new_breakpoint_ids = self.set_source_breakpoints(
self.main_path, [loop_line], [{"condition": "i==4"}]
)
self.assertEqual(
breakpoint_ids,
new_breakpoint_ids,
"existing breakpoint should have its condition " "updated",
)
self.continue_to_breakpoints(breakpoint_ids)
i = int(self.dap_server.get_local_variable_value("i"))
self.assertEqual(i, 4, "i != 4 showing conditional works")
new_breakpoint_ids = self.set_source_breakpoints(
self.main_path, [loop_line], [{"hitCondition": "2"}]
)
self.assertEqual(
breakpoint_ids,
new_breakpoint_ids,
"existing breakpoint should have its condition " "updated",
)
self.continue_to_breakpoints(breakpoint_ids)
i = int(self.dap_server.get_local_variable_value("i"))
self.assertEqual(i, 6, "i != 6 showing hitCondition works")
self.continue_to_breakpoints(breakpoint_ids)
i = int(self.dap_server.get_local_variable_value("i"))
self.assertEqual(i, 7, "i != 7 showing post hitCondition hits every time")