Flutter iOS Embedder
platform_message_handler_ios_test.mm
Go to the documentation of this file.
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 
5 #import <XCTest/XCTest.h>
6 
8 
9 #import "flutter/common/task_runners.h"
10 #import "flutter/fml/message_loop.h"
11 #import "flutter/fml/thread.h"
12 #import "flutter/lib/ui/window/platform_message.h"
13 #import "flutter/lib/ui/window/platform_message_response.h"
14 #import "flutter/shell/common/thread_host.h"
16 
18 
19 // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks)
20 namespace {
21 using namespace flutter;
22 fml::RefPtr<fml::TaskRunner> CreateNewThread(const std::string& name) {
23  auto thread = std::make_unique<fml::Thread>(name);
24  auto runner = thread->GetTaskRunner();
25  return runner;
26 }
27 
28 fml::RefPtr<fml::TaskRunner> GetCurrentTaskRunner() {
29  fml::MessageLoop::EnsureInitializedForCurrentThread();
30  return fml::MessageLoop::GetCurrent().GetTaskRunner();
31 }
32 
33 class MockPlatformMessageResponse : public PlatformMessageResponse {
34  public:
35  static fml::RefPtr<MockPlatformMessageResponse> Create() {
36  return fml::AdoptRef(new MockPlatformMessageResponse());
37  }
38  void Complete(std::unique_ptr<fml::Mapping> data) override { is_complete_ = true; }
39  void CompleteEmpty() override { is_complete_ = true; }
40 };
41 } // namespace
42 
43 @interface PlatformMessageHandlerIosTest : XCTestCase
44 @end
45 
46 @implementation PlatformMessageHandlerIosTest
47 - (void)testCreate {
48  TaskRunners task_runners("test", GetCurrentTaskRunner(), CreateNewThread("raster"),
49  CreateNewThread("ui"), CreateNewThread("io"));
50  auto handler = std::make_unique<PlatformMessageHandlerIos>(task_runners.GetPlatformTaskRunner());
51  XCTAssertTrue(handler);
52 }
53 
54 - (void)testSetAndCallHandler {
55  ThreadHost thread_host("io.flutter.test." + std::string(self.name.UTF8String),
56  ThreadHost::Type::kRaster | ThreadHost::Type::kIo | ThreadHost::Type::kUi);
57  TaskRunners task_runners(
58  "test", GetCurrentTaskRunner(), thread_host.raster_thread->GetTaskRunner(),
59  thread_host.ui_thread->GetTaskRunner(), thread_host.io_thread->GetTaskRunner());
60 
61  auto handler = std::make_unique<PlatformMessageHandlerIos>(task_runners.GetPlatformTaskRunner());
62  std::string channel = "foo";
63  XCTestExpectation* didCallReply = [self expectationWithDescription:@"didCallReply"];
64  handler->SetMessageHandler(
65  channel,
66  ^(NSData* _Nullable data, FlutterBinaryReply _Nonnull reply) {
67  reply(nil);
68  [didCallReply fulfill];
69  },
70  nil);
71  auto response = MockPlatformMessageResponse::Create();
72  task_runners.GetUITaskRunner()->PostTask([channel, response, &handler] {
73  auto platform_message = std::make_unique<flutter::PlatformMessage>(channel, response);
74  handler->HandlePlatformMessage(std::move(platform_message));
75  });
76  [self waitForExpectationsWithTimeout:1.0 handler:nil];
77  XCTAssertTrue(response->is_complete());
78 }
79 
80 - (void)testSetClearAndCallHandler {
81  ThreadHost thread_host("io.flutter.test." + std::string(self.name.UTF8String),
82  ThreadHost::Type::kRaster | ThreadHost::Type::kIo | ThreadHost::Type::kUi);
83  TaskRunners task_runners(
84  "test", GetCurrentTaskRunner(), thread_host.raster_thread->GetTaskRunner(),
85  thread_host.ui_thread->GetTaskRunner(), thread_host.io_thread->GetTaskRunner());
86 
87  auto handler = std::make_unique<PlatformMessageHandlerIos>(task_runners.GetPlatformTaskRunner());
88  std::string channel = "foo";
89  XCTestExpectation* didCallMessage = [self expectationWithDescription:@"didCallMessage"];
90  handler->SetMessageHandler(
91  channel,
92  ^(NSData* _Nullable data, FlutterBinaryReply _Nonnull reply) {
93  XCTFail(@"This shouldn't be called");
94  reply(nil);
95  },
96  nil);
97  handler->SetMessageHandler(channel, nil, nil);
98  auto response = MockPlatformMessageResponse::Create();
99  task_runners.GetUITaskRunner()->PostTask([channel, response, &handler, &didCallMessage] {
100  auto platform_message = std::make_unique<flutter::PlatformMessage>(channel, response);
101  handler->HandlePlatformMessage(std::move(platform_message));
102  [didCallMessage fulfill];
103  });
104  [self waitForExpectationsWithTimeout:1.0 handler:nil];
105  XCTAssertTrue(response->is_complete());
106 }
107 
108 - (void)testSetAndCallHandlerTaskQueue {
109  ThreadHost thread_host("io.flutter.test." + std::string(self.name.UTF8String),
110  ThreadHost::Type::kRaster | ThreadHost::Type::kIo | ThreadHost::Type::kUi);
111  TaskRunners task_runners(
112  "test", GetCurrentTaskRunner(), thread_host.raster_thread->GetTaskRunner(),
113  thread_host.ui_thread->GetTaskRunner(), thread_host.io_thread->GetTaskRunner());
114 
115  auto handler = std::make_unique<PlatformMessageHandlerIos>(task_runners.GetPlatformTaskRunner());
116  std::string channel = "foo";
117  XCTestExpectation* didCallReply = [self expectationWithDescription:@"didCallReply"];
118  NSObject<FlutterTaskQueue>* taskQueue = PlatformMessageHandlerIos::MakeBackgroundTaskQueue();
119  handler->SetMessageHandler(
120  channel,
121  ^(NSData* _Nullable data, FlutterBinaryReply _Nonnull reply) {
122  XCTAssertFalse([NSThread isMainThread]);
123  reply(nil);
124  [didCallReply fulfill];
125  },
126  taskQueue);
127  auto response = MockPlatformMessageResponse::Create();
128  task_runners.GetUITaskRunner()->PostTask([channel, response, &handler] {
129  auto platform_message = std::make_unique<flutter::PlatformMessage>(channel, response);
130  handler->HandlePlatformMessage(std::move(platform_message));
131  });
132  [self waitForExpectationsWithTimeout:1.0 handler:nil];
133  XCTAssertTrue(response->is_complete());
134 }
135 @end
136 // NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterBinaryReply)(NSData *_Nullable reply)
void Complete(std::unique_ptr< fml::Mapping > data) override
static fml::RefPtr< MockPlatformMessageResponse > Create()
fml::RefPtr< fml::TaskRunner > CreateNewThread(const std::string &name)
fml::RefPtr< fml::TaskRunner > GetCurrentTaskRunner()