| Flutter iOS Embedder |

FlutterChannelsTest.m
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 "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h"
6 #import "flutter/shell/platform/darwin/ios/flutter_task_queue_dispatch.h"
7
8 #import <OCMock/OCMock.h>
9 #import <XCTest/XCTest.h>
10
11 FLUTTER_ASSERT_ARC
12
13 @interface MockBinaryMessenger : NSObject <FlutterBinaryMessenger>
14 @property(nonatomic, copy) NSString* channel;
15 @property(nonatomic, strong) NSData* message;
16 @property(nonatomic, strong) NSMutableDictionary<NSString*, FlutterBinaryMessageHandler>* handlers;
17 @end
18 @implementation MockBinaryMessenger
19 - (instancetype)init {
20 self = [super init];
21 if (self) {
22 _handlers = [[NSMutableDictionary<NSString*, FlutterBinaryMessageHandler> alloc] init];
23 }
24 return self;
25 }
26
27 - (void)sendOnChannel:(NSString*)channel message:(NSData* _Nullable)message {
28 [self sendOnChannel:channel message:message binaryReply:nil];
29 }
30
31 - (void)sendOnChannel:(NSString*)channel
32 message:(NSData* _Nullable)message
33 binaryReply:(FlutterBinaryReply _Nullable)callback {
34 self.channel = channel;
35 self.message = message;
36 }
37
38 - (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channel
39 binaryMessageHandler:
40 (FlutterBinaryMessageHandler _Nullable)handler {
41 [self.handlers setObject:handler forKey:channel];
42 return 0;
43 }
44
45 - (void)cleanUpConnection:(FlutterBinaryMessengerConnection)connection {
46 }
47
48 @end
49
50 @interface FlutterChannelsTest : XCTestCase
51 @end
52
53 @implementation FlutterChannelsTest
54
55 - (void)testMethodInvoke {
56 NSString* channelName = @"foo";
57 id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
58 id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
59 FlutterMethodChannel* channel = [[FlutterMethodChannel alloc] initWithName:channelName
60 binaryMessenger:binaryMessenger
61 codec:codec];
62 XCTAssertNotNil(channel);
63 NSData* encodedMethodCall = [@"hey" dataUsingEncoding:NSUTF8StringEncoding];
64 OCMStub([codec encodeMethodCall:[OCMArg any]]).andReturn(encodedMethodCall);
65 [channel invokeMethod:@"foo" arguments:@[ @(1) ]];
66 OCMVerify([binaryMessenger sendOnChannel:channelName message:encodedMethodCall]);
67 }
68
69 - (void)testMethodInvokeWithReply {
70 NSString* channelName = @"foo";
71 id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
72 id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
73 FlutterMethodChannel* channel = [[FlutterMethodChannel alloc] initWithName:channelName
74 binaryMessenger:binaryMessenger
75 codec:codec];
76 XCTAssertNotNil(channel);
77 NSData* encodedMethodCall = [@"hey" dataUsingEncoding:NSUTF8StringEncoding];
78 OCMStub([codec encodeMethodCall:[OCMArg any]]).andReturn(encodedMethodCall);
79 XCTestExpectation* didCallReply = [self expectationWithDescription:@"didCallReply"];
80 OCMExpect([binaryMessenger sendOnChannel:channelName
81 message:encodedMethodCall
82 binaryReply:[OCMArg checkWithBlock:^BOOL(id obj) {
83 FlutterBinaryReply reply = obj;
84 reply(nil);
85 return YES;
86 }]]);
87 [channel invokeMethod:@"foo"
88 arguments:@[ @1 ]
89 result:^(id _Nullable result) {
90 [didCallReply fulfill];
91 XCTAssertEqual(FlutterMethodNotImplemented, result);
92 }];
93 OCMVerifyAll(binaryMessenger);
94 [self waitForExpectationsWithTimeout:1.0 handler:nil];
95 }
96
97 - (void)testMethodMessageHandler {
98 NSString* channelName = @"foo";
99 id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
100 id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
101 FlutterMethodChannel* channel = [[FlutterMethodChannel alloc] initWithName:channelName
102 binaryMessenger:binaryMessenger
103 codec:codec];
104 XCTAssertNotNil(channel);
105
106 NSData* encodedMethodCall = [@"hey" dataUsingEncoding:NSUTF8StringEncoding];
107 OCMStub([codec encodeMethodCall:[OCMArg any]]).andReturn(encodedMethodCall);
108 FlutterMethodCallHandler handler =
109 ^(FlutterMethodCall* _Nonnull call, FlutterResult _Nonnull result) {
110 };
111 [channel setMethodCallHandler:handler];
112 OCMVerify([binaryMessenger setMessageHandlerOnChannel:channelName
113 binaryMessageHandler:[OCMArg isNotNil]]);
114 }
115
116 - (void)testCallMethodHandler {
117 NSString* channelName = @"foo";
118 MockBinaryMessenger* binaryMessenger = [[MockBinaryMessenger alloc] init];
119 id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
120 FlutterMethodChannel* channel = [[FlutterMethodChannel alloc] initWithName:channelName
121 binaryMessenger:binaryMessenger
122 codec:codec];
123 XCTAssertNotNil(channel);
124
125 NSData* encodedMethodCall = [@"encoded" dataUsingEncoding:NSUTF8StringEncoding];
126 NSData* replyData = [@"reply" dataUsingEncoding:NSUTF8StringEncoding];
127 NSData* replyEnvelopeData = [@"reply-envelope" dataUsingEncoding:NSUTF8StringEncoding];
128 FlutterMethodCall* methodCall = [[FlutterMethodCall alloc] init];
129 OCMStub([codec decodeMethodCall:encodedMethodCall]).andReturn(methodCall);
130 OCMStub([codec encodeSuccessEnvelope:replyData]).andReturn(replyEnvelopeData);
131 XCTestExpectation* didCallHandler = [self expectationWithDescription:@"didCallHandler"];
132 XCTestExpectation* didCallReply = [self expectationWithDescription:@"didCallReply"];
133 FlutterMethodCallHandler handler =
134 ^(FlutterMethodCall* _Nonnull call, FlutterResult _Nonnull result) {
135 XCTAssertEqual(methodCall, call);
136 [didCallHandler fulfill];
137 result(replyData);
138 };
139 [channel setMethodCallHandler:handler];
140 binaryMessenger.handlers[channelName](encodedMethodCall, ^(NSData* reply) {
141 [didCallReply fulfill];
142 XCTAssertEqual(replyEnvelopeData, reply);
143 });
144 [self waitForExpectationsWithTimeout:1.0 handler:nil];
145 }
146
147 - (void)testResize {
148 NSString* channelName = @"flutter/test";
149 id binaryMessenger = OCMStrictProtocolMock(@protocol(FlutterBinaryMessenger));
150 id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
151 FlutterBasicMessageChannel* channel =
152 [[FlutterBasicMessageChannel alloc] initWithName:channelName
153 binaryMessenger:binaryMessenger
154 codec:codec];
155 XCTAssertNotNil(channel);
156
157 // The expected content was created from the following Dart code:
158 // MethodCall call = MethodCall('resize', ['flutter/test',3]);
159 // StandardMethodCodec().encodeMethodCall(call).buffer.asUint8List();
160 const unsigned char bytes[] = {7, 6, 114, 101, 115, 105, 122, 101, 12, 2,
161 7, 12, 102, 108, 117, 116, 116, 101, 114, 47,
162 116, 101, 115, 116, 3, 3, 0, 0, 0};
163 NSData* expectedMessage = [NSData dataWithBytes:bytes length:sizeof(bytes)];
164
165 OCMExpect([binaryMessenger sendOnChannel:@"dev.flutter/channel-buffers" message:expectedMessage]);
166 [channel resizeChannelBuffer:3];
167 OCMVerifyAll(binaryMessenger);
168 [binaryMessenger stopMocking];
169 }
170
171 - (void)testSetWarnsOnOverflow {
172 NSString* channelName = @"flutter/test";
173 id binaryMessenger = OCMStrictProtocolMock(@protocol(FlutterBinaryMessenger));
174 id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
175 FlutterBasicMessageChannel* channel =
176 [[FlutterBasicMessageChannel alloc] initWithName:channelName
177 binaryMessenger:binaryMessenger
178 codec:codec];
179 XCTAssertNotNil(channel);
180
181 // The expected content was created from the following Dart code:
182 // MethodCall call = MethodCall('overflow',['flutter/test', true]);
183 // StandardMethodCodec().encodeMethodCall(call).buffer.asUint8List();
184 const unsigned char bytes[] = {7, 8, 111, 118, 101, 114, 102, 108, 111, 119, 12, 2, 7, 12,
185 102, 108, 117, 116, 116, 101, 114, 47, 116, 101, 115, 116, 1};
186 NSData* expectedMessage = [NSData dataWithBytes:bytes length:sizeof(bytes)];
187
188 OCMExpect([binaryMessenger sendOnChannel:@"dev.flutter/channel-buffers" message:expectedMessage]);
189 [channel setWarnsOnOverflow:NO];
190 OCMVerifyAll(binaryMessenger);
191 [binaryMessenger stopMocking];
192 }
193
194 - (void)testBasicMessageChannelCleanup {
195 NSString* channelName = @"foo";
196 FlutterBinaryMessengerConnection connection = 123;
197 id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
198 id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
199 FlutterBasicMessageChannel* channel =
200 [[FlutterBasicMessageChannel alloc] initWithName:channelName
201 binaryMessenger:binaryMessenger
202 codec:codec];
203 FlutterMessageHandler handler = ^(id _Nullable message, FlutterReply callback) {
204 };
205 OCMStub([binaryMessenger setMessageHandlerOnChannel:channelName
206 binaryMessageHandler:[OCMArg any]])
207 .andReturn(connection);
208 [channel setMessageHandler:handler];
209 OCMVerify([binaryMessenger setMessageHandlerOnChannel:channelName
210 binaryMessageHandler:[OCMArg isNotNil]]);
211 [channel setMessageHandler:nil];
212 OCMVerify([binaryMessenger cleanUpConnection:connection]);
213 }
214
215 - (void)testMethodChannelCleanup {
216 NSString* channelName = @"foo";
217 FlutterBinaryMessengerConnection connection = 123;
218 id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
219 id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
220 FlutterMethodChannel* channel = [[FlutterMethodChannel alloc] initWithName:channelName
221 binaryMessenger:binaryMessenger
222 codec:codec];
223 XCTAssertNotNil(channel);
224
225 OCMStub([binaryMessenger setMessageHandlerOnChannel:channelName
226 binaryMessageHandler:[OCMArg any]])
227 .andReturn(connection);
228
229 FlutterMethodCallHandler handler =
230 ^(FlutterMethodCall* _Nonnull call, FlutterResult _Nonnull result) {
231 };
232 [channel setMethodCallHandler:handler];
233 OCMVerify([binaryMessenger setMessageHandlerOnChannel:channelName
234 binaryMessageHandler:[OCMArg isNotNil]]);
235 [channel setMethodCallHandler:nil];
236 OCMVerify([binaryMessenger cleanUpConnection:connection]);
237 }
238
239 - (void)testBasicMessageChannelTaskQueue {
240 NSString* channelName = @"foo";
241 FlutterBinaryMessengerConnection connection = 123;
242 id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
243 id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
244 id taskQueue = OCMProtocolMock(@protocol(FlutterTaskQueueDispatch));
245 FlutterBasicMessageChannel* channel =
246 [[FlutterBasicMessageChannel alloc] initWithName:channelName
247 binaryMessenger:binaryMessenger
248 codec:codec
249 taskQueue:taskQueue];
250 FlutterMessageHandler handler = ^(id _Nullable message, FlutterReply callback) {
251 };
252 OCMStub([binaryMessenger setMessageHandlerOnChannel:channelName
253 binaryMessageHandler:[OCMArg any]
254 taskQueue:taskQueue])
255 .andReturn(connection);
256 [channel setMessageHandler:handler];
257 OCMVerify([binaryMessenger setMessageHandlerOnChannel:channelName
258 binaryMessageHandler:[OCMArg isNotNil]
259 taskQueue:taskQueue]);
260 [channel setMessageHandler:nil];
261 OCMVerify([binaryMessenger cleanUpConnection:connection]);
262 }
263
264 - (void)testBasicMessageChannelInvokeHandlerAfterChannelReleased {
265 NSString* channelName = @"foo";
266 __block NSString* handlerMessage;
267 __block FlutterBinaryMessageHandler messageHandler;
268 @autoreleasepool {
269 FlutterBinaryMessengerConnection connection = 123;
270 id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
271 id codec = OCMProtocolMock(@protocol(FlutterMessageCodec));
272 id taskQueue = OCMProtocolMock(@protocol(FlutterTaskQueueDispatch));
273 FlutterBasicMessageChannel* channel =
274 [[FlutterBasicMessageChannel alloc] initWithName:channelName
275 binaryMessenger:binaryMessenger
276 codec:codec
277 taskQueue:taskQueue];
278
279 FlutterMessageHandler handler = ^(id _Nullable message, FlutterReply callback) {
280 handlerMessage = message;
281 };
282 OCMStub([binaryMessenger
283 setMessageHandlerOnChannel:channelName
284 binaryMessageHandler:[OCMArg checkWithBlock:^BOOL(
285 FlutterBinaryMessageHandler handler) {
286 messageHandler = handler;
287 return YES;
288 }]
289 taskQueue:taskQueue])
290 .andReturn(connection);
291 OCMStub([codec decode:[OCMArg any]]).andReturn(@"decoded message");
292 [channel setMessageHandler:handler];
293 }
294 // Channel is released, messageHandler should still retain the codec. The codec
295 // internally makes a `decode` call and updates the `handlerMessage` to "decoded message".
296 messageHandler([NSData data], ^(NSData* data){
297 });
298 XCTAssertEqualObjects(handlerMessage, @"decoded message");
299 }
300
301 - (void)testMethodChannelInvokeHandlerAfterChannelReleased {
302 NSString* channelName = @"foo";
303 FlutterBinaryMessengerConnection connection = 123;
304 __block FlutterMethodCall* decodedMethodCall;
305 __block FlutterBinaryMessageHandler messageHandler;
306 @autoreleasepool {
307 id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
308 id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
309 id taskQueue = OCMProtocolMock(@protocol(FlutterTaskQueueDispatch));
310 FlutterMethodChannel* channel = [[FlutterMethodChannel alloc] initWithName:channelName
311 binaryMessenger:binaryMessenger
312 codec:codec
313 taskQueue:taskQueue];
314 FlutterMethodCallHandler handler = ^(FlutterMethodCall* call, FlutterResult result) {
315 decodedMethodCall = call;
316 };
317 OCMStub([binaryMessenger
318 setMessageHandlerOnChannel:channelName
319 binaryMessageHandler:[OCMArg checkWithBlock:^BOOL(
320 FlutterBinaryMessageHandler handler) {
321 messageHandler = handler;
322 return YES;
323 }]
324 taskQueue:taskQueue])
325 .andReturn(connection);
326 OCMStub([codec decodeMethodCall:[OCMArg any]])
327 .andReturn([FlutterMethodCall methodCallWithMethodName:@"decoded method call"
328 arguments:nil]);
329 [channel setMethodCallHandler:handler];
330 }
331 messageHandler([NSData data], ^(NSData* data){
332 });
333 XCTAssertEqualObjects(decodedMethodCall.method, @"decoded method call");
334 }
335
336 - (void)testMethodChannelTaskQueue {
337 NSString* channelName = @"foo";
338 FlutterBinaryMessengerConnection connection = 123;
339 id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
340 id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
341 id taskQueue = OCMProtocolMock(@protocol(FlutterTaskQueueDispatch));
342 FlutterMethodChannel* channel = [[FlutterMethodChannel alloc] initWithName:channelName
343 binaryMessenger:binaryMessenger
344 codec:codec
345 taskQueue:taskQueue];
346 XCTAssertNotNil(channel);
347 FlutterMethodCallHandler handler = ^(FlutterMethodCall* call, FlutterResult result) {
348 };
349 OCMStub([binaryMessenger setMessageHandlerOnChannel:channelName
350 binaryMessageHandler:[OCMArg any]
351 taskQueue:taskQueue])
352 .andReturn(connection);
353 [channel setMethodCallHandler:handler];
354 OCMVerify([binaryMessenger setMessageHandlerOnChannel:channelName
355 binaryMessageHandler:[OCMArg isNotNil]
356 taskQueue:taskQueue]);
357 [channel setMethodCallHandler:nil];
358 OCMVerify([binaryMessenger cleanUpConnection:connection]);
359 }
360
361 - (void)testEventChannelTaskQueue {
362 NSString* channelName = @"foo";
363 FlutterBinaryMessengerConnection connection = 123;
364 id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
365 id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
366 id taskQueue = OCMProtocolMock(@protocol(FlutterTaskQueueDispatch));
367 id handler = OCMProtocolMock(@protocol(FlutterStreamHandler));
368 FlutterEventChannel* channel = [[FlutterEventChannel alloc] initWithName:channelName
369 binaryMessenger:binaryMessenger
370 codec:codec
371 taskQueue:taskQueue];
372 XCTAssertNotNil(channel);
373 OCMStub([binaryMessenger setMessageHandlerOnChannel:channelName
374 binaryMessageHandler:[OCMArg any]
375 taskQueue:taskQueue])
376 .andReturn(connection);
377 [channel setStreamHandler:handler];
378 OCMVerify([binaryMessenger setMessageHandlerOnChannel:channelName
379 binaryMessageHandler:[OCMArg isNotNil]
380 taskQueue:taskQueue]);
381 [channel setStreamHandler:nil];
382 OCMVerify([binaryMessenger cleanUpConnection:connection]);
383 }
384
385 @end
FlutterBasicMessageChannel
Definition: FlutterChannels.h:37
flutter_task_queue_dispatch.h
FlutterMethodChannel
Definition: FlutterChannels.h:220
-[FlutterMethodChannel invokeMethod:arguments:result:]
void invokeMethod:arguments:result:(NSString *method,[arguments] id _Nullable arguments,[result] FlutterResult _Nullable callback)
FlutterChannels.h
FlutterMethodCallHandler
void(^ FlutterMethodCallHandler)(FlutterMethodCall *call, FlutterResult result)
Definition: FlutterChannels.h:206
FlutterEventChannel
Definition: FlutterChannels.h:400
-[FlutterBasicMessageChannel resizeChannelBuffer:]
void resizeChannelBuffer:(NSInteger newSize)
Definition: FlutterChannels.mm:152
FlutterBinaryMessageHandler
void(^ FlutterBinaryMessageHandler)(NSData *_Nullable message, FlutterBinaryReply reply)
Definition: FlutterBinaryMessenger.h:30
-[FlutterMethodChannel invokeMethod:arguments:]
void invokeMethod:arguments:(NSString *method,[arguments] id _Nullable arguments)
-[FlutterMethodChannel setMethodCallHandler:]
void setMethodCallHandler:(FlutterMethodCallHandler _Nullable handler)
MockBinaryMessenger::handlers
NSMutableDictionary< NSString *, FlutterBinaryMessageHandler > * handlers
Definition: FlutterChannelsTest.m:16
MockBinaryMessenger::channel
NSString * channel
Definition: FlutterChannelsTest.m:14
FlutterMethodCall
Definition: FlutterCodecs.h:220
FlutterChannelsTest
Definition: FlutterChannelsTest.m:50
FlutterResult
void(^ FlutterResult)(id _Nullable result)
Definition: FlutterChannels.h:194
-[FlutterEventChannel setStreamHandler:]
void setStreamHandler:(NSObject< FlutterStreamHandler > *_Nullable handler)
MockBinaryMessenger
Definition: FlutterChannelsTest.m:13
FlutterReply
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterReply)(id _Nullable reply)
-[FlutterBasicMessageChannel setWarnsOnOverflow:]
void setWarnsOnOverflow:(BOOL warns)
Definition: FlutterChannels.mm:162
FlutterTaskQueueDispatch-p
Definition: flutter_task_queue_dispatch.h:16
FlutterMessageCodec-p
Definition: FlutterCodecs.h:18
FlutterStreamHandler-p
Definition: FlutterChannels.h:356
-[FlutterBasicMessageChannel setMessageHandler:]
void setMessageHandler:(FlutterMessageHandler _Nullable handler)
MockBinaryMessenger::message
NSData * message
Definition: FlutterChannelsTest.m:15
FlutterMessageHandler
void(^ FlutterMessageHandler)(id _Nullable message, FlutterReply callback)
Definition: FlutterChannels.h:30
FlutterBinaryMessenger-p
Definition: FlutterBinaryMessenger.h:49
FLUTTER_ASSERT_ARC
Definition: FlutterChannelKeyResponder.mm:13
FlutterBinaryMessengerConnection
int64_t FlutterBinaryMessengerConnection
Definition: FlutterBinaryMessenger.h:32
FlutterBinaryReply
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterBinaryReply)(NSData *_Nullable reply)