Skip to content

[lldb-dap] Migrate all DAP variables test.#208215

Open
da-viper wants to merge 1 commit into
llvm:mainfrom
da-viper:migrate-test-dap-variables
Open

[lldb-dap] Migrate all DAP variables test.#208215
da-viper wants to merge 1 commit into
llvm:mainfrom
da-viper:migrate-test-dap-variables

Conversation

@da-viper

@da-viper da-viper commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

migrate TestDAP_variables and TestDAP_variables_children.

migrate TestDAP_variables and TestDAP_variables_children
@da-viper da-viper requested review from DrSergei and ashgti July 8, 2026 13:18
@da-viper da-viper requested a review from JDevlieghere as a code owner July 8, 2026 13:18
@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-lldb

Author: Ebuka Ezike (da-viper)

Changes

migrate TestDAP_variables and TestDAP_variables_children.


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

3 Files Affected:

  • (modified) lldb/packages/Python/lldbsuite/test/tools/lldb_dap/session_helpers.py (+3-1)
  • (modified) lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py (+613-846)
  • (modified) lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py (+54-68)
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..3fb47323efffa 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")
+        ...
[truncated]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant