Author: Ebuka Ezike
Date: 2026-08-13T16:46:16+01:00
New Revision: bd7af6744d4e604582841f512bc5886d21509ae1

URL: 
https://github.com/llvm/llvm-project/commit/bd7af6744d4e604582841f512bc5886d21509ae1
DIFF: 
https://github.com/llvm/llvm-project/commit/bd7af6744d4e604582841f512bc5886d21509ae1.diff

LOG: [lldb-dap] Migrate memory and disconnect tests (#215821)

In Disconnect `test_attach` test, use a breakpoint to stop the process
to ensure we are in the `handle_attach` frame to change the
`wait_for_attach` variable.

Added: 
    

Modified: 
    lldb/test/API/tools/lldb-dap/disconnect/TestDAP_disconnect.py
    lldb/test/API/tools/lldb-dap/disconnect/main.cpp
    lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py
    lldb/test/API/tools/lldb-dap/server/main.c

Removed: 
    


################################################################################
diff  --git a/lldb/test/API/tools/lldb-dap/disconnect/TestDAP_disconnect.py 
b/lldb/test/API/tools/lldb-dap/disconnect/TestDAP_disconnect.py
index c6ebef2e584a1..4c82f34b9232f 100644
--- a/lldb/test/API/tools/lldb-dap/disconnect/TestDAP_disconnect.py
+++ b/lldb/test/API/tools/lldb-dap/disconnect/TestDAP_disconnect.py
@@ -2,28 +2,23 @@
 Test lldb-dap disconnect request
 """
 
+import os
+import subprocess
+import uuid
 
+from lldbsuite.test import lldbutil
 from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
-import lldbdap_testcase
-import time
-import os
+from lldbsuite.test.tools.lldb_dap import DAPTestCaseBase
+from lldbsuite.test.tools.lldb_dap.types import *
 
 
 @requireNotWasm("no attach support")
-class TestDAP_disconnect(lldbdap_testcase.DAPTestCaseBase):
+class TestDAP_disconnect(DAPTestCaseBase):
     SHARED_BUILD_TESTCASE = False
 
     source = "main.cpp"
 
-    def disconnect_and_assert_no_output_printed(self):
-        self.dap_server.request_disconnect()
-        # verify we didn't get any input after disconnect
-        time.sleep(2)
-        output = self.get_stdout()
-        self.assertTrue(output is None or len(output) == 0)
-
     @skipIfWindows
     def test_launch(self):
         """
@@ -32,22 +27,23 @@ def test_launch(self):
         created.
         """
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program, stopOnEntry=True, 
disconnectAutomatically=False)
-
-        # We set a breakpoint right before the side effect file is created
-        self.set_source_breakpoints(
-            self.source, [line_number(self.source, "// breakpoint")]
-        )
-        self.continue_to_next_stop()
+        side_effect = f"{program}.side_effect"
+        session = self.build_and_create_session(disconnect_automatically=False)
+        with session.configure(LaunchArgs(program, stopOnEntry=True)) as ctx:
+            # We set a breakpoint right before the side effect file is created
+            session.resolve_source_breakpoints(
+                self.source, [line_number(self.source, "// breakpoint")]
+            )
+        stop_event = session.verify_stopped_on_entry(after=ctx.process_event)
 
-        # verify we haven't produced the side effect file yet
-        self.assertFalse(os.path.exists(program + ".side_effect"))
+        # Verify we haven't produced the side effect file yet.
+        self.assertFalse(os.path.exists(side_effect))
 
-        self.dap_server.request_disconnect()
+        session.disconnect(terminateDebuggee=True)
+        session.wait_for_event(TerminatedEvent, after=stop_event)
 
-        # verify we didn't produce the side effect file
-        time.sleep(1)
-        self.assertFalse(os.path.exists(program + ".side_effect"))
+        # Verify we didn't produce the side effect file.
+        self.assertFalse(os.path.exists(side_effect))
 
     @skipIfWindows
     @expectedFailureNetBSD
@@ -57,29 +53,40 @@ def test_attach(self):
         before the file is created, and as the process is not terminated upon 
disconnection,
         the file is created anyway.
         """
-        self.build_and_create_debug_adapter()
+        session = self.build_and_create_session(disconnect_automatically=False)
         program = self.getBuildArtifact("a.out")
+        side_effect = program + ".side_effect"
 
         # Use a file as a synchronization point between test and inferior.
         sync_file_path = lldbutil.append_to_process_working_directory(
-            self, "sync_file_%d" % (int(time.time()))
+            self, f"sync_file_{uuid.uuid4().hex}"
         )
-        self.addTearDownHook(
-            lambda: self.run_platform_command("rm %s" % (sync_file_path))
+
+        proc = self.spawnSubprocess(
+            program, [sync_file_path], stdout=subprocess.PIPE, 
stderr=subprocess.PIPE
         )
+        self.addTearDownHook(lambda: proc.kill())
 
-        proc = self.spawnSubprocess(program, [sync_file_path])
         lldbutil.wait_for_file_on_target(self, sync_file_path)
 
-        self.attach(pid=proc.pid, disconnectAutomatically=False, 
stopOnEntry=True)
-        self.continue_to_next_stop()
-        response = self.dap_server.request_evaluate("wait_for_attach = false;")
-        self.assertTrue(response["success"])
+        with session.configure(AttachArgs(pid=proc.pid)) as cm:
+            line = line_number(self.source, "// attach breakpoint")
+            [bp_id] = session.resolve_source_breakpoints(self.source, [line])
+        stop_event = session.verify_stopped_on_breakpoint(bp_id, 
after=cm.process_event)
+
+        self.assertFalse(os.path.exists(side_effect))
+
+        top_frame = session.top_frame_from(stop_event)
+        self.logger.info("frame name: %s", top_frame.name)
+        top_frame.evaluate("`expr wait_for_attach = false;", context="repl")
+
+        # Verify the variable changed.
+        wait_for_attach_var = top_frame.evaluate("wait_for_attach", 
context="hover")
+        self.assertEqual(wait_for_attach_var.result, "false")
+
+        session.disconnect()
 
-        # verify we haven't produced the side effect file yet
-        self.assertFalse(os.path.exists(program + ".side_effect"))
+        # Wait for the process to run to completion.
+        proc.wait(timeout=10)
 
-        self.dap_server.request_disconnect()
-        time.sleep(2)
-        # verify we produced the side effect file, as the program continued 
after disconnecting
-        self.assertTrue(os.path.exists(program + ".side_effect"))
+        self.assertTrue(os.path.exists(side_effect))

diff  --git a/lldb/test/API/tools/lldb-dap/disconnect/main.cpp 
b/lldb/test/API/tools/lldb-dap/disconnect/main.cpp
index ca9610da4566a..92effee48023b 100644
--- a/lldb/test/API/tools/lldb-dap/disconnect/main.cpp
+++ b/lldb/test/API/tools/lldb-dap/disconnect/main.cpp
@@ -16,8 +16,10 @@ void handle_attach(char *sync_file_path) {
     sync_file.open(sync_file_path);
   }
 
-  while (wait_for_attach)
-    std::this_thread::sleep_for(std::chrono::milliseconds(10));
+  while (wait_for_attach) {
+    const auto sleep_time = std::chrono::milliseconds(10);
+    std::this_thread::sleep_for(sleep_time); // attach breakpoint
+  }
 }
 
 int main(int argc, char **args) {

diff  --git a/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py 
b/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py
index 7c32ae4fb8c38..e9adf6921b373 100644
--- a/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py
+++ b/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py
@@ -3,209 +3,180 @@
 """
 
 from base64 import b64decode
-import dap_server
+
 from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
-import lldbdap_testcase
-import os
+from lldbsuite.test.tools.lldb_dap import DAPTestCaseBase, DAPTestSession
+from lldbsuite.test.tools.lldb_dap.types import *
 
 
-class TestDAP_memory(lldbdap_testcase.DAPTestCaseBase):
-    @skipIfWindows
-    def test_memory_refs_variables(self):
-        """
-        Tests memory references for evaluate
-        """
+class TestDAP_memory(DAPTestCaseBase):
+    def stop_at_breakpoint(self, session: DAPTestSession):
+        """Build, launch, and stop at the `// Breakpoint` line. Returns the
+        top frame at that stop."""
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program)
-        source = "main.cpp"
-        self.source_path = os.path.join(os.getcwd(), source)
-        self.set_source_breakpoints(
-            source,
-            [line_number(source, "// Breakpoint")],
-        )
-        self.continue_to_next_stop()
+        source = self.getSourcePath("main.cpp")
+        bp_line = line_number(source, "// Breakpoint")
+        with session.configure(LaunchArgs(program)) as ctx:
+            session.resolve_source_breakpoints(source, [bp_line])
+        stop_event = 
session.verify_stopped_on_breakpoint(after=ctx.process_event)
+        thread_ctx = session.thread_context_from(stop_event)
+        return thread_ctx.top_frame()
 
-        locals = {l["name"]: l for l in self.dap_server.get_local_variables()}
+    @skipIfWindows
+    def test_memory_refs_variables(self):
+        """Tests memory references on local variables."""
+        session = self.build_and_create_session()
+        top_frame = self.stop_at_breakpoint(session)
+        locals = top_frame.locals
 
-        # Pointers should have memory-references
-        self.assertIn("memoryReference", locals["rawptr"].keys())
-        # Non-pointers should also have memory-references
-        self.assertIn("memoryReference", locals["not_a_ptr"].keys())
+        # Pointers should have memory references.
+        self.assertIsNotNone(locals["rawptr"].memoryReference)
+        # Non-pointers should also have memory references.
+        self.assertIsNotNone(locals["not_a_ptr"].memoryReference)
 
     @skipIfWindows
     def test_memory_refs_evaluate(self):
-        """
-        Tests memory references for evaluate
-        """
-        program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program)
-        source = "main.cpp"
-        self.source_path = os.path.join(os.getcwd(), source)
-        self.set_source_breakpoints(
-            source,
-            [line_number(source, "// Breakpoint")],
-        )
-        self.continue_to_next_stop()
+        """Tests memory references on `evaluate` responses."""
+        session = self.build_and_create_session()
+        top_frame = self.stop_at_breakpoint(session)
 
-        self.assertIn(
-            "memoryReference",
-            self.dap_server.request_evaluate("rawptr")["body"].keys(),
-        )
+        eval_body = session.evaluate("rawptr", frameId=top_frame.id)
+        self.assertIsNotNone(eval_body.memoryReference)
 
     @skipIfWindows
     def test_memory_refs_set_variable(self):
-        """
-        Tests memory references for `setVariable`
-        """
-        program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program)
-        source = "main.cpp"
-        self.source_path = os.path.join(os.getcwd(), source)
-        self.set_source_breakpoints(
-            source,
-            [line_number(source, "// Breakpoint")],
-        )
-        self.continue_to_next_stop()
+        """Tests memory references on `setVariable` responses."""
+        session = self.build_and_create_session()
+        top_frame = self.stop_at_breakpoint(session)
+        locals = top_frame.locals
 
-        ptr_value = self.get_local_as_int("rawptr")
-        self.assertIn(
-            "memoryReference",
-            self.set_local("rawptr", ptr_value + 2)["body"].keys(),
-        )
+        ptr_value = locals["rawptr"].variable.value_as_int
+        response = locals.set("rawptr", ptr_value + 2)
+        response = self.expect_success(response)
+        self.assertIsNotNone(response.body.memoryReference)
 
     @skipIfWindows
-    @skipIfWasm  # the test finds the memory to read by evaluating an 
expression
+    @requireExpressionEvaluation
     def test_readMemory(self):
-        """
-        Tests the 'readMemory' request
-        """
-        program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program)
-        source = "main.cpp"
-        self.source_path = os.path.join(os.getcwd(), source)
-        self.set_source_breakpoints(
-            source,
-            [line_number(source, "// Breakpoint")],
+        """Tests the `readMemory` request."""
+        session = self.build_and_create_session()
+        top_frame = self.stop_at_breakpoint(session)
+
+        eval_body = session.evaluate("*rawptr", frameId=top_frame.id)
+        memref = self.expect_not_none(eval_body.memoryReference)
+
+        # We can read the complete string.
+        response = session.read_memory(memref, count=5, offset=0).result()
+        data = self.expect_not_none(response.body.data)
+        self.assertEqual(b64decode(data), b"dead\0")
+
+        # Large reads return partial results.
+        response = session.read_memory(memref, count=4096, offset=0).result()
+        data = self.expect_not_none(response.body.data)
+        self.assertEqual(b64decode(data)[0:5], b"dead\0")
+
+        # Offsets work.
+        response = session.read_memory(memref, count=3, offset=2).result()
+        data = self.expect_not_none(response.body.data)
+        self.assertEqual(b64decode(data), b"ad\0")
+
+        # Reads of size 0 are successful.
+        # VSCode uses these to probe whether a memoryReference can actually be 
dereferenced.
+        response = session.read_memory(memref, count=0, offset=0).result()
+        self.assertIsNone(
+            response.body.data, f"expects no data in response: {response!r}"
         )
-        self.continue_to_next_stop()
 
-        ptr_deref = self.dap_server.request_evaluate("*rawptr")["body"]
-        memref = ptr_deref["memoryReference"]
-
-        # We can read the complete string
-        mem = self.dap_server.request_readMemory(memref, 0, 5)["body"]
-        self.assertEqual(b64decode(mem["data"]), b"dead\0")
-
-        # We can read large chunks, potentially returning partial results
-        mem = self.dap_server.request_readMemory(memref, 0, 4096)["body"]
-        self.assertEqual(b64decode(mem["data"])[0:5], b"dead\0")
-
-        # Use an offset
-        mem = self.dap_server.request_readMemory(memref, 2, 3)["body"]
-        self.assertEqual(b64decode(mem["data"]), b"ad\0")
-
-        # Reads of size 0 are successful
-        # VS Code sends those in order to check if a `memoryReference` can 
actually be dereferenced.
-        mem = self.dap_server.request_readMemory(memref, 0, 0)
-        self.assertEqual(mem["success"], True)
-        self.assertNotIn(
-            "data", mem["body"], f"expects no data key in response: {mem!r}"
-        )
-
-        # Reads at offset 0x0 return unreadable bytes
+        # Reads at offset 0x0 return unreadable bytes.
         bytes_to_read = 6
-        mem = self.dap_server.request_readMemory("0x0", 0, bytes_to_read)
-        self.assertEqual(mem["body"]["unreadableBytes"], bytes_to_read)
+        response = session.read_memory("0x0", count=bytes_to_read, 
offset=0).result()
+        self.assertEqual(response.body.unreadableBytes, bytes_to_read)
 
-        # Reads with invalid address fails.
-        mem = self.dap_server.request_readMemory("-3204", 0, 10)
-        self.assertFalse(mem["success"], "expect fail on reading memory.")
+        # Reads with an invalid address fail.
+        session.read_memory("-3204", count=10, offset=0).error(
+            "expect fail on reading memory."
+        )
 
-        self.continue_to_exit()
+        session.continue_to_exit()
 
     # Flakey on 32-bit Arm Linux.
     @skipIf(oslist=["linux"], archs=["arm$"])
-    @skipIfWasm  # the test finds the memory to write by evaluating an 
expression
+    @requireExpressionEvaluation
     def test_writeMemory(self):
-        """
-        Tests the 'writeMemory' request
-        """
-        program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program)
-        source = "main.cpp"
-        self.source_path = os.path.join(os.getcwd(), source)
-        self.set_source_breakpoints(
-            source,
-            [line_number(source, "// Breakpoint")],
-        )
-        self.continue_to_next_stop()
+        """Tests the `writeMemory` request."""
+        session = self.build_and_create_session()
+        top_frame = self.stop_at_breakpoint(session)
 
-        # Get the 'not_a_ptr' writable variable reference address.
-        ptr_deref = self.dap_server.request_evaluate("not_a_ptr")["body"]
-        memref = ptr_deref["memoryReference"]
+        # Get `not_a_ptr`'s writable variable's memory reference.
+        eval_body = session.evaluate("not_a_ptr", frameId=top_frame.id)
+        memref = self.expect_not_none(eval_body.memoryReference)
 
         # Write the decimal value 50 (0x32 in hexadecimal) to memory.
-        # This corresponds to the ASCII character '2' and encodes to Base64 as 
"Mg==".
-        mem_response = self.writeMemory(memref, 50, 0, True)
-        self.assertEqual(mem_response["success"], True)
-        self.assertEqual(mem_response["body"]["bytesWritten"], 1)
-
-        # Read back the modified memory and verify that the written data 
matches
-        # the expected result.
-        mem_response = self.dap_server.request_readMemory(memref, 0, 1)
-        self.assertEqual(mem_response["success"], True)
-        self.assertEqual(mem_response["body"]["data"], "Mg==")
-
-        # Write the decimal value 100 (0x64 in hexadecimal) to memory.
-        # This corresponds to the ASCII character 'd' and encodes to Base64 as 
"ZA==".
-        # allowPartial=False
-        mem_response = self.writeMemory(memref, 100, 0, False)
-        self.assertEqual(mem_response["success"], True)
-        self.assertEqual(mem_response["body"]["bytesWritten"], 1)
-
-        # Read back the modified memory and verify that the written data 
matches
-        # the expected result.
-        mem_response = self.dap_server.request_readMemory(memref, 0, 1)
-        self.assertEqual(mem_response["success"], True)
-        self.assertEqual(mem_response["body"]["data"], "ZA==")
-
-        # Memory write failed for 0x0.
-        mem_response = self.writeMemory("0x0", 50, 0, True)
-        self.assertEqual(mem_response["success"], False)
-
-        # Malformed memory reference.
-        mem_response = self.writeMemory("12345", 50, 0, True)
-        self.assertEqual(mem_response["success"], False)
-
-        ptr_deref = self.dap_server.request_evaluate("nonWritable")["body"]
-        memref = ptr_deref["memoryReference"]
-
-        # Writing to non-writable region should return an appropriate error.
-        mem_response = self.writeMemory(memref, 50, 0, False)
-        self.assertEqual(mem_response["success"], False)
+        # This corresponds to the ASCII character '2' and encodes to base64
+        # as "Mg==".
+        response = session.write_memory(memref, value=50, offset=0, 
allowPartial=True)
+        response = self.expect_success(response)
+        self.assertEqual(response.body.bytesWritten, 1)
+
+        # Read back and verify.
+        read_response = session.read_memory(memref, count=1, offset=0).result()
+        self.assertEqual(read_response.body.data, "Mg==")
+
+        # Write the decimal value 100 (0x64 in hexadecimal) to memory with
+        # allowPartial=False. This corresponds to the ASCII character 'd' and
+        # encodes to base64 as "ZA==".
+        response = session.write_memory(memref, value=100, offset=0, 
allowPartial=False)
+        response = self.expect_success(response)
+        self.assertEqual(response.body.bytesWritten, 1)
+
+        # Read back and verify.
+        read_response = session.read_memory(memref, count=1, offset=0).result()
+        self.assertEqual(read_response.body.data, "ZA==")
+
+        # Writing to 0x0 fails.
+        response = session.write_memory("0x0", value=50, offset=0, 
allowPartial=True)
+        self.expect_error(response)
+
+        # Writing to a malformed memory reference fails.
+        response = session.write_memory("12345", value=50, offset=0, 
allowPartial=True)
+        self.expect_error(response)
+
+        # Writing to a non-writable region returns a not-writable error.
+        eval_body = session.evaluate("nonWritable", frameId=top_frame.id)
+        nonwritable_ref = self.expect_not_none(eval_body.memoryReference)
+        response = session.write_memory(
+            nonwritable_ref, value=50, offset=0, allowPartial=False
+        )
+        err = self.expect_error(response)
+        err_msg = self.expect_not_none(err.body and err.body.error)
         self.assertRegex(
-            mem_response["body"]["error"]["format"],
-            r"Memory " + memref + " region is not writable",
+            err_msg.format,
+            rf"Memory {nonwritable_ref} region is not writable",
         )
 
-        # Trying to write empty value; data=""
-        mem_response = self.writeMemory(memref)
-        self.assertEqual(mem_response["success"], False)
+        # Writing an empty value (no data) fails.
+        response = session.write_memory(nonwritable_ref, value="")
+        err = self.expect_error(response)
+        err_msg = self.expect_not_none(err.body and err.body.error)
         self.assertRegex(
-            mem_response["body"]["error"]["format"],
+            err_msg.format,
             r"Data cannot be empty value. Provide valid data",
         )
 
-        # Verify that large memory writes fail if the range spans non-writable
-        # or non -contiguous regions.
+        # Large writes spanning non-writable regions fail.
         data = bytes([0xFF] * 8192)
-        mem_response = self.writeMemory(
-            memref, int.from_bytes(data, byteorder="little"), 0, False
+
+        response = session.write_memory(
+            nonwritable_ref,
+            value=data,
+            offset=0,
+            allowPartial=False,
         )
-        self.assertEqual(mem_response["success"], False)
+        err = self.expect_error(response)
+        err_msg = self.expect_not_none(err.body and err.body.error)
         self.assertRegex(
-            mem_response["body"]["error"]["format"],
-            r"Memory " + memref + " region is not writable",
+            err_msg.format, rf"Memory {nonwritable_ref} region is not writable"
         )
+
+        session.continue_to_exit()

diff  --git a/lldb/test/API/tools/lldb-dap/server/main.c 
b/lldb/test/API/tools/lldb-dap/server/main.c
index 446ae82532af5..6f69c9568b037 100644
--- a/lldb/test/API/tools/lldb-dap/server/main.c
+++ b/lldb/test/API/tools/lldb-dap/server/main.c
@@ -6,5 +6,5 @@ int main(int argc, char const *argv[]) {
   } else {
     printf("Hello World!\n");
   }
-  return 0;
+  return 0; // breakpoint 2
 }


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

Reply via email to