Flutter macOS 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 
6 #import "flutter/shell/platform/darwin/ios/flutter_task_queue_dispatch.h"
7 
8 #import <OCMock/OCMock.h>
9 #import <XCTest/XCTest.h>
10 
12 
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));
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 - (bool)testSetWarnsOnOverflow {
172  NSString* channelName = @"flutter/test";
173  id binaryMessenger = OCMStrictProtocolMock(@protocol(FlutterBinaryMessenger));
174  id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
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));
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));
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));
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
FLUTTER_ASSERT_ARC
#define FLUTTER_ASSERT_ARC
Definition: FlutterMacros.h:44
FlutterBasicMessageChannel
Definition: FlutterChannels.h:37
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
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
FlutterBinaryMessengerConnection
int64_t FlutterBinaryMessengerConnection
Definition: FlutterBinaryMessenger.h:32
FlutterBinaryReply
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterBinaryReply)(NSData *_Nullable reply)