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