https://github.com/da-viper updated 
https://github.com/llvm/llvm-project/pull/209285

>From e735b2cd5d063f628c8024525d357d59490c5142 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <[email protected]>
Date: Mon, 13 Jul 2026 20:37:14 +0100
Subject: [PATCH] [lldb-dap] Migrate lldb-dap events tests.

Migrate
- TestDAP_breakpointEvent.py
- TestDAP_eventStatistic.py
- TestDAP_invalidatedEvent.py
- TestDAP_sendEvent.py
- TestDAP_stopped_events.py
- TestDAP_terminatedEvent.py
---
 .../test/tools/lldb_dap/session_helpers.py    |  13 +-
 .../TestDAP_breakpointEvents.py               | 202 +++++++--------
 ...Statistic.py => TestDAP_eventStatistic.py} |  46 ++--
 .../TestDAP_invalidatedEvent.py               |  68 +++---
 .../lldb-dap/send-event/TestDAP_sendEvent.py  |  77 +++---
 .../stopped-events/TestDAP_stopped_events.py  | 229 ++++++++----------
 .../TestDAP_terminatedEvent.py                |  55 ++---
 7 files changed, 347 insertions(+), 343 deletions(-)
 rename 
lldb/test/API/tools/lldb-dap/eventStatistic/{TestVSCode_eventStatistic.py => 
TestDAP_eventStatistic.py} (54%)

diff --git 
a/lldb/packages/Python/lldbsuite/test/tools/lldb_dap/session_helpers.py 
b/lldb/packages/Python/lldbsuite/test/tools/lldb_dap/session_helpers.py
index 29f6d52571c67..613bf70d53479 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb_dap/session_helpers.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb_dap/session_helpers.py
@@ -1583,17 +1583,22 @@ def get_variables(
         )
         return response.body.variables
 
-    def thread_context_from(self, thread_ref: int | StoppedEvent) -> 
ThreadContext:
-        if isinstance(thread_ref, StoppedEvent):
+    def thread_context_from(
+        self, thread_ref: int | StoppedEvent | InvalidatedEvent
+    ) -> ThreadContext:
+        if isinstance(thread_ref, (StoppedEvent, InvalidatedEvent)):
             self.test_case.assertIsNotNone(thread_ref.body.threadId)
             thread_id = cast(int, thread_ref.body.threadId)
         elif isinstance(thread_ref, int):
             thread_id = thread_ref
         else:
-            self.test_case.fail(f"cannot get thread context from 
'{type(thread_ref)}'.")
+            ref_type_name = type(thread_ref).__name__
+            self.test_case.fail(f"cannot get thread context from 
'{ref_type_name}'.")
         return ThreadContext(thread_id, self)
 
-    def top_frame_from(self, thread_ref: int | StoppedEvent) -> FrameContext:
+    def top_frame_from(
+        self, thread_ref: int | StoppedEvent | InvalidatedEvent
+    ) -> FrameContext:
         """Top FrameContext of the currently stopped thread."""
         return self.thread_context_from(thread_ref).top_frame()
 
diff --git 
a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py 
b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py
index dff3b9e76e748..ac94e35ce9d60 100644
--- a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py
+++ b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py
@@ -2,49 +2,65 @@
 Test lldb-dap setBreakpoints request
 """
 
-from dap_server import Source
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
-import lldbdap_testcase
 import os
+from typing import List
+
+from lldbsuite.test.decorators import (
+    skipIfTargetDoesNotSupportSharedLibraries,
+    skipIfWindows,
+)
+from lldbsuite.test.lldbtest import line_number
+from lldbsuite.test.tools.lldb_dap.dap_types import (
+    Breakpoint,
+    BreakpointEvent,
+    BreakpointReason,
+    Event,
+    LaunchArgs,
+)
+from lldbsuite.test.tools.lldb_dap.lldb_dap_testcase import DAPTestCaseBase
 
 
 @skipIfTargetDoesNotSupportSharedLibraries()
-class TestDAP_breakpointEvents(lldbdap_testcase.DAPTestCaseBase):
+class TestDAP_breakpointEvents(DAPTestCaseBase):
+    def collect_breakpoint_changed_events(self, session, *, after, until: 
Event):
+        """Collect every changed BreakpointEvent recorded in (after ..= until) 
inclusive."""
+        self.assertLess(after.seq, until.seq)
+        events: List[Breakpoint] = []
+
+        def visit(evt: Event) -> bool:
+            if isinstance(evt, BreakpointEvent):
+                if evt.body.reason == BreakpointReason.CHANGED:
+                    events.append(evt.body.breakpoint)
+            return evt.seq >= until.seq
+
+        session.wait_for_any_event(
+            (BreakpointEvent, type(until)), after=after, until=visit
+        )
+        return events
+
     @skipIfWindows
     def test_breakpoint_events(self):
         """
         This test follows the following steps.
-        - Sets a breakpoint in a shared library from the preCommands.
-        - Runs and stops at the entry point of a program.
-        - Sets two new breakpoints, one in the main executable and one in the 
shared library
-        - Both breakpoint is set but only the the shared library breakpoint is 
not verified yet.
-        - We will then continue and expect to get a breakpoint event that
-            informs us the breakpoint in the shared library has "changed"
-            and the correct line number should be supplied.
-        - We also verify the breakpoint set via the command interpreter should 
not
-            be have breakpoint events sent back to VS Code as the UI isn't 
able to
-            add new breakpoints to their UI.
+        - Sets a breakpoint in a shared library using the preRunCommands.
+        - Sets two new breakpoints, a line breakpoint in the main executable 
and a function
+          breakpoint on `foo` (defined in the shared library).
+        - The main breakpoint is not verified but the foo breakpoint is
+            unverified initially (the shared library isn't loaded yet).
+        - After the shared library loads, both DAP breakpoints emit
+            `breakpoint` events with reason=`changed`. The command-line
+            breakpoint set via preRunCommands must NOT emit any event,
+            because the IDE didn't ask for it.
 
         Code has been added that tags breakpoints set from VS Code
         DAP packets so we know the IDE knows about them. If VS Code is ever
         able to register breakpoints that aren't initially set in the GUI,
         then we will need to revise this.
         """
+        program = self.getBuildArtifact("a.out")
+        session = self.build_and_create_session()
         main_source_path = self.getSourcePath("main.cpp")
         main_bp_line = line_number(main_source_path, "main breakpoint 1")
-        main_source = Source.build(path=main_source_path)
-        program = self.getBuildArtifact("a.out")
-
-        # Set a breakpoint after creating the target by running a command line
-        # command. It will eventually resolve and cause a breakpoint changed
-        # event to be sent to lldb-dap. We want to make sure we don't send a
-        # breakpoint any breakpoints that were set from the command line.
-        # Breakpoints that are set via the VS code DAP packets will be
-        # registered and marked with a special keyword to ensure we deliver
-        # breakpoint events for these breakpoints but not for ones that are not
-        # set via the command interpreter.
 
         shlib_env_key = self.platformContext.shlib_environment_var
         path_separator = self.platformContext.shlib_path_separator
@@ -55,81 +71,77 @@ def test_breakpoint_events(self):
             else (shlib_env_value + path_separator + self.getBuildDir())
         )
 
-        # Set preCommand breakpoint
-        func_unique_function_name = "unique_function_name"
-        bp_command = f"breakpoint set --name {func_unique_function_name}"
-        launch_seq = self.build_and_launch(
-            program,
+        # Set a breakpoint via the command interpreter. lldb-dap tags DAP-set
+        # breakpoints with a marker. events from command-line breakpoints (like
+        # this one) must not be sent back to the client.
+        unique_function = "unique_function_name"
+        bp_command = f"breakpoint set --name {unique_function}"
+        unique_bp_id = 1
+
+        launch_args = LaunchArgs(
+            program=program,
             preRunCommands=[bp_command],
             env={shlib_env_key: shlib_env_new_value},
         )
-        self.dap_server.wait_for_event(["initialized"])
-        dap_breakpoint_ids = []
-
-        # We set the breakpoints after initialized event.
-        # Set and verify new line breakpoint.
-        response = self.dap_server.request_setBreakpoints(main_source, 
[main_bp_line])
-        self.assertTrue(response["success"])
-        breakpoints = response["body"]["breakpoints"]
-        self.assertEqual(len(breakpoints), 1, "expects only one line 
breakpoint")
-        main_breakpoint = breakpoints[0]
-        main_bp_id = main_breakpoint["id"]
-        dap_breakpoint_ids.append(main_bp_id)
-        self.assertTrue(
-            main_breakpoint["verified"], "expects main breakpoint to be 
verified"
+        with session.configure(launch_args) as ctx:
+            [main_bp_id] = session.resolve_source_breakpoints(
+                main_source_path, [main_bp_line]
+            )
+
+            # Set a function breakpoint on foo (in the shared library).
+            # It must arrive unverified because the shlib isn't loaded yet.
+            foo_resp = session.set_function_breakpoints(["foo"])
+            self.assertEqual(
+                len(foo_resp.body.breakpoints),
+                1,
+                "expects only one function breakpoint",
+            )
+            foo_bp = foo_resp.body.breakpoints[0]
+            foo_bp_id = self.expect_not_none(foo_bp.id)
+            self.assertFalse(
+                foo_bp.verified,
+                "expects unique function breakpoint to not be verified",
+            )
+
+        # First stop: foo breakpoint hit (after the shared library loaded).
+        foo_stop = session.verify_stopped_on_breakpoint(
+            foo_bp_id, after=ctx.process_event
         )
 
-        # Set and verify new function breakpoint.
-        func_foo = "foo"
-        response = self.dap_server.request_setFunctionBreakpoints([func_foo])
-        self.assertTrue(response["success"])
-        breakpoints = response["body"]["breakpoints"]
-        self.assertEqual(len(breakpoints), 1, "expects only one function 
breakpoint")
-        func_foo_breakpoint = breakpoints[0]
-        foo_bp_id = func_foo_breakpoint["id"]
-        dap_breakpoint_ids.append(foo_bp_id)
-        self.assertFalse(
-            func_foo_breakpoint["verified"],
-            "expects unique function breakpoint to not be verified",
+        # Collect every 'BreakpointEvent' with reason 'changed' between 
'InitalizeResponse
+        # and and the 'foo breakpoint stop'.
+        # The IDE-tracked breakpoints (main + foo) should emit breakpoint 
`changed` events.
+        evt_breakpoints = self.collect_breakpoint_changed_events(
+            session, after=ctx.init_response, until=foo_stop
         )
 
-        self.dap_server.request_configurationDone()
-        launch_response = self.dap_server.receive_response(launch_seq)
-        self.assertIsNotNone(launch_response)
-        self.assertTrue(launch_response["success"])
-
-        # Wait for the next stop (breakpoint foo).
-        self.verify_breakpoint_hit([foo_bp_id])
-        unique_bp_id = 1
+        # A breakpoint may emit several `changed` events as it progresses
+        # (e.g. unverified -> verified once the shlib loads). Keep the last
+        # observed state per breakpoint id. The final state for DAP-tracked 
breakpoints
+        # must be verified, and the command-line breakpoint must not appear.
+        last_state = {bp.id: bp for bp in evt_breakpoints}
+
+        for bp_id, name in [(main_bp_id, "main"), (foo_bp_id, "foo")]:
+            final_bp = self.expect_not_none(
+                last_state.get(bp_id),
+                f"expected a changed event for {name} breakpoint {bp_id}",
+            )
+            self.assertTrue(
+                final_bp.verified, f"{name} breakpoint must finish verified: 
{final_bp}"
+            )
+
+        self.assertNotIn(
+            unique_bp_id,
+            last_state,
+            "command-line breakpoint must not emit any event",
+        )
 
-        # Check the breakpoints set in dap is verified.
-        verified_breakpoint_ids = []
-        events = self.dap_server.wait_for_breakpoint_events()
-        for breakpoint_event in events:
-            breakpoint_event_body = breakpoint_event["body"]
-            if breakpoint_event_body["reason"] != "changed":
-                continue
-            breakpoint = breakpoint_event_body["breakpoint"]
-
-            if "verified" in breakpoint_event_body:
-                self.assertFalse(
-                    breakpoint_event_body["verified"],
-                    f"expects changed breakpoint to be verified. event: 
{breakpoint_event}",
-                )
-            id = breakpoint["id"]
-            verified_breakpoint_ids.append(id)
-
-        self.assertIn(main_bp_id, verified_breakpoint_ids)
-        self.assertIn(foo_bp_id, verified_breakpoint_ids)
-        self.assertNotIn(unique_bp_id, verified_breakpoint_ids)
-
-        # Continue to the unique function breakpoint set from preRunCommands.
-        unique_function_stop_event = self.continue_to_next_stop()[0]
-        unique_body = unique_function_stop_event["body"]
-        self.assertEqual(unique_body["reason"], "breakpoint")
-        self.assertIn(unique_bp_id, unique_body["hitBreakpointIds"])
+        # Continue to the unique_function breakpoint (set via preRunCommands).
+        unique_func_stop = session.continue_to_next_stop()
+        self.assertEqual(unique_func_stop.body.reason, "breakpoint")
+        self.assertIn(unique_bp_id, unique_func_stop.body.hitBreakpointIds or 
[])
 
         # Clear line and function breakpoints and exit.
-        self.dap_server.request_setFunctionBreakpoints([])
-        self.dap_server.request_setBreakpoints(main_source, [])
-        self.continue_to_exit()
+        session.set_function_breakpoints([])
+        session.set_source_breakpoints(main_source_path, [])
+        session.continue_to_exit()
diff --git 
a/lldb/test/API/tools/lldb-dap/eventStatistic/TestVSCode_eventStatistic.py 
b/lldb/test/API/tools/lldb-dap/eventStatistic/TestDAP_eventStatistic.py
similarity index 54%
rename from 
lldb/test/API/tools/lldb-dap/eventStatistic/TestVSCode_eventStatistic.py
rename to lldb/test/API/tools/lldb-dap/eventStatistic/TestDAP_eventStatistic.py
index f9d7a90d481a7..54f4c49d3c802 100644
--- a/lldb/test/API/tools/lldb-dap/eventStatistic/TestVSCode_eventStatistic.py
+++ b/lldb/test/API/tools/lldb-dap/eventStatistic/TestDAP_eventStatistic.py
@@ -2,24 +2,25 @@
 Test lldb-dap terminated event
 """
 
-import dap_server
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
 import json
-import re
 
-import lldbdap_testcase
-from lldbsuite.test import lldbutil
+from lldbsuite.test.decorators import (
+    skipIfRemote,
+    skipIfTargetDoesNotSupportSharedLibraries,
+    skipIfWindows,
+)
+from lldbsuite.test.tools.lldb_dap.dap_types import InitializedEvent, 
LaunchArgs
+from lldbsuite.test.tools.lldb_dap.lldb_dap_testcase import DAPTestCaseBase
 
 
 @skipIfTargetDoesNotSupportSharedLibraries()
-class TestDAP_eventStatistic(lldbdap_testcase.DAPTestCaseBase):
+class TestDAP_eventStatistic(DAPTestCaseBase):
     """
 
     Test case that captures both initialized and terminated events.
 
-    META-ONLY: Intended to succeed TestDAP_terminatedEvent.py, but upstream 
keeps updating that file, so both that and this file will probably exist for a 
while.
-
+    META-ONLY: Intended to succeed TestDAP_terminatedEvent.py,
+    but upstream keeps updating that file, so both that and this file will 
probably exist for a while.
     """
 
     def check_statistics_summary(self, statistics):
@@ -30,7 +31,7 @@ def check_statistics_summary(self, statistics):
         self.assertNotIn("modules", statistics.keys())
 
     def check_target_summary(self, statistics):
-        # lldb-dap debugs one target at a time
+        # lldb-dap debugs one target at a time.
         target = json.loads(statistics["targets"])[0]
         self.assertIn("totalSharedLibraryEventHitCount", target)
 
@@ -40,7 +41,7 @@ def test_terminated_event(self):
         """
         Terminated Event
         Now contains the statistics of a debug session:
-        metatdata:
+        metadata:
             totalDebugInfoByteSize > 0
             totalDebugInfoEnabled > 0
             totalModuleCountHasDebugInfo > 0
@@ -49,10 +50,13 @@ def test_terminated_event(self):
 
         program_basename = "a.out.stripped"
         program = self.getBuildArtifact(program_basename)
-        self.build_and_launch(program)
-        self.continue_to_exit()
+        session = self.build_and_create_session()
+        process_event = session.launch(LaunchArgs(program))
+        session.verify_process_exited()
 
-        statistics = 
self.dap_server.wait_for_terminated()["body"]["$__lldb_statistics"]
+        terminated_event = 
session.wait_for_terminated_event(after=process_event)
+        terminated_body = self.expect_not_none(terminated_event.body)
+        statistics = terminated_body.lldb_statistics
         self.check_statistics_summary(statistics)
         self.check_target_summary(statistics)
 
@@ -70,8 +74,14 @@ def test_initialized_event(self):
 
         program_basename = "a.out"
         program = self.getBuildArtifact(program_basename)
-        self.build_and_launch(program)
-        self.dap_server.wait_for_event("initialized")
-        statistics = 
self.dap_server.initialized_event["body"]["$__lldb_statistics"]
+        session = self.build_and_create_session()
+        pending_launch = session.initialize_and_launch(LaunchArgs(program))
+
+        init_event = session.wait_for_earliest_event(InitializedEvent)
+        init_body = self.expect_not_none(init_event.body)
+        statistics = init_body.lldb_statistics
         self.check_statistics_summary(statistics)
-        self.continue_to_exit()
+
+        session.verify_configuration_done()
+        launch_response = pending_launch.result()
+        session.verify_process_exited(after=launch_response)
diff --git 
a/lldb/test/API/tools/lldb-dap/invalidated-event/TestDAP_invalidatedEvent.py 
b/lldb/test/API/tools/lldb-dap/invalidated-event/TestDAP_invalidatedEvent.py
index 8ba56b0bb27ca..0fc8e921f2b72 100644
--- a/lldb/test/API/tools/lldb-dap/invalidated-event/TestDAP_invalidatedEvent.py
+++ b/lldb/test/API/tools/lldb-dap/invalidated-event/TestDAP_invalidatedEvent.py
@@ -4,18 +4,13 @@
 know about it.
 """
 
-import lldbdap_testcase
 from lldbsuite.test.lldbtest import line_number
-from dap_server import Event
+from lldbsuite.test.tools.lldb_dap.dap_types import LaunchArgs
+from lldbsuite.test.tools.lldb_dap.lldb_dap_testcase import DAPTestCaseBase
+from lldbsuite.test.tools.lldb_dap.session_helpers import DAPTestSession
 
 
-class TestDAP_invalidatedEvent(lldbdap_testcase.DAPTestCaseBase):
-    def verify_top_frame_name(self, frame_name: str):
-        all_frames = self.get_stackFrames()
-        self.assertGreaterEqual(len(all_frames), 1, "Expected at least one 
frame.")
-        top_frame_name = all_frames[0]["name"]
-        self.assertRegex(top_frame_name, f"{frame_name}.*")
-
+class TestDAP_invalidatedEvent(DAPTestCaseBase):
     def test_invalidated_stack_area_event(self):
         """
         Test an invalidated event for the stack area.
@@ -23,33 +18,36 @@ def test_invalidated_stack_area_event(self):
         """
         other_source = "other.h"
         return_bp_line = line_number(other_source, "// thread return 
breakpoint")
-
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program)
-        self.set_source_breakpoints(other_source, [return_bp_line])
-        self.continue_to_next_stop()
-
-        self.verify_top_frame_name("add")
-        thread_id = self.dap_server.get_thread_id()
-        self.assertIsNotNone(thread_id, "Exepected a thread id.")
-
-        # run thread return
-        thread_command = "thread return 20"
-        eval_resp = self.dap_server.request_evaluate(thread_command, 
context="repl")
-        self.assertTrue(eval_resp["success"], f"Failed to evaluate 
`{thread_command}`.")
-
-        # wait for the invalidated stack event.
-        stack_event = self.dap_server.wait_for_event(["invalidated"])
-        self.assertIsNotNone(stack_event, "Expected an invalidated event.")
-        event_body: Event = stack_event["body"]
-        self.assertIn("stacks", event_body["areas"])
-        self.assertIn("threadId", event_body.keys())
+        session = self.build_and_create_session()
+        with session.configure(LaunchArgs(program)) as ctx:
+            session.resolve_source_breakpoints(other_source, [return_bp_line])
+
+        stopped_event = 
session.verify_stopped_on_breakpoint(after=ctx.process_event)
+
+        thread_ctx = session.thread_context_from(stopped_event)
+        top_frame = thread_ctx.top_frame()
+        self.assertRegex(top_frame.name, "add.*")
+
+        last_event = session.last_event()
+        # Run thread return.
+        session.evaluate("thread return 20", context="repl")
+
+        # Wait for the invalidated stack event.
+        invalid_event = session.wait_for_invalidated_event(after=last_event)
+        self.assertIsNotNone(invalid_event, "Expected an invalidated event.")
+        event_body = invalid_event.body
+        self.assertIsNotNone(event_body.areas)
+        self.assertIn("stacks", event_body.areas or [])
+        self.assertIsNotNone(event_body.threadId)
         self.assertEqual(
-            thread_id,
-            event_body["threadId"],
-            f"Expected the event from thread {thread_id}.",
+            thread_ctx.thread_id,
+            event_body.threadId,
+            f"Expected the event from thread {thread_ctx.thread_id}.",
         )
 
-        # confirm we are back at the main frame.
-        self.verify_top_frame_name("main")
-        self.continue_to_exit()
+        # Confirm we are back at the main frame.
+        top_frame = session.top_frame_from(invalid_event)
+        self.assertRegex(top_frame.name, "main.*")
+
+        session.continue_to_exit()
diff --git a/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py 
b/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py
index a01845669666f..5795b55f07c03 100644
--- a/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py
+++ b/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py
@@ -3,46 +3,58 @@
 """
 
 import json
+from dataclasses import dataclass
+from typing import List, Optional
 
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-import lldbdap_testcase
+from lldbsuite.test.decorators import skipIfWindows
+from lldbsuite.test.lldbtest import line_number
+from lldbsuite.test.tools.lldb_dap.dap_types import Event, LaunchArgs, 
message_to_dict
+from lldbsuite.test.tools.lldb_dap.lldb_dap_testcase import DAPTestCaseBase
 
 
-class TestDAP_sendEvent(lldbdap_testcase.DAPTestCaseBase):
+@dataclass(frozen=True)
+class CustomEvent(Event, event="my-custom-event"):
+    @dataclass
+    class Body:
+        key: int
+        arr: List[bool]
+
+    body: Optional[Body] = None
+
+
+class TestDAP_sendEvent(DAPTestCaseBase):
     @skipIfWindows
     def test_send_event(self):
         """
         Test sending a custom event.
         """
-        program = self.getBuildArtifact("a.out")
+        session = self.build_and_create_session()
         source = "main.c"
-        breakpoint_line = line_number(source, "// breakpoint")
-        custom_event_body = {
-            "key": 321,
-            "arr": [True],
-        }
-        self.build_and_launch(
+        program = self.getBuildArtifact("a.out")
+        custom_event_body = CustomEvent.Body(key=321, arr=[True])
+
+        custom_event_body_json = json.dumps(message_to_dict(custom_event_body))
+        launch_args = LaunchArgs(
             program,
             stopCommands=[
-                "lldb-dap send-event my-custom-event-no-body",
-                "lldb-dap send-event my-custom-event '{}'".format(
-                    json.dumps(custom_event_body)
-                ),
+                "lldb-dap send-event my-custom-event ",
+                f"lldb-dap send-event my-custom-event 
'{custom_event_body_json}'",
             ],
         )
-        self.set_source_breakpoints(source, [breakpoint_line])
-        self.continue_to_next_stop()
+        with session.configure(launch_args) as ctx:
+            breakpoint_line = line_number(source, "// breakpoint")
+            session.resolve_source_breakpoints(source, [breakpoint_line])
+        process_event = ctx.process_event
 
-        custom_event = self.dap_server.wait_for_event(
-            filter=["my-custom-event-no-body"]
-        )
-        self.assertEqual(custom_event["event"], "my-custom-event-no-body")
-        self.assertIsNone(custom_event.get("body", None))
+        stop_event = session.verify_stopped_on_breakpoint(after=process_event)
+
+        custom_event = session.wait_for_event(CustomEvent, after=stop_event)
+        self.assertEqual(custom_event.event, "my-custom-event")
+        self.assertIsNone(custom_event.body, None)
 
-        custom_event = 
self.dap_server.wait_for_event(filter=["my-custom-event"])
-        self.assertEqual(custom_event["event"], "my-custom-event")
-        self.assertEqual(custom_event["body"], custom_event_body)
+        custom_event_with_body = session.wait_for_event(CustomEvent, 
after=custom_event)
+        self.assertEqual(custom_event_with_body.event, "my-custom-event")
+        self.assertEqual(custom_event_with_body.body, custom_event_body)
 
     @skipIfWindows
     def test_send_internal_event(self):
@@ -50,18 +62,13 @@ def test_send_internal_event(self):
         Test sending an internal event produces an error.
         """
         program = self.getBuildArtifact("a.out")
-        source = "main.c"
-        self.build_and_launch(program)
+        session = self.build_and_create_session()
+        process_event = session.launch(LaunchArgs(program, stopOnEntry=True))
 
-        breakpoint_line = line_number(source, "// breakpoint")
+        session.verify_stopped_on_entry(after=process_event)
+        expr_resp = session.do_evaluate("`lldb-dap send-event 
stopped").result()
 
-        self.set_source_breakpoints(source, [breakpoint_line])
-        self.continue_to_next_stop()
-
-        resp = self.dap_server.request_evaluate(
-            "`lldb-dap send-event stopped", context="repl"
-        )
         self.assertRegex(
-            resp["body"]["result"],
+            expr_resp.body.result,
             r"Invalid use of lldb-dap send-event, event \"stopped\" should be 
handled by lldb-dap internally.",
         )
diff --git 
a/lldb/test/API/tools/lldb-dap/stopped-events/TestDAP_stopped_events.py 
b/lldb/test/API/tools/lldb-dap/stopped-events/TestDAP_stopped_events.py
index 158d521d6859c..806ff1a6fdc83 100644
--- a/lldb/test/API/tools/lldb-dap/stopped-events/TestDAP_stopped_events.py
+++ b/lldb/test/API/tools/lldb-dap/stopped-events/TestDAP_stopped_events.py
@@ -2,40 +2,81 @@
 Test lldb-dap 'stopped' events.
 """
 
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-import lldbdap_testcase
+from typing import Sequence
+
+from lldbsuite.test.decorators import (
+    expectedFailureAll,
+    expectedFailureNetBSD,
+    skipIfLinux,
+    skipIfWindows,
+)
+from lldbsuite.test.lldbtest import line_number
+from lldbsuite.test.tools.lldb_dap import DAPTestCaseBase, DAPTestSession
+from lldbsuite.test.tools.lldb_dap.dap_types import (
+    LaunchArgs,
+    StoppedEvent,
+    ThreadsArgs,
+)
 
 
 @skipIfWindows  # This is flakey on Windows: llvm.org/pr24668, llvm.org/pr38373
 @skipIfLinux
-class TestDAP_stopped_events(lldbdap_testcase.DAPTestCaseBase):
+class TestDAP_stopped_events(DAPTestCaseBase):
     """
     Test validates different operations that produce 'stopped' events.
     """
 
-    ANY_THREAD = {}
+    def collect_two_stops(self, session: DAPTestSession, *, after):
+        """Collect two consecutive StoppedEvents (one per thread that hit the
+        breakpoint). Both threads release the barrier together so the events
+        arrive close in time"""
+        first = session.wait_for_stopped_event(
+            after=after, timeout_msg="waiting for first stop"
+        )
+        second = session.wait_for_stopped_event(
+            after=first, timeout_msg="waiting for second stop"
+        )
+
+        self.assertNotEqual(
+            first.body.threadId,
+            second.body.threadId,
+            "expected stopped event on different threads.",
+        )
+        return first, second
+
+    def verify_threads(
+        self, session: DAPTestSession, stopped_events: Sequence[StoppedEvent]
+    ):
+        """Verify the threads response and the focused-thread invariants.
 
-    def is_subdict(self, small: dict, big: dict) -> bool:
-        """Returns true if 'small' is a subset of 'big', otherwise false."""
-        return big | small == big
+        One of `stopped_events` must carry threads[1].id as its threadId.
+        That event must not set preserveFocusHint=True.
 
-    def verify_threads(self, expected_threads):
-        threads_resp = self.dap_server.request_threads()
-        self.assertTrue(threads_resp["success"])
-        threads = threads_resp["body"]["threads"]
+        Should return something like:
+         Process 1234 stopped
+           thread #1: tid = 0x01, 0x0a 
libsystem_pthread.dylib`pthread_mutex_lock + 12, queue = 'com.apple.main-thread'
+         * thread #2: tid = 0x02, 0x0b a.out`add(a=1, b=2) at main.cpp:10:32, 
stop reason = breakpoint 1.1 2.1
+           thread #3: tid = 0x03, 0x0c a.out`add(a=4, b=5) at main.cpp:10:32, 
stop reason = breakpoint 1.1 2.1
+        """
+        threads = session.send_request(ThreadsArgs()).result().body.threads
+        expected_count = 3
         self.assertGreaterEqual(
             len(threads),
-            len(expected_threads),
-            f"thread: {threads!r}\n expected threads: {expected_threads}",
+            expected_count,
+            f"expected at least {expected_count} threads, got {threads!r}",
         )
 
-        for idx, expected_thread in enumerate(expected_threads):
-            thread = threads[idx]
-            self.assertTrue(
-                self.is_subdict(expected_thread, thread),
-                f"Invalid thread state in {threads_resp}",
-            )
+        focused_tid = threads[1].id
+        events_by_tid = {e.body.threadId: e for e in stopped_events}
+        focused_event = self.expect_not_none(
+            events_by_tid.get(focused_tid),
+            f"expected a stopped event for focused thread {focused_tid}",
+        )
+        self.assertNotEqual(
+            focused_event.body.preserveFocusHint,
+            True,
+            "focused thread's stopped event must not set 
preserveFocusHint=True",
+        )
 
     @expectedFailureAll(
         oslist=["freebsd"],
@@ -44,64 +85,26 @@ def verify_threads(self, expected_threads):
     @expectedFailureNetBSD
     def test_multiple_threads_same_breakpoint(self):
         """
-        Test that multiple threads being stopped on the same breakpoint 
produces multiple 'stopped' event.
+        Test that multiple threads being stopped on the same breakpoint
+        produces multiple 'stopped' events.
         """
         program = self.getBuildArtifact("a.out")
-        launch_seq = self.build_and_launch(program)
-        self.dap_server.wait_for_event(["initialized"])
-        [bp] = self.set_function_breakpoints(["my_add"])
-        self.verify_configuration_done()
-        response = self.dap_server.receive_response(launch_seq)
-        self.assertTrue(response["success"])
-
-        events = self.dap_server.wait_for_stopped()
-        if len(events) == 1:
-            # we may not catch both events at the same time if we run with 
sanitizers
-            # enabled or on slow or heavily used computer.
-            events.extend(self.dap_server.wait_for_stopped())
-
-        self.assertEqual(
-            len(events),
-            2,
-            f"Expected two 'stopped' events, seen events: {events!r}",
-        )
-        for event in events:
-            body = event["body"]
-            self.assertEqual(body["reason"], "breakpoint")
-            self.assertEqual(body["text"], "breakpoint 1.1")
-            self.assertEqual(body["description"], "breakpoint 1.1")
-            self.assertEqual(body["hitBreakpointIds"], [int(bp)])
-            self.assertIsNotNone(body["threadId"])
-
-        # We should have three threads, something along the lines of:
-        #
-        # Process 1234 stopped
-        #   thread #1: tid = 0x01, 0x0a 
libsystem_pthread.dylib`pthread_mutex_lock + 12, queue = 'com.apple.main-thread'
-        # * thread #2: tid = 0x02, 0x0b a.out`add(a=1, b=2) at main.cpp:10:32, 
stop reason = breakpoint 1.1
-        #   thread #3: tid = 0x03, 0x0c a.out`add(a=4, b=5) at main.cpp:10:32, 
stop reason = breakpoint 1.1
-        self.verify_threads(
-            [
-                self.ANY_THREAD,
-                {
-                    "reason": "breakpoint",
-                    "text": "breakpoint 1.1",
-                    "description": "breakpoint 1.1",
-                },
-                {
-                    "reason": "breakpoint",
-                    "text": "breakpoint 1.1",
-                    "description": "breakpoint 1.1",
-                },
-            ]
-        )
-
-        self.assertEqual(
-            self.dap_server.threads[1]["id"],
-            self.dap_server.focused_tid,
-            "Expected thread#2 to be focused",
-        )
-
-        self.continue_to_exit()
+        session = self.build_and_create_session()
+        with session.configure(LaunchArgs(program)) as ctx:
+            [bp] = session.resolve_function_breakpoints(["my_add"])
+        process_event = ctx.process_event
+        first, second = self.collect_two_stops(session, after=process_event)
+
+        for event in (first, second):
+            body = event.body
+            self.assertEqual(body.reason, "breakpoint")
+            self.assertEqual(body.text, "breakpoint 1.1")
+            self.assertEqual(body.description, "breakpoint 1.1")
+            self.assertEqual(body.hitBreakpointIds, [bp])
+            self.assertIsNotNone(body.threadId)
+
+        self.verify_threads(session, (first, second))
+        session.continue_to_exit()
 
     @expectedFailureAll(
         oslist=["freebsd"],
@@ -110,58 +113,26 @@ def test_multiple_threads_same_breakpoint(self):
     @expectedFailureNetBSD
     def test_multiple_breakpoints_same_location(self):
         """
-        Test stopping at a location that reports multiple overlapping 
breakpoints.
+        Test stopping at a location that reports multiple overlapping
+        breakpoints.
         """
         program = self.getBuildArtifact("a.out")
-        launch_seq = self.build_and_launch(program)
-        self.dap_server.wait_for_event(["initialized"])
-        line_1 = line_number("main.cpp", "breakpoint")
-        [bp1] = self.set_source_breakpoints("main.cpp", [line_1])
-        [bp2] = self.set_function_breakpoints(["my_add"])
-        self.verify_configuration_done()
-        response = self.dap_server.receive_response(launch_seq)
-        self.assertTrue(response["success"])
-
-        events = self.dap_server.wait_for_stopped()
-        if len(events) == 1:
-            # we may not catch both events at the same time if we run with 
sanitizers
-            # enabled or on slow or heavily used computer.
-            events.extend(self.dap_server.wait_for_stopped())
-
-        self.assertEqual(len(events), 2, "Expected two stopped events")
-        for event in events:
-            body = event["body"]
-            self.assertEqual(body["reason"], "breakpoint")
-            self.assertEqual(body["text"], "breakpoint 1.1 2.1")
-            self.assertEqual(body["description"], "breakpoint 1.1 2.1")
-            self.assertEqual(body["hitBreakpointIds"], [int(bp1), int(bp2)])
-            self.assertIsNotNone(body["threadId"])
-
-        # Should return something like:
-        # Process 1234 stopped
-        #   thread #1: tid = 0x01, 0x0a 
libsystem_pthread.dylib`pthread_mutex_lock + 12, queue = 'com.apple.main-thread'
-        # * thread #2: tid = 0x02, 0x0b a.out`add(a=1, b=2) at main.cpp:10:32, 
stop reason = breakpoint 1.1 2.1
-        #   thread #3: tid = 0x03, 0x0c a.out`add(a=4, b=5) at main.cpp:10:32, 
stop reason = breakpoint 1.1 2.1
-        self.verify_threads(
-            [
-                self.ANY_THREAD,
-                {
-                    "reason": "breakpoint",
-                    "description": "breakpoint 1.1 2.1",
-                    "text": "breakpoint 1.1 2.1",
-                },
-                {
-                    "reason": "breakpoint",
-                    "description": "breakpoint 1.1 2.1",
-                    "text": "breakpoint 1.1 2.1",
-                },
-            ]
-        )
-
-        self.assertEqual(
-            self.dap_server.threads[1]["id"],
-            self.dap_server.focused_tid,
-            "Expected thread#2 to be focused",
-        )
-
-        self.continue_to_exit()
+        session = self.build_and_create_session()
+        source = self.getSourcePath("main.cpp")
+        bp_line = line_number(source, "breakpoint")
+
+        with session.configure(LaunchArgs(program)) as ctx:
+            [bp1] = session.resolve_source_breakpoints(source, [bp_line])
+            [bp2] = session.resolve_function_breakpoints(["my_add"])
+        first, second = self.collect_two_stops(session, 
after=ctx.process_event)
+
+        for event in (first, second):
+            body = event.body
+            self.assertEqual(body.reason, "breakpoint")
+            self.assertEqual(body.text, "breakpoint 1.1 2.1")
+            self.assertEqual(body.description, "breakpoint 1.1 2.1")
+            self.assertEqual(body.hitBreakpointIds, [bp1, bp2])
+            self.assertIsNotNone(body.threadId)
+
+        self.verify_threads(session, (first, second))
+        session.continue_to_exit()
diff --git 
a/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py 
b/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py
index 6af19416e4987..144625f12a7b0 100644
--- a/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py
+++ b/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py
@@ -2,17 +2,19 @@
 Test lldb-dap terminated event
 """
 
-import dap_server
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
-import lldbdap_testcase
-import re
 import json
 
+from lldbsuite.test.decorators import (
+    skipIfTargetDoesNotSupportSharedLibraries,
+    skipIfWindows,
+)
+from lldbsuite.test.lldbtest import line_number
+from lldbsuite.test.tools.lldb_dap.dap_types import LaunchArgs
+from lldbsuite.test.tools.lldb_dap.lldb_dap_testcase import DAPTestCaseBase
+
 
 @skipIfTargetDoesNotSupportSharedLibraries()
-class TestDAP_terminatedEvent(lldbdap_testcase.DAPTestCaseBase):
+class TestDAP_terminatedEvent(DAPTestCaseBase):
     @skipIfWindows
     def test_terminated_event(self):
         """
@@ -28,31 +30,30 @@ def test_terminated_event(self):
         breakpoints:
             recognize function breakpoint
             recognize source line breakpoint
-        It should contains the breakpoints info: function bp & source line bp
+        It should contain the breakpoints info: function bp & source line bp
         """
+        program = self.getBuildArtifact("a.out.stripped")
+        session = self.build_and_create_session()
+        source = self.getSourcePath("main.cpp")
+        main_bp_line = line_number(source, "// main breakpoint 1")
 
-        program_basename = "a.out.stripped"
-        program = self.getBuildArtifact(program_basename)
-        self.build_and_launch(program)
-        # Set breakpoints
-        functions = ["foo"]
-
-        # This breakpoint will be resolved only when the libfoo module is 
loaded
-        breakpoint_ids = self.set_function_breakpoints(
-            functions, wait_for_resolve=False
-        )
-        self.assertEqual(len(breakpoint_ids), len(functions), "expect one 
breakpoint")
-        main_bp_line = line_number("main.cpp", "// main breakpoint 1")
-        breakpoint_ids.extend(
-            self.set_source_breakpoints(
-                "main.cpp", [main_bp_line], wait_for_resolve=False
+        with session.configure(LaunchArgs(program=program)) as ctx:
+            # This breakpoint will be resolved only when the libfoo module is 
loaded.
+            func_response = session.set_function_breakpoints(["foo"])
+            breakpoints = func_response.body.breakpoints
+            breakpoints.extend(
+                session.set_source_breakpoints(source, 
[main_bp_line]).body.breakpoints
             )
+        breakpoint_ids = session.breakpoints_to_ids(breakpoints)
+        self.assertEqual(len(breakpoint_ids), 2, "expect one breakpoint")
+        last_bp_event = session.wait_until_any_breakpoint_hit(
+            breakpoint_ids, after=ctx.process_event
         )
+        session.continue_to_exit()
 
-        self.continue_to_breakpoints(breakpoint_ids)
-        self.continue_to_exit()
+        terminated = session.wait_for_terminated_event(after=last_bp_event)
+        statistics = self.expect_not_none(terminated.body).lldb_statistics
 
-        statistics = 
self.dap_server.wait_for_terminated()["body"]["$__lldb_statistics"]
         self.assertGreater(statistics["totalDebugInfoByteSize"], 0)
         self.assertGreater(statistics["totalDebugInfoEnabled"], 0)
         self.assertGreater(statistics["totalModuleCountHasDebugInfo"], 0)
@@ -60,7 +61,7 @@ def test_terminated_event(self):
         self.assertIsNotNone(statistics["memory"])
         self.assertNotIn("modules", statistics.keys())
 
-        # lldb-dap debugs one target at a time
+        # lldb-dap debugs one target at a time.
         target = json.loads(statistics["targets"])[0]
         self.assertGreater(target["totalBreakpointResolveTime"], 0)
 

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to