Author: Ebuka Ezike
Date: 2026-07-13T13:43:14+01:00
New Revision: 40f2fda52c4b3b110f38acded24521217473d106

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

LOG: [lldb-dap] Migrate all DAP variables test. (#208215)

migrate TestDAP_variables and TestDAP_variables_children.

Added: 
    

Modified: 
    lldb/packages/Python/lldbsuite/test/tools/lldb_dap/session_helpers.py
    lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
    
lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py

Removed: 
    


################################################################################
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 34eb33f03c450..35a2d6c2f281a 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
@@ -1578,7 +1578,9 @@ def get_variables(
             count=count,
             format=format,
         )
-        response = self.send_request(args).result()
+        response = self.send_request(args).result(
+            f"failed to get variables for reference: {variablesReference}"
+        )
         return response.body.variables
 
     def thread_context_from(self, thread_ref: int | StoppedEvent) -> 
ThreadContext:

diff  --git a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py 
b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
index 66c8d7f720aef..200e978c98a16 100644
--- a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
+++ b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
@@ -3,401 +3,277 @@
 """
 
 import os
-
-import lldbdap_testcase
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-
-
-def make_buffer_verify_dict(start_idx, count, offset=0):
-    verify_dict = {}
-    for i in range(start_idx, start_idx + count):
-        verify_dict["[%i]" % (i)] = {"type": "int", "value": str(i + offset)}
-    return verify_dict
-
-
-class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase):
+from typing import List, Optional
+
+from lldbsuite.test import lldbplatformutil
+from lldbsuite.test.decorators import (
+    no_debug_info_test,
+    skipIfAsan,
+    skipIfWindows,
+    skipUnlessDarwin,
+)
+from lldbsuite.test.lldbtest import line_number
+from lldbsuite.test.tools.lldb_dap.dap_types import (
+    EvaluateContext,
+    LaunchArgs,
+    VariablesArgs,
+)
+from lldbsuite.test.tools.lldb_dap.lldb_dap_testcase import DAPTestCaseBase
+from lldbsuite.test.tools.lldb_dap.session_helpers import ExpectEval, ExpectVar
+
+
+def make_expected_buffer(start_idx, count, offset=0):
+    return {
+        f"[{i}]": ExpectVar(type="int", value=str(i + offset))
+        for i in range(start_idx, start_idx + count)
+    }
+
+
+class TestDAP_variables(DAPTestCaseBase):
     SHARED_BUILD_TESTCASE = False
 
-    def verify_values(self, verify_dict, actual, varref_dict=None, 
expression=None):
-        if "equals" in verify_dict:
-            verify = verify_dict["equals"]
-            for key in verify:
-                verify_value = verify[key]
-                actual_value = actual[key]
-                self.assertEqual(
-                    verify_value,
-                    actual_value,
-                    '"%s" keys don\'t match (%s != %s) from:\n%s'
-                    % (key, actual_value, verify_value, actual),
-                )
-        if "startswith" in verify_dict:
-            verify = verify_dict["startswith"]
-            for key in verify:
-                verify_value = verify[key]
-                actual_value = actual[key]
-                startswith = actual_value.startswith(verify_value)
-                self.assertTrue(
-                    startswith,
-                    ('"%s" value "%s" doesn\'t start with "%s")')
-                    % (key, actual_value, verify_value),
-                )
-        if "matches" in verify_dict:
-            verify = verify_dict["matches"]
-            for key in verify:
-                verify_value = verify[key]
-                actual_value = actual[key]
-                self.assertRegex(
-                    actual_value,
-                    verify_value,
-                    ('"%s" value "%s" doesn\'t match pattern "%s")')
-                    % (key, actual_value, verify_value),
-                )
-        if "contains" in verify_dict:
-            verify = verify_dict["contains"]
-            for key in verify:
-                contains_array = verify[key]
-                actual_value = actual[key]
-                self.assertIsInstance(contains_array, list)
-                for verify_value in contains_array:
-                    self.assertIn(verify_value, actual_value)
-        if "missing" in verify_dict:
-            missing = verify_dict["missing"]
-            for key in missing:
-                self.assertNotIn(
-                    key, actual, 'key "%s" is not expected in %s' % (key, 
actual)
-                )
-        isReadOnly = verify_dict.get("readOnly", False)
-        attributes = actual.get("presentationHint", {}).get("attributes", [])
-        self.assertEqual(
-            isReadOnly, "readOnly" in attributes, "%s %s" % (verify_dict, 
actual)
-        )
-        hasVariablesReference = "variablesReference" in actual
-        varRef = None
-        if hasVariablesReference:
-            # Remember variable references in case we want to test further
-            # by using the evaluate name.
-            varRef = actual["variablesReference"]
-            if varRef != 0 and varref_dict is not None:
-                if expression is None:
-                    evaluateName = actual["evaluateName"]
-                else:
-                    evaluateName = expression
-                varref_dict[evaluateName] = varRef
-        if (
-            "hasVariablesReference" in verify_dict
-            and verify_dict["hasVariablesReference"]
-        ):
-            self.assertTrue(hasVariablesReference, "verify variable reference")
-        if "children" in verify_dict:
-            self.assertTrue(
-                hasVariablesReference and varRef is not None and varRef != 0,
-                ("children verify values specified for " "variable without 
children"),
-            )
-
-            response = self.dap_server.request_variables(varRef)
-            self.verify_variables(
-                verify_dict["children"], response["body"]["variables"], 
varref_dict
-            )
-
-    def verify_variables(self, verify_dict, variables, varref_dict=None):
-        self.assertGreaterEqual(
-            len(variables),
-            1,
-            f"No variables to verify, verify_dict={json.dumps(verify_dict, 
indent=4)}",
-        )
-        for variable in variables:
-            name = variable["name"]
-            if not name.startswith("std::"):
-                self.assertIn(
-                    name, verify_dict, 'variable "%s" in verify dictionary' % 
(name)
-                )
-                self.verify_values(verify_dict[name], variable, varref_dict)
-
-    def darwin_dwarf_missing_obj(self, initCommands):
+    def darwin_dwarf_missing_obj(self, initCommands: Optional[List[str]]):
         self.build(debug_info="dwarf")
         program = self.getBuildArtifact("a.out")
         main_obj = self.getBuildArtifact("main.o")
         self.assertTrue(os.path.exists(main_obj))
+
         # Delete the main.o file that contains the debug info so we force an
-        # error when we run to main and try to get variables
+        # error when we run to main and try to get variables.
         os.unlink(main_obj)
-
-        self.create_debug_adapter()
         self.assertTrue(os.path.exists(program), "executable must exist")
 
-        self.launch(program, initCommands=initCommands)
+        session = self.create_session()
+        with session.configure(
+            LaunchArgs(program=program, initCommands=initCommands)
+        ) as ctx:
+            breakpoint_ids = session.resolve_function_breakpoints(["main"])
+            self.assertEqual(len(breakpoint_ids), 1, "expect one breakpoint")
 
-        functions = ["main"]
-        breakpoint_ids = self.set_function_breakpoints(functions)
-        self.assertEqual(len(breakpoint_ids), len(functions), "expect one 
breakpoint")
-        self.continue_to_breakpoints(breakpoint_ids)
+        stop_event = session.verify_stopped_on_breakpoint(
+            breakpoint_ids, after=ctx.process_event
+        )
+        thread_id = self.expect_not_none(stop_event.body.threadId)
+        frame = session.thread_context_from(thread_id).top_frame()
 
-        resp = self.dap_server.get_local_variables()
-        self.assertFalse(resp["success"], "Expected to fail")
+        var_args = 
VariablesArgs(variablesReference=frame.locals.variablesReference)
+        error_response = session.send_request(var_args).error()
+        error_body = self.expect_not_none(error_response.body)
+        error_message = self.expect_not_none(error_body.error)
         self.assertEqual(
             f'debug map object file "{main_obj}" containing debug info does 
not exist, debug info will not be loaded',
-            resp["body"]["error"]["format"],
+            error_message.format,
         )
-        self.assertTrue(resp["body"]["error"]["showUser"])
+        self.assertTrue(error_message.showUser)
 
     def do_test_scopes_variables_setVariable_evaluate(
         self, enableAutoVariableSummaries: bool
     ):
-        """
-        Tests the "scopes", "variables", "setVariable", and "evaluate" packets.
-        """
+        """Tests the "scopes", "variables", "setVariable", and "evaluate" 
packets."""
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(
-            program, enableAutoVariableSummaries=enableAutoVariableSummaries
-        )
+        session = self.build_and_create_session()
         source = "main.cpp"
         breakpoint1_line = line_number(source, "// breakpoint 1")
-        lines = [breakpoint1_line]
-        # Set breakpoint in the thread function so we can step the threads
-        breakpoint_ids = self.set_source_breakpoints(source, lines)
-        self.assertEqual(
-            len(breakpoint_ids), len(lines), "expect correct number of 
breakpoints"
+        breakpoint2_line = line_number(source, "// breakpoint 2")
+        breakpoint3_line = line_number(source, "// breakpoint 3")
+
+        launch_args = LaunchArgs(
+            program=program, 
enableAutoVariableSummaries=enableAutoVariableSummaries
         )
-        self.continue_to_breakpoints(breakpoint_ids)
-        locals = self.dap_server.get_local_variables()
-        globals = self.dap_server.get_global_variables()
-        buffer_children = make_buffer_verify_dict(0, 16)
-        verify_locals = {
-            "argc": {
-                "equals": {
-                    "type": "int",
-                    "value": "1",
-                },
-            },
-            "argv": {
-                "equals": {"type": "const char **"},
-                "startswith": {"value": "0x"},
-                "hasVariablesReference": True,
-            },
-            "pt": {
-                "equals": {
-                    "type": "PointType",
-                },
-                "hasVariablesReference": True,
-                "children": {
-                    "x": {"equals": {"type": "int", "value": "11"}},
-                    "y": {"equals": {"type": "int", "value": "22"}},
-                    "buffer": {"children": buffer_children, "readOnly": True},
+        with session.configure(launch_args) as ctx:
+            breakpoint_ids = session.resolve_source_breakpoints(
+                source, [breakpoint1_line, breakpoint2_line, breakpoint3_line]
+            )
+
+        bp1, bp2, bp3 = breakpoint_ids
+        stop_event = session.verify_stopped_on_breakpoint(bp1, 
after=ctx.process_event)
+        thread_id = self.expect_not_none(stop_event.body.threadId)
+        frame = session.top_frame_from(thread_id)
+        local_vars = session.get_variables(frame.locals.variablesReference)
+        global_vars = session.get_variables(frame.globals.variablesReference)
+
+        buffer_children = make_expected_buffer(0, 16)
+        expect_locals = {
+            "argc": ExpectVar(type="int", value="1"),
+            "argv": ExpectVar(type="const char **", startswith="0x", 
has_var_ref=True),
+            "pt": ExpectVar(
+                type="PointType",
+                has_var_ref=True,
+                read_only=True,
+                children={
+                    "x": ExpectVar(type="int", value="11"),
+                    "y": ExpectVar(type="int", value="22"),
+                    "buffer": ExpectVar(read_only=True, 
children=buffer_children),
                 },
-                "readOnly": True,
-            },
-            "valid_str": {},
-            "malformed_str": {},
-            "x": {"equals": {"type": "int"}},
+            ),
+            "valid_str": ExpectVar(),
+            "malformed_str": ExpectVar(),
+            "x": ExpectVar(type="int"),
         }
 
-        verify_globals = {
-            "s_local": {"equals": {"type": "float", "value": "2.25"}},
+        s_global = ExpectVar(type="int", value="234")
+        g_global = ExpectVar(type="int", value="123")
+        expect_globals = {
+            "s_local": ExpectVar(type="float", value="2.25"),
         }
-        s_global = {"equals": {"type": "int", "value": "234"}}
-        g_global = {"equals": {"type": "int", "value": "123"}}
         if lldbplatformutil.getHostPlatform() == "windows":
-            verify_globals["::s_global"] = s_global
-            verify_globals["g_global"] = g_global
+            expect_globals["::s_global"] = s_global
+            expect_globals["g_global"] = g_global
         else:
-            verify_globals["s_global"] = s_global
-            verify_globals["::g_global"] = g_global
+            expect_globals["s_global"] = s_global
+            expect_globals["::g_global"] = g_global
+
+        session.verify_variables(local_vars, expect_locals)
+        session.verify_variables(global_vars, expect_globals)
+
+        pt_var = frame.locals["pt"]
+        pt_buffer = pt_var["buffer"]
 
-        varref_dict = {}
-        self.verify_variables(verify_locals, locals, varref_dict)
-        self.verify_variables(verify_globals, globals, varref_dict)
-        # pprint.PrettyPrinter(indent=4).pprint(varref_dict)
         # We need to test the functionality of the "variables" request as it
         # has optional parameters like "start" and "count" to limit the number
-        # of variables that are fetched
-        varRef = varref_dict["pt.buffer"]
-        response = self.dap_server.request_variables(varRef)
-        self.verify_variables(buffer_children, response["body"]["variables"])
-        # Verify setting start=0 in the arguments still gets all children
-        response = self.dap_server.request_variables(varRef, start=0)
-        self.verify_variables(buffer_children, response["body"]["variables"])
-        # Verify setting count=0 in the arguments still gets all children.
-        # If count is zero, it means to get all children.
-        response = self.dap_server.request_variables(varRef, count=0)
-        self.verify_variables(buffer_children, response["body"]["variables"])
-        # Verify setting count to a value that is too large in the arguments
-        # still gets all children, and no more
-        response = self.dap_server.request_variables(varRef, count=1000)
-        self.verify_variables(buffer_children, response["body"]["variables"])
-        # Verify setting the start index and count gets only the children we
-        # want
-        response = self.dap_server.request_variables(varRef, start=5, count=5)
-        self.verify_variables(
-            make_buffer_verify_dict(5, 5), response["body"]["variables"]
-        )
-        # Verify setting the start index to a value that is out of range
-        # results in an empty list
-        response = self.dap_server.request_variables(varRef, start=32, count=1)
+        # of variables that are fetched.
+        var_ref = pt_buffer.variablesReference
+        children = session.get_variables(var_ref)
+        session.verify_variables(children, buffer_children)
+        # start=0 still gets all children.
+        children = session.get_variables(var_ref, start=0)
+        session.verify_variables(children, buffer_children)
+        # count=0 gets all children.
+        children = session.get_variables(var_ref, count=0)
+        session.verify_variables(children, buffer_children)
+        # An oversized count gets all children, no more.
+        children = session.get_variables(var_ref, count=1000)
+        session.verify_variables(children, buffer_children)
+        # start and count gets only the children we want.
+        children = session.get_variables(var_ref, start=5, count=5)
+        session.verify_variables(children, make_expected_buffer(5, 5))
+        # An out-of-range start gets an empty list.
+        children = session.get_variables(var_ref, start=32, count=1)
         self.assertEqual(
-            len(response["body"]["variables"]),
-            0,
-            "verify we get no variable back for invalid start",
+            len(children), 0, "verify we get no variables back for an invalid 
start"
         )
 
-        # Test evaluate
+        # Test evaluate.
+        if enableAutoVariableSummaries:
+            pt_summary = "{x:11, y:22, buffer:{...}}"
+            buf_summary = "{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...}"
+        else:
+            pt_summary = "PointType"
+            buf_summary = "int[16]"
+
         expressions = {
-            "pt.x": {
-                "equals": {"result": "11", "type": "int"},
-                "hasVariablesReference": False,
-            },
-            "pt.buffer[2]": {
-                "equals": {"result": "2", "type": "int"},
-                "hasVariablesReference": False,
-            },
-            "pt": {
-                "equals": {"type": "PointType"},
-                "startswith": {
-                    "result": (
-                        "{x:11, y:22, buffer:{...}}"
-                        if enableAutoVariableSummaries
-                        else "PointType"
-                    )
-                },
-                "hasVariablesReference": True,
-            },
-            "pt.buffer": {
-                "equals": {"type": "int[16]"},
-                "startswith": {
-                    "result": (
-                        "{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...}"
-                        if enableAutoVariableSummaries
-                        else "int[16]"
-                    )
-                },
-                "hasVariablesReference": True,
-            },
-            "argv": {
-                "equals": {"type": "const char **"},
-                "startswith": {"result": "0x"},
-                "hasVariablesReference": True,
-            },
-            "argv[0]": {
-                "equals": {"type": "const char *"},
-                "startswith": {"result": "0x"},
-                "hasVariablesReference": True,
-            },
-            "2+3": {
-                "equals": {"result": "5", "type": "int"},
-                "hasVariablesReference": False,
-            },
+            "pt.x": ExpectEval(type="int", result="11", has_var_ref=False),
+            "pt.buffer[2]": ExpectEval(type="int", result="2", 
has_var_ref=False),
+            "pt": ExpectEval(type="PointType", startswith=pt_summary, 
has_var_ref=True),
+            "pt.buffer": ExpectEval(
+                type="int[16]",
+                startswith=buf_summary,
+                has_var_ref=True,
+            ),
+            "argv": ExpectEval(type="const char **", startswith="0x", 
has_var_ref=True),
+            "argv[0]": ExpectEval(
+                type="const char *", startswith="0x", has_var_ref=True
+            ),
+            "2+3": ExpectEval(type="int", result="5", has_var_ref=False),
         }
-        for expression in expressions:
-            response = self.dap_server.request_evaluate(expression)
-            self.verify_values(expressions[expression], response["body"])
+        for expression, expected in expressions.items():
+            expr_result = frame.evaluate(expression)
+            session.verify_evaluate(expr_result, expected)
 
-        # Test setting variables
-        self.set_local("argc", 123)
-        argc = self.get_local_as_int("argc")
-        self.assertEqual(argc, 123, "verify argc was set to 123 (123 != %i)" % 
(argc))
+        # Test setting variables.
+        self.expect_success(frame.locals.set("argc", 123))
+        argc = frame.locals["argc"].value_as_int
+        self.assertEqual(argc, 123, f"verify argc was set to 123 (123 != 
{argc})")
 
-        self.set_local("argv", 0x1234)
-        argv = self.get_local_as_int("argv")
+        self.expect_success(frame.locals.set("argv", 0x1234))
+        argv = frame.locals["argv"].value_as_int
         self.assertEqual(
-            argv, 0x1234, "verify argv was set to 0x1234 (0x1234 != %#x)" % 
(argv)
+            argv, 0x1234, f"verify argv was set to 0x1234 (0x1234 != 
{argv:#x})"
         )
 
-        # Test hexadecimal format
-        response = self.set_local("argc", 42, is_hex=True)
-        verify_response = {
-            "type": "int",
-            "value": "0x0000002a",
-        }
-        for key, value in verify_response.items():
-            self.assertEqual(value, response["body"][key])
-        self.set_local("argc", 123)
+        # Test hexadecimal format.
+        hex_set = self.expect_success(frame.locals.set("argc", 42, 
is_hex=True))
+        self.assertEqual(hex_set.body.type, "int")
+        self.assertEqual(hex_set.body.value, "0x0000002a")
+        self.expect_success(frame.locals.set("argc", 123))
 
-        # Set a variable value whose name is synthetic, like a variable index
-        # and verify the value by reading it
+        # Set a variable whose name is synthetic (an array index) and verify
+        # the value by reading it back.
         variable_value = 100
-        response = self.set_variable(varRef, "[0]", variable_value)
-        # Verify dap sent the correct response
-        verify_response = {
-            "type": "int",
-            "value": str(variable_value),
-        }
-        for key, value in verify_response.items():
-            self.assertEqual(value, response["body"][key])
-
-        response = self.dap_server.request_variables(varRef, start=0, count=1)
-        self.verify_variables(
-            make_buffer_verify_dict(0, 1, variable_value), 
response["body"]["variables"]
-        )
-
-        # Set a variable value whose name is a real child value, like "pt.x"
-        # and verify the value by reading it
-        varRef = varref_dict["pt"]
-        self.set_variable(varRef, "x", "g_global - 12")
-        response = self.dap_server.request_variables(varRef, start=0, count=1)
-        value = response["body"]["variables"][0]["value"]
-        self.assertEqual(
-            value, "111", "verify pt.x got set to 111 (111 != %s)" % (value)
-        )
-
-        # We check shadowed variables and that a new get_local_variables 
request
-        # gets the right data
-        breakpoint2_line = line_number(source, "// breakpoint 2")
-        lines = [breakpoint2_line]
-        breakpoint_ids = self.set_source_breakpoints(source, lines)
-        self.assertEqual(
-            len(breakpoint_ids), len(lines), "expect correct number of 
breakpoints"
-        )
-        self.continue_to_breakpoints(breakpoint_ids)
-
-        verify_locals["argc"]["equals"]["value"] = "123"
-        verify_locals["pt"]["children"]["x"]["equals"]["value"] = "111"
-        verify_locals["x @ main.cpp:27"] = {"equals": {"type": "int", "value": 
"89"}}
-        verify_locals["x @ main.cpp:29"] = {"equals": {"type": "int", "value": 
"42"}}
-        verify_locals["x @ main.cpp:31"] = {"equals": {"type": "int", "value": 
"72"}}
-
-        self.verify_variables(verify_locals, 
self.dap_server.get_local_variables())
-
-        # Now we verify that we correctly change the name of a variable with 
and without 
diff erentiator suffix
-        self.assertFalse(self.set_local("x2", 9)["success"])
-        self.assertFalse(self.set_local("x @ main.cpp:0", 9)["success"])
-
-        self.assertTrue(self.set_local("x @ main.cpp:27", 19)["success"])
-        self.assertTrue(self.set_local("x @ main.cpp:29", 21)["success"])
-        self.assertTrue(self.set_local("x @ main.cpp:31", 23)["success"])
-
-        # The following should have no effect
-        self.assertFalse(self.set_local("x @ main.cpp:31", 
"invalid")["success"])
-
-        verify_locals["x @ main.cpp:27"]["equals"]["value"] = "19"
-        verify_locals["x @ main.cpp:29"]["equals"]["value"] = "21"
-        verify_locals["x @ main.cpp:31"]["equals"]["value"] = "23"
-
-        self.verify_variables(verify_locals, 
self.dap_server.get_local_variables())
-
-        # The plain x variable shold refer to the innermost x
-        self.assertTrue(self.set_local("x", 22)["success"])
-        verify_locals["x @ main.cpp:31"]["equals"]["value"] = "22"
-
-        self.verify_variables(verify_locals, 
self.dap_server.get_local_variables())
-
-        # In breakpoint 3, there should be no shadowed variables
-        breakpoint3_line = line_number(source, "// breakpoint 3")
-        lines = [breakpoint3_line]
-        breakpoint_ids = self.set_source_breakpoints(source, lines)
-        self.assertEqual(
-            len(breakpoint_ids), len(lines), "expect correct number of 
breakpoints"
-        )
-        self.continue_to_breakpoints(breakpoint_ids)
-
-        locals = self.dap_server.get_local_variables()
-        names = [var["name"] for var in locals]
-        # The first shadowed x shouldn't have a suffix anymore
-        verify_locals["x"] = {"equals": {"type": "int", "value": "19"}}
+        set_result = self.expect_success(pt_buffer.set("[0]", variable_value))
+        self.assertEqual(set_result.body.type, "int")
+        self.assertEqual(set_result.body.value, str(variable_value))
+
+        pt_buffer_ref = pt_buffer.variablesReference
+        children = session.get_variables(pt_buffer_ref, start=0, count=1)
+        session.verify_variables(children, make_expected_buffer(0, 1, 
variable_value))
+        # Update the new value in the buffer expectations so subsequent
+        # verifications stay consistent.
+        buffer_children["[0]"].value = str(variable_value)
+
+        # Set a variable whose name is a real child value (e.g. "pt.x") and
+        # verify the value by reading it back.
+        pt_var_ref = pt_var.variablesReference
+        self.expect_success(pt_var.set("x", "g_global - 12"))
+        children = session.get_variables(pt_var_ref, start=0, count=1)
+        value = children[0].value
+        self.assertEqual(value, "111", f"verify pt.x got set to 111 (111 != 
{value})")
+
+        # Continue to the second breakpoint to check shadowed variables and 
the new
+        # local variables is update to the new values.
+        session.continue_to_breakpoint(bp2)
+        frame = session.top_frame_from(thread_id)
+
+        expect_locals["argc"].value = "123"
+        # Build a child dict with `pt.x` updated to its new value.
+        pt_children = self.expect_not_none(expect_locals["pt"].children)
+        pt_children["x"].value = "111"
+        expect_locals["x @ main.cpp:27"] = ExpectVar(type="int", value="89")
+        expect_locals["x @ main.cpp:29"] = ExpectVar(type="int", value="42")
+        expect_locals["x @ main.cpp:31"] = ExpectVar(type="int", value="72")
+
+        local_variables = 
session.get_variables(frame.locals.variablesReference)
+        session.verify_variables(local_variables, expect_locals)
+
+        # Renaming a variable with and without the 
diff erentiator suffix.
+        self.expect_error(frame.locals.set("x2", 9))
+        self.expect_error(frame.locals.set("x @ main.cpp:0", 9))
+
+        self.expect_success(frame.locals.set("x @ main.cpp:27", 19))
+        self.expect_success(frame.locals.set("x @ main.cpp:29", 21))
+        self.expect_success(frame.locals.set("x @ main.cpp:31", 23))
+
+        # An invalid value should have no effect.
+        self.expect_error(frame.locals.set("x @ main.cpp:31", "invalid"))
+
+        expect_locals["x @ main.cpp:27"].value = "19"
+        expect_locals["x @ main.cpp:29"].value = "21"
+        expect_locals["x @ main.cpp:31"].value = "23"
+
+        local_vars = session.get_variables(frame.locals.variablesReference)
+        session.verify_variables(local_vars, expect_locals)
+
+        # The plain `x` variable should refer to the innermost x.
+        self.expect_success(frame.locals.set("x", 22))
+        expect_locals["x @ main.cpp:31"].value = "22"
+
+        local_vars = session.get_variables(frame.locals.variablesReference)
+        session.verify_variables(local_vars, expect_locals)
+
+        # At breakpoint 3 there should be no shadowed variables.
+        session.continue_to_breakpoint(bp3)
+        frame = session.top_frame_from(thread_id)
+
+        local_vars = session.get_variables(frame.locals.variablesReference)
+        names = [var.name for var in local_vars]
+        # The first shadowed `x` shouldn't have a suffix anymore.
+        expect_locals["x"] = ExpectVar(type="int", value="19")
         self.assertNotIn("x @ main.cpp:27", names)
         self.assertNotIn("x @ main.cpp:29", names)
         self.assertNotIn("x @ main.cpp:31", names)
 
-        self.verify_variables(verify_locals, locals)
+        session.verify_variables(local_vars, expect_locals)
+        session.continue_to_exit()
 
     @skipIfWindows
     def test_scopes_variables_setVariable_evaluate(self):
@@ -406,103 +282,83 @@ def test_scopes_variables_setVariable_evaluate(self):
         )
 
     @skipIfWindows
-    def 
test_scopes_variables_setVariable_evaluate_with_descriptive_summaries(self):
+    def test_scopes_variables_setVariable_evaluate_with_descriptive_summaries(
+        self,
+    ):
         self.do_test_scopes_variables_setVariable_evaluate(
             enableAutoVariableSummaries=True
         )
 
     @skipIfWindows
     def do_test_scopes_and_evaluate_expansion(self, 
enableAutoVariableSummaries: bool):
-        """
-        Tests the evaluated expression expands successfully after "scopes" 
packets
-        and permanent expressions persist.
-        """
+        """Test that an evaluated expression expands successfully after 
"scopes"
+        packets, and that permanent expressions persist across resumes."""
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(
-            program, enableAutoVariableSummaries=enableAutoVariableSummaries
-        )
+        session = self.build_and_create_session()
         source = "main.cpp"
-        lines = [
-            line_number(source, "// breakpoint 1"),
-            line_number(source, "// breakpoint 3"),
-            line_number(source, "// breakpoint 6"),
-            line_number(source, "// breakpoint 7"),
-            line_number(source, "// breakpoint 8"),
-        ]
-        breakpoint_ids = self.set_source_breakpoints(source, lines)
-        self.assertEqual(
-            len(breakpoint_ids), len(lines), "expect correct number of 
breakpoints"
+
+        launch_args = LaunchArgs(
+            program=program, 
enableAutoVariableSummaries=enableAutoVariableSummaries
         )
-        [bp1, bp3, bp6, bp7, bp8] = breakpoint_ids
-        self.continue_to_breakpoint(bp1)
-
-        # Verify locals
-        locals = self.dap_server.get_local_variables()
-        buffer_children = make_buffer_verify_dict(0, 32)
-        verify_locals = {
-            "argc": {
-                "equals": {"type": "int", "value": "1"},
-                "missing": ["indexedVariables"],
-            },
-            "argv": {
-                "equals": {"type": "const char **"},
-                "startswith": {"value": "0x"},
-                "hasVariablesReference": True,
-                "missing": ["indexedVariables"],
-            },
-            "pt": {
-                "equals": {"type": "PointType"},
-                "hasVariablesReference": True,
-                "missing": ["indexedVariables"],
-                "children": {
-                    "x": {
-                        "equals": {"type": "int", "value": "11"},
-                        "missing": ["indexedVariables"],
-                    },
-                    "y": {
-                        "equals": {"type": "int", "value": "22"},
-                        "missing": ["indexedVariables"],
-                    },
-                    "buffer": {
-                        "children": buffer_children,
-                        "equals": {"indexedVariables": 16},
-                        "readOnly": True,
-                    },
+        with session.configure(launch_args) as ctx:
+            lines = [
+                line_number(source, "// breakpoint 1"),
+                line_number(source, "// breakpoint 3"),
+                line_number(source, "// breakpoint 6"),
+                line_number(source, "// breakpoint 7"),
+                line_number(source, "// breakpoint 8"),
+            ]
+            breakpoint_ids = session.resolve_source_breakpoints(source, lines)
+
+        bp1, bp3, bp6, bp7, bp8 = breakpoint_ids
+        stop_event = session.verify_stopped_on_breakpoint(bp1, 
after=ctx.process_event)
+        thread_id = self.expect_not_none(stop_event.body.threadId)
+        frame = session.thread_context_from(thread_id).top_frame()
+
+        # Verify locals.
+        local_vars = session.get_variables(frame.locals.variablesReference)
+        buffer_children = make_expected_buffer(0, 32)
+        expect_locals: dict[str, ExpectVar] = {
+            "argc": ExpectVar(type="int", value="1", 
has_indexed_variables=False),
+            "argv": ExpectVar(
+                type="const char **",
+                startswith="0x",
+                has_var_ref=True,
+                has_indexed_variables=False,
+            ),
+            "pt": ExpectVar(
+                type="PointType",
+                has_var_ref=True,
+                read_only=True,
+                has_indexed_variables=False,
+                children={
+                    "x": ExpectVar(type="int", value="11", 
has_indexed_variables=False),
+                    "y": ExpectVar(type="int", value="22", 
has_indexed_variables=False),
+                    "buffer": ExpectVar(
+                        indexed_variables=16,
+                        read_only=True,
+                        children=buffer_children,
+                    ),
                 },
-                "readOnly": True,
-            },
-            "valid_str": {
-                "equals": {
-                    "type": "const char *",
-                },
-                "matches": {
-                    "value": r'0x\w+ "𐌢𐌰L𐌾𐍈 CπˆπŒΌπŒ΄πƒ"',
-                },
-            },
-            "malformed_str": {
-                "equals": {
-                    "type": "const char *",
-                },
-                "matches": {
-                    "value": r'0x\w+ "lone trailing \\x81\\x82 bytes"',
-                },
-            },
-            "x": {
-                "equals": {"type": "int"},
-                "missing": ["indexedVariables"],
-            },
+            ),
+            "valid_str": ExpectVar(
+                type="const char *",
+                matches=r'0x\w+ "𐌢𐌰L𐌾𐍈 CπˆπŒΌπŒ΄πƒ"',
+            ),
+            "malformed_str": ExpectVar(
+                type="const char *",
+                matches=r'0x\w+ "lone trailing \\x81\\x82 bytes"',
+            ),
+            "x": ExpectVar(type="int", has_indexed_variables=False),
         }
-        self.verify_variables(verify_locals, locals)
-
-        # Evaluate expandable expression twice: once permanent (from repl)
-        # the other temporary (from other UI).
-        expandable_expression = {
-            "name": "pt",
-            "context": {
-                "repl": {
-                    "equals": {"type": "PointType"},
-                    "equals": {
-                        "result": """(PointType) $0 = {
+        session.verify_variables(local_vars, expect_locals)
+
+        expandable_name = "pt"
+        if enableAutoVariableSummaries:
+            pt_summary = "{x:11, y:22, buffer:{...}}"
+        else:
+            pt_summary = "PointType"
+        repl_result = """(PointType) $0 = {
   x = 11
   y = 22
   buffer = {
@@ -524,251 +380,189 @@ def do_test_scopes_and_evaluate_expansion(self, 
enableAutoVariableSummaries: boo
     [15] = 15
   }
 }"""
-                    },
-                    "missing": ["indexedVariables"],
-                    "hasVariablesReference": True,
-                },
-                "hover": {
-                    "equals": {"type": "PointType"},
-                    "startswith": {
-                        "result": (
-                            "{x:11, y:22, buffer:{...}}"
-                            if enableAutoVariableSummaries
-                            else "PointType"
-                        )
-                    },
-                    "missing": ["indexedVariables"],
-                    "hasVariablesReference": True,
-                },
-                "watch": {
-                    "equals": {"type": "PointType"},
-                    "startswith": {
-                        "result": (
-                            "{x:11, y:22, buffer:{...}}"
-                            if enableAutoVariableSummaries
-                            else "PointType"
-                        )
-                    },
-                    "missing": ["indexedVariables"],
-                    "hasVariablesReference": True,
-                },
-                "variables": {
-                    "equals": {"type": "PointType"},
-                    "startswith": {
-                        "result": (
-                            "{x:11, y:22, buffer:{...}}"
-                            if enableAutoVariableSummaries
-                            else "PointType"
-                        )
-                    },
-                    "missing": ["indexedVariables"],
-                    "hasVariablesReference": True,
-                },
-            },
-            "children": {
-                "x": {"equals": {"type": "int", "value": "11"}},
-                "y": {"equals": {"type": "int", "value": "22"}},
-                "buffer": {"children": buffer_children, "readOnly": True},
-            },
+
+        expandable_children: dict[str, ExpectVar] = {
+            "x": ExpectVar(type="int", value="11"),
+            "y": ExpectVar(type="int", value="22"),
+            "buffer": ExpectVar(read_only=True, children=buffer_children),
+        }
+        expected_contexts_evals: dict[EvaluateContext, ExpectEval] = {
+            "repl": ExpectEval(
+                type="PointType",
+                result=repl_result,
+                has_var_ref=True,
+                has_indexed_variables=False,
+                children=expandable_children,
+            ),
+            "hover": ExpectEval(
+                type="PointType",
+                startswith=pt_summary,
+                has_var_ref=True,
+                has_indexed_variables=False,
+                children=expandable_children,
+            ),
+            "watch": ExpectEval(
+                type="PointType",
+                startswith=pt_summary,
+                has_var_ref=True,
+                has_indexed_variables=False,
+                children=expandable_children,
+            ),
+            "variables": ExpectEval(
+                type="PointType",
+                startswith=pt_summary,
+                has_var_ref=True,
+                has_indexed_variables=False,
+                children=expandable_children,
+            ),
         }
 
-        # Evaluate from known contexts.
-        expr_varref_dict = {}
-        permanent_expandable_ref = None
-        for context, verify_dict in expandable_expression["context"].items():
-            response = self.dap_server.request_evaluate(
-                expandable_expression["name"],
-                frameIndex=0,
-                threadId=None,
-                context=context,
+        # Evaluate from each known context.
+        permanent_expandable_ref: Optional[int] = None
+        temporary_expandable_ref: Optional[int] = None
+        for context, expected_eval in expected_contexts_evals.items():
+            result = session.evaluate(
+                expandable_name, frameId=frame.id, context=context
             )
 
-            response_body = response["body"]
-            if context == "repl":  # save the variablesReference
-                self.assertIn("variablesReference", response_body)
-                permanent_expandable_ref = response_body["variablesReference"]
+            if context == "repl":  # Save the variablesReference.
+                permanent_expandable_ref = result.variablesReference
+            else:
+                temporary_expandable_ref = result.variablesReference
 
-            self.verify_values(
-                verify_dict,
-                response_body,
-                expr_varref_dict,
-                expandable_expression["name"],
-            )
+            session.verify_evaluate(result, expected_eval)
 
         # Evaluate locals again.
-        locals = self.dap_server.get_local_variables()
-        self.verify_variables(verify_locals, locals)
-
-        # Verify the evaluated expressions before second locals evaluation
-        # can be expanded.
-        var_ref = expr_varref_dict[expandable_expression["name"]]
-        response = self.dap_server.request_variables(var_ref)
-        self.verify_variables(
-            expandable_expression["children"], response["body"]["variables"]
-        )
+        local_vars = session.get_variables(frame.locals.variablesReference)
+        session.verify_variables(local_vars, expect_locals)
 
-        self.continue_to_breakpoint(bp6)
+        # The previously evaluated expression should still expand.
+        var_ref = self.expect_not_none(temporary_expandable_ref)
+        session.verify_variables(session.get_variables(var_ref), 
expandable_children)
 
-        locals = self.dap_server.get_local_variables()
-        self.verify_variables(
-            {
-                "my_var": {
-                    "equals": {
-                        "type": "(unnamed struct)",
-                        "value": '{name:"hello world!", x:42, y:7}'
-                        if enableAutoVariableSummaries
-                        else "(unnamed struct)",
-                        "evaluateName": "my_var",
-                    },
-                    "readOnly": True,
-                },
-            },
-            locals,
+        session.continue_to_breakpoint(bp6)
+        frame = session.top_frame_from(thread_id)
+        if enableAutoVariableSummaries:
+            my_var_value = '{name:"hello world!", x:42, y:7}'
+        else:
+            my_var_value = "(unnamed struct)"
+        session.verify_variable(
+            frame.locals["my_var"].variable,
+            ExpectVar(
+                type="(unnamed struct)",
+                value=my_var_value,
+                evaluate_name="my_var",
+                read_only=True,
+            ),
         )
 
-        self.continue_to_breakpoint(bp7)
-
-        expr_varref_dict = {}
-        locals = self.dap_server.get_local_variables()
-        self.verify_variables(
-            {
-                "home": {
-                    "equals": {
-                        "type": "MySock",
-                        "value": "MySock",
-                        "evaluateName": "home",
-                    },
-                    "readOnly": True,
-                },
-            },
-            locals,
-            expr_varref_dict,
+        session.continue_to_breakpoint(bp7)
+        frame = session.top_frame_from(thread_id)
+
+        home_var = frame.locals["home"]
+        session.verify_variable(
+            home_var.variable,
+            ExpectVar(
+                type="MySock",
+                value="MySock",
+                evaluate_name="home",
+                read_only=True,
+            ),
         )
 
-        inner_var_ref = expr_varref_dict["home"]
-        anon_vars = self.dap_server.request_variables(inner_var_ref)["body"][
-            "variables"
-        ]
-        self.verify_variables(
-            {
-                "(anonymous)": {
-                    "equals": {"type": "MySock::(anonymous union)"},
-                    "matches": {
-                        "value": r"{ipv4:.*, ipv6:.*}"
-                        if enableAutoVariableSummaries
-                        else r"MySock::\(anonymous union\)",
-                    },
-                    "readOnly": True,
-                    "missing": ["evaluateName"],
-                }
-            },
-            anon_vars,
+        anon_var = home_var["(anonymous)"]
+        if enableAutoVariableSummaries:
+            anon_value_re = r"{ipv4:.*, ipv6:.*}"
+        else:
+            anon_value_re = r"MySock::\(anonymous union\)"
+        session.verify_variable(
+            anon_var.variable,
+            ExpectVar(
+                type="MySock::(anonymous union)",
+                matches=anon_value_re,
+                read_only=True,
+                has_evaluate_name=False,
+            ),
         )
-        inner_union_vars = self.dap_server.request_variables(
-            anon_vars[0]["variablesReference"]
-        )["body"]["variables"]
-        self.verify_variables(
+        inner_union_vars = session.get_variables(anon_var.variablesReference)
+        session.verify_variables(
+            inner_union_vars,
             {
-                "ipv4": {
-                    "equals": {
-                        "type": "unsigned char[4]",
-                        "evaluateName": "home.ipv4",
-                    },
-                    "readOnly": True,
-                },
-                "ipv6": {
-                    "equals": {
-                        "type": "unsigned char[6]",
-                        "evaluateName": "home.ipv6",
-                    },
-                    "readOnly": True,
-                },
+                "ipv4": ExpectVar(
+                    type="unsigned char[4]",
+                    evaluate_name="home.ipv4",
+                    read_only=True,
+                ),
+                "ipv6": ExpectVar(
+                    type="unsigned char[6]",
+                    evaluate_name="home.ipv6",
+                    read_only=True,
+                ),
             },
-            inner_union_vars,
         )
 
-        self.continue_to_breakpoint(bp8)
+        session.continue_to_breakpoint(bp8)
+        frame = session.top_frame_from(thread_id)
 
-        locals = self.dap_server.get_local_variables()
-        self.verify_variables(
-            {
-                "e": {
-                    "equals": {
-                        "type": "example",
-                        "value": "{lo:10, hi:11}"
-                        if enableAutoVariableSummaries
-                        else "example",
-                        "evaluateName": "e",
-                    },
-                    "readOnly": True,
-                },
-            },
-            locals,
+        if enableAutoVariableSummaries:
+            e_value = "{lo:10, hi:11}"
+        else:
+            e_value = "example"
+        e_var = frame.locals["e"]
+        session.verify_variable(
+            e_var.variable,
+            ExpectVar(
+                type="example",
+                value=e_value,
+                evaluate_name="e",
+                read_only=True,
+            ),
         )
-        inner_bitfields_struct = self.dap_server.request_variables(
-            locals[0]["variablesReference"]
-        )["body"]["variables"]
-        self.verify_variables(
+        inner_bitfields_struct = 
session.get_variables(e_var.variablesReference)
+        session.verify_variables(
+            inner_bitfields_struct,
             {
-                "lo": {
-                    "equals": {
-                        "type": "unsigned int",
-                        "value": "10",
-                        "evaluateName": "e.lo",
-                        "variablesReference": 0,
-                    }
-                },
-                "(anonymous)": {
-                    "equals": {
-                        "type": "int",
-                        "value": "0",
-                        "variablesReference": 0,
-                    }
-                },
-                "hi": {
-                    "equals": {
-                        "type": "unsigned int",
-                        "value": "11",
-                        "evaluateName": "e.hi",
-                        "variablesReference": 0,
-                    }
-                },
+                "lo": ExpectVar(
+                    type="unsigned int",
+                    value="10",
+                    evaluate_name="e.lo",
+                    variables_reference=0,
+                ),
+                "(anonymous)": ExpectVar(type="int", value="0", 
variables_reference=0),
+                "hi": ExpectVar(
+                    type="unsigned int",
+                    value="11",
+                    evaluate_name="e.hi",
+                    variables_reference=0,
+                ),
             },
-            inner_bitfields_struct,
         )
 
-        # Continue to breakpoint 3, permanent variable should still exist
-        # after resume.
-        self.continue_to_breakpoint(bp3)
+        # Continue to breakpoint 3. The permanent variable should still exist 
after the resume.
+        session.continue_to_breakpoint(bp3)
+        frame = session.top_frame_from(thread_id)
 
-        var_ref = permanent_expandable_ref
-        response = self.dap_server.request_variables(var_ref)
-        self.verify_variables(
-            expandable_expression["children"], response["body"]["variables"]
-        )
+        permanent_ref = self.expect_not_none(permanent_expandable_ref)
+        permanent_ref_children = session.get_variables(permanent_ref)
+        session.verify_variables(permanent_ref_children, expandable_children)
 
-        # Test that frame scopes have corresponding presentation hints.
-        frame_id = self.dap_server.get_stackFrame()["id"]
-        scopes = self.dap_server.request_scopes(frame_id)["body"]["scopes"]
+        # The frame's scopes should carry corresponding presentation hints.
+        self.assertEqual(frame.globals.scope.name, "Globals")
+        self.assertEqual(frame.locals.scope.name, "Locals")
+        self.assertEqual(frame.locals.scope.presentationHint, "locals")
+        self.assertEqual(frame.registers.scope.name, "Registers")
+        self.assertEqual(frame.registers.scope.presentationHint, "registers")
 
-        scope_names = [scope["name"] for scope in scopes]
-        self.assertIn("Locals", scope_names)
-        self.assertIn("Registers", scope_names)
-
-        for scope in scopes:
-            if scope["name"] == "Locals":
-                self.assertEqual(scope.get("presentationHint"), "locals")
-            if scope["name"] == "Registers":
-                self.assertEqual(scope.get("presentationHint"), "registers")
-
-        # Test invalid variablesReference.
+        # An invalid variablesReference should produce a clear error.
         for wrong_var_ref in (-6000, -1, 4000):
-            response = self.dap_server.request_variables(wrong_var_ref)
-            self.assertFalse(response["success"])
-            error_msg: str = response["body"]["error"]["format"]
+            var_args = VariablesArgs(variablesReference=wrong_var_ref)
+            response = session.send_request(var_args).error()
+
+            error_body = self.expect_not_none(response.body)
+            error_msg = self.expect_not_none(error_body.error)
             self.assertTrue(
-                error_msg.startswith("invalid variablesReference"),
-                f"seen error message : {error_msg}",
+                error_msg.format.startswith("invalid variablesReference"),
+                f"seen error message: {error_msg.format}",
             )
 
     def test_scopes_and_evaluate_expansion(self):
@@ -778,132 +572,108 @@ def 
test_scopes_and_evaluate_expansion_with_descriptive_summaries(self):
         
self.do_test_scopes_and_evaluate_expansion(enableAutoVariableSummaries=True)
 
     def do_test_indexedVariables(self, enableSyntheticChildDebugging: bool):
-        """
-        Tests that arrays and lldb.SBValue objects that have synthetic child
-        providers have "indexedVariables" key/value pairs. This helps the IDE
-        not to fetch too many children all at once.
-        """
+        """Test that arrays and `lldb.SBValue` objects with synthetic child
+        providers expose `indexedVariables`. This lets the IDE avoid fetching
+        too many children at once."""
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(
-            program, 
enableSyntheticChildDebugging=enableSyntheticChildDebugging
-        )
+        session = self.build_and_create_session()
         source = "main.cpp"
-        breakpoint1_line = line_number(source, "// breakpoint 4")
-        lines = [breakpoint1_line]
-        # Set breakpoint in the thread function so we can step the threads
-        breakpoint_ids = self.set_source_breakpoints(source, lines)
-        self.assertEqual(
-            len(breakpoint_ids), len(lines), "expect correct number of 
breakpoints"
+        breakpoint_line = line_number(source, "// breakpoint 4")
+
+        launch_args = LaunchArgs(
+            program=program,
+            enableSyntheticChildDebugging=enableSyntheticChildDebugging,
+        )
+        with session.configure(launch_args) as ctx:
+            breakpoint_ids = session.resolve_source_breakpoints(
+                source, [breakpoint_line]
+            )
+
+        stop_event = session.verify_stopped_on_breakpoint(
+            breakpoint_ids, after=ctx.process_event
         )
-        self.continue_to_breakpoints(breakpoint_ids)
+        thread_id = self.expect_not_none(stop_event.body.threadId)
+        frame = session.thread_context_from(thread_id).top_frame()
 
-        # Verify locals
-        locals = self.dap_server.get_local_variables()
-        # The vector variables might have one additional entry from the fake
-        # "[raw]" child.
+        # Verify locals. Vector variables can have one extra entry from the
+        # fake "[raw]" child.
+        local_vars = session.get_variables(frame.locals.variablesReference)
         raw_child_count = 1 if enableSyntheticChildDebugging else 0
-        verify_locals = {
-            "small_array": {"equals": {"indexedVariables": 5}, "readOnly": 
True},
-            "large_array": {"equals": {"indexedVariables": 200}, "readOnly": 
True},
-            "small_vector": {
-                "equals": {"indexedVariables": 5 + raw_child_count},
-                "readOnly": True,
-            },
-            "large_vector": {
-                "equals": {"indexedVariables": 200 + raw_child_count},
-                "readOnly": True,
-            },
-            "pt": {"missing": ["indexedVariables"], "readOnly": True},
+        expect_locals: dict[str, ExpectVar] = {
+            "small_array": ExpectVar(indexed_variables=5, read_only=True),
+            "large_array": ExpectVar(indexed_variables=200, read_only=True),
+            "small_vector": ExpectVar(
+                indexed_variables=5 + raw_child_count, read_only=True
+            ),
+            "large_vector": ExpectVar(
+                indexed_variables=200 + raw_child_count, read_only=True
+            ),
+            "pt": ExpectVar(read_only=True, has_indexed_variables=False),
         }
-        self.verify_variables(verify_locals, locals)
-
-        # We also verify that we produce a "[raw]" fake child with the real
-        # SBValue for the synthetic type.
-        verify_children = {
-            "[0]": {"equals": {"type": "int", "value": "0"}},
-            "[1]": {"equals": {"type": "int", "value": "0"}},
-            "[2]": {"equals": {"type": "int", "value": "0"}},
-            "[3]": {"equals": {"type": "int", "value": "0"}},
-            "[4]": {"equals": {"type": "int", "value": "0"}},
+        session.verify_variables(local_vars, expect_locals)
+
+        # Verify we produce a "[raw]" fake child carrying the real SBValue
+        # for the synthetic type.
+        expect_children: dict[str, ExpectVar] = {
+            f"[{i}]": ExpectVar(type="int", value="0") for i in range(5)
         }
         if enableSyntheticChildDebugging:
-            verify_children["[raw]"] = {
-                "equals": {"type": "std::vector<int>", "value": "size=5"},
-                "readOnly": True,
-            }
+            expect_children["[raw]"] = ExpectVar(
+                type="std::vector<int>", value="size=5", read_only=True
+            )
 
-        children = 
self.dap_server.request_variables(locals[2]["variablesReference"])[
-            "body"
-        ]["variables"]
-        varref_dict = {}
-        self.verify_variables(verify_children, children, varref_dict)
+        small_vector = frame.locals["small_vector"]
+        children = session.get_variables(small_vector.variablesReference)
+        session.verify_variables(children, expect_children)
 
         if enableSyntheticChildDebugging:
-            self.assertIn(
+            raw_child = next(c for c in children if c.name == "[raw]")
+            self.assertEqual(
+                raw_child.evaluateName,
                 "small_vector",
-                varref_dict,
                 "'evaluateName' for '[raw]' field should be the original 
variable name.",
             )
-            raw_children = self.dap_server.request_variables(
-                varref_dict["small_vector"]
-            )
-            self.assertTrue(
-                len(raw_children["body"]["variables"]) > 0,
+            raw_children = session.get_variables(raw_child.variablesReference)
+            self.assertGreater(
+                len(raw_children),
+                0,
                 "Expected std::vector to contain a raw underlying value with 
internal properties.",
             )
 
     @skipIfWindows
     def test_return_variables(self):
-        """
-        Test the stepping out of a function with return value show the 
variable correctly.
-        """
+        """Stepping out of a function with a return value should expose the
+        returned value as a local."""
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program)
-
-        return_name = "(Return Value)"
-        verify_locals = {
-            return_name: {"equals": {"type": "int", "value": "300"}, 
"readOnly": True},
-            "argc": {},
-            "argv": {},
-            "pt": {"readOnly": True},
-            "valid_str": {},
-            "malformed_str": {},
-            "x": {},
-            "return_result": {"equals": {"type": "int"}},
-        }
+        session = self.build_and_create_session()
 
         function_name = "test_return_variable"
-        breakpoint_ids = self.set_function_breakpoints([function_name])
-
-        self.assertEqual(len(breakpoint_ids), 1)
-        self.continue_to_breakpoints(breakpoint_ids)
+        with session.configure(LaunchArgs(program=program)) as ctx:
+            [bp_id] = session.resolve_function_breakpoints([function_name])
 
-        threads = self.dap_server.get_threads()
-        for thread in threads:
-            if thread.get("reason") == "breakpoint":
-                thread_id = thread["id"]
-
-                self.stepOut(threadId=thread_id)
-
-                local_variables = self.dap_server.get_local_variables()
-                varref_dict = {}
+        stop_event = session.verify_stopped_on_breakpoint(
+            bp_id, after=ctx.process_event
+        )
+        thread_ctx = session.thread_context_from(stop_event)
+        thread_ctx.step_out()
 
-                # `verify_variable` function only checks if the local variables
-                # are in the `verify_dict` passed  this will cause this test 
to pass
-                # even if there is no return value.
-                local_variable_names = [
-                    variable["name"] for variable in local_variables
-                ]
-                self.assertIn(
-                    return_name,
-                    local_variable_names,
-                    "return variable is not in local variables",
-                )
+        frame = thread_ctx.top_frame()
+        local_vars = session.get_variables(frame.locals.variablesReference)
 
-                self.verify_variables(verify_locals, local_variables, 
varref_dict)
-                break
+        return_name = "(Return Value)"
+        expect_locals: dict[str, ExpectVar] = {
+            return_name: ExpectVar(type="int", value="300", read_only=True),
+            "argc": ExpectVar(),
+            "argv": ExpectVar(),
+            "pt": ExpectVar(read_only=True),
+            "valid_str": ExpectVar(),
+            "malformed_str": ExpectVar(),
+            "x": ExpectVar(),
+            "return_result": ExpectVar(type="int"),
+        }
+        session.verify_variables(local_vars, expect_locals)
 
-        self.assertFalse(self.set_local("(Return Value)", 20)["success"])
+        self.expect_error(frame.locals.set("(Return Value)", 20))
 
     @skipIfWindows
     def test_indexedVariables(self):
@@ -916,50 +686,43 @@ def 
test_indexedVariables_with_raw_child_for_synthetics(self):
     @skipIfWindows
     @skipIfAsan  # FIXME this fails with a non-asan issue on green dragon.
     def test_registers(self):
-        """
-        Test that registers whose byte size is the size of a pointer on
-        the current system get formatted as lldb::eFormatAddressInfo. This
-        will show the pointer value followed by a description of the address
-        itself. To test this we attempt to find the PC value in the general
-        purpose registers, and since we will be stopped in main.cpp, verify
-        that the value for the PC starts with a pointer and is followed by
-        a description that contains main.cpp.
-        """
+        """Test that registers whose byte size is the size of a pointer on
+        the current system get formatted as `lldb::eFormatAddressInfo`. The
+        formatted value should be a pointer followed by a description of the
+        address. To test this we look for the PC value in the general purpose
+        registers, and since we will be stopped in main.cpp, verify that its
+        value starts with a pointer and is followed by a description that
+        contains main.cpp."""
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program)
-        source = "main.cpp"
-        breakpoint1_line = line_number(source, "// breakpoint 1")
-        lines = [breakpoint1_line]
-        # Set breakpoint in the thread function so we can step the threads
-        breakpoint_ids = self.set_source_breakpoints(source, lines)
-        self.assertEqual(
-            len(breakpoint_ids), len(lines), "expect correct number of 
breakpoints"
+        session = self.build_and_create_session()
+        with session.configure(LaunchArgs(program)) as ctx:
+            source = "main.cpp"
+            breakpoint1_line = line_number(source, "// breakpoint 1")
+            breakpoint_ids = session.resolve_source_breakpoints(
+                source, [breakpoint1_line]
+            )
+        stop_event = session.verify_stopped_on_breakpoint(
+            breakpoint_ids, after=ctx.process_event
         )
-        self.continue_to_breakpoints(breakpoint_ids)
 
-        pc_name = None
+        pc_name: Optional[str] = None
         arch = self.getArchitecture()
-        if arch == "x86_64":
-            pc_name = "rip"
-        elif arch == "x86":
+        if arch in ("x86", "x86_64"):
             pc_name = "rip"
         elif arch.startswith("arm"):
             pc_name = "pc"
 
         if pc_name is None:
-            return
-        # Verify locals
-        reg_sets = self.dap_server.get_registers()
-        for reg_set in reg_sets:
-            if reg_set["name"] == "General Purpose Registers":
-                varRef = reg_set["variablesReference"]
-                regs = 
self.dap_server.request_variables(varRef)["body"]["variables"]
-                for reg in regs:
-                    if reg["name"] == pc_name:
-                        value = reg["value"]
-                        self.assertTrue(value.startswith("0x"))
-                        self.assertIn("a.out`main + ", value)
-                        self.assertIn("at main.cpp:", value)
+            self.skipTest(f"unknown program counter name for architecture: 
{arch}")
+
+        # Verify locals.
+        top_frame = session.top_frame_from(stop_event)
+        gpr_reg_set = top_frame.registers["General Purpose Registers"]
+        pc_reg = gpr_reg_set[pc_name].variable
+
+        self.assertTrue(pc_reg.value.startswith("0x"))
+        self.assertIn("a.out`main + ", pc_reg.value)
+        self.assertIn("at main.cpp:", pc_reg.value)
 
     @no_debug_info_test
     @skipUnlessDarwin
@@ -967,7 +730,7 @@ def test_darwin_dwarf_missing_obj(self):
         """
         Test that if we build a binary with DWARF in .o files and we remove
         the .o file for main.cpp, that we get a variable named "<error>"
-        whose value matches the appriopriate error. Errors when getting
+        whose value matches the appropriate error. Errors when getting
         variables are returned in the LLDB API when the user should be
         notified of issues that can easily be solved by rebuilding or
         changing compiler options and are designed to give better feedback
@@ -981,7 +744,7 @@ def 
test_darwin_dwarf_missing_obj_with_symbol_ondemand_enabled(self):
         """
         Test that if we build a binary with DWARF in .o files and we remove
         the .o file for main.cpp, that we get a variable named "<error>"
-        whose value matches the appriopriate error. Test with 
symbol_ondemand_enabled.
+        whose value matches the appropriate error. Test with 
symbol.load-on-demand enabled.
         """
         initCommands = ["settings set symbols.load-on-demand true"]
         self.darwin_dwarf_missing_obj(initCommands)
@@ -989,41 +752,36 @@ def 
test_darwin_dwarf_missing_obj_with_symbol_ondemand_enabled(self):
     @no_debug_info_test
     @skipIfWindows
     def test_value_format(self):
-        """
-        Test that toggle variables value format between decimal and hexical 
works.
-        """
+        """Test that toggling a variable's value format between decimal and
+        hexadecimal works."""
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program)
-        source = "main.cpp"
-        breakpoint1_line = line_number(source, "// breakpoint 1")
-        lines = [breakpoint1_line]
-
-        breakpoint_ids = self.set_source_breakpoints(source, lines)
-        self.assertEqual(
-            len(breakpoint_ids), len(lines), "expect correct number of 
breakpoints"
+        session = self.build_and_create_session()
+        with session.configure(LaunchArgs(program)) as ctx:
+            source = "main.cpp"
+            breakpoint1_line = line_number(source, "// breakpoint 1")
+            breakpoint_ids = session.resolve_source_breakpoints(
+                source, [breakpoint1_line]
+            )
+        stop_event = session.verify_stopped_on_breakpoint(
+            breakpoint_ids, after=ctx.process_event
         )
-        self.continue_to_breakpoints(breakpoint_ids)
-
-        # Verify locals value format decimal
-        is_hex = False
-        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", 
is_hex=is_hex)
-        self.assertEqual(var_pt_x["value"], "11")
-        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", 
is_hex=is_hex)
-        self.assertEqual(var_pt_y["value"], "22")
-
-        # Verify locals value format hexical
-        is_hex = True
-        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", 
is_hex=is_hex)
-        self.assertEqual(var_pt_x["value"], "0x0000000b")
-        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", 
is_hex=is_hex)
-        self.assertEqual(var_pt_y["value"], "0x00000016")
-
-        # Toggle and verify locals value format decimal again
-        is_hex = False
-        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", 
is_hex=is_hex)
-        self.assertEqual(var_pt_x["value"], "11")
-        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", 
is_hex=is_hex)
-        self.assertEqual(var_pt_y["value"], "22")
+
+        thread_ctx = session.thread_context_from(stop_event)
+        top_frame = thread_ctx.top_frame()
+        # Verify locals with decimal value format.
+        var_pt = top_frame.locals.with_format(is_hex=False)["pt"]
+        self.assertEqual(var_pt["x"].value, "11")
+        self.assertEqual(var_pt["y"].value, "22")
+
+        # Verify locals with hex value format.
+        var_pt = top_frame.locals.with_format(is_hex=True)["pt"]
+        self.assertEqual(var_pt["x"].value, "0x0000000b")
+        self.assertEqual(var_pt["y"].value, "0x00000016")
+
+        # Toggle back and verify decimal value format again.
+        var_pt = top_frame.locals.with_format(is_hex=False)["pt"]
+        self.assertEqual(var_pt["x"].value, "11")
+        self.assertEqual(var_pt["y"].value, "22")
 
     @skipIfWindows
     def test_variable_id_uniqueness_simple(self):
@@ -1032,31 +790,41 @@ def test_variable_id_uniqueness_simple(self):
         Ensures variable IDs are not reused between 
diff erent scopes/frames.
         """
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program)
-        source = "main.cpp"
-
-        bp_line = line_number(source, "// breakpoint 3")
-        self.set_source_breakpoints(source, [bp_line])
-        self.continue_to_next_stop()
-
-        frames = self.get_stackFrames()
-        self.assertGreaterEqual(len(frames), 2, "Need at least 2 frames")
-
-        all_refs = set()
-
-        for i in range(min(3, len(frames))):
-            frame_id = frames[i]["id"]
-            scopes = self.dap_server.request_scopes(frame_id)["body"]["scopes"]
-
-            for scope in scopes:
-                ref = scope["variablesReference"]
-                if ref != 0:
+        session = self.build_and_create_session()
+        with session.configure(LaunchArgs(program)) as ctx:
+            source = "main.cpp"
+            bp_line = line_number(source, "// breakpoint 3")
+            [bp_id] = session.resolve_source_breakpoints(source, [bp_line])
+
+        stop_event = session.verify_stopped_on_breakpoint(
+            bp_id, after=ctx.process_event
+        )
+        frames = session.thread_context_from(stop_event).frames()
+        self.assertGreaterEqual(len(frames), 2, "need at least 2 frames")
+
+        # Collect scope reference that has children.
+        scope_refs = [
+            scope.variablesReference
+            for frame in frames[:3]
+            for scope in frame.scopes()
+            if scope.variablesReference != 0
+        ]
+        self.assertGreater(len(scope_refs), 0, "should have found variable 
references")
+
+        seen_refs: set[int] = set()
+        # Verify scope references are unique.
+        for scope_ref in scope_refs:
+            self.assertNotIn(scope_ref, seen_refs, f"{scope_ref=} was reused!")
+            seen_refs.add(scope_ref)
+
+        # Verify variable references are unique.
+        for scope_ref in scope_refs:
+            for var in session.get_variables(scope_ref):
+                var_ref = var.variablesReference
+                if var_ref != 0:
                     self.assertNotIn(
-                        ref, all_refs, f"Variable reference {ref} was reused!"
+                        var_ref,
+                        seen_refs,
+                        f"variable {var.name} {var_ref=} was reused!",
                     )
-                    all_refs.add(ref)
-
-        self.assertGreater(len(all_refs), 0, "Should have found variable 
references")
-        for ref in all_refs:
-            response = self.dap_server.request_variables(ref)
-            self.assertTrue(response["success"], f"Failed to access reference 
{ref}")
+                    seen_refs.add(var_ref)

diff  --git 
a/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py 
b/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py
index 4622523931804..a993f815c056e 100644
--- 
a/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py
+++ 
b/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py
@@ -1,91 +1,77 @@
-import os
+from lldbsuite.test.decorators import expectedFailureAll
+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
+from lldbsuite.test.tools.lldb_dap.session_helpers import ExpectVar
 
-import dap_server
-import lldbdap_testcase
-from lldbsuite.test import lldbutil
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
 
-
-class TestDAP_variables_children(lldbdap_testcase.DAPTestCaseBase):
+class TestDAP_variables_children(DAPTestCaseBase):
     def test_get_num_children(self):
         """Test that GetNumChildren is not called for formatters not producing 
indexed children."""
+        session = self.build_and_create_session()
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(
+
+        launch_args = LaunchArgs(
             program,
             preRunCommands=[
-                "command script import '%s'" % 
self.getSourcePath("formatter.py")
+                f"command script import '{self.getSourcePath('formatter.py')}'"
             ],
         )
-        source = "main.cpp"
-        breakpoint_ids = self.set_source_breakpoints(
-            source, [line_number(source, "// break here")]
+        with session.configure(launch_args) as ctx:
+            source = self.getSourcePath("main.cpp")
+            [bp_id] = session.resolve_source_breakpoints(
+                source, [line_number(source, "// break here")]
+            )
+
+        stopped_event = session.verify_stopped_on_breakpoint(
+            bp_id, after=ctx.process_event
         )
-        self.continue_to_breakpoints(breakpoint_ids)
+        thread = session.thread_context_from(stopped_event)
+        local_vars = thread.top_frame().locals.variables()
+        indexed_var = next(x for x in local_vars if x.name == "indexed")
+        not_indexed_var = next(x for x in local_vars if x.name == 
"not_indexed")
 
-        local_vars = self.dap_server.get_local_variables()
-        print(local_vars)
-        indexed = next(filter(lambda x: x["name"] == "indexed", local_vars))
-        not_indexed = next(filter(lambda x: x["name"] == "not_indexed", 
local_vars))
-        self.assertIn("indexedVariables", indexed)
-        self.assertEqual(indexed["indexedVariables"], 1)
-        self.assertNotIn("indexedVariables", not_indexed)
+        self.assertIsNotNone(indexed_var.indexedVariables)
+        self.assertEqual(indexed_var.indexedVariables, 1)
+        self.assertIsNone(not_indexed_var.indexedVariables)
 
-        self.assertIn(
-            "['Indexed']",
-            self.dap_server.request_evaluate(
-                "`script formatter.num_children_calls", context="repl"
-            )["body"]["result"],
+        resp_body = session.evaluate(
+            "`script formatter.num_children_calls", context="repl"
         )
+        self.assertIn("['Indexed']", resp_body.result)
 
     @expectedFailureAll(archs=["arm$", "arm64", "aarch64"])
     def test_return_variable_with_children(self):
         """
         Test the stepping out of a function with return value show the 
children correctly
         """
+        session = self.build_and_create_session()
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program)
-
-        function_name = "test_return_variable_with_children"
-        breakpoint_ids = self.set_function_breakpoints([function_name])
-
-        self.assertEqual(len(breakpoint_ids), 1)
-        self.continue_to_breakpoints(breakpoint_ids)
-
-        threads = self.dap_server.get_threads()
-        for thread in threads:
-            if thread.get("reason") == "breakpoint":
-                thread_id = thread.get("id")
-                self.assertIsNot(thread_id, None)
 
-                self.stepOut(threadId=thread_id)
+        with session.configure(LaunchArgs(program)) as ctx:
+            function_name = "test_return_variable_with_children"
+            [func_bp_id] = 
session.resolve_function_breakpoints([function_name])
 
-                local_variables = self.dap_server.get_local_variables()
-
-                # Verify return value is the first item in as locals.
-                self.assertIsNot(len(local_variables), 0)
-                return_variable = local_variables[0]
-                self.assertEqual(return_variable["name"], "(Return Value)")
-
-                result_var_ref = return_variable.get("variablesReference")
-                self.assertIsNot(result_var_ref, None, "There is no result 
value")
-
-                result_value = 
self.dap_server.request_variables(result_var_ref)
-                result_children = result_value["body"]["variables"]
-                self.assertNotEqual(
-                    result_children, None, "The result does not have children"
-                )
-
-                verify_children = {"buffer": '"hello world!"', "x": "10", "y": 
"20"}
-                for child in result_children:
-                    actual_name = child["name"]
-                    actual_value = child["value"]
-                    verify_value = verify_children.get(actual_name)
-                    self.assertNotEqual(verify_value, None)
-                    self.assertEqual(
-                        actual_value,
-                        verify_value,
-                        "Expected child value does not match",
-                    )
+        stopped_event = session.verify_stopped_on_breakpoint(
+            func_bp_id, after=ctx.process_event
+        )
 
-                break
+        thread_ctx = session.thread_context_from(stopped_event)
+        thread_ctx.step_out()
+
+        local_variables = thread_ctx.top_frame().locals.variables()
+        self.assertIsNot(len(local_variables), 0)
+        return_variable = local_variables[0].variable
+        self.assertEqual(return_variable.name, "(Return Value)")
+
+        result_var_ref = return_variable.variablesReference
+        self.assertIsNot(result_var_ref, None, "There is no result value")
+
+        result_children = session.get_variables(result_var_ref)
+        verify_children = {"buffer": '"hello world!"', "x": "10", "y": "20"}
+        for child in result_children:
+            verify_value = verify_children.get(child.name)
+            self.assertNotEqual(verify_value, None)
+            self.assertEqual(
+                child.value, verify_value, "Expected child value does not 
match"
+            )


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

Reply via email to