| // Copyright 2018 The Fuchsia Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "src/developer/debug/zxdb/console/actions.h" | |
| #include <gtest/gtest.h> | |
| #include "src/developer/debug/shared/platform_message_loop.h" | |
| #include "src/developer/debug/zxdb/client/session.h" | |
| #include "src/developer/debug/zxdb/common/test_with_loop.h" | |
| #include "src/developer/debug/zxdb/console/console_impl.h" | |
| #include "src/lib/fxl/strings/string_printf.h" | |
| namespace zxdb { | |
| namespace { | |
| using debug_ipc::MessageLoop; | |
| #define STOP_MESSAGE_LOOP() \ | |
| MessageLoop::Current()->PostTask(FROM_HERE, []() { MessageLoop::Current()->QuitNow(); }) | |
| // We override the Console in order to be able to override the dispatch | |
| // function | |
| class ConsoleTest : public ConsoleImpl { | |
| public: | |
| ConsoleTest(Session* session) : ConsoleImpl(session) {} | |
| void ProcessInputLine(const std::string& line, CommandCallback callback = nullptr) override { | |
| // We update the info | |
| calls.push_back(line); | |
| if (callback) { | |
| callback(errors_to_run[call_count]); | |
| } | |
| call_count++; | |
| } | |
| std::vector<std::string> calls; | |
| std::vector<Err> errors_to_run; | |
| size_t call_count = 0; | |
| }; | |
| class ActionsTest : public TestWithLoop { | |
| protected: | |
| ActionsTest() { | |
| session = std::make_unique<Session>(); | |
| console = std::make_unique<ConsoleTest>(session.get()); | |
| } | |
| std::unique_ptr<Session> session; | |
| std::unique_ptr<ConsoleTest> console; | |
| }; | |
| } // namespace | |
| using debug_ipc::MessageLoop; | |
| TEST_F(ActionsTest, ScriptFile) { | |
| // We expect 3 calls | |
| console->errors_to_run = {Err(), Err(), Err()}; | |
| // Setup the mock contents | |
| std::vector<std::string> mock_commands = {"help", "connect 192.168.0.1 2345", "break main", | |
| "run /path/to/binary"}; | |
| std::stringstream ss; | |
| ss << mock_commands[0] << "\n" << mock_commands[1] << "\n" << mock_commands[2]; | |
| std::string mock_contents = ss.str(); | |
| auto actions = CommandsToActions(mock_contents); | |
| ASSERT_EQ(actions.size(), 3u); | |
| EXPECT_EQ(actions[0].name(), mock_commands[0]); | |
| EXPECT_EQ(actions[1].name(), mock_commands[1]); | |
| EXPECT_EQ(actions[2].name(), mock_commands[2]); | |
| Err callback_err("FAIL"); | |
| auto callback = [&](Err err) { | |
| callback_err = err; | |
| STOP_MESSAGE_LOOP(); | |
| }; | |
| // The callback mechanism depends on a global ActionFlow | |
| ActionFlow& flow = ActionFlow::Singleton(); | |
| flow.ScheduleActions(std::move(actions), session.get(), console.get(), callback); | |
| loop().Run(); | |
| EXPECT_FALSE(callback_err.has_error()) << callback_err.msg(); | |
| ASSERT_EQ(console->calls.size(), 3u); | |
| EXPECT_EQ(console->calls[0], mock_commands[0]); | |
| EXPECT_EQ(console->calls[1], mock_commands[1]); | |
| EXPECT_EQ(console->calls[2], mock_commands[2]); | |
| ASSERT_EQ(flow.callbacks().size(), 3u); | |
| EXPECT_FALSE(flow.callbacks()[0].has_error()); | |
| EXPECT_FALSE(flow.callbacks()[1].has_error()); | |
| EXPECT_FALSE(flow.callbacks()[2].has_error()); | |
| } | |
| TEST_F(ActionsTest, ScriptFileWithFailure) { | |
| // We expect an error | |
| console->errors_to_run = {Err(), Err("ERROR"), Err()}; | |
| // Setup the mock contents | |
| std::vector<std::string> mock_commands = {"help", "connect 192.168.0.1 2345", | |
| "run /path/to/binary"}; | |
| std::stringstream ss; | |
| ss << mock_commands[0] << "\n" << mock_commands[1] << "\n" << mock_commands[2]; | |
| std::string mock_contents = ss.str(); | |
| auto actions = CommandsToActions(mock_contents); | |
| ASSERT_EQ(actions.size(), 3u); | |
| EXPECT_EQ(actions[0].name(), mock_commands[0]); | |
| EXPECT_EQ(actions[1].name(), mock_commands[1]); | |
| EXPECT_EQ(actions[2].name(), mock_commands[2]); | |
| Err callback_err("FAIL"); | |
| auto callback = [&](Err err) { | |
| callback_err = err; | |
| STOP_MESSAGE_LOOP(); | |
| }; | |
| // The callback mechanism depends on a global ActionFlow | |
| ActionFlow& flow = ActionFlow::Singleton(); | |
| flow.Clear(); | |
| flow.ScheduleActions(std::move(actions), session.get(), console.get(), callback); | |
| loop().Run(); | |
| // The error callback was called | |
| EXPECT_TRUE(callback_err.has_error()); | |
| // The second call fails | |
| ASSERT_EQ(console->calls.size(), 2u); | |
| EXPECT_EQ(console->calls[0], mock_commands[0]); | |
| EXPECT_EQ(console->calls[1], mock_commands[1]); | |
| ASSERT_EQ(flow.callbacks().size(), 2u); | |
| EXPECT_FALSE(flow.callbacks()[0].has_error()); | |
| EXPECT_TRUE(flow.callbacks()[1].has_error()); | |
| } | |
| } // namespace zxdb |