xref: /llvm-project/lldb/test/API/commands/command/script/TestCommandScript.py (revision 5784bf85bc5143266565586ece0113cd773a8616)
199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtTest lldb Python commands.
399451b44SJordan Rupprecht"""
499451b44SJordan Rupprecht
599451b44SJordan Rupprecht
699451b44SJordan Rupprechtimport sys
799451b44SJordan Rupprechtimport lldb
899451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
999451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
1099451b44SJordan Rupprecht
1199451b44SJordan Rupprecht
1299451b44SJordan Rupprechtclass CmdPythonTestCase(TestBase):
1399451b44SJordan Rupprecht    NO_DEBUG_INFO_TESTCASE = True
1499451b44SJordan Rupprecht
1599451b44SJordan Rupprecht    def test(self):
1699451b44SJordan Rupprecht        self.build()
1799451b44SJordan Rupprecht        self.pycmd_tests()
1899451b44SJordan Rupprecht
1999451b44SJordan Rupprecht    def pycmd_tests(self):
2099451b44SJordan Rupprecht        self.runCmd("command source py_import")
2199451b44SJordan Rupprecht
224eb694e3SJim Ingham        # Test that we did indeed add these commands as user commands:
234eb694e3SJim Ingham        interp = self.dbg.GetCommandInterpreter()
2400b2c33cSJim Ingham        self.assertTrue(interp.UserCommandExists("foobar"), "foobar exists")
2500b2c33cSJim Ingham        self.assertFalse(interp.CommandExists("foobar"), "It is not a builtin.")
264eb694e3SJim Ingham
2799451b44SJordan Rupprecht        # Test a bunch of different kinds of python callables with
2899451b44SJordan Rupprecht        # both 4 and 5 positional arguments.
2999451b44SJordan Rupprecht        self.expect("foobar", substrs=["All good"])
3099451b44SJordan Rupprecht        self.expect("foobar4", substrs=["All good"])
3199451b44SJordan Rupprecht        self.expect("vfoobar", substrs=["All good"])
3299451b44SJordan Rupprecht        self.expect("v5foobar", substrs=["All good"])
3399451b44SJordan Rupprecht        self.expect("sfoobar", substrs=["All good"])
3499451b44SJordan Rupprecht        self.expect("cfoobar", substrs=["All good"])
3599451b44SJordan Rupprecht        self.expect("ifoobar", substrs=["All good"])
3699451b44SJordan Rupprecht        self.expect("sfoobar4", substrs=["All good"])
3799451b44SJordan Rupprecht        self.expect("cfoobar4", substrs=["All good"])
3899451b44SJordan Rupprecht        self.expect("ifoobar4", substrs=["All good"])
3999451b44SJordan Rupprecht        self.expect("ofoobar", substrs=["All good"])
4099451b44SJordan Rupprecht        self.expect("ofoobar4", substrs=["All good"])
4199451b44SJordan Rupprecht
4299451b44SJordan Rupprecht        # Verify command that specifies eCommandRequiresTarget returns failure
4399451b44SJordan Rupprecht        # without a target.
442238dcc3SJonas Devlieghere        self.expect("targetname", substrs=["a.out"], matching=False, error=True)
4599451b44SJordan Rupprecht
4699451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
472238dcc3SJonas Devlieghere        self.expect("file " + exe, patterns=["Current executable set to .*a.out"])
4899451b44SJordan Rupprecht
492238dcc3SJonas Devlieghere        self.expect("targetname", substrs=["a.out"], matching=True, error=False)
5099451b44SJordan Rupprecht
5199451b44SJordan Rupprecht        # This is the function to remove the custom commands in order to have a
5299451b44SJordan Rupprecht        # clean slate for the next test case.
5399451b44SJordan Rupprecht        def cleanup():
542238dcc3SJonas Devlieghere            self.runCmd("command script delete welcome", check=False)
552238dcc3SJonas Devlieghere            self.runCmd("command script delete targetname", check=False)
562238dcc3SJonas Devlieghere            self.runCmd("command script delete longwait", check=False)
572238dcc3SJonas Devlieghere            self.runCmd("command script delete mysto", check=False)
582238dcc3SJonas Devlieghere            self.runCmd("command script delete tell_sync", check=False)
592238dcc3SJonas Devlieghere            self.runCmd("command script delete tell_async", check=False)
602238dcc3SJonas Devlieghere            self.runCmd("command script delete tell_curr", check=False)
612238dcc3SJonas Devlieghere            self.runCmd("command script delete bug11569", check=False)
622238dcc3SJonas Devlieghere            self.runCmd("command script delete takes_exe_ctx", check=False)
632238dcc3SJonas Devlieghere            self.runCmd("command script delete decorated", check=False)
6499451b44SJordan Rupprecht
6599451b44SJordan Rupprecht        # Execute the cleanup function during test case tear down.
6699451b44SJordan Rupprecht        self.addTearDownHook(cleanup)
6799451b44SJordan Rupprecht
6899451b44SJordan Rupprecht        # Interact with debugger in synchronous mode
6999451b44SJordan Rupprecht        self.setAsync(False)
7099451b44SJordan Rupprecht
7199451b44SJordan Rupprecht        # We don't want to display the stdout if not in TraceOn() mode.
7299451b44SJordan Rupprecht        if not self.TraceOn():
7399451b44SJordan Rupprecht            self.HideStdout()
7499451b44SJordan Rupprecht
752238dcc3SJonas Devlieghere        self.expect("welcome Enrico", substrs=["Hello Enrico, welcome to LLDB"])
7699451b44SJordan Rupprecht
772238dcc3SJonas Devlieghere        self.expect(
782238dcc3SJonas Devlieghere            "help welcome",
792238dcc3SJonas Devlieghere            substrs=[
802238dcc3SJonas Devlieghere                "Just a docstring for welcome_impl",
812238dcc3SJonas Devlieghere                "A command that says hello to LLDB users",
822238dcc3SJonas Devlieghere            ],
832238dcc3SJonas Devlieghere        )
8499451b44SJordan Rupprecht
8599451b44SJordan Rupprecht        decorated_commands = ["decorated" + str(n) for n in range(1, 5)]
8699451b44SJordan Rupprecht        for name in decorated_commands:
8799451b44SJordan Rupprecht            self.expect(name, substrs=["hello from " + name])
882238dcc3SJonas Devlieghere            self.expect(
892238dcc3SJonas Devlieghere                "help " + name, substrs=["Python command defined by @lldb.command"]
902238dcc3SJonas Devlieghere            )
9199451b44SJordan Rupprecht
922238dcc3SJonas Devlieghere        self.expect(
932238dcc3SJonas Devlieghere            "help",
942238dcc3SJonas Devlieghere            substrs=["For more information run"] + decorated_commands + ["welcome"],
952238dcc3SJonas Devlieghere        )
9699451b44SJordan Rupprecht
972238dcc3SJonas Devlieghere        self.expect(
982238dcc3SJonas Devlieghere            "help -a",
992238dcc3SJonas Devlieghere            substrs=["For more information run"] + decorated_commands + ["welcome"],
1002238dcc3SJonas Devlieghere        )
10199451b44SJordan Rupprecht
1022238dcc3SJonas Devlieghere        self.expect("help -u", matching=False, substrs=["For more information run"])
10399451b44SJordan Rupprecht
10499451b44SJordan Rupprecht        self.runCmd("command script delete welcome")
10599451b44SJordan Rupprecht
1062238dcc3SJonas Devlieghere        self.expect(
1072238dcc3SJonas Devlieghere            "welcome Enrico",
1082238dcc3SJonas Devlieghere            matching=False,
1092238dcc3SJonas Devlieghere            error=True,
1102238dcc3SJonas Devlieghere            substrs=["Hello Enrico, welcome to LLDB"],
1112238dcc3SJonas Devlieghere        )
11299451b44SJordan Rupprecht
1132238dcc3SJonas Devlieghere        self.expect(
1142238dcc3SJonas Devlieghere            "targetname fail", error=True, substrs=["a test for error in command"]
1152238dcc3SJonas Devlieghere        )
11699451b44SJordan Rupprecht
1172238dcc3SJonas Devlieghere        self.expect(
1182238dcc3SJonas Devlieghere            "command script list", substrs=["targetname", "For more information run"]
1192238dcc3SJonas Devlieghere        )
12099451b44SJordan Rupprecht
1212238dcc3SJonas Devlieghere        self.expect(
1222238dcc3SJonas Devlieghere            "help targetname",
1232238dcc3SJonas Devlieghere            substrs=["Expects", "'raw'", "input", "help", "raw-input"],
1242238dcc3SJonas Devlieghere        )
12599451b44SJordan Rupprecht
1262238dcc3SJonas Devlieghere        self.expect("longwait", substrs=["Done; if you saw the delays I am doing OK"])
12799451b44SJordan Rupprecht
128dd01d9aaSMuhammad Omair Javaid        self.runCmd("break set -f main.cpp -l 48")
12999451b44SJordan Rupprecht        self.runCmd("run")
13099451b44SJordan Rupprecht        self.runCmd("mysto 3")
1312238dcc3SJonas Devlieghere        self.expect(
1322238dcc3SJonas Devlieghere            "frame variable array",
1332238dcc3SJonas Devlieghere            substrs=["[0] = 79630", "[1] = 388785018", "[2] = 0"],
1342238dcc3SJonas Devlieghere        )
13599451b44SJordan Rupprecht        self.runCmd("mysto 3")
1362238dcc3SJonas Devlieghere        self.expect(
1372238dcc3SJonas Devlieghere            "frame variable array",
1382238dcc3SJonas Devlieghere            substrs=["[0] = 79630", "[4] = 388785018", "[5] = 0"],
1392238dcc3SJonas Devlieghere        )
14099451b44SJordan Rupprecht
14199451b44SJordan Rupprecht        # we cannot use the stepover command to check for async execution mode since LLDB
14299451b44SJordan Rupprecht        # seems to get confused when events start to queue up
1432238dcc3SJonas Devlieghere        self.expect("tell_sync", substrs=["running sync"])
1442238dcc3SJonas Devlieghere        self.expect("tell_async", substrs=["running async"])
1452238dcc3SJonas Devlieghere        self.expect("tell_curr", substrs=["I am running sync"])
14699451b44SJordan Rupprecht
14799451b44SJordan Rupprecht        # check that the execution context is passed in to commands that ask for it
14899451b44SJordan Rupprecht        self.expect("takes_exe_ctx", substrs=["a.out"])
14999451b44SJordan Rupprecht
15099451b44SJordan Rupprecht        # Test that a python command can redefine itself
15199451b44SJordan Rupprecht        self.expect('command script add -f foobar welcome -h "just some help"')
15299451b44SJordan Rupprecht
15399451b44SJordan Rupprecht        self.runCmd("command script clear")
15499451b44SJordan Rupprecht
15599451b44SJordan Rupprecht        # Test that re-defining an existing command works
1562238dcc3SJonas Devlieghere        self.runCmd("command script add my_command --class welcome.WelcomeCommand")
1572238dcc3SJonas Devlieghere        self.expect("my_command Blah", substrs=["Hello Blah, welcome to LLDB"])
15899451b44SJordan Rupprecht
15999451b44SJordan Rupprecht        self.runCmd(
1602238dcc3SJonas Devlieghere            "command script add my_command -o --class welcome.TargetnameCommand"
1612238dcc3SJonas Devlieghere        )
1622238dcc3SJonas Devlieghere        self.expect("my_command", substrs=["a.out"])
16399451b44SJordan Rupprecht
164cf0be7b4SFelipe de Azevedo Piovezan        # Test that without --overwrite we are not allowed to redefine the command.
165cf0be7b4SFelipe de Azevedo Piovezan        self.expect(
166cf0be7b4SFelipe de Azevedo Piovezan            "command script add my_command --class welcome.TargetnameCommand",
167cf0be7b4SFelipe de Azevedo Piovezan            substrs=[
168cf0be7b4SFelipe de Azevedo Piovezan                (
169cf0be7b4SFelipe de Azevedo Piovezan                    'user command "my_command" already exists and force replace was'
170cf0be7b4SFelipe de Azevedo Piovezan                    " not set by --overwrite or 'settings set"
171cf0be7b4SFelipe de Azevedo Piovezan                    " interpreter.require-overwrite false'"
172cf0be7b4SFelipe de Azevedo Piovezan                ),
173cf0be7b4SFelipe de Azevedo Piovezan            ],
174cf0be7b4SFelipe de Azevedo Piovezan            error=True,
175cf0be7b4SFelipe de Azevedo Piovezan        )
176cf0be7b4SFelipe de Azevedo Piovezan
17799451b44SJordan Rupprecht        self.runCmd("command script clear")
17899451b44SJordan Rupprecht
1792238dcc3SJonas Devlieghere        self.expect(
1802238dcc3SJonas Devlieghere            "command script list", matching=False, substrs=["targetname", "longwait"]
1812238dcc3SJonas Devlieghere        )
18299451b44SJordan Rupprecht
1832238dcc3SJonas Devlieghere        self.expect(
1842238dcc3SJonas Devlieghere            "command script add -f foobar frame",
1852238dcc3SJonas Devlieghere            error=True,
1862238dcc3SJonas Devlieghere            substrs=["cannot add command"],
1872238dcc3SJonas Devlieghere        )
18899451b44SJordan Rupprecht
18999451b44SJordan Rupprecht        # http://llvm.org/bugs/show_bug.cgi?id=11569
19099451b44SJordan Rupprecht        # LLDBSwigPythonCallCommand crashes when a command script returns an
19199451b44SJordan Rupprecht        # object
1922238dcc3SJonas Devlieghere        self.runCmd("command script add -f bug11569 bug11569")
19399451b44SJordan Rupprecht        # This should not crash.
1942238dcc3SJonas Devlieghere        self.runCmd("bug11569", check=False)
1957406d236SPavel Labath
1969093f3c3SJim Ingham        # Make sure that a reference to a non-existent class raises an error:
1979093f3c3SJim Ingham        bad_class_name = "LLDBNoSuchModule.LLDBNoSuchClass"
1982238dcc3SJonas Devlieghere        self.expect(
1992238dcc3SJonas Devlieghere            "command script add wont-work --class {0}".format(bad_class_name),
2002238dcc3SJonas Devlieghere            error=True,
2012238dcc3SJonas Devlieghere            substrs=[bad_class_name],
2022238dcc3SJonas Devlieghere        )
2039093f3c3SJim Ingham
2047406d236SPavel Labath    def test_persistence(self):
2050a07c966SPavel Labath        """
2060a07c966SPavel Labath        Ensure that function arguments meaningfully persist (and do not crash!)
2070a07c966SPavel Labath        even after the function terminates.
2080a07c966SPavel Labath        """
2097406d236SPavel Labath        self.runCmd("command script import persistence.py")
2107406d236SPavel Labath        self.runCmd("command script add -f persistence.save_debugger save_debugger")
2117406d236SPavel Labath        self.expect("save_debugger", substrs=[str(self.dbg)])
2120a07c966SPavel Labath
2130a07c966SPavel Labath        # After the command completes, the debugger object should still be
2140a07c966SPavel Labath        # valid.
2157406d236SPavel Labath        self.expect("script str(persistence.debugger_copy)", substrs=[str(self.dbg)])
2160a07c966SPavel Labath        # The result object will be replaced by an empty result object (in the
2170a07c966SPavel Labath        # "Started" state).
2180a07c966SPavel Labath        self.expect("script str(persistence.result_copy)", substrs=["Started"])
219*5784bf85Sjimingham
220*5784bf85Sjimingham    def test_interactive(self):
221*5784bf85Sjimingham        """
222*5784bf85Sjimingham        Test that we can add multiple lines interactively.
223*5784bf85Sjimingham        """
224*5784bf85Sjimingham        interp = self.dbg.GetCommandInterpreter()
225*5784bf85Sjimingham        cmd_file = self.getSourcePath("cmd_file.lldb")
226*5784bf85Sjimingham        result = lldb.SBCommandReturnObject()
227*5784bf85Sjimingham        interp.HandleCommand(f"command source {cmd_file}", result)
228*5784bf85Sjimingham        self.assertCommandReturn(result, "Sourcing the command should cause no errors.")
229*5784bf85Sjimingham        self.assertTrue(interp.UserCommandExists("my_cmd"), "Command defined.")
230*5784bf85Sjimingham        interp.HandleCommand("my_cmd", result)
231*5784bf85Sjimingham        self.assertCommandReturn(result, "Running the command succeeds")
232*5784bf85Sjimingham        self.assertIn("My Command Result", result.GetOutput(), "Command was correct")
233