"""
Test lldb-dap logpoints feature.
"""
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_logpoints(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_logmessage_basic(self):
"""Tests breakpoint logmessage basic functionality."""
before_loop_line = line_number("main.cpp", "// before loop")
loop_line = line_number("main.cpp", "// break loop")
after_loop_line = line_number("main.cpp", "// after loop")
program = self.getBuildArtifact("a.out")
self.build_and_launch(program)
# Set a breakpoint at a line before loop
before_loop_breakpoint_ids = self.set_source_breakpoints(
self.main_path, [before_loop_line]
)
self.assertEqual(len(before_loop_breakpoint_ids), 1, "expect one breakpoint")
self.dap_server.request_continue()
# Verify we hit the breakpoint before loop line
self.verify_breakpoint_hit(before_loop_breakpoint_ids)
# Swallow old console output
self.get_console()
# Set two breakpoints:
# 1. First at the loop line with logMessage
# 2. Second guard breakpoint at a line after loop
logMessage_prefix = "This is log message for { -- "
logMessage = logMessage_prefix + "{i + 3}, {message}"
[loop_breakpoint_id, post_loop_breakpoint_id] = self.set_source_breakpoints(
self.main_path,
[loop_line, after_loop_line],
[{"logMessage": logMessage}, {}],
)
# Continue to trigger the breakpoint with log messages
self.dap_server.request_continue()
# Verify we hit the breakpoint after loop line
self.verify_breakpoint_hit([post_loop_breakpoint_id])
output = self.get_console()
lines = output.splitlines()
logMessage_output = []
for line in lines:
if line.startswith(logMessage_prefix):
logMessage_output.append(line)
# Verify logMessage count
loop_count = 10
self.assertEqual(len(logMessage_output), loop_count)
message_addr_pattern = r"\b0x[0-9A-Fa-f]+\b"
message_content = '"Hello from main!"'
# Verify log message match
for idx, logMessage_line in enumerate(logMessage_output):
result = idx + 3
reg_str = (
f"{logMessage_prefix}{result}, {message_addr_pattern} {message_content}"
)
self.assertRegex(logMessage_line, reg_str)
@skipIfWindows
def test_logmessage_advanced(self):
"""Tests breakpoint logmessage functionality for complex expression."""
before_loop_line = line_number("main.cpp", "// before loop")
loop_line = line_number("main.cpp", "// break loop")
after_loop_line = line_number("main.cpp", "// after loop")
program = self.getBuildArtifact("a.out")
self.build_and_launch(program)
# Set a breakpoint at a line before loop
before_loop_breakpoint_ids = self.set_source_breakpoints(
self.main_path, [before_loop_line]
)
self.assertEqual(len(before_loop_breakpoint_ids), 1, "expect one breakpoint")
self.dap_server.request_continue()
# Verify we hit the breakpoint before loop line
self.verify_breakpoint_hit(before_loop_breakpoint_ids)
# Swallow old console output
self.get_console()
# Set two breakpoints:
# 1. First at the loop line with logMessage
# 2. Second guard breakpoint at a line after loop
logMessage_prefix = "This is log message for { -- "
logMessage = (
logMessage_prefix
+ "{int y = 0; if (i % 3 == 0) { y = i + 3;} else {y = i * 3;} y}"
)
[loop_breakpoint_id, post_loop_breakpoint_id] = self.set_source_breakpoints(
self.main_path,
[loop_line, after_loop_line],
[{"logMessage": logMessage}, {}],
)
# Continue to trigger the breakpoint with log messages
self.dap_server.request_continue()
# Verify we hit the breakpoint after loop line
self.verify_breakpoint_hit([post_loop_breakpoint_id])
output = self.get_console()
lines = output.splitlines()
logMessage_output = []
for line in lines:
if line.startswith(logMessage_prefix):
logMessage_output.append(line)
# Verify logMessage count
loop_count = 10
self.assertEqual(len(logMessage_output), loop_count)
# Verify log message match
for idx, logMessage_line in enumerate(logMessage_output):
result = idx + 3 if idx % 3 == 0 else idx * 3
self.assertEqual(logMessage_line, logMessage_prefix + str(result))
@skipIfWindows
def test_logmessage_format(self):
"""
Tests breakpoint logmessage functionality with format.
"""
before_loop_line = line_number("main.cpp", "// before loop")
loop_line = line_number("main.cpp", "// break loop")
after_loop_line = line_number("main.cpp", "// after loop")
program = self.getBuildArtifact("a.out")
self.build_and_launch(program)
# Set a breakpoint at a line before loop
before_loop_breakpoint_ids = self.set_source_breakpoints(
self.main_path, [before_loop_line]
)
self.assertEqual(len(before_loop_breakpoint_ids), 1, "expect one breakpoint")
self.dap_server.request_continue()
# Verify we hit the breakpoint before loop line
self.verify_breakpoint_hit(before_loop_breakpoint_ids)
# Swallow old console output
self.get_console()
# Set two breakpoints:
# 1. First at the loop line with logMessage
# 2. Second guard breakpoint at a line after loop
logMessage_prefix = "This is log message for -- "
logMessage_with_format = "part1\tpart2\bpart3\x64part4"
logMessage_with_format_raw = r"part1\tpart2\bpart3\x64part4"
logMessage = logMessage_prefix + logMessage_with_format_raw + "{i - 1}"
[loop_breakpoint_id, post_loop_breakpoint_id] = self.set_source_breakpoints(
self.main_path,
[loop_line, after_loop_line],
[{"logMessage": logMessage}, {}],
)
# Continue to trigger the breakpoint with log messages
self.dap_server.request_continue()
# Verify we hit the breakpoint after loop line
self.verify_breakpoint_hit([post_loop_breakpoint_id])
output = self.get_console()
lines = output.splitlines()
logMessage_output = []
for line in lines:
if line.startswith(logMessage_prefix):
logMessage_output.append(line)
# Verify logMessage count
loop_count = 10
self.assertEqual(len(logMessage_output), loop_count)
# Verify log message match
for idx, logMessage_line in enumerate(logMessage_output):
result = idx - 1
self.assertEqual(
logMessage_line,
logMessage_prefix + logMessage_with_format + str(result),
)
@skipIfWindows
def test_logmessage_format_failure(self):
"""
Tests breakpoint logmessage format with parsing failure.
"""
before_loop_line = line_number("main.cpp", "// before loop")
loop_line = line_number("main.cpp", "// break loop")
after_loop_line = line_number("main.cpp", "// after loop")
program = self.getBuildArtifact("a.out")
self.build_and_launch(program)
# Set a breakpoint at a line before loop
before_loop_breakpoint_ids = self.set_source_breakpoints(
self.main_path, [before_loop_line]
)
self.assertEqual(len(before_loop_breakpoint_ids), 1, "expect one breakpoint")
self.dap_server.request_continue()
# Verify we hit the breakpoint before loop line
self.verify_breakpoint_hit(before_loop_breakpoint_ids)
# Swallow old console output
self.get_console()
# Set two breakpoints:
# 1. First at the loop line with logMessage
# 2. Second guard breakpoint at a line after loop
logMessage_prefix = "This is log message for -- "
# log message missing hex number.
logMessage_with_format_raw = r"part1\x"
logMessage = logMessage_prefix + logMessage_with_format_raw
[loop_breakpoint_id, post_loop_breakpoint_id] = self.set_source_breakpoints(
self.main_path,
[loop_line, after_loop_line],
[{"logMessage": logMessage}, {}],
)
# Continue to trigger the breakpoint with log messages
self.dap_server.request_continue()
# Verify we hit logpoint breakpoint if it's format has error.
self.verify_breakpoint_hit([loop_breakpoint_id])
output = self.get_console()
lines = output.splitlines()
failure_prefix = "Log message has error:"
logMessage_output = []
logMessage_failure_output = []
for line in lines:
if line.startswith(logMessage_prefix):
logMessage_output.append(line)
elif line.startswith(failure_prefix):
logMessage_failure_output.append(line)
# Verify logMessage failure message
self.assertEqual(len(logMessage_failure_output), 1)
self.assertEqual(
logMessage_failure_output[0].strip(),
failure_prefix + " missing hex number following '\\x'",
)