// Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #if !__has_feature(objc_arc) #error ARC must be enabled! #endif #import #import #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h" @interface MockBinaryMessenger : NSObject @property(nonatomic, copy) NSString* channel; @property(nonatomic, strong) NSData* message; @property(nonatomic, strong) NSMutableDictionary* handlers; @end @implementation MockBinaryMessenger - (instancetype)init { self = [super init]; if (self) { _handlers = [[NSMutableDictionary alloc] init]; } return self; } - (void)sendOnChannel:(NSString*)channel message:(NSData* _Nullable)message { [self sendOnChannel:channel message:message binaryReply:nil]; } - (void)sendOnChannel:(NSString*)channel message:(NSData* _Nullable)message binaryReply:(FlutterBinaryReply _Nullable)callback { self.channel = channel; self.message = message; } - (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channel binaryMessageHandler: (FlutterBinaryMessageHandler _Nullable)handler { [self.handlers setObject:handler forKey:channel]; return 0; } - (void)cleanupConnection:(FlutterBinaryMessengerConnection)connection { } @end @interface FlutterChannelsTest : XCTestCase @end @implementation FlutterChannelsTest - (void)testMethodInvoke { NSString* channelName = @"foo"; id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); id codec = OCMProtocolMock(@protocol(FlutterMethodCodec)); FlutterMethodChannel* channel = [[FlutterMethodChannel alloc] initWithName:channelName binaryMessenger:binaryMessenger codec:codec]; XCTAssertNotNil(channel); NSData* encodedMethodCall = [@"hey" dataUsingEncoding:NSUTF8StringEncoding]; OCMStub([codec encodeMethodCall:[OCMArg any]]).andReturn(encodedMethodCall); [channel invokeMethod:@"foo" arguments:@[ @(1) ]]; OCMVerify([binaryMessenger sendOnChannel:channelName message:encodedMethodCall]); } - (void)testMethodInvokeWithReply { NSString* channelName = @"foo"; id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); id codec = OCMProtocolMock(@protocol(FlutterMethodCodec)); FlutterMethodChannel* channel = [[FlutterMethodChannel alloc] initWithName:channelName binaryMessenger:binaryMessenger codec:codec]; XCTAssertNotNil(channel); NSData* encodedMethodCall = [@"hey" dataUsingEncoding:NSUTF8StringEncoding]; OCMStub([codec encodeMethodCall:[OCMArg any]]).andReturn(encodedMethodCall); XCTestExpectation* didCallReply = [self expectationWithDescription:@"didCallReply"]; OCMExpect([binaryMessenger sendOnChannel:channelName message:encodedMethodCall binaryReply:[OCMArg checkWithBlock:^BOOL(id obj) { FlutterBinaryReply reply = obj; reply(nil); return YES; }]]); [channel invokeMethod:@"foo" arguments:@[ @1 ] result:^(id _Nullable result) { [didCallReply fulfill]; XCTAssertEqual(FlutterMethodNotImplemented, result); }]; OCMVerifyAll(binaryMessenger); [self waitForExpectationsWithTimeout:1.0 handler:nil]; } - (void)testMethodMessageHandler { NSString* channelName = @"foo"; id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); id codec = OCMProtocolMock(@protocol(FlutterMethodCodec)); FlutterMethodChannel* channel = [[FlutterMethodChannel alloc] initWithName:channelName binaryMessenger:binaryMessenger codec:codec]; XCTAssertNotNil(channel); NSData* encodedMethodCall = [@"hey" dataUsingEncoding:NSUTF8StringEncoding]; OCMStub([codec encodeMethodCall:[OCMArg any]]).andReturn(encodedMethodCall); FlutterMethodCallHandler handler = ^(FlutterMethodCall* _Nonnull call, FlutterResult _Nonnull result) { NSLog(@"hey"); }; [channel setMethodCallHandler:handler]; OCMVerify([binaryMessenger setMessageHandlerOnChannel:channelName binaryMessageHandler:[OCMArg isNotNil]]); } - (void)testCallMethodHandler { NSString* channelName = @"foo"; MockBinaryMessenger* binaryMessenger = [[MockBinaryMessenger alloc] init]; id codec = OCMProtocolMock(@protocol(FlutterMethodCodec)); FlutterMethodChannel* channel = [[FlutterMethodChannel alloc] initWithName:channelName binaryMessenger:binaryMessenger codec:codec]; XCTAssertNotNil(channel); NSData* encodedMethodCall = [@"encoded" dataUsingEncoding:NSUTF8StringEncoding]; NSData* replyData = [@"reply" dataUsingEncoding:NSUTF8StringEncoding]; NSData* replyEnvelopeData = [@"reply-envelope" dataUsingEncoding:NSUTF8StringEncoding]; FlutterMethodCall* methodCall = [[FlutterMethodCall alloc] init]; OCMStub([codec decodeMethodCall:encodedMethodCall]).andReturn(methodCall); OCMStub([codec encodeSuccessEnvelope:replyData]).andReturn(replyEnvelopeData); XCTestExpectation* didCallHandler = [self expectationWithDescription:@"didCallHandler"]; XCTestExpectation* didCallReply = [self expectationWithDescription:@"didCallReply"]; FlutterMethodCallHandler handler = ^(FlutterMethodCall* _Nonnull call, FlutterResult _Nonnull result) { XCTAssertEqual(methodCall, call); [didCallHandler fulfill]; result(replyData); }; [channel setMethodCallHandler:handler]; binaryMessenger.handlers[channelName](encodedMethodCall, ^(NSData* reply) { [didCallReply fulfill]; XCTAssertEqual(replyEnvelopeData, reply); }); [self waitForExpectationsWithTimeout:1.0 handler:nil]; } - (void)testResize { NSString* channelName = @"foo"; id binaryMessenger = OCMStrictProtocolMock(@protocol(FlutterBinaryMessenger)); id codec = OCMProtocolMock(@protocol(FlutterMethodCodec)); FlutterBasicMessageChannel* channel = [[FlutterBasicMessageChannel alloc] initWithName:channelName binaryMessenger:binaryMessenger codec:codec]; XCTAssertNotNil(channel); NSString* expectedMessageString = [NSString stringWithFormat:@"resize\r%@\r%@", channelName, @100]; NSData* expectedMessage = [expectedMessageString dataUsingEncoding:NSUTF8StringEncoding]; OCMExpect([binaryMessenger sendOnChannel:@"dev.flutter/channel-buffers" message:expectedMessage]); [channel resizeChannelBuffer:100]; OCMVerifyAll(binaryMessenger); [binaryMessenger stopMocking]; } - (void)testBasicMessageChannelCleanup { NSString* channelName = @"foo"; FlutterBinaryMessengerConnection connection = 123; id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); id codec = OCMProtocolMock(@protocol(FlutterMethodCodec)); FlutterBasicMessageChannel* channel = [[FlutterBasicMessageChannel alloc] initWithName:channelName binaryMessenger:binaryMessenger codec:codec]; FlutterMessageHandler handler = ^(id _Nullable message, FlutterReply callback) { NSLog(@"hey"); }; OCMStub([binaryMessenger setMessageHandlerOnChannel:channelName binaryMessageHandler:[OCMArg any]]) .andReturn(connection); [channel setMessageHandler:handler]; OCMVerify([binaryMessenger setMessageHandlerOnChannel:channelName binaryMessageHandler:[OCMArg isNotNil]]); [channel setMessageHandler:nil]; OCMVerify([binaryMessenger cleanupConnection:connection]); } - (void)testMethodChannelCleanup { NSString* channelName = @"foo"; FlutterBinaryMessengerConnection connection = 123; id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); id codec = OCMProtocolMock(@protocol(FlutterMethodCodec)); FlutterMethodChannel* channel = [[FlutterMethodChannel alloc] initWithName:channelName binaryMessenger:binaryMessenger codec:codec]; XCTAssertNotNil(channel); OCMStub([binaryMessenger setMessageHandlerOnChannel:channelName binaryMessageHandler:[OCMArg any]]) .andReturn(connection); FlutterMethodCallHandler handler = ^(FlutterMethodCall* _Nonnull call, FlutterResult _Nonnull result) { }; [channel setMethodCallHandler:handler]; OCMVerify([binaryMessenger setMessageHandlerOnChannel:channelName binaryMessageHandler:[OCMArg isNotNil]]); [channel setMethodCallHandler:nil]; OCMVerify([binaryMessenger cleanupConnection:connection]); } @end