196 lines · python
1"""2Test dwim-print with variables, variable paths, and expressions.3"""4 5import re6import lldb7from lldbsuite.test.lldbtest import *8from lldbsuite.test.decorators import *9import lldbsuite.test.lldbutil as lldbutil10 11 12class TestCase(TestBase):13 def _run_cmd(self, cmd: str) -> str:14 """Run the given lldb command and return its output."""15 result = lldb.SBCommandReturnObject()16 self.ci.HandleCommand(cmd, result)17 return result.GetOutput().rstrip()18 19 VAR_IDENT = re.compile(r"(?:\$\d+|(?:::)?[\w.]+) = ")20 21 def _strip_result_var(self, string: str) -> str:22 """23 Strip (persistent) result variables (ex '$0 = ', or 'someVar = ', etc).24 25 This allows for using the output of `expression`/`frame variable`, to26 compare it to `dwim-print` output, which disables result variables.27 """28 return self.VAR_IDENT.subn("", string, 1)[0]29 30 def _expect_cmd(31 self,32 dwim_cmd: str,33 actual_cmd: str,34 ) -> None:35 """Run dwim-print and verify the output against the expected command."""36 # Resolve the dwim-print command to either `expression` or `frame variable`.37 substitute_cmd = dwim_cmd.replace("dwim-print", actual_cmd, 1)38 interp = self.dbg.GetCommandInterpreter()39 result = lldb.SBCommandReturnObject()40 interp.ResolveCommand(substitute_cmd, result)41 self.assertTrue(result.Succeeded(), result.GetError())42 43 resolved_cmd = result.GetOutput()44 if actual_cmd == "frame variable":45 resolved_cmd = resolved_cmd.replace(" -- ", " ", 1)46 47 resolved_cmd_output = self._run_cmd(resolved_cmd)48 dwim_cmd_output = self._strip_result_var(resolved_cmd_output)49 50 # Verify dwim-print chose the expected command.51 self.runCmd("settings set dwim-print-verbosity full")52 53 self.expect(54 dwim_cmd,55 substrs=[56 f"note: ran `{resolved_cmd}`",57 dwim_cmd_output,58 ],59 )60 61 def test_variables(self):62 """Test dwim-print with variables."""63 self.build()64 lldbutil.run_to_name_breakpoint(self, "main")65 vars = ("argc", "argv")66 for var in vars:67 self._expect_cmd(f"dwim-print {var}", "frame variable")68 69 def test_variable_paths(self):70 """Test dwim-print with variable path expressions."""71 self.build()72 lldbutil.run_to_name_breakpoint(self, "main")73 exprs = ("&argc", "*argv", "argv[0]")74 for expr in exprs:75 self._expect_cmd(f"dwim-print {expr}", "expression")76 77 def test_expressions(self):78 """Test dwim-print with expressions."""79 self.build()80 lldbutil.run_to_name_breakpoint(self, "main")81 exprs = ("argc + 1", "(void)argc", "(int)abs(argc)")82 for expr in exprs:83 self._expect_cmd(f"dwim-print {expr}", "expression")84 85 def test_dummy_target_expressions(self):86 """Test dwim-print's ability to evaluate expressions without a target."""87 self._expect_cmd("dwim-print 1 + 2", "expression")88 89 def test_gdb_format(self):90 self.build()91 lldbutil.run_to_name_breakpoint(self, "main")92 self._expect_cmd(f"dwim-print/x argc", "frame variable")93 self._expect_cmd(f"dwim-print/x argc + 1", "expression")94 95 def test_format_flags(self):96 self.build()97 lldbutil.run_to_name_breakpoint(self, "main")98 self._expect_cmd(f"dwim-print -fx -- argc", "frame variable")99 self._expect_cmd(f"dwim-print -fx -- argc + 1", "expression")100 101 def test_display_flags(self):102 self.build()103 lldbutil.run_to_name_breakpoint(self, "main")104 self._expect_cmd(f"dwim-print -T -- argc", "frame variable")105 self._expect_cmd(f"dwim-print -T -- argc + 1", "expression")106 107 def test_expression_language(self):108 """Test that the language flag doesn't affect the choice of command."""109 self.build()110 lldbutil.run_to_name_breakpoint(self, "main")111 self._expect_cmd(f"dwim-print -l c++ -- argc", "frame variable")112 self._expect_cmd(f"dwim-print -l c++ -- argc + 1", "expression")113 114 def test_empty_expression(self):115 self.build()116 lldbutil.run_to_name_breakpoint(self, "main")117 error_msg = "error: 'dwim-print' takes a variable or expression"118 self.expect(f"dwim-print", error=True, startstr=error_msg)119 self.expect(f"dwim-print -- ", error=True, startstr=error_msg)120 121 def test_nested_values(self):122 """Test dwim-print with nested values (structs, etc)."""123 self.build()124 lldbutil.run_to_source_breakpoint(125 self, "break here", lldb.SBFileSpec("main.cpp")126 )127 self.runCmd("settings set auto-one-line-summaries false")128 self._expect_cmd(f"dwim-print s", "frame variable")129 self._expect_cmd(f"dwim-print (struct Structure)s", "expression")130 131 def test_summary_strings(self):132 """Test dwim-print with type summaries."""133 self.build()134 lldbutil.run_to_source_breakpoint(135 self, "break here", lldb.SBFileSpec("main.cpp")136 )137 self.runCmd("settings set auto-one-line-summaries false")138 self.runCmd("type summary add -e -s 'stub summary' Structure")139 self._expect_cmd(f"dwim-print s", "frame variable")140 self._expect_cmd(f"dwim-print (struct Structure)s", "expression")141 self.runCmd("type summary delete Structure")142 143 def test_void_result(self):144 """Test dwim-print does not surface an error message for void expressions."""145 self.build()146 lldbutil.run_to_source_breakpoint(147 self, "break here", lldb.SBFileSpec("main.cpp")148 )149 self.expect("dwim-print (void)15", matching=False, patterns=["(?i)error"])150 151 def test_preserves_persistent_variables(self):152 """Test dwim-print does not delete persistent variables."""153 self.build()154 lldbutil.run_to_source_breakpoint(155 self, "break here", lldb.SBFileSpec("main.cpp")156 )157 self.expect("dwim-print int $i = 15")158 # Run the same expression twice and verify success. This ensures the159 # first command does not delete the persistent variable.160 for _ in range(2):161 self.expect("dwim-print $i", startstr="(int) 15")162 163 def test_missing_type(self):164 """The expected output of po opaque is its address (no error)"""165 self.build()166 lldbutil.run_to_source_breakpoint(167 self, "break here", lldb.SBFileSpec("main.cpp")168 )169 self.expect("dwim-print -O -- opaque", substrs=["0x"])170 171 def test_variable_expression_path(self):172 """Test dwim-print supports certain variable expression paths."""173 self.build()174 lldbutil.run_to_source_breakpoint(175 self, "break here", lldb.SBFileSpec("main.cpp")176 )177 self.runCmd("settings set auto-one-line-summaries false")178 self._expect_cmd("dwim-print w.s", "frame variable")179 self._expect_cmd("dwim-print wp->s", "expression")180 181 def test_direct_child_access(self):182 """Test dwim-print supports accessing members/ivars without qualification."""183 self.build()184 lldbutil.run_to_source_breakpoint(185 self, "break inside", lldb.SBFileSpec("main.cpp")186 )187 self._expect_cmd("dwim-print number", "frame variable")188 189 def test_global_variables(self):190 """Test dwim-print supports global variables."""191 self.build()192 lldbutil.run_to_source_breakpoint(193 self, "break here", lldb.SBFileSpec("main.cpp")194 )195 self._expect_cmd("dwim-print gGlobal", "frame variable")196