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 _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
