1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4// FLUTTER_NOLINT
5
6#include "flutter/runtime/dart_vm_lifecycle.h"
7#include "flutter/shell/common/engine.h"
8#include "flutter/shell/common/thread_host.h"
9#include "flutter/testing/testing.h"
10#include "gmock/gmock.h"
11#include "rapidjson/document.h"
12#include "rapidjson/stringbuffer.h"
13#include "rapidjson/writer.h"
14
15///\note Deprecated MOCK_METHOD macros used until this issue is resolved:
16// https://github.com/google/googletest/issues/2490
17
18namespace flutter {
19
20namespace {
21class MockDelegate : public Engine::Delegate {
22 MOCK_METHOD2(OnEngineUpdateSemantics,
23 void(SemanticsNodeUpdates, CustomAccessibilityActionUpdates));
24 MOCK_METHOD1(OnEngineHandlePlatformMessage,
25 void(fml::RefPtr<PlatformMessage>));
26 MOCK_METHOD0(OnPreEngineRestart, void());
27 MOCK_METHOD2(UpdateIsolateDescription, void(const std::string, int64_t));
28 MOCK_METHOD1(SetNeedsReportTimings, void(bool));
29 MOCK_METHOD1(ComputePlatformResolvedLocale,
30 std::unique_ptr<std::vector<std::string>>(
31 const std::vector<std::string>&));
32};
33
34class MockResponse : public PlatformMessageResponse {
35 public:
36 MOCK_METHOD1(Complete, void(std::unique_ptr<fml::Mapping> data));
37 MOCK_METHOD0(CompleteEmpty, void());
38};
39
40class MockRuntimeDelegate : public RuntimeDelegate {
41 public:
42 MOCK_METHOD0(DefaultRouteName, std::string());
43 MOCK_METHOD1(ScheduleFrame, void(bool));
44 MOCK_METHOD1(Render, void(std::unique_ptr<flutter::LayerTree>));
45 MOCK_METHOD2(UpdateSemantics,
46 void(SemanticsNodeUpdates, CustomAccessibilityActionUpdates));
47 MOCK_METHOD1(HandlePlatformMessage, void(fml::RefPtr<PlatformMessage>));
48 MOCK_METHOD0(GetFontCollection, FontCollection&());
49 MOCK_METHOD2(UpdateIsolateDescription, void(const std::string, int64_t));
50 MOCK_METHOD1(SetNeedsReportTimings, void(bool));
51 MOCK_METHOD1(ComputePlatformResolvedLocale,
52 std::unique_ptr<std::vector<std::string>>(
53 const std::vector<std::string>&));
54};
55
56class MockRuntimeController : public RuntimeController {
57 public:
58 MockRuntimeController(RuntimeDelegate& client, TaskRunners p_task_runners)
59 : RuntimeController(client, p_task_runners) {}
60 MOCK_CONST_METHOD0(IsRootIsolateRunning, bool());
61 MOCK_METHOD1(DispatchPlatformMessage, bool(fml::RefPtr<PlatformMessage>));
62};
63
64fml::RefPtr<PlatformMessage> MakePlatformMessage(
65 const std::string& channel,
66 const std::map<std::string, std::string>& values,
67 fml::RefPtr<PlatformMessageResponse> response) {
68 rapidjson::Document document;
69 auto& allocator = document.GetAllocator();
70 document.SetObject();
71
72 for (const auto& pair : values) {
73 rapidjson::Value key(pair.first.c_str(), strlen(pair.first.c_str()),
74 allocator);
75 rapidjson::Value value(pair.second.c_str(), strlen(pair.second.c_str()),
76 allocator);
77 document.AddMember(key, value, allocator);
78 }
79
80 rapidjson::StringBuffer buffer;
81 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
82 document.Accept(writer);
83 const uint8_t* data = reinterpret_cast<const uint8_t*>(buffer.GetString());
84
85 fml::RefPtr<PlatformMessage> message = fml::MakeRefCounted<PlatformMessage>(
86 channel, std::vector<uint8_t>(data, data + buffer.GetSize()), response);
87 return message;
88}
89
90class EngineTest : public ::testing::Test {
91 public:
92 EngineTest()
93 : thread_host_("EngineTest",
94 ThreadHost::Type::Platform | ThreadHost::Type::IO |
95 ThreadHost::Type::UI | ThreadHost::Type::GPU),
96 task_runners_({
97 "EngineTest",
98 thread_host_.platform_thread->GetTaskRunner(), // platform
99 thread_host_.raster_thread->GetTaskRunner(), // raster
100 thread_host_.ui_thread->GetTaskRunner(), // ui
101 thread_host_.io_thread->GetTaskRunner() // io
102 }) {}
103
104 void PostUITaskSync(const std::function<void()>& function) {
105 fml::AutoResetWaitableEvent latch;
106 task_runners_.GetUITaskRunner()->PostTask([&] {
107 function();
108 latch.Signal();
109 });
110 latch.Wait();
111 }
112
113 protected:
114 void SetUp() override {
115 dispatcher_maker_ = [](PointerDataDispatcher::Delegate&) {
116 return nullptr;
117 };
118 }
119
120 MockDelegate delegate_;
121 PointerDataDispatcherMaker dispatcher_maker_;
122 ThreadHost thread_host_;
123 TaskRunners task_runners_;
124 Settings settings_;
125 std::unique_ptr<Animator> animator_;
126 fml::WeakPtr<IOManager> io_manager_;
127 std::unique_ptr<RuntimeController> runtime_controller_;
128 std::shared_ptr<fml::ConcurrentTaskRunner> image_decoder_task_runner_;
129};
130} // namespace
131
132TEST_F(EngineTest, Create) {
133 PostUITaskSync([this] {
134 auto engine = std::make_unique<Engine>(
135 /*delegate=*/delegate_,
136 /*dispatcher_maker=*/dispatcher_maker_,
137 /*image_decoder_task_runner=*/image_decoder_task_runner_,
138 /*task_runners=*/task_runners_,
139 /*settings=*/settings_,
140 /*animator=*/std::move(animator_),
141 /*io_manager=*/io_manager_,
142 /*runtime_controller=*/std::move(runtime_controller_));
143 EXPECT_TRUE(engine);
144 });
145}
146
147TEST_F(EngineTest, DispatchPlatformMessageUnknown) {
148 PostUITaskSync([this] {
149 MockRuntimeDelegate client;
150 auto mock_runtime_controller =
151 std::make_unique<MockRuntimeController>(client, task_runners_);
152 EXPECT_CALL(*mock_runtime_controller, IsRootIsolateRunning())
153 .WillRepeatedly(::testing::Return(false));
154 auto engine = std::make_unique<Engine>(
155 /*delegate=*/delegate_,
156 /*dispatcher_maker=*/dispatcher_maker_,
157 /*image_decoder_task_runner=*/image_decoder_task_runner_,
158 /*task_runners=*/task_runners_,
159 /*settings=*/settings_,
160 /*animator=*/std::move(animator_),
161 /*io_manager=*/io_manager_,
162 /*runtime_controller=*/std::move(mock_runtime_controller));
163
164 fml::RefPtr<PlatformMessageResponse> response =
165 fml::MakeRefCounted<MockResponse>();
166 fml::RefPtr<PlatformMessage> message =
167 fml::MakeRefCounted<PlatformMessage>("foo", response);
168 engine->DispatchPlatformMessage(message);
169 });
170}
171
172TEST_F(EngineTest, DispatchPlatformMessageInitialRoute) {
173 PostUITaskSync([this] {
174 MockRuntimeDelegate client;
175 auto mock_runtime_controller =
176 std::make_unique<MockRuntimeController>(client, task_runners_);
177 EXPECT_CALL(*mock_runtime_controller, IsRootIsolateRunning())
178 .WillRepeatedly(::testing::Return(false));
179 auto engine = std::make_unique<Engine>(
180 /*delegate=*/delegate_,
181 /*dispatcher_maker=*/dispatcher_maker_,
182 /*image_decoder_task_runner=*/image_decoder_task_runner_,
183 /*task_runners=*/task_runners_,
184 /*settings=*/settings_,
185 /*animator=*/std::move(animator_),
186 /*io_manager=*/io_manager_,
187 /*runtime_controller=*/std::move(mock_runtime_controller));
188
189 fml::RefPtr<PlatformMessageResponse> response =
190 fml::MakeRefCounted<MockResponse>();
191 std::map<std::string, std::string> values{
192 {"method", "setInitialRoute"},
193 {"args", "test_initial_route"},
194 };
195 fml::RefPtr<PlatformMessage> message =
196 MakePlatformMessage("flutter/navigation", values, response);
197 engine->DispatchPlatformMessage(message);
198 EXPECT_EQ(engine->InitialRoute(), "test_initial_route");
199 });
200}
201
202TEST_F(EngineTest, DispatchPlatformMessageInitialRouteIgnored) {
203 PostUITaskSync([this] {
204 MockRuntimeDelegate client;
205 auto mock_runtime_controller =
206 std::make_unique<MockRuntimeController>(client, task_runners_);
207 EXPECT_CALL(*mock_runtime_controller, IsRootIsolateRunning())
208 .WillRepeatedly(::testing::Return(true));
209 EXPECT_CALL(*mock_runtime_controller, DispatchPlatformMessage(::testing::_))
210 .WillRepeatedly(::testing::Return(true));
211 auto engine = std::make_unique<Engine>(
212 /*delegate=*/delegate_,
213 /*dispatcher_maker=*/dispatcher_maker_,
214 /*image_decoder_task_runner=*/image_decoder_task_runner_,
215 /*task_runners=*/task_runners_,
216 /*settings=*/settings_,
217 /*animator=*/std::move(animator_),
218 /*io_manager=*/io_manager_,
219 /*runtime_controller=*/std::move(mock_runtime_controller));
220
221 fml::RefPtr<PlatformMessageResponse> response =
222 fml::MakeRefCounted<MockResponse>();
223 std::map<std::string, std::string> values{
224 {"method", "setInitialRoute"},
225 {"args", "test_initial_route"},
226 };
227 fml::RefPtr<PlatformMessage> message =
228 MakePlatformMessage("flutter/navigation", values, response);
229 engine->DispatchPlatformMessage(message);
230 EXPECT_EQ(engine->InitialRoute(), "");
231 });
232}
233
234} // namespace flutter
235