[Lldb-commits] [lldb] [lldb-dap] Migrate all DAP variables test. (PR #208215)
via lldb-commits
lldb-commits at lists.llvm.org
Wed Jul 8 06:18:58 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: Ebuka Ezike (da-viper)
<details>
<summary>Changes</summary>
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
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]
``````````
</details>
https://github.com/llvm/llvm-project/pull/208215
More information about the lldb-commits
mailing list