未验证 提交 2ea83968 编写于 作者: G gaaclarke 提交者: GitHub

Added unit tests to the engine. (#20216)

上级 ecc934e6
......@@ -600,6 +600,7 @@ FILE: ../../../flutter/shell/common/canvas_spy.h
FILE: ../../../flutter/shell/common/canvas_spy_unittests.cc
FILE: ../../../flutter/shell/common/engine.cc
FILE: ../../../flutter/shell/common/engine.h
FILE: ../../../flutter/shell/common/engine_unittests.cc
FILE: ../../../flutter/shell/common/fixtures/shell_test.dart
FILE: ../../../flutter/shell/common/fixtures/shelltest_screenshot.png
FILE: ../../../flutter/shell/common/input_events_unittests.cc
......
......@@ -16,6 +16,10 @@
namespace flutter {
RuntimeController::RuntimeController(RuntimeDelegate& client,
TaskRunners p_task_runners)
: client_(client), vm_(nullptr), task_runners_(p_task_runners) {}
RuntimeController::RuntimeController(
RuntimeDelegate& p_client,
DartVM* p_vm,
......
......@@ -38,7 +38,7 @@ class Window;
/// used by the engine to copy the currently accumulated window state so it can
/// be referenced by the new runtime controller.
///
class RuntimeController final : public PlatformConfigurationClient {
class RuntimeController : public PlatformConfigurationClient {
public:
//----------------------------------------------------------------------------
/// @brief Creates a new instance of a runtime controller. This is
......@@ -340,7 +340,7 @@ class RuntimeController final : public PlatformConfigurationClient {
///
/// @return True if root isolate running, False otherwise.
///
bool IsRootIsolateRunning() const;
virtual bool IsRootIsolateRunning() const;
//----------------------------------------------------------------------------
/// @brief Dispatch the specified platform message to running root
......@@ -351,7 +351,7 @@ class RuntimeController final : public PlatformConfigurationClient {
/// @return If the message was dispatched to the running root isolate.
/// This may fail is an isolate is not running.
///
bool DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message);
virtual bool DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message);
//----------------------------------------------------------------------------
/// @brief Dispatch the specified pointer data message to the running
......@@ -440,6 +440,10 @@ class RuntimeController final : public PlatformConfigurationClient {
///
std::pair<bool, uint32_t> GetRootIsolateReturnCode();
protected:
/// Constructor for Mocks.
RuntimeController(RuntimeDelegate& client, TaskRunners p_task_runners);
private:
struct Locale {
Locale(std::string language_code_,
......
......@@ -258,6 +258,7 @@ if (enable_unittests) {
sources = [
"animator_unittests.cc",
"canvas_spy_unittests.cc",
"engine_unittests.cc",
"input_events_unittests.cc",
"persistent_cache_unittests.cc",
"pipeline_unittests.cc",
......@@ -268,6 +269,7 @@ if (enable_unittests) {
deps = [
"//flutter/assets",
"//flutter/shell/version",
"//third_party/googletest:gmock",
]
public_deps_legacy_and_next = [ ":shell_test_fixture_sources" ]
......
......@@ -35,6 +35,27 @@ static constexpr char kLocalizationChannel[] = "flutter/localization";
static constexpr char kSettingsChannel[] = "flutter/settings";
static constexpr char kIsolateChannel[] = "flutter/isolate";
Engine::Engine(
Delegate& delegate,
const PointerDataDispatcherMaker& dispatcher_maker,
std::shared_ptr<fml::ConcurrentTaskRunner> image_decoder_task_runner,
TaskRunners task_runners,
Settings settings,
std::unique_ptr<Animator> animator,
fml::WeakPtr<IOManager> io_manager,
std::unique_ptr<RuntimeController> runtime_controller)
: delegate_(delegate),
settings_(std::move(settings)),
animator_(std::move(animator)),
runtime_controller_(std::move(runtime_controller)),
activity_running_(true),
have_surface_(false),
image_decoder_(task_runners, image_decoder_task_runner, io_manager),
task_runners_(std::move(task_runners)),
weak_factory_(this) {
pointer_data_dispatcher_ = dispatcher_maker(*this);
}
Engine::Engine(Delegate& delegate,
const PointerDataDispatcherMaker& dispatcher_maker,
DartVM& vm,
......@@ -46,19 +67,14 @@ Engine::Engine(Delegate& delegate,
fml::WeakPtr<IOManager> io_manager,
fml::RefPtr<SkiaUnrefQueue> unref_queue,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate)
: delegate_(delegate),
settings_(std::move(settings)),
animator_(std::move(animator)),
activity_running_(true),
have_surface_(false),
image_decoder_(task_runners,
vm.GetConcurrentWorkerTaskRunner(),
io_manager),
task_runners_(std::move(task_runners)),
weak_factory_(this) {
// Runtime controller is initialized here because it takes a reference to this
// object as its delegate. The delegate may be called in the constructor and
// we want to be fully initilazed by that point.
: Engine(delegate,
dispatcher_maker,
vm.GetConcurrentWorkerTaskRunner(),
task_runners,
settings,
std::move(animator),
io_manager,
nullptr) {
runtime_controller_ = std::make_unique<RuntimeController>(
*this, // runtime delegate
&vm, // VM
......@@ -76,8 +92,6 @@ Engine::Engine(Delegate& delegate,
settings_.isolate_shutdown_callback, // isolate shutdown callback
settings_.persistent_isolate_data // persistent isolate data
);
pointer_data_dispatcher_ = dispatcher_maker(*this);
}
Engine::~Engine() = default;
......
......@@ -248,6 +248,20 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
const std::vector<std::string>& supported_locale_data) = 0;
};
//----------------------------------------------------------------------------
/// @brief Creates an instance of the engine with a supplied
/// `RuntimeController`. Use the other constructor except for
/// tests.
///
Engine(Delegate& delegate,
const PointerDataDispatcherMaker& dispatcher_maker,
std::shared_ptr<fml::ConcurrentTaskRunner> image_decoder_task_runner,
TaskRunners task_runners,
Settings settings,
std::unique_ptr<Animator> animator,
fml::WeakPtr<IOManager> io_manager,
std::unique_ptr<RuntimeController> runtime_controller);
//----------------------------------------------------------------------------
/// @brief Creates an instance of the engine. This is done by the Shell
/// on the UI task runner.
......@@ -756,6 +770,12 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
///
const std::string& GetLastEntrypointLibrary() const;
//----------------------------------------------------------------------------
/// @brief Getter for the initial route. This can be set with a platform
/// message.
///
const std::string& InitialRoute() const { return initial_route_; }
private:
Engine::Delegate& delegate_;
const Settings settings_;
......
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// FLUTTER_NOLINT
#include "flutter/runtime/dart_vm_lifecycle.h"
#include "flutter/shell/common/engine.h"
#include "flutter/shell/common/thread_host.h"
#include "flutter/testing/testing.h"
#include "gmock/gmock.h"
#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
///\note Deprecated MOCK_METHOD macros used until this issue is resolved:
// https://github.com/google/googletest/issues/2490
namespace flutter {
namespace {
class MockDelegate : public Engine::Delegate {
MOCK_METHOD2(OnEngineUpdateSemantics,
void(SemanticsNodeUpdates, CustomAccessibilityActionUpdates));
MOCK_METHOD1(OnEngineHandlePlatformMessage,
void(fml::RefPtr<PlatformMessage>));
MOCK_METHOD0(OnPreEngineRestart, void());
MOCK_METHOD2(UpdateIsolateDescription, void(const std::string, int64_t));
MOCK_METHOD1(SetNeedsReportTimings, void(bool));
MOCK_METHOD1(ComputePlatformResolvedLocale,
std::unique_ptr<std::vector<std::string>>(
const std::vector<std::string>&));
};
class MockResponse : public PlatformMessageResponse {
public:
MOCK_METHOD1(Complete, void(std::unique_ptr<fml::Mapping> data));
MOCK_METHOD0(CompleteEmpty, void());
};
class MockRuntimeDelegate : public RuntimeDelegate {
public:
MOCK_METHOD0(DefaultRouteName, std::string());
MOCK_METHOD1(ScheduleFrame, void(bool));
MOCK_METHOD1(Render, void(std::unique_ptr<flutter::LayerTree>));
MOCK_METHOD2(UpdateSemantics,
void(SemanticsNodeUpdates, CustomAccessibilityActionUpdates));
MOCK_METHOD1(HandlePlatformMessage, void(fml::RefPtr<PlatformMessage>));
MOCK_METHOD0(GetFontCollection, FontCollection&());
MOCK_METHOD2(UpdateIsolateDescription, void(const std::string, int64_t));
MOCK_METHOD1(SetNeedsReportTimings, void(bool));
MOCK_METHOD1(ComputePlatformResolvedLocale,
std::unique_ptr<std::vector<std::string>>(
const std::vector<std::string>&));
};
class MockRuntimeController : public RuntimeController {
public:
MockRuntimeController(RuntimeDelegate& client, TaskRunners p_task_runners)
: RuntimeController(client, p_task_runners) {}
MOCK_CONST_METHOD0(IsRootIsolateRunning, bool());
MOCK_METHOD1(DispatchPlatformMessage, bool(fml::RefPtr<PlatformMessage>));
};
fml::RefPtr<PlatformMessage> MakePlatformMessage(
const std::string& channel,
const std::map<std::string, std::string>& values,
fml::RefPtr<PlatformMessageResponse> response) {
rapidjson::Document document;
auto& allocator = document.GetAllocator();
document.SetObject();
for (const auto& pair : values) {
rapidjson::Value key(pair.first.c_str(), strlen(pair.first.c_str()),
allocator);
rapidjson::Value value(pair.second.c_str(), strlen(pair.second.c_str()),
allocator);
document.AddMember(key, value, allocator);
}
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
document.Accept(writer);
const uint8_t* data = reinterpret_cast<const uint8_t*>(buffer.GetString());
fml::RefPtr<PlatformMessage> message = fml::MakeRefCounted<PlatformMessage>(
channel, std::vector<uint8_t>(data, data + buffer.GetSize()), response);
return message;
}
class EngineTest : public ::testing::Test {
public:
EngineTest()
: thread_host_("EngineTest",
ThreadHost::Type::Platform | ThreadHost::Type::IO |
ThreadHost::Type::UI | ThreadHost::Type::GPU),
task_runners_({
"EngineTest",
thread_host_.platform_thread->GetTaskRunner(), // platform
thread_host_.raster_thread->GetTaskRunner(), // raster
thread_host_.ui_thread->GetTaskRunner(), // ui
thread_host_.io_thread->GetTaskRunner() // io
}) {}
void PostUITaskSync(const std::function<void()>& function) {
fml::AutoResetWaitableEvent latch;
task_runners_.GetUITaskRunner()->PostTask([&] {
function();
latch.Signal();
});
latch.Wait();
}
protected:
void SetUp() override {
dispatcher_maker_ = [](PointerDataDispatcher::Delegate&) {
return nullptr;
};
}
MockDelegate delegate_;
PointerDataDispatcherMaker dispatcher_maker_;
ThreadHost thread_host_;
TaskRunners task_runners_;
Settings settings_;
std::unique_ptr<Animator> animator_;
fml::WeakPtr<IOManager> io_manager_;
std::unique_ptr<RuntimeController> runtime_controller_;
std::shared_ptr<fml::ConcurrentTaskRunner> image_decoder_task_runner_;
};
} // namespace
TEST_F(EngineTest, Create) {
PostUITaskSync([this] {
auto engine = std::make_unique<Engine>(
/*delegate=*/delegate_,
/*dispatcher_maker=*/dispatcher_maker_,
/*image_decoder_task_runner=*/image_decoder_task_runner_,
/*task_runners=*/task_runners_,
/*settings=*/settings_,
/*animator=*/std::move(animator_),
/*io_manager=*/io_manager_,
/*runtime_controller=*/std::move(runtime_controller_));
EXPECT_TRUE(engine);
});
}
TEST_F(EngineTest, DispatchPlatformMessageUnknown) {
PostUITaskSync([this] {
MockRuntimeDelegate client;
auto mock_runtime_controller =
std::make_unique<MockRuntimeController>(client, task_runners_);
EXPECT_CALL(*mock_runtime_controller, IsRootIsolateRunning())
.WillRepeatedly(::testing::Return(false));
auto engine = std::make_unique<Engine>(
/*delegate=*/delegate_,
/*dispatcher_maker=*/dispatcher_maker_,
/*image_decoder_task_runner=*/image_decoder_task_runner_,
/*task_runners=*/task_runners_,
/*settings=*/settings_,
/*animator=*/std::move(animator_),
/*io_manager=*/io_manager_,
/*runtime_controller=*/std::move(mock_runtime_controller));
fml::RefPtr<PlatformMessageResponse> response =
fml::MakeRefCounted<MockResponse>();
fml::RefPtr<PlatformMessage> message =
fml::MakeRefCounted<PlatformMessage>("foo", response);
engine->DispatchPlatformMessage(message);
});
}
TEST_F(EngineTest, DispatchPlatformMessageInitialRoute) {
PostUITaskSync([this] {
MockRuntimeDelegate client;
auto mock_runtime_controller =
std::make_unique<MockRuntimeController>(client, task_runners_);
EXPECT_CALL(*mock_runtime_controller, IsRootIsolateRunning())
.WillRepeatedly(::testing::Return(false));
auto engine = std::make_unique<Engine>(
/*delegate=*/delegate_,
/*dispatcher_maker=*/dispatcher_maker_,
/*image_decoder_task_runner=*/image_decoder_task_runner_,
/*task_runners=*/task_runners_,
/*settings=*/settings_,
/*animator=*/std::move(animator_),
/*io_manager=*/io_manager_,
/*runtime_controller=*/std::move(mock_runtime_controller));
fml::RefPtr<PlatformMessageResponse> response =
fml::MakeRefCounted<MockResponse>();
std::map<std::string, std::string> values{
{"method", "setInitialRoute"},
{"args", "test_initial_route"},
};
fml::RefPtr<PlatformMessage> message =
MakePlatformMessage("flutter/navigation", values, response);
engine->DispatchPlatformMessage(message);
EXPECT_EQ(engine->InitialRoute(), "test_initial_route");
});
}
TEST_F(EngineTest, DispatchPlatformMessageInitialRouteIgnored) {
PostUITaskSync([this] {
MockRuntimeDelegate client;
auto mock_runtime_controller =
std::make_unique<MockRuntimeController>(client, task_runners_);
EXPECT_CALL(*mock_runtime_controller, IsRootIsolateRunning())
.WillRepeatedly(::testing::Return(true));
EXPECT_CALL(*mock_runtime_controller, DispatchPlatformMessage(::testing::_))
.WillRepeatedly(::testing::Return(true));
auto engine = std::make_unique<Engine>(
/*delegate=*/delegate_,
/*dispatcher_maker=*/dispatcher_maker_,
/*image_decoder_task_runner=*/image_decoder_task_runner_,
/*task_runners=*/task_runners_,
/*settings=*/settings_,
/*animator=*/std::move(animator_),
/*io_manager=*/io_manager_,
/*runtime_controller=*/std::move(mock_runtime_controller));
fml::RefPtr<PlatformMessageResponse> response =
fml::MakeRefCounted<MockResponse>();
std::map<std::string, std::string> values{
{"method", "setInitialRoute"},
{"args", "test_initial_route"},
};
fml::RefPtr<PlatformMessage> message =
MakePlatformMessage("flutter/navigation", values, response);
engine->DispatchPlatformMessage(message);
EXPECT_EQ(engine->InitialRoute(), "");
});
}
} // namespace flutter
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册