wallace created this revision. wallace added a reviewer: jingham. Herald added a project: All. wallace requested review of this revision. Herald added a project: LLDB. Herald added a subscriber: lldb-commits.
This adds some tests for removing lldb commands, user command and aliases. I've done in the SB API side for comleteness of this features. Besides that, I found a bug in the creation of the DummyCommand used in the test file: they were being allocated in the stack but they should have been allocated in the heap because CommandPluginInterfaceImplementation ends up owning the pointer passed to it, which is internally managed by a shared_ptr. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D149379 Files: lldb/include/lldb/API/SBCommandInterpreter.h lldb/source/API/SBCommandInterpreter.cpp lldb/unittests/API/SBCommandInterpreterTest.cpp
Index: lldb/unittests/API/SBCommandInterpreterTest.cpp =================================================================== --- lldb/unittests/API/SBCommandInterpreterTest.cpp +++ lldb/unittests/API/SBCommandInterpreterTest.cpp @@ -44,15 +44,41 @@ std::string m_message; }; +TEST_F(SBCommandInterpreterTest, RemoveCommandsAndAliases) { + // We first test removing non-existent commands + EXPECT_FALSE(m_interp.RemoveUserCommand("non-existent-user-command")); + EXPECT_FALSE(m_interp.RemoveCommand("non-existent-command")); + EXPECT_FALSE(m_interp.RemoveAlias("non-existent-alias")); + + // We now test removing a built-in command + EXPECT_TRUE(m_interp.CommandExists("target")); + EXPECT_FALSE(m_interp.RemoveCommand("target")); + // Built-in commands need to be force removed. + EXPECT_TRUE(m_interp.RemoveCommand("target", /*force=*/true)); + EXPECT_FALSE(m_interp.CommandExists("target")); + + // Finally we test with a user defined command + m_interp.AddCommand("dummy", new DummyCommand("A dummy command"), + /*help=*/nullptr); + EXPECT_TRUE(m_interp.UserCommandExists("dummy")); + EXPECT_TRUE(m_interp.RemoveUserCommand("dummy")); + EXPECT_FALSE(m_interp.UserCommandExists("dummy")); + + // Now we remove an alias + EXPECT_TRUE(m_interp.AliasExists("b")); + EXPECT_TRUE(m_interp.RemoveAlias("b")); + EXPECT_FALSE(m_interp.AliasExists("b")); +} + TEST_F(SBCommandInterpreterTest, SingleWordCommand) { // We first test a command without autorepeat - DummyCommand dummy("It worked"); - m_interp.AddCommand("dummy", &dummy, /*help=*/nullptr); + m_interp.AddCommand("dummy", new DummyCommand("Dummy command"), + /*help=*/nullptr); { SBCommandReturnObject result; m_interp.HandleCommand("dummy", result, /*add_to_history=*/true); EXPECT_TRUE(result.Succeeded()); - EXPECT_STREQ(result.GetOutput(), "It worked\n"); + EXPECT_STREQ(result.GetOutput(), "Dummy command\n"); } { SBCommandReturnObject result; @@ -62,34 +88,36 @@ } // Now we test a command with autorepeat - m_interp.AddCommand("dummy_with_autorepeat", &dummy, /*help=*/nullptr, + m_interp.AddCommand("dummy_with_autorepeat", + new DummyCommand("Command with autorepeat"), + /*help=*/nullptr, /*syntax=*/nullptr, /*auto_repeat_command=*/nullptr); { SBCommandReturnObject result; m_interp.HandleCommand("dummy_with_autorepeat", result, /*add_to_history=*/true); EXPECT_TRUE(result.Succeeded()); - EXPECT_STREQ(result.GetOutput(), "It worked\n"); + EXPECT_STREQ(result.GetOutput(), "Command with autorepeat\n"); } { SBCommandReturnObject result; m_interp.HandleCommand("", result); EXPECT_TRUE(result.Succeeded()); - EXPECT_STREQ(result.GetOutput(), "It worked\n"); + EXPECT_STREQ(result.GetOutput(), "Command with autorepeat\n"); } } TEST_F(SBCommandInterpreterTest, MultiWordCommand) { auto command = m_interp.AddMultiwordCommand("multicommand", /*help=*/nullptr); // We first test a subcommand without autorepeat - DummyCommand subcommand("It worked again"); - command.AddCommand("subcommand", &subcommand, /*help=*/nullptr); + command.AddCommand("subcommand", new DummyCommand("Dummy command"), + /*help=*/nullptr); { SBCommandReturnObject result; m_interp.HandleCommand("multicommand subcommand", result, /*add_to_history=*/true); EXPECT_TRUE(result.Succeeded()); - EXPECT_STREQ(result.GetOutput(), "It worked again\n"); + EXPECT_STREQ(result.GetOutput(), "Dummy command\n"); } { SBCommandReturnObject result; @@ -99,7 +127,8 @@ } // We first test a subcommand with autorepeat - command.AddCommand("subcommand_with_autorepeat", &subcommand, + command.AddCommand("subcommand_with_autorepeat", + new DummyCommand("Dummy command with autorepeat"), /*help=*/nullptr, /*syntax=*/nullptr, /*auto_repeat_command=*/nullptr); { @@ -107,19 +136,19 @@ m_interp.HandleCommand("multicommand subcommand_with_autorepeat", result, /*add_to_history=*/true); EXPECT_TRUE(result.Succeeded()); - EXPECT_STREQ(result.GetOutput(), "It worked again\n"); + EXPECT_STREQ(result.GetOutput(), "Dummy command with autorepeat\n"); } { SBCommandReturnObject result; m_interp.HandleCommand("", result); EXPECT_TRUE(result.Succeeded()); - EXPECT_STREQ(result.GetOutput(), "It worked again\n"); + EXPECT_STREQ(result.GetOutput(), "Dummy command with autorepeat\n"); } - DummyCommand subcommand2("It worked again 2"); // We now test a subcommand with autorepeat of the command name command.AddCommand( - "subcommand_with_custom_autorepeat", &subcommand2, /*help=*/nullptr, + "subcommand_with_custom_autorepeat", + new DummyCommand("Another dummy command"), /*help=*/nullptr, /*syntax=*/nullptr, /*auto_repeat_command=*/"multicommand subcommand_with_autorepeat"); { @@ -127,12 +156,12 @@ m_interp.HandleCommand("multicommand subcommand_with_custom_autorepeat", result, /*add_to_history=*/true); EXPECT_TRUE(result.Succeeded()); - EXPECT_STREQ(result.GetOutput(), "It worked again 2\n"); + EXPECT_STREQ(result.GetOutput(), "Another dummy command\n"); } { SBCommandReturnObject result; m_interp.HandleCommand("", result); EXPECT_TRUE(result.Succeeded()); - EXPECT_STREQ(result.GetOutput(), "It worked again\n"); + EXPECT_STREQ(result.GetOutput(), "Dummy command with autorepeat\n"); } } Index: lldb/source/API/SBCommandInterpreter.cpp =================================================================== --- lldb/source/API/SBCommandInterpreter.cpp +++ lldb/source/API/SBCommandInterpreter.cpp @@ -132,6 +132,30 @@ : false); } +bool SBCommandInterpreter::RemoveCommand(const char *command, bool force) { + LLDB_INSTRUMENT_VA(this, command, force); + + if (!IsValid()) + return false; + return m_opaque_ptr->RemoveCommand(command, force); +} + +bool SBCommandInterpreter::RemoveUserCommand(const char *command) { + LLDB_INSTRUMENT_VA(this, command); + + if (!IsValid()) + return false; + return m_opaque_ptr->RemoveUser(command); +} + +bool SBCommandInterpreter::RemoveAlias(const char *alias) { + LLDB_INSTRUMENT_VA(this, alias); + + if (!IsValid()) + return false; + return m_opaque_ptr->RemoveAlias(alias); +} + bool SBCommandInterpreter::IsActive() { LLDB_INSTRUMENT_VA(this); @@ -146,7 +170,7 @@ bool SBCommandInterpreter::InterruptCommand() { LLDB_INSTRUMENT_VA(this); - + return (IsValid() ? m_opaque_ptr->InterruptCommand() : false); } Index: lldb/include/lldb/API/SBCommandInterpreter.h =================================================================== --- lldb/include/lldb/API/SBCommandInterpreter.h +++ lldb/include/lldb/API/SBCommandInterpreter.h @@ -241,13 +241,13 @@ lldb::SBStringList &matches, lldb::SBStringList &descriptions); - /// Returns whether an interrupt flag was raised either by the SBDebugger - + /// Returns whether an interrupt flag was raised either by the SBDebugger - /// when the function is not running on the RunCommandInterpreter thread, or /// by SBCommandInterpreter::InterruptCommand if it is. If your code is doing - /// interruptible work, check this API periodically, and interrupt if it + /// interruptible work, check this API periodically, and interrupt if it /// returns true. bool WasInterrupted() const; - + /// Interrupts the command currently executing in the RunCommandInterpreter /// thread. /// @@ -313,6 +313,25 @@ /// and aliases. If successful, result->GetOutput has the full expansion. void ResolveCommand(const char *command_line, SBCommandReturnObject &result); + /// Remove a command if it is removable (python or regex command). If \b force + /// is provided, the command is removed regardless of its removable status. + /// + /// \return + /// \b true if and only if the command was effectively removed. + bool RemoveCommand(const char *command, bool force = false); + + /// Remove a user-defined command. + /// + /// \return + /// \b true if and only if the command was effectively removed. + bool RemoveUserCommand(const char *command); + + /// Remove an alias command. + /// + /// \return + /// \b true if and only if the alias was effectively removed. + bool RemoveAlias(const char *alias); + protected: lldb_private::CommandInterpreter &ref();
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits