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