xref: /llvm-project/lldb/unittests/Interpreter/TestCommandPaths.cpp (revision d667840465b0ea0dbd39dcbd56788e73698dc853)
1 //===-- ProcessEventDataTest.cpp ------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
10 #include "Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h"
11 #include "lldb/Core/Debugger.h"
12 #include "lldb/Host/FileSystem.h"
13 #include "lldb/Host/HostInfo.h"
14 #include "lldb/Interpreter/CommandInterpreter.h"
15 #include "lldb/Interpreter/CommandObject.h"
16 #include "lldb/Interpreter/CommandObjectMultiword.h"
17 #include "lldb/Interpreter/CommandReturnObject.h"
18 #include "lldb/Utility/Args.h"
19 #include "lldb/Utility/Status.h"
20 
21 #include "gtest/gtest.h"
22 
23 using namespace lldb_private;
24 using namespace lldb_private::repro;
25 using namespace lldb;
26 
27 namespace {
28 class VerifyUserMultiwordCmdPathTest : public ::testing::Test {
29   void SetUp() override {
30     FileSystem::Initialize();
31     HostInfo::Initialize();
32     PlatformMacOSX::Initialize();
33   }
34   void TearDown() override {
35     PlatformMacOSX::Terminate();
36     HostInfo::Terminate();
37     FileSystem::Terminate();
38   }
39 };
40 } // namespace
41 
42 class CommandObjectLeaf : public CommandObjectParsed {
43 public:
44   CommandObjectLeaf(CommandInterpreter &interpreter)
45       : CommandObjectParsed(interpreter, "dummy subcommand leaf",
46                             "Does nothing", "dummy subcommand leaf") {
47     SetIsUserCommand(true);
48   }
49 
50 protected:
51   bool DoExecute(Args &command, CommandReturnObject &result) override {
52     result.SetStatus(eReturnStatusSuccessFinishResult);
53     result.AppendMessage("I did nothing");
54     return true;
55   }
56 };
57 
58 class CommandObjectMultiwordSubDummy : public CommandObjectMultiword {
59 public:
60   CommandObjectMultiwordSubDummy(CommandInterpreter &interpreter)
61       : CommandObjectMultiword(interpreter, "dummy subcommand", "Does nothing",
62                                "dummy subcommand") {
63     SetIsUserCommand(true);
64     LoadSubCommand("leaf", CommandObjectSP(new CommandObjectLeaf(interpreter)));
65   }
66 
67   ~CommandObjectMultiwordSubDummy() override = default;
68 };
69 
70 class CommandObjectMultiwordDummy : public CommandObjectMultiword {
71 public:
72   CommandObjectMultiwordDummy(CommandInterpreter &interpreter)
73       : CommandObjectMultiword(interpreter, "dummy", "Does nothing", "dummy") {
74     SetIsUserCommand(true);
75     LoadSubCommand(
76         "subcommand",
77         CommandObjectSP(new CommandObjectMultiwordSubDummy(interpreter)));
78   }
79 
80   ~CommandObjectMultiwordDummy() override = default;
81 };
82 
83 // Pass in the command path to args.  If success is true, we make sure the MWC
84 // returned matches the test string.  If success is false, we make sure the
85 // lookup error matches test_str.
86 void RunTest(CommandInterpreter &interp, const char *args, bool is_leaf,
87              bool success, const char *test_str) {
88   CommandObjectMultiword *multi_word_cmd = nullptr;
89   Args test_args(args);
90   Status error;
91   multi_word_cmd =
92       interp.VerifyUserMultiwordCmdPath(test_args, is_leaf, error);
93   if (success) {
94     ASSERT_NE(multi_word_cmd, nullptr);
95     ASSERT_TRUE(error.Success());
96     ASSERT_STREQ(multi_word_cmd->GetCommandName().str().c_str(), test_str);
97   } else {
98     ASSERT_EQ(multi_word_cmd, nullptr);
99     ASSERT_TRUE(error.Fail());
100     ASSERT_STREQ(error.AsCString(), test_str);
101   }
102 }
103 
104 TEST_F(VerifyUserMultiwordCmdPathTest, TestErrors) {
105   ArchSpec arch("x86_64-apple-macosx-");
106 
107   Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
108 
109   DebuggerSP debugger_sp = Debugger::CreateInstance();
110   ASSERT_TRUE(debugger_sp);
111 
112   CommandInterpreter &interp = debugger_sp->GetCommandInterpreter();
113 
114   Status error;
115   bool success;
116   bool is_leaf;
117 
118   // Test that we reject non-user path components:
119   success = false;
120   is_leaf = true;
121   RunTest(interp, "process launch", is_leaf, success,
122           "Path component: 'process' is not a user command");
123 
124   // Test that we reject non-existent commands:
125   is_leaf = true;
126   success = false;
127   RunTest(interp, "wewouldnevernameacommandthis subcommand", is_leaf, success,
128           "Path component: 'wewouldnevernameacommandthis' not found");
129 
130   // Now we have to add a multiword command, and then probe it.
131   error = interp.AddUserCommand(
132       "dummy", CommandObjectSP(new CommandObjectMultiwordDummy(interp)), true);
133   ASSERT_TRUE(error.Success());
134 
135   // Now pass the correct path, and make sure we get back the right MWC.
136   is_leaf = false;
137   success = true;
138   RunTest(interp, "dummy subcommand", is_leaf, success, "dummy subcommand");
139 
140   is_leaf = true;
141   RunTest(interp, "dummy subcommand", is_leaf, success, "dummy");
142 
143   // If you tell us the last node is a leaf, we don't check that.  Make sure
144   // that is true:
145   is_leaf = true;
146   success = true;
147   RunTest(interp, "dummy subcommand leaf", is_leaf, success,
148           "dummy subcommand");
149   // But we should fail if we say the last component is a multiword:
150 
151   is_leaf = false;
152   success = false;
153   RunTest(interp, "dummy subcommand leaf", is_leaf, success,
154           "Path component: 'leaf' is not a container command");
155 
156   // We should fail if we get the second path component wrong:
157   is_leaf = false;
158   success = false;
159   RunTest(interp, "dummy not-subcommand", is_leaf, success,
160           "Path component: 'not-subcommand' not found");
161 }
162