| """ |
| Test dwim-print with variables, variable paths, and expressions. |
| """ |
| |
| import re |
| import lldb |
| from lldbsuite.test.lldbtest import * |
| from lldbsuite.test.decorators import * |
| import lldbsuite.test.lldbutil as lldbutil |
| |
| |
| class TestCase(TestBase): |
| def _run_cmd(self, cmd: str) -> str: |
| """Run the given lldb command and return its output.""" |
| result = lldb.SBCommandReturnObject() |
| self.ci.HandleCommand(cmd, result) |
| return result.GetOutput().rstrip() |
| |
| VAR_IDENT = re.compile(r"(?:\$\d+|\w+) = ") |
| |
| def _strip_result_var(self, string: str) -> str: |
| """ |
| Strip (persistent) result variables (ex '$0 = ', or 'someVar = ', etc). |
| |
| This allows for using the output of `expression`/`frame variable`, to |
| compare it to `dwim-print` output, which disables result variables. |
| """ |
| return self.VAR_IDENT.subn("", string, 1)[0] |
| |
| def _expect_cmd( |
| self, |
| dwim_cmd: str, |
| actual_cmd: str, |
| ) -> None: |
| """Run dwim-print and verify the output against the expected command.""" |
| # Resolve the dwim-print command to either `expression` or `frame variable`. |
| substitute_cmd = dwim_cmd.replace("dwim-print", actual_cmd, 1) |
| interp = self.dbg.GetCommandInterpreter() |
| result = lldb.SBCommandReturnObject() |
| interp.ResolveCommand(substitute_cmd, result) |
| self.assertTrue(result.Succeeded(), result.GetError()) |
| |
| resolved_cmd = result.GetOutput() |
| if actual_cmd == "frame variable": |
| resolved_cmd = resolved_cmd.replace(" -- ", " ", 1) |
| |
| resolved_cmd_output = self._run_cmd(resolved_cmd) |
| dwim_cmd_output = self._strip_result_var(resolved_cmd_output) |
| |
| # Verify dwim-print chose the expected command. |
| self.runCmd("settings set dwim-print-verbosity full") |
| |
| self.expect( |
| dwim_cmd, |
| substrs=[ |
| f"note: ran `{resolved_cmd}`", |
| dwim_cmd_output, |
| ], |
| ) |
| |
| def test_variables(self): |
| """Test dwim-print with variables.""" |
| self.build() |
| lldbutil.run_to_name_breakpoint(self, "main") |
| vars = ("argc", "argv") |
| for var in vars: |
| self._expect_cmd(f"dwim-print {var}", "frame variable") |
| |
| def test_variable_paths(self): |
| """Test dwim-print with variable path expressions.""" |
| self.build() |
| lldbutil.run_to_name_breakpoint(self, "main") |
| exprs = ("&argc", "*argv", "argv[0]") |
| for expr in exprs: |
| self._expect_cmd(f"dwim-print {expr}", "expression") |
| |
| def test_expressions(self): |
| """Test dwim-print with expressions.""" |
| self.build() |
| lldbutil.run_to_name_breakpoint(self, "main") |
| exprs = ("argc + 1", "(void)argc", "(int)abs(argc)") |
| for expr in exprs: |
| self._expect_cmd(f"dwim-print {expr}", "expression") |
| |
| def test_dummy_target_expressions(self): |
| """Test dwim-print's ability to evaluate expressions without a target.""" |
| self._expect_cmd("dwim-print 1 + 2", "expression") |
| |
| def test_gdb_format(self): |
| self.build() |
| lldbutil.run_to_name_breakpoint(self, "main") |
| self._expect_cmd(f"dwim-print/x argc", "frame variable") |
| self._expect_cmd(f"dwim-print/x argc + 1", "expression") |
| |
| def test_format_flags(self): |
| self.build() |
| lldbutil.run_to_name_breakpoint(self, "main") |
| self._expect_cmd(f"dwim-print -fx -- argc", "frame variable") |
| self._expect_cmd(f"dwim-print -fx -- argc + 1", "expression") |
| |
| def test_display_flags(self): |
| self.build() |
| lldbutil.run_to_name_breakpoint(self, "main") |
| self._expect_cmd(f"dwim-print -T -- argc", "frame variable") |
| self._expect_cmd(f"dwim-print -T -- argc + 1", "expression") |
| |
| def test_expression_language(self): |
| """Test that the language flag doesn't affect the choice of command.""" |
| self.build() |
| lldbutil.run_to_name_breakpoint(self, "main") |
| self._expect_cmd(f"dwim-print -l c++ -- argc", "frame variable") |
| self._expect_cmd(f"dwim-print -l c++ -- argc + 1", "expression") |
| |
| def test_empty_expression(self): |
| self.build() |
| lldbutil.run_to_name_breakpoint(self, "main") |
| error_msg = "error: 'dwim-print' takes a variable or expression" |
| self.expect(f"dwim-print", error=True, startstr=error_msg) |
| self.expect(f"dwim-print -- ", error=True, startstr=error_msg) |
| |
| def test_nested_values(self): |
| """Test dwim-print with nested values (structs, etc).""" |
| self.build() |
| lldbutil.run_to_source_breakpoint( |
| self, "// break here", lldb.SBFileSpec("main.c") |
| ) |
| self.runCmd("settings set auto-one-line-summaries false") |
| self._expect_cmd(f"dwim-print s", "frame variable") |
| self._expect_cmd(f"dwim-print (struct Structure)s", "expression") |
| |
| def test_summary_strings(self): |
| """Test dwim-print with nested values (structs, etc).""" |
| self.build() |
| lldbutil.run_to_source_breakpoint( |
| self, "// break here", lldb.SBFileSpec("main.c") |
| ) |
| self.runCmd("settings set auto-one-line-summaries false") |
| self.runCmd("type summary add -e -s 'stub summary' Structure") |
| self._expect_cmd(f"dwim-print s", "frame variable") |
| self._expect_cmd(f"dwim-print (struct Structure)s", "expression") |
| |
| def test_void_result(self): |
| """Test dwim-print does not surface an error message for void expressions.""" |
| self.build() |
| lldbutil.run_to_source_breakpoint( |
| self, "// break here", lldb.SBFileSpec("main.c") |
| ) |
| self.expect("dwim-print (void)15", matching=False, patterns=["(?i)error"]) |