xref: /llvm-project/lldb/test/API/commands/command/container/TestContainerCommands.py (revision 2238dcc39358353cac21df75c3c3286ab20b8f53)
1"""
2Test user added container commands
3"""
4
5
6import sys
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10
11
12class TestCmdContainer(TestBase):
13    NO_DEBUG_INFO_TESTCASE = True
14
15    def test_container_add(self):
16        self.container_add()
17
18    def check_command_tree_exists(self):
19        """This makes sure we can still run the command tree we added."""
20        self.runCmd("test-multi")
21        self.runCmd("test-multi test-multi-sub")
22        self.runCmd("test-multi test-multi-sub welcome")
23
24    def container_add(self):
25        # Make sure we can't overwrite built-in commands:
26        self.expect(
27            "command container add process",
28            "Can't replace builtin container command",
29            substrs=["can't replace builtin command"],
30            error=True,
31        )
32        self.expect(
33            "command container add process non_such_subcommand",
34            "Can't add to built-in subcommand",
35            substrs=["Path component: 'process' is not a user command"],
36            error=True,
37        )
38        self.expect(
39            "command container add process launch",
40            "Can't replace builtin subcommand",
41            substrs=["Path component: 'process' is not a user command"],
42            error=True,
43        )
44
45        # Now lets make a container command:
46        self.runCmd("command container add -h 'A test container command' test-multi")
47        # Make sure the help works:
48        self.expect(
49            "help test-multi",
50            "Help works for top-level multi",
51            substrs=["A test container command"],
52        )
53        # Add a subcommand:
54        self.runCmd(
55            "command container add -h 'A test container sub-command' test-multi test-multi-sub"
56        )
57        # Make sure the help works:
58        self.expect(
59            "help test-multi",
60            "Help shows sub-multi",
61            substrs=[
62                "A test container command",
63                "test-multi-sub -- A test container sub-command",
64            ],
65        )
66        self.expect(
67            "help test-multi test-multi-sub",
68            "Help shows sub-multi",
69            substrs=["A test container sub-command"],
70        )
71
72        # Now add a script based command to the container command:
73        self.runCmd("command script import welcome.py")
74        self.runCmd(
75            "command script add -c welcome.WelcomeCommand test-multi test-multi-sub welcome"
76        )
77        # Make sure the help still works:
78        self.expect(
79            "help test-multi test-multi-sub",
80            "Listing subcommands works",
81            substrs=[
82                "A test container sub-command",
83                "welcome -- Just a docstring for Welcome",
84            ],
85        )
86        self.expect(
87            "help test-multi test-multi-sub welcome",
88            "Subcommand help works",
89            substrs=["Just a docstring for Welcome"],
90        )
91        # And make sure it actually works:
92        self.expect(
93            "test-multi test-multi-sub welcome friend",
94            "Test command works",
95            substrs=["Hello friend, welcome to LLDB"],
96        )
97
98        # Make sure we can make an alias to this:
99        self.runCmd(
100            "command alias my-welcome test-multi test-multi-sub welcome",
101            "We can make an alias to multi-word",
102        )
103        self.expect(
104            "my-welcome friend",
105            "Test command works",
106            substrs=["Hello friend, welcome to LLDB"],
107        )
108        self.runCmd("command unalias my-welcome")
109
110        # Make sure overwriting works on the leaf command.  First using the
111        # explicit option so we should not be able to remove extant commands by default:
112
113        self.expect(
114            "command script add -c welcome.WelcomeCommand2 test-multi test-multi-sub welcome",
115            "overwrite command w/o -o",
116            substrs=["cannot add command: sub-command already exists"],
117            error=True,
118        )
119        # But we can with the -o option:
120        self.runCmd(
121            "command script add -c welcome.WelcomeCommand2 -o test-multi test-multi-sub welcome"
122        )
123        # Make sure we really did overwrite:
124        self.expect(
125            "test-multi test-multi-sub welcome friend",
126            "Used the new command class",
127            substrs=["Hello friend, welcome again to LLDB"],
128        )
129        self.expect(
130            "apropos welcome",
131            "welcome should show up in apropos",
132            substrs=["A docstring for the second Welcome"],
133        )
134        self.expect(
135            "help test-multi test-multi-sub welcome",
136            "welcome should show up in help",
137            substrs=["A docstring for the second Welcome"],
138        )
139        self.expect("help", "test-multi should show up in help", substrs=["test-multi"])
140
141        # Now switch the default and make sure we can now delete w/o the overwrite option:
142        self.runCmd("settings set interpreter.require-overwrite 0")
143        self.runCmd(
144            "command script add -c welcome.WelcomeCommand test-multi test-multi-sub welcome"
145        )
146        # Make sure we really did overwrite:
147        self.expect(
148            "test-multi test-multi-sub welcome friend",
149            "Used the new command class",
150            substrs=["Hello friend, welcome to LLDB"],
151        )
152
153        # Make sure we give good errors when the input is wrong:
154        self.expect(
155            "command script delete test-mult test-multi-sub welcome",
156            "Delete script command - wrong first path component",
157            substrs=["'test-mult' not found"],
158            error=True,
159        )
160
161        self.expect(
162            "command script delete test-multi test-multi-su welcome",
163            "Delete script command - wrong second path component",
164            substrs=["'test-multi-su' not found"],
165            error=True,
166        )
167        self.check_command_tree_exists()
168
169        self.expect(
170            "command script delete test-multi test-multi-sub welcom",
171            "Delete script command - wrong leaf component",
172            substrs=["'welcom' not found"],
173            error=True,
174        )
175        self.check_command_tree_exists()
176
177        self.expect(
178            "command script delete test-multi test-multi-sub",
179            "Delete script command - no leaf component",
180            substrs=["subcommand 'test-multi-sub' is not a user command"],
181            error=True,
182        )
183        self.check_command_tree_exists()
184
185        # You can't use command script delete to delete container commands:
186        self.expect(
187            "command script delete test-multi",
188            "Delete script - can't delete container",
189            substrs=["command 'test-multi' is a multi-word command."],
190            error=True,
191        )
192        self.expect(
193            "command script delete test-multi test-multi-sub",
194            "Delete script - can't delete container",
195            substrs=["subcommand 'test-multi-sub' is not a user command"],
196            error=True,
197        )
198
199        # You can't use command container delete to delete scripted commands:
200        self.expect(
201            "command container delete test-multi test-multi-sub welcome",
202            "command container can't delete user commands",
203            substrs=["subcommand 'welcome' is not a container command"],
204            error=True,
205        )
206
207        # Also make sure you can't alias on top of container commands:
208        self.expect(
209            "command alias test-multi process launch",
210            "Tried to alias on top of a container command",
211            substrs=[
212                "'test-multi' is a user container command and cannot be overwritten."
213            ],
214            error=True,
215        )
216        self.check_command_tree_exists()
217
218        # Also assert that we can't delete builtin commands:
219        self.expect(
220            "command script delete process launch",
221            "Delete builtin command fails",
222            substrs=["command 'process' is not a user command"],
223            error=True,
224        )
225        # Now let's do the version that works
226        self.expect(
227            "command script delete test-multi test-multi-sub welcome",
228            "Delete script command by path",
229            substrs=["Deleted command: test-multi test-multi-sub welcome"],
230        )
231
232        # Now overwrite the sub-command, it should end up empty:
233        self.runCmd(
234            "command container add -h 'A different help string' -o test-multi test-multi-sub"
235        )
236        # welcome should be gone:
237        self.expect(
238            "test-multi test-multi-sub welcome friend",
239            "did remove subcommand",
240            substrs=["'test-multi-sub' does not have any subcommands."],
241            error=True,
242        )
243        # We should have the new help:
244        self.expect(
245            "help test-multi test-multi-sub",
246            "help changed",
247            substrs=["A different help string"],
248        )
249
250        # Now try deleting commands.
251        self.runCmd("command container delete test-multi test-multi-sub")
252        self.expect(
253            "test-multi test-multi-sub",
254            "Command is not active",
255            error=True,
256            substrs=["'test-multi' does not have any subcommands"],
257        )
258        self.expect("help test-multi", matching=False, substrs=["test-multi-sub"])
259
260        # Next the root command:
261        self.runCmd("command container delete test-multi")
262        self.expect(
263            "test-multi",
264            "Root command gone",
265            substrs=["'test-multi' is not a valid command."],
266            error=True,
267        )
268