[Lldb-commits] [lldb] [lldb-dap] Migrate extended stackTrace and source test (PR #213234)
Ebuka Ezike via lldb-commits
lldb-commits at lists.llvm.org
Fri Jul 31 02:35:40 PDT 2026
https://github.com/da-viper created https://github.com/llvm/llvm-project/pull/213234
Migrated tests
- TestDAP_extendedStackTrace.py
- TestDAP_source.py
- TestDAP_source_x86.py
>From 28d27c061fa06209fd2a086ec354941d2f8e2ddb Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Wed, 29 Jul 2026 21:26:01 +0100
Subject: [PATCH] [lldb-dap] Migrate extended stackTrace and source test
Migrated tests
- TestDAP_extendedStackTrace.py
- TestDAP_source.py
- TestDAP_source_x86.py
---
.../lldbsuite/test/tools/lldb_dap/types.py | 2 +-
.../TestDAP_extendedStackTrace.py | 147 +++++++++--------
.../tools/lldb-dap/source/TestDAP_source.py | 150 +++++++-----------
lldb/test/API/tools/lldb-dap/source/main.c | 4 +-
.../stackTrace-x86/TestDAP_source_x86.py | 57 +++----
5 files changed, 166 insertions(+), 194 deletions(-)
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb_dap/types.py b/lldb/packages/Python/lldbsuite/test/tools/lldb_dap/types.py
index 19bd0d9dc26e5..d75a1ea8fb3b9 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb_dap/types.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb_dap/types.py
@@ -653,7 +653,7 @@ class Source:
checksums: Optional[List[Checksum]] = None
def __post_init__(self):
- if not self.name and not self.path and not self.sourceReference:
+ if not self.name and not self.path and self.sourceReference is None:
raise ValueError(
f"Source requires either name, path, or source_reference. {self}"
)
diff --git a/lldb/test/API/tools/lldb-dap/extendedStackTrace/TestDAP_extendedStackTrace.py b/lldb/test/API/tools/lldb-dap/extendedStackTrace/TestDAP_extendedStackTrace.py
index 33a3bde3a5a42..3ee3e203c2767 100644
--- a/lldb/test/API/tools/lldb-dap/extendedStackTrace/TestDAP_extendedStackTrace.py
+++ b/lldb/test/API/tools/lldb-dap/extendedStackTrace/TestDAP_extendedStackTrace.py
@@ -4,122 +4,121 @@
import os
-import lldbdap_testcase
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test.lldbplatformutil import *
+from lldbsuite.test.decorators import skipUnlessDarwin
+from lldbsuite.test.lldbplatformutil import findBacktraceRecordingDylib
+from lldbsuite.test.lldbtest import line_number
+from lldbsuite.test.tools.lldb_dap import DAPTestCaseBase
+from lldbsuite.test.tools.lldb_dap.types import LaunchArgs, StackFrameFormat
-class TestDAP_extendedStackTrace(lldbdap_testcase.DAPTestCaseBase):
- def build_and_run(self, displayExtendedBacktrace=True):
+class TestDAP_extendedStackTrace(DAPTestCaseBase):
+ def build_and_run_to_breakpoint(self, display_extended_backtrace: bool = True):
backtrace_recording_lib = findBacktraceRecordingDylib()
if not backtrace_recording_lib:
self.skipTest(
- "Skipped because libBacktraceRecording.dylib was present on the system."
+ "Skipped because libBacktraceRecording.dylib was not present on the system."
)
-
if not os.path.isfile("/usr/lib/system/introspection/libdispatch.dylib"):
self.skipTest(
"Skipped because introspection libdispatch dylib is not present."
)
program = self.getBuildArtifact("a.out")
+ session = self.build_and_create_session()
+ source = self.getSourcePath("main.m")
+ bp_line = line_number(source, "breakpoint 1")
- self.build_and_launch(
- program,
+ launch_args = LaunchArgs(
+ program=program,
env=[
"DYLD_LIBRARY_PATH=/usr/lib/system/introspection",
- "DYLD_INSERT_LIBRARIES=" + backtrace_recording_lib,
+ f"DYLD_INSERT_LIBRARIES={backtrace_recording_lib}",
],
- displayExtendedBacktrace=displayExtendedBacktrace,
+ displayExtendedBacktrace=display_extended_backtrace,
)
- source = "main.m"
- breakpoint = line_number(source, "breakpoint 1")
- lines = [breakpoint]
+ with session.configure(launch_args) as cm:
+ [bp_id] = session.resolve_source_breakpoints(source, [bp_line])
- breakpoint_ids = self.set_source_breakpoints(source, lines)
- self.assertEqual(
- len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
- )
+ stop_event = session.verify_stopped_on_breakpoint(bp_id, after=cm.process_event)
+ return session, stop_event
@skipUnlessDarwin
def test_stackTrace(self):
- """
- Tests the 'stackTrace' packet on a thread with an extended backtrace.
- """
- self.build_and_run()
- events = self.continue_to_next_stop()
-
- stackFrames, totalFrames = self.get_stackFrames_and_totalFramesCount(
- threadId=events[0]["body"]["threadId"]
- )
- self.assertGreaterEqual(len(stackFrames), 3, "expect >= 3 frames")
- self.assertEqual(len(stackFrames), totalFrames)
- self.assertEqual(stackFrames[0]["name"], "one")
- self.assertEqual(stackFrames[1]["name"], "two")
- self.assertEqual(stackFrames[2]["name"], "three")
+ """Tests the 'stackTrace' packet on a thread with an extended backtrace."""
+ session, stop_event = self.build_and_run_to_breakpoint()
+ thread_id = self.expect_not_none(stop_event.body.threadId)
+
+ response = session.stack_trace(thread_id)
+ stack_frames = response.body.stackFrames
+ total_frames = response.body.totalFrames
- stackLabels = [
+ self.assertGreaterEqual(len(stack_frames), 3, "expect >= 3 frames")
+ self.assertEqual(len(stack_frames), total_frames)
+ self.assertEqual(stack_frames[0].name, "one")
+ self.assertEqual(stack_frames[1].name, "two")
+ self.assertEqual(stack_frames[2].name, "three")
+
+ stack_labels = [
(i, frame)
- for i, frame in enumerate(stackFrames)
- if frame.get("presentationHint", "") == "label"
+ for i, frame in enumerate(stack_frames)
+ if frame.presentationHint == "label"
]
- self.assertEqual(len(stackLabels), 2, "expected two label stack frames")
+ self.assertEqual(len(stack_labels), 2, "expected two label stack frames")
self.assertRegex(
- stackLabels[0][1]["name"],
+ stack_labels[0][1].name,
r"Enqueued from com.apple.root.default-qos \(Thread \d\)",
)
self.assertRegex(
- stackLabels[1][1]["name"],
+ stack_labels[1][1].name,
r"Enqueued from com.apple.main-thread \(Thread \d\)",
)
- for i, frame in stackLabels:
+ for i, frame in stack_labels:
# Ensure requesting startFrame+levels across thread backtraces works as expected.
- stackFrames, totalFrames = self.get_stackFrames_and_totalFramesCount(
- threadId=events[0]["body"]["threadId"], startFrame=i - 1, levels=3
- )
- self.assertEqual(len(stackFrames), 3, "expected 3 frames with levels=3")
+ response = session.stack_trace(thread_id, startFrame=i - 1, levels=3)
+ stack_frames = response.body.stackFrames
+ total_frames = self.expect_not_none(response.body.totalFrames)
+ self.assertEqual(len(stack_frames), 3, "expected 3 frames with levels=3")
self.assertGreaterEqual(
- totalFrames, i + 3, "total frames should include a pagination offset"
+ total_frames, i + 3, "total frames should include a pagination offset"
)
- self.assertEqual(stackFrames[1], frame)
+ self.assertEqual(stack_frames[1], frame)
- # Ensure requesting startFrame+levels at the beginning of a thread backtraces works as expected.
- stackFrames, totalFrames = self.get_stackFrames_and_totalFramesCount(
- threadId=events[0]["body"]["threadId"], startFrame=i, levels=3
- )
- self.assertEqual(len(stackFrames), 3, "expected 3 frames with levels=3")
+ # Ensure requesting startFrame+levels at the beginning of a thread backtrace works as expected.
+ response = session.stack_trace(thread_id, startFrame=i, levels=3)
+ stack_frames = response.body.stackFrames
+ total_frames = self.expect_not_none(response.body.totalFrames)
+ self.assertEqual(len(stack_frames), 3, "expected 3 frames with levels=3")
self.assertGreaterEqual(
- totalFrames, i + 3, "total frames should include a pagination offset"
+ total_frames, i + 3, "total frames should include a pagination offset"
)
- self.assertEqual(stackFrames[0], frame)
-
- # Ensure requests with startFrame+levels that end precisely on the last frame includes the totalFrames pagination offset.
- stackFrames, totalFrames = self.get_stackFrames_and_totalFramesCount(
- threadId=events[0]["body"]["threadId"], startFrame=i - 1, levels=1
- )
- self.assertEqual(len(stackFrames), 1, "expected 1 frames with levels=1")
+ self.assertEqual(stack_frames[0], frame)
+
+ # Ensure requests with startFrame+levels that end precisely on the
+ # last frame include the totalFrames pagination offset.
+ response = session.stack_trace(thread_id, startFrame=i - 1, levels=1)
+ stack_frames = response.body.stackFrames
+ total_frames = self.expect_not_none(response.body.totalFrames)
+ self.assertEqual(len(stack_frames), 1, "expected 1 frame with levels=1")
self.assertGreaterEqual(
- totalFrames, i, "total frames should include a pagination offset"
+ total_frames, i, "total frames should include a pagination offset"
)
@skipUnlessDarwin
def test_stackTraceWithFormat(self):
- """
- Tests the 'stackTrace' packet on a thread with an extended backtrace using stack trace formats.
- """
- self.build_and_run(displayExtendedBacktrace=False)
- events = self.continue_to_next_stop()
-
- stackFrames, _ = self.get_stackFrames_and_totalFramesCount(
- threadId=events[0]["body"]["threadId"], format={"includeAll": True}
+ """Tests the 'stackTrace' packet using stack trace formats."""
+ session, stop_event = self.build_and_run_to_breakpoint(
+ display_extended_backtrace=False
)
+ thread_id = self.expect_not_none(stop_event.body.threadId)
- stackLabels = [
- (i, frame)
- for i, frame in enumerate(stackFrames)
- if frame.get("presentationHint", "") == "label"
- ]
+ response = session.stack_trace(
+ thread_id, format=StackFrameFormat(includeAll=True)
+ )
- self.assertEqual(len(stackLabels), 2, "expected two label stack frames")
+ stack_labels = [
+ frame
+ for frame in response.body.stackFrames
+ if frame.presentationHint == "label"
+ ]
+ self.assertEqual(len(stack_labels), 2, "expected two label stack frames")
diff --git a/lldb/test/API/tools/lldb-dap/source/TestDAP_source.py b/lldb/test/API/tools/lldb-dap/source/TestDAP_source.py
index 01c28fe7a568e..f8ab1b3f04056 100644
--- a/lldb/test/API/tools/lldb-dap/source/TestDAP_source.py
+++ b/lldb/test/API/tools/lldb-dap/source/TestDAP_source.py
@@ -2,111 +2,81 @@
Test lldb-dap source request
"""
+from lldbsuite.test.decorators import skipIfWindows
+from lldbsuite.test.lldbtest import line_number
+from lldbsuite.test.tools.lldb_dap import DAPTestCaseBase
+from lldbsuite.test.tools.lldb_dap.types import LaunchArgs, Source, SourceArgs
-import os
-import lldbdap_testcase
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-
-
-class TestDAP_source(lldbdap_testcase.DAPTestCaseBase):
+class TestDAP_source(DAPTestCaseBase):
@skipIfWindows
def test_source(self):
- """
- Tests the 'source' packet.
- """
+ """Tests the Source Request."""
program = self.getBuildArtifact("a.out")
- self.build_and_launch(program)
source = self.getSourcePath("main.c")
- breakpoint_line = line_number(source, "breakpoint")
+ session = self.build_and_create_session()
+ with session.configure(LaunchArgs(program)) as ctx:
+ breakpoint_line = line_number(source, "breakpoint")
+ [bp_id] = session.resolve_source_breakpoints(source, [breakpoint_line])
- lines = [breakpoint_line]
- breakpoint_ids = self.set_source_breakpoints(source, lines)
- self.assertEqual(
- len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
+ stop_event = session.verify_stopped_on_breakpoint(
+ bp_id, after=ctx.process_event
)
- self.continue_to_breakpoints(breakpoint_ids)
-
- response = self.dap_server.request_source(sourceReference=0)
- self.assertFalse(response["success"], "verify invalid sourceReference fails")
-
+ src_args = SourceArgs(source=Source(sourceReference=0), sourceReference=0)
+ session.send_request(src_args).error()
# Check only source reference in the arguments field.
- response = self.dap_server.request_custom("source", {"sourceReference": 0})
- self.assertFalse(response["success"], "expected failed response")
- error_format = self.get_dict_value(response, ["body", "error", "format"])
- self.assertIn("unknown source reference", error_format)
+ resp = session.send_request(SourceArgs(sourceReference=0)).error(
+ "verify invalid sourceReference fails"
+ )
+ resp_body = self.expect_not_none(resp.body)
+ error_msg = self.expect_not_none(resp_body.error)
+ self.assertIn("unknown source reference", error_msg.format)
- (stackFrames, totalFrames) = self.get_stackFrames_and_totalFramesCount()
- frameCount = len(stackFrames)
- self.assertGreaterEqual(frameCount, 3, "verify we got up to main at least")
+ # Verify the top three frames handler, add and main.
+ thread_id = session.thread_context_from(stop_event).thread_id
+ response = session.stack_trace(thread_id)
+ frames = response.body.stackFrames
+ self.assertGreaterEqual(len(frames), 3, "verify we got up to main at least.")
self.assertEqual(
- totalFrames,
- frameCount,
+ len(frames),
+ response.body.totalFrames,
"verify total frames returns a speculative page size",
)
- wantFrames = [
- {
- "name": "handler",
- "line": 8,
- "source": {
- "name": "main.c",
- "path": source,
- "containsSourceReference": False,
- },
- },
- {
- "name": "add",
- "source": {
- "name": "add",
- "path": program + "`add",
- "containsSourceReference": True,
- },
- },
- {
- "name": "main",
- "line": 12,
- "source": {
- "name": "main.c",
- "path": source,
- "containsSourceReference": False,
- },
- },
- ]
- for idx, want in enumerate(wantFrames):
- got = stackFrames[idx]
- name = self.get_dict_value(got, ["name"])
- self.assertEqual(name, want["name"])
- if "line" in want:
- line = self.get_dict_value(got, ["line"])
- self.assertEqual(line, want["line"])
+ handler_frame, add_frame, main_frame, *_ = frames
- wantSource = want["source"]
- source_name = self.get_dict_value(got, ["source", "name"])
- self.assertEqual(source_name, wantSource["name"])
+ # Verify frame 0 handler.
+ self.assertEqual(handler_frame.name, "handler")
+ self.assertEqual(handler_frame.line, line_number(source, "first_frame"))
+ handler_source = self.expect_not_none(handler_frame.source)
+ self.assertEqual(handler_source.name, "main.c")
+ self.assertEqual(handler_source.path, source)
+ self.assertIsNone(handler_source.sourceReference)
+
+ # Verify frame 1 add.
+ self.assertEqual(add_frame.name, "add")
+ add_source = self.expect_not_none(add_frame.source)
+ self.assertEqual(add_source.name, "add")
+ self.assertEqual(add_source.path, program + "`add")
+
+ source_ref = self.expect_not_none(add_source.sourceReference)
+ disasm = session.send_request(SourceArgs(source_ref)).result()
+ self.assertGreater(
+ len(disasm.body.content), 0, "verify content returned disassembly"
+ )
+ self.assertEqual(
+ disasm.body.mimeType,
+ "text/x-lldb.disassembly",
+ "verify mime type returned",
+ )
- source_path = self.get_dict_value(got, ["source", "path"])
- self.assertEqual(source_path, wantSource["path"])
+ # Verify frame 2 main.
+ self.assertEqual(main_frame.name, "main")
+ self.assertEqual(main_frame.line, line_number(source, "third_frame"))
+ main_source = self.expect_not_none(main_frame.source)
+ self.assertEqual(main_source.name, "main.c")
+ self.assertEqual(main_source.path, source)
+ self.assertIsNone(main_source.sourceReference)
- if wantSource["containsSourceReference"]:
- sourceReference = self.get_dict_value(
- got, ["source", "sourceReference"]
- )
- response = self.dap_server.request_source(
- sourceReference=sourceReference
- )
- self.assertTrue(response["success"])
- self.assertGreater(
- len(self.get_dict_value(response, ["body", "content"])),
- 0,
- "verify content returned disassembly",
- )
- self.assertEqual(
- self.get_dict_value(response, ["body", "mimeType"]),
- "text/x-lldb.disassembly",
- "verify mime type returned",
- )
- else:
- self.assertNotIn("sourceReference", got["source"])
+ session.continue_to_exit()
diff --git a/lldb/test/API/tools/lldb-dap/source/main.c b/lldb/test/API/tools/lldb-dap/source/main.c
index 39420dba7874f..60fb0931ba105 100644
--- a/lldb/test/API/tools/lldb-dap/source/main.c
+++ b/lldb/test/API/tools/lldb-dap/source/main.c
@@ -5,10 +5,10 @@ __attribute__((nodebug)) static void add(int i, int j, void handler(int)) {
}
static void handler(int result) {
- printf("result %d\n", result); // breakpoint
+ printf("result %d\n", result); // first_frame, breakpoint
}
int main(int argc, char const *argv[]) {
- add(2, 3, handler);
+ add(2, 3, handler); // third_frame
return 0;
}
diff --git a/lldb/test/API/tools/lldb-dap/stackTrace-x86/TestDAP_source_x86.py b/lldb/test/API/tools/lldb-dap/stackTrace-x86/TestDAP_source_x86.py
index 6239e1af53ecd..f6c6e5c9e73d5 100644
--- a/lldb/test/API/tools/lldb-dap/stackTrace-x86/TestDAP_source_x86.py
+++ b/lldb/test/API/tools/lldb-dap/stackTrace-x86/TestDAP_source_x86.py
@@ -2,64 +2,67 @@
Test lldb-dap stack trace containing x86 assembly
"""
-import lldbdap_testcase
from lldbsuite.test import lldbplatformutil
from lldbsuite.test.decorators import skipUnlessArch, skipUnlessPlatform
from lldbsuite.test.lldbtest import line_number
+from lldbsuite.test.tools.lldb_dap import DAPTestCaseBase
+from lldbsuite.test.tools.lldb_dap.types import LaunchArgs
-class TestDAP_stacktrace_x86(lldbdap_testcase.DAPTestCaseBase):
+class TestDAP_stacktrace_x86(DAPTestCaseBase):
@skipUnlessArch("x86_64")
@skipUnlessPlatform(["linux"] + lldbplatformutil.getDarwinOSTriples())
def test_stacktrace_x86(self):
- """
- Tests that lldb-dap steps through correctly and the source lines are correct in x86 assembly.
- """
+ """Tests that lldb-dap steps through x86 assembly correctly and reports the right source lines."""
program = self.getBuildArtifact("a.out")
- self.build_and_launch(
+ session = self.build_and_create_session()
+ launch_args = LaunchArgs(
program,
initCommands=[
"settings set target.process.thread.step-in-avoid-nodebug false"
],
)
+ with session.configure(launch_args) as ctx:
+ source = "main.c"
+ [breakpoint_id] = session.resolve_source_breakpoints(
+ source, [line_number(source, "// Break here")]
+ )
- source = "main.c"
- breakpoint_ids = self.set_source_breakpoints(
- source,
- [line_number(source, "// Break here")],
+ stop_event = session.verify_stopped_on_breakpoint(
+ breakpoint_id, after=ctx.process_event
)
- self.continue_to_breakpoints(breakpoint_ids)
- self.stepIn()
+ thread_ctx = session.thread_context_from(stop_event)
+ thread_ctx.step_in()
- frame = self.get_stackFrames()[0]
+ frame = thread_ctx.top_frame().frame
self.assertEqual(
- frame["name"],
+ frame.name,
"no_branch_func",
- "verify we are in the no_branch_func function",
+ "expected to be in the no_branch_func function",
)
+ self.assertEqual(frame.line, 1, "expected to be at the start of the function")
- self.assertEqual(frame["line"], 1, "verify we are at the start of the function")
minimum_assembly_lines = (
line_number(source, "Assembly end")
- line_number(source, "Assembly start")
+ 1
)
- self.assertLessEqual(
- 10,
+ self.assertGreaterEqual(
minimum_assembly_lines,
- "verify we have a reasonable number of assembly lines",
+ 10,
+ "expected a reasonable number of assembly lines",
)
- for i in range(2, minimum_assembly_lines):
- self.stepIn()
- frame = self.get_stackFrames()[0]
+ for expected_line in range(2, minimum_assembly_lines):
+ thread_ctx.step_in()
+ top_frame = thread_ctx.top_frame().frame
self.assertEqual(
- frame["name"],
+ top_frame.name,
"no_branch_func",
- "verify we are still in the no_branch_func function",
+ "expected to still be in the no_branch_func function",
)
self.assertEqual(
- frame["line"],
- i,
- f"step in should advance a single line in the function to {i}",
+ top_frame.line,
+ expected_line,
+ f"step-in should advance a single line in the function to {expected_line}",
)
More information about the lldb-commits
mailing list