[Lldb-commits] [lldb] [lldb-dap] Migrate extended stackTrace and source test (PR #213234)

via lldb-commits lldb-commits at lists.llvm.org
Fri Jul 31 02:36:27 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Ebuka Ezike (da-viper)

<details>
<summary>Changes</summary>

Migrated tests
- TestDAP_extendedStackTrace.py
- TestDAP_source.py
- TestDAP_source_x86.py

---

Patch is 22.14 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/213234.diff


5 Files Affected:

- (modified) lldb/packages/Python/lldbsuite/test/tools/lldb_dap/types.py (+1-1) 
- (modified) lldb/test/API/tools/lldb-dap/extendedStackTrace/TestDAP_extendedStackTrace.py (+73-74) 
- (modified) lldb/test/API/tools/lldb-dap/source/TestDAP_source.py (+60-90) 
- (modified) lldb/test/API/tools/lldb-dap/source/main.c (+2-2) 
- (modified) lldb/test/API/tools/lldb-dap/stackTrace-x86/TestDAP_source_x86.py (+30-27) 


``````````diff
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,
-            [lin...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/213234


More information about the lldb-commits mailing list