xref: /llvm-project/lldb/test/API/commands/command/script/TestCommandScript.py (revision 00b2c33c9359e1f75dd29d5083fac66bfd52db6e)
1"""
2Test lldb Python commands.
3"""
4
5
6import sys
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10
11
12class CmdPythonTestCase(TestBase):
13    NO_DEBUG_INFO_TESTCASE = True
14
15    def test(self):
16        self.build()
17        self.pycmd_tests()
18
19    def pycmd_tests(self):
20        self.runCmd("command source py_import")
21
22        # Test that we did indeed add these commands as user commands:
23        interp = self.dbg.GetCommandInterpreter()
24        self.assertTrue(interp.UserCommandExists("foobar"), "foobar exists")
25        self.assertFalse(interp.CommandExists("foobar"), "It is not a builtin.")
26
27        # Test a bunch of different kinds of python callables with
28        # both 4 and 5 positional arguments.
29        self.expect("foobar", substrs=["All good"])
30        self.expect("foobar4", substrs=["All good"])
31        self.expect("vfoobar", substrs=["All good"])
32        self.expect("v5foobar", substrs=["All good"])
33        self.expect("sfoobar", substrs=["All good"])
34        self.expect("cfoobar", substrs=["All good"])
35        self.expect("ifoobar", substrs=["All good"])
36        self.expect("sfoobar4", substrs=["All good"])
37        self.expect("cfoobar4", substrs=["All good"])
38        self.expect("ifoobar4", substrs=["All good"])
39        self.expect("ofoobar", substrs=["All good"])
40        self.expect("ofoobar4", substrs=["All good"])
41
42        # Verify command that specifies eCommandRequiresTarget returns failure
43        # without a target.
44        self.expect('targetname',
45                    substrs=['a.out'], matching=False, error=True)
46
47        exe = self.getBuildArtifact("a.out")
48        self.expect("file " + exe,
49                    patterns=["Current executable set to .*a.out"])
50
51        self.expect('targetname',
52                    substrs=['a.out'], matching=True, error=False)
53
54        # This is the function to remove the custom commands in order to have a
55        # clean slate for the next test case.
56        def cleanup():
57            self.runCmd('command script delete welcome', check=False)
58            self.runCmd('command script delete targetname', check=False)
59            self.runCmd('command script delete longwait', check=False)
60            self.runCmd('command script delete mysto', check=False)
61            self.runCmd('command script delete tell_sync', check=False)
62            self.runCmd('command script delete tell_async', check=False)
63            self.runCmd('command script delete tell_curr', check=False)
64            self.runCmd('command script delete bug11569', check=False)
65            self.runCmd('command script delete takes_exe_ctx', check=False)
66            self.runCmd('command script delete decorated', check=False)
67
68        # Execute the cleanup function during test case tear down.
69        self.addTearDownHook(cleanup)
70
71        # Interact with debugger in synchronous mode
72        self.setAsync(False)
73
74        # We don't want to display the stdout if not in TraceOn() mode.
75        if not self.TraceOn():
76            self.HideStdout()
77
78        self.expect('welcome Enrico',
79                    substrs=['Hello Enrico, welcome to LLDB'])
80
81        self.expect("help welcome",
82                    substrs=['Just a docstring for welcome_impl',
83                             'A command that says hello to LLDB users'])
84
85        decorated_commands = ["decorated" + str(n) for n in range(1, 5)]
86        for name in decorated_commands:
87            self.expect(name, substrs=["hello from " + name])
88            self.expect("help " + name,
89                        substrs=["Python command defined by @lldb.command"])
90
91        self.expect("help",
92                    substrs=['For more information run']
93                             + decorated_commands + ['welcome'])
94
95        self.expect("help -a",
96                    substrs=['For more information run']
97                             + decorated_commands + ['welcome'])
98
99        self.expect("help -u", matching=False,
100                    substrs=['For more information run'])
101
102        self.runCmd("command script delete welcome")
103
104        self.expect('welcome Enrico', matching=False, error=True,
105                    substrs=['Hello Enrico, welcome to LLDB'])
106
107        self.expect('targetname fail', error=True,
108                    substrs=['a test for error in command'])
109
110        self.expect('command script list',
111                    substrs=['targetname',
112                             'For more information run'])
113
114        self.expect("help targetname",
115                    substrs=['Expects', '\'raw\'', 'input',
116                             'help', 'raw-input'])
117
118        self.expect("longwait",
119                    substrs=['Done; if you saw the delays I am doing OK'])
120
121        self.runCmd("break set -f main.cpp -l 48")
122        self.runCmd("run")
123        self.runCmd("mysto 3")
124        self.expect("frame variable array",
125                    substrs=['[0] = 79630', '[1] = 388785018', '[2] = 0'])
126        self.runCmd("mysto 3")
127        self.expect("frame variable array",
128                    substrs=['[0] = 79630', '[4] = 388785018', '[5] = 0'])
129
130# we cannot use the stepover command to check for async execution mode since LLDB
131# seems to get confused when events start to queue up
132        self.expect("tell_sync",
133                    substrs=['running sync'])
134        self.expect("tell_async",
135                    substrs=['running async'])
136        self.expect("tell_curr",
137                    substrs=['I am running sync'])
138
139# check that the execution context is passed in to commands that ask for it
140        self.expect("takes_exe_ctx", substrs=["a.out"])
141
142        # Test that a python command can redefine itself
143        self.expect('command script add -f foobar welcome -h "just some help"')
144
145        self.runCmd("command script clear")
146
147        # Test that re-defining an existing command works
148        self.runCmd(
149            'command script add my_command --class welcome.WelcomeCommand')
150        self.expect('my_command Blah', substrs=['Hello Blah, welcome to LLDB'])
151
152        self.runCmd(
153            'command script add my_command -o --class welcome.TargetnameCommand')
154        self.expect('my_command', substrs=['a.out'])
155
156        self.runCmd("command script clear")
157
158        self.expect('command script list', matching=False,
159                    substrs=['targetname',
160                             'longwait'])
161
162        self.expect('command script add -f foobar frame', error=True,
163                    substrs=['cannot add command'])
164
165        # http://llvm.org/bugs/show_bug.cgi?id=11569
166        # LLDBSwigPythonCallCommand crashes when a command script returns an
167        # object
168        self.runCmd('command script add -f bug11569 bug11569')
169        # This should not crash.
170        self.runCmd('bug11569', check=False)
171
172        # Make sure that a reference to a non-existent class raises an error:
173        bad_class_name = "LLDBNoSuchModule.LLDBNoSuchClass"
174        self.expect("command script add wont-work --class {0}".format(bad_class_name), error=True, substrs = [bad_class_name])
175
176    def test_persistence(self):
177        """
178        Ensure that function arguments meaningfully persist (and do not crash!)
179        even after the function terminates.
180        """
181        self.runCmd("command script import persistence.py")
182        self.runCmd("command script add -f persistence.save_debugger save_debugger")
183        self.expect("save_debugger", substrs=[str(self.dbg)])
184
185        # After the command completes, the debugger object should still be
186        # valid.
187        self.expect("script str(persistence.debugger_copy)", substrs=[str(self.dbg)])
188        # The result object will be replaced by an empty result object (in the
189        # "Started" state).
190        self.expect("script str(persistence.result_copy)", substrs=["Started"])
191