[Lldb-commits] [lldb] [lldb-dap] Mirgate TestDAP_evaluate. (PR #212282)
via lldb-commits
lldb-commits at lists.llvm.org
Mon Jul 27 08:50:55 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: Ebuka Ezike (da-viper)
<details>
<summary>Changes</summary>
rewrite the `assertEvaluate` and `assertEvaluateFailure` helpers to use the already existing `session.verify_evaluate` function. THe helpers are now inlined functions.
---
Patch is 34.37 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/212282.diff
1 Files Affected:
- (modified) lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py (+304-431)
``````````diff
diff --git a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py
index 556168e5adfa8..7c3f698a2db2c 100644
--- a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py
+++ b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py
@@ -2,500 +2,373 @@
Test lldb-dap evaluate request
"""
-import re
+from typing import Optional
-import lldbdap_testcase
from lldbsuite.test.decorators import skipIfWindows
from lldbsuite.test.lldbtest import line_number
-from typing import TypedDict, Optional
+from lldbsuite.test.tools.lldb_dap import DAPTestCaseBase
+from lldbsuite.test.tools.lldb_dap.session_helpers import ExpectEval, FrameContext
+from lldbsuite.test.tools.lldb_dap.types import EvaluateContext, LaunchArgs, ValueFormat
-class EvaluateResponseBody(TypedDict, total=False):
- result: str
- variablesReference: int
- type: Optional[str]
- memoryReference: Optional[str]
- valueLocationReference: Optional[int]
+class TestDAP_evaluate(DAPTestCaseBase):
+ # The frame that `assert_eval*` functions calls evaluate in.
+ _eval_frame: Optional[FrameContext] = None
+ def set_evaluation_frame(self, frame: Optional[FrameContext]):
+ """Set the frame that `assert_eval*` functions calls evaluate in."""
+ self._eval_frame = frame
-class TestDAP_evaluate(lldbdap_testcase.DAPTestCaseBase):
- def assertEvaluate(
+ def run_evaluate_expressions(
self,
- expression,
- result: str,
- want_type="",
- want_varref=False,
- want_memref=True,
- want_locref=False,
- frame_index: Optional[int] = 0,
- is_hex=None,
+ context: Optional[EvaluateContext] = None,
+ enableAutoVariableSummaries: bool = False,
):
- resp = self.dap_server.request_evaluate(
- expression, context=self.context, is_hex=is_hex, frameIndex=frame_index
+ self.set_evaluation_frame(None)
+ is_result_expanded = context == "repl"
+ is_result_brief = context == "clipboard"
+ is_result_summary = (
+ not is_result_expanded
+ and not is_result_brief
+ and enableAutoVariableSummaries
)
- self.assertTrue(
- resp["success"],
- f"Failed to evaluate expression {expression!r} in frame {frame_index}",
- )
- body: EvaluateResponseBody = resp["body"]
- self.assertRegex(
- body["result"],
- result,
- f"Unexpected 'result' for expression {expression!r} in response body {body}",
- )
- if want_varref:
- self.assertNotEqual(
- body["variablesReference"],
- 0,
- f"Unexpected 'variablesReference' for expression {expression!r} in response body {body}",
- )
- else:
- self.assertEqual(
- body["variablesReference"],
- 0,
- f"Unexpected 'variablesReference' for expression {expression!r} in response body {body}",
- )
- if want_type:
- self.assertEqual(
- body["type"],
- want_type,
- f"Unexpected 'type' for expression {expression!r} in response body {body}",
- )
- if want_memref:
- self.assertIn(
- "memoryReference",
- body,
- f"Unexpected 'memoryReference' for expression {expression!r} in response body {body}",
- )
- if want_locref:
- self.assertIn(
- "valueLocationReference",
- body,
- f"Unexpected 'valueLocationReference' for expression {expression!r} in response body {body}",
- )
-
- def assertEvaluateFailure(self, expression):
- response = self.dap_server.request_evaluate(expression, context=self.context)
- self.assertFalse(
- response["success"],
- f"Expression:'{expression}' should fail in {self.context} context, got {response!r}",
- )
- self.assertNotIn(
- "result",
- response["body"],
- )
-
- def isResultExpandedDescription(self):
- return self.context == "repl"
+ context_parses_expressions = context != "hover"
+ session = self.build_and_create_session()
- def isResultShortDescription(self):
- return self.context == "clipboard"
+ def assert_eval(expression: str, matches: str, *, as_hex=False, **expects):
+ fmt = ValueFormat(hex=True) if as_hex else None
+ if eval_frame := self._eval_frame:
+ body = eval_frame.evaluate(expression, context=context, format=fmt)
+ else:
+ body = session.evaluate(expression, context=context, format=fmt)
+ expects.setdefault("has_mem_ref", True)
+ session.verify_evaluate(body, ExpectEval(matches=matches, **expects))
+ return body
- def isExpressionParsedExpected(self):
- return self.context != "hover"
+ def assert_eval_fails(expression: str):
+ frame_id = self._eval_frame.id if self._eval_frame else None
+ session.do_evaluate(expression, frameId=frame_id, context=context).error(
+ f"expected {expression!r} to fail using {context=!r} in {frame_id=!r}"
+ )
- def run_test_evaluate_expressions(
- self, context=None, enableAutoVariableSummaries=False
- ):
- """
- Tests the evaluate expression request at different breakpoints
- """
- self.context = context
- program = self.getBuildArtifact("a.out")
- self.build_and_launch(
- program,
- enableAutoVariableSummaries=enableAutoVariableSummaries,
- )
source = "main.cpp"
+ program = self.getBuildArtifact("a.out")
breakpoint_lines = [
- line_number(source, "// breakpoint 1"),
- line_number(source, "// breakpoint 2"),
- line_number(source, "// breakpoint 3"),
- line_number(source, "// breakpoint 4"),
- line_number(source, "// breakpoint 5"),
- line_number(source, "// breakpoint 6"),
- line_number(source, "// breakpoint 7"),
- line_number(source, "// breakpoint 8"),
+ line_number(source, f"// breakpoint 1"),
+ line_number(source, f"// breakpoint 2"),
+ line_number(source, f"// breakpoint 3"),
+ line_number(source, f"// breakpoint 4"),
+ line_number(source, f"// breakpoint 5"),
+ line_number(source, f"// breakpoint 6"),
+ line_number(source, f"// breakpoint 7"),
+ line_number(source, f"// breakpoint 8"),
]
- breakpoint_ids = self.set_source_breakpoints(source, breakpoint_lines)
- self.assertEqual(
- len(breakpoint_ids),
- len(breakpoint_lines),
- "Did not resolve all the breakpoints.",
+ launch = LaunchArgs(
+ program, enableAutoVariableSummaries=enableAutoVariableSummaries
)
- breakpoint_1 = breakpoint_ids[0]
- breakpoint_2 = breakpoint_ids[1]
- breakpoint_3 = breakpoint_ids[2]
- breakpoint_4 = breakpoint_ids[3]
- breakpoint_5 = breakpoint_ids[4]
- breakpoint_6 = breakpoint_ids[5]
- breakpoint_7 = breakpoint_ids[6]
- breakpoint_8 = breakpoint_ids[7]
- self.continue_to_breakpoint(breakpoint_1)
-
- # Expressions at breakpoint 1, which is in main
- self.assertEvaluate("var1", "20", want_type="int")
- # Empty expression should equate to the previous expression.
+ with session.configure(launch) as cfg:
+ bp_ids = session.resolve_source_breakpoints(source, breakpoint_lines)
+ bp1, bp2, bp3, bp4, bp5, bp6, bp7, bp8 = bp_ids
+
+ # Expression at breakpoint 1: In main.
+ stop_event = session.verify_stopped_on_breakpoint(bp1, after=cfg.process_event)
+ main_frames = session.thread_context_from(stop_event).frames(levels=2)
+ main_frame, caller_frame = main_frames[0], main_frames[1]
+ self.set_evaluation_frame(main_frame)
+
+ assert_eval("var1", "20", type="int")
+
+ # In repl context, an empty expression repeats the previous expression.
if context == "repl":
- self.assertEvaluate("", "20")
+ assert_eval("", "20")
else:
- self.assertEvaluateFailure("")
- self.assertEvaluate("var2", "21", want_type="int")
+ assert_eval_fails("")
+
+ assert_eval("var2", "21", type="int")
if context == "repl":
- self.assertEvaluate("", "21", want_type="int")
- self.assertEvaluate("", "21", want_type="int")
- self.assertEvaluate("static_int", "0x0000002a", want_type="int", is_hex=True)
- self.assertEvaluate(
- "non_static_int", "0x0000002b", want_type="int", is_hex=True
- )
- self.assertEvaluate("struct1.foo", "0x0000000f", want_type="int", is_hex=True)
- self.assertEvaluate("struct2->foo", "0x00000010", want_type="int", is_hex=True)
- self.assertEvaluate("static_int", "42", want_type="int")
- self.assertEvaluate("non_static_int", "43", want_type="int")
- self.assertEvaluate("struct1.foo", "15", want_type="int")
- self.assertEvaluate("struct2->foo", "16", want_type="int")
-
- if self.isResultExpandedDescription():
- self.assertEvaluate(
- "struct1",
- r"\(my_struct\) (struct1|\$\d+) = \(foo = 15\)",
- want_type="my_struct",
- want_varref=True,
- )
- self.assertEvaluate(
- "struct2",
- r"\(my_struct \*\) (struct2|\$\d+) = 0x.*",
- want_type="my_struct *",
- want_varref=True,
- )
- self.assertEvaluate(
- "struct3",
- r"\(my_struct \*\) (struct3|\$\d+) = nullptr",
- want_type="my_struct *",
- want_varref=True,
- )
- elif self.isResultShortDescription():
- self.assertEvaluate(
- "struct1",
- "(foo = 15)",
- want_type="my_struct",
- want_varref=True,
- )
- self.assertEvaluate(
- "struct2",
- r"0x.*",
- want_type="my_struct *",
- want_varref=True,
- )
- self.assertEvaluate(
- "struct3",
- "nullptr",
- want_type="my_struct *",
- want_varref=True,
- )
+ assert_eval("", "21", type="int")
+ assert_eval("", "21", type="int")
+
+ # Verify hex and decimal formatting.
+ assert_eval("static_int", "0x0000002a", type="int", as_hex=True)
+ assert_eval("static_int", "42", type="int")
+ assert_eval("non_static_int", "0x0000002b", type="int", as_hex=True)
+ assert_eval("non_static_int", "43", type="int")
+ assert_eval("struct1.foo", "0x0000000f", type="int", as_hex=True)
+ assert_eval("struct1.foo", "15", type="int")
+ assert_eval("struct2->foo", "0x00000010", type="int", as_hex=True)
+ assert_eval("struct2->foo", "16", type="int")
+
+ if is_result_expanded:
+ struct1_match = r"\(my_struct\) (struct1|\$\d+) = \(foo = 15\)"
+ elif is_result_brief:
+ struct1_match = r"\(foo = 15\)"
+ elif is_result_summary:
+ struct1_match = r"\{foo:15\}"
else:
- self.assertEvaluate(
- "struct1",
- (re.escape("{foo:15}") if enableAutoVariableSummaries else "my_struct"),
- want_varref=True,
- )
- self.assertEvaluate(
- "struct2",
- "0x.* {foo:16}" if enableAutoVariableSummaries else "0x.*",
- want_varref=True,
- want_type="my_struct *",
- )
- self.assertEvaluate(
- "struct3", "0x.*0", want_varref=True, want_type="my_struct *"
- )
+ struct1_match = "my_struct"
+ assert_eval("struct1", struct1_match, type="my_struct", has_var_ref=True)
- if context == "repl" or context is None:
+ if is_result_expanded:
+ struct2_match = r"\(my_struct \*\) (struct2|\$\d+) = 0x.*"
+ elif is_result_summary:
+ struct2_match = r"0x.* \{foo:16\}"
+ else:
+ struct2_match = r"0x.*"
+ assert_eval("struct2", struct2_match, type="my_struct *", has_var_ref=True)
+
+ if is_result_expanded:
+ struct3_match = r"\(my_struct \*\) (struct3|\$\d+) = nullptr"
+ elif is_result_brief:
+ struct3_match = "nullptr"
+ else:
+ struct3_match = r"0x.*0"
+ assert_eval("struct3", struct3_match, type="my_struct *", has_var_ref=True)
+
+ if context in ("repl", None):
# In repl or unknown context expressions may be interpreted as lldb
# commands since no variables have the same name as the command.
- self.assertEvaluate("list", r".*", want_memref=False)
- # Changing the frame index should not make a difference
- self.assertEvaluate(
- "version", r".*lldb.+", want_memref=False, frame_index=1
- )
-
+ eval_body = main_frame.evaluate("list")
+ session.verify_evaluate(eval_body, matches=r".*", has_mem_ref=False)
+ # Changing the frame should not make a difference.
+ eval_body = caller_frame.evaluate("version")
+ session.verify_evaluate(eval_body, matches=r".*lldb.+", has_mem_ref=False)
else:
- self.assertEvaluateFailure("list") # local variable of a_function
+ assert_eval_fails("list") # local variable of a_function.
+ assert_eval_fails("version")
- self.assertEvaluateFailure("my_struct") # type name
- self.assertEvaluateFailure("int") # type name
- self.assertEvaluateFailure("foo") # member of my_struct
+ # Identifiers and variables not in scope should fail.
+ assert_eval_fails("my_struct") # struct name.
+ assert_eval_fails("int") # type name.
+ assert_eval_fails("foo") # member variable of my_struct.
- if self.isExpressionParsedExpected():
- self.assertEvaluate(
+ if context_parses_expressions:
+ assert_eval(
"a_function",
- "0x.*a.out`a_function.*",
- want_type="int (*)(int)",
- want_varref=True,
- want_memref=False,
- want_locref=True,
- )
- self.assertEvaluate(
- "a_function(1)", "1", want_memref=False, want_type="int"
- )
- self.assertEvaluate("var2 + struct1.foo", "36", want_memref=False)
- self.assertEvaluate(
+ r"0x.*a.out`a_function.*",
+ type="int (*)(int)",
+ has_var_ref=True,
+ has_mem_ref=False,
+ has_loc_ref=True,
+ )
+ assert_eval("a_function(1)", "1", type="int", has_mem_ref=False)
+ assert_eval("var2 + struct1.foo", "36", has_mem_ref=False)
+ assert_eval(
"foo_func",
- "0x.*a.out`foo_func.*",
- want_type="int (*)()",
- want_varref=True,
- want_memref=False,
- want_locref=True,
+ r"0x.*a.out`foo_func.*",
+ type="int (*)()",
+ has_var_ref=True,
+ has_mem_ref=False,
+ has_loc_ref=True,
)
- self.assertEvaluate("foo_var", "44")
else:
- self.assertEvaluateFailure("a_function")
- self.assertEvaluateFailure("a_function(1)")
- self.assertEvaluateFailure("var2 + struct1.foo")
- self.assertEvaluateFailure("foo_func")
- self.assertEvaluateFailure("(float) var2")
- self.assertEvaluate("foo_var", "44")
-
- # Expressions at breakpoint 2, which is an anonymous block
- self.continue_to_breakpoint(breakpoint_2)
- self.assertEvaluate("var1", "20")
- self.assertEvaluate("var2", "2") # different variable with the same name
- self.assertEvaluate("static_int", "42")
- self.assertEvaluate(
- "non_static_int", "10"
- ) # different variable with the same name
- if self.isResultExpandedDescription():
- self.assertEvaluate(
- "struct1",
- r"\(my_struct\) (struct1|\$\d+) = \(foo = 15\)",
- want_type="my_struct",
- want_varref=True,
- )
- elif self.isResultShortDescription():
- self.assertEvaluate(
- "struct1",
- "(foo = 15)",
- want_type="my_struct",
- want_varref=True,
- )
- else:
- self.assertEvaluate(
- "struct1",
- (re.escape("{foo:15}") if enableAutoVariableSummaries else "my_struct"),
- want_type="my_struct",
- want_varref=True,
- )
- self.assertEvaluate("struct1.foo", "15")
- self.assertEvaluate("struct2->foo", "16")
-
- if self.isExpressionParsedExpected():
- self.assertEvaluate(
+ assert_eval_fails("a_function")
+ assert_eval_fails("a_function(1)")
+ assert_eval_fails("var2 + struct1.foo")
+ assert_eval_fails("foo_func")
+ assert_eval_fails("(float) var2")
+
+ # foo_var is a global variable and should evaluate.
+ assert_eval("foo_var", "44")
+
+ # Expressions at breakpoint 2: In an anonymous block.
+ stop_event = session.continue_to_breakpoint(bp2)
+ self.set_evaluation_frame(session.top_frame_from(stop_event))
+
+ assert_eval("var1", "20")
+ assert_eval("var2", "2") # shadowed variable.
+ assert_eval("static_int", "42")
+ assert_eval("non_static_int", "10") # shadowed variable.
+ assert_eval("struct1", struct1_match, type="my_struct", has_var_ref=True)
+ assert_eval("struct1.foo", "15")
+ assert_eval("struct2->foo", "16")
+
+ if context_parses_expressions:
+ assert_eval(
"a_function",
- "0x.*a.out`a_function.*",
- want_type="int (*)(int)",
- want_varref=True,
- want_memref=False,
- want_locref=True,
- )
- self.assertEvaluate("a_function(1)", "1", want_memref=False)
- self.assertEvaluate("var2 + struct1.foo", "17", want_memref=False)
- self.assertEvaluate(
- "foo_func", "0x.*a.out`foo_func.*", want_varref=True, want_memref=False
+ r"0x.*a.out`a_function.*",
+ type="int (*)(int)",
+ has_var_ref=True,
+ has_mem_ref=False,
+ has_loc_ref=True,
+ )
+ assert_eval("a_function(1)", "1", has_mem_ref=False)
+ assert_eval("var2 + struct1.foo", "17", has_mem_ref=False)
+ assert_eval(
+ "foo_func",
+ r"0x.*a.out`foo_func.*",
+ has_var_ref=True,
+ has_mem_ref=False,
)
- self.assertEvaluate("foo_var", "44")
else:
- self.assertEvaluateFailure("a_function")
- self.assertEvaluateFailure("a_function(1)")
- self.assertEvaluateFailure("var2 + struct1.foo")
- self.assertEvaluateFailure("foo_func")
- self.assertEvaluate("foo_var", "44")
-
- # Expressions at breakpoint 3, which is inside a_function
- self.continue_to_breakpoint(breakpoint_3)
- self.assertEvaluate("list", "42")
- self.assertEvaluate("static_int", "42")
- self.assertEvaluate("non_static_int", "43")
- # variable from a different frame
- self.assertEvaluate("var1", "20", frame_index=1)
-
- if self.isExpressionParsedExp...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/212282
More information about the lldb-commits
mailing list