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