blob: c77368111622a25496a85b824efc8bf64d3a6d15 [file] [log] [blame]
// Copyright 2020 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/shell/interpreter/test/interpreter_test.h"
#include <sstream>
#include <string>
#include "fuchsia/shell/cpp/fidl.h"
#include "fuchsia/sys/cpp/fidl.h"
#include "lib/async-loop/default.h"
#include "zircon/status.h"
InterpreterTest::InterpreterTest()
: loop_(&kAsyncLoopConfigAttachToCurrentThread), context_(sys::ComponentContext::Create()) {
::fidl::InterfaceHandle<fuchsia::io::Directory> directory;
fuchsia::sys::LaunchInfo launch_info;
launch_info.url = "fuchsia-pkg://fuchsia.com/shell_server#meta/shell_server.cmx";
launch_info.directory_request = directory.NewRequest().TakeChannel();
fuchsia::sys::LauncherPtr launcher;
context_->svc()->Connect(launcher.NewRequest());
launcher->CreateComponent(std::move(launch_info), controller_.NewRequest());
shell_provider_ = std::make_unique<sys::ServiceDirectory>(std::move(directory));
shell_.set_error_handler([this](zx_status_t status) {
global_error_stream_ << "Shell server closed connection: " << zx_status_get_string(status)
<< "\n";
loop_.Quit();
ASSERT_FALSE(running_) << "Unexpected server termination.";
});
shell_.events().OnError = [this](uint64_t context_id,
std::vector<fuchsia::shell::Location> locations,
std::string error_message) {
if (context_id == 0) {
global_error_stream_ << error_message << "\n";
Quit();
} else {
InterpreterTestContext* context = GetContext(context_id);
ASSERT_NE(nullptr, context);
for (const auto& location : locations) {
if (location.has_node_id()) {
context->error_stream << "node " << location.node_id().file_id << ':'
<< location.node_id().node_id << ' ';
}
}
context->error_stream << error_message << "\n";
}
};
shell_.events().OnDumpDone = [this](uint64_t context_id) {
InterpreterTestContext* context = GetContext(context_id);
ASSERT_NE(nullptr, context);
Quit();
};
shell_.events().OnExecutionDone = [this](uint64_t context_id,
fuchsia::shell::ExecuteResult result) {
InterpreterTestContext* context = GetContext(context_id);
ASSERT_NE(nullptr, context);
context->result = result;
if (globals_to_load_.empty() || (result != fuchsia::shell::ExecuteResult::OK)) {
Quit();
} else {
// Now that the execution is finished, loads all the global variables we asked using
// LoadGlobal.
for (const auto& global : globals_to_load_) {
++pending_globals_;
shell()->LoadGlobal(global, [this, global](std::vector<fuchsia::shell::Node> nodes) {
if (!nodes.empty()) {
// Currently we only support single values.
ASSERT_EQ(nodes.size(), static_cast<size_t>(1));
globals_[global] = std::move(nodes[0]);
}
if (--pending_globals_ == 0) {
Quit();
}
});
}
}
};
shell_.events().OnTextResult = [this](uint64_t context_id, std::string result,
bool partial_result) {
InterpreterTestContext* context = GetContext(context_id);
ASSERT_NE(nullptr, context);
if (last_result_partial_) {
ASSERT_FALSE(results_.empty());
results_.back() += result;
} else {
results_.emplace_back(std::move(result));
}
last_result_partial_ = partial_result;
};
}
InterpreterTestContext* InterpreterTest::CreateContext() {
uint64_t id = ++last_context_id_;
auto context = std::make_unique<InterpreterTestContext>(id);
auto result = context.get();
contexts_.emplace(id, std::move(context));
return result;
}
InterpreterTestContext* InterpreterTest::GetContext(uint64_t context_id) {
auto result = contexts_.find(context_id);
if (result == contexts_.end()) {
return nullptr;
}
return result->second.get();
}
void InterpreterTest::SetUp() {
// Reset context ids.
last_context_id_ = 0;
// Resets the global error stream for the test (to be able to run multiple tests).
global_error_stream_.str() = "";
// Creates a new connection to the server.
shell_provider_->Connect(shell_.NewRequest());
}