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