diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEnginePlatformViewTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterEnginePlatformViewTest.mm index 53d8688077068..2af636a71c13e 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEnginePlatformViewTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEnginePlatformViewTest.mm @@ -87,17 +87,24 @@ - (void)testCallsNotifyLowMemory { OCMVerify([mockEngine notifyLowMemory]); OCMReject([mockEngine notifyLowMemory]); + XCTNSNotificationExpectation* memoryExpectation = [[XCTNSNotificationExpectation alloc] + initWithName:UIApplicationDidReceiveMemoryWarningNotification]; [[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidReceiveMemoryWarningNotification object:nil]; + [self waitForExpectations:@[ memoryExpectation ] timeout:5.0]; OCMVerify([mockEngine notifyLowMemory]); OCMReject([mockEngine notifyLowMemory]); + XCTNSNotificationExpectation* backgroundExpectation = [[XCTNSNotificationExpectation alloc] + initWithName:UIApplicationDidEnterBackgroundNotification]; [[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidEnterBackgroundNotification object:nil]; + [self waitForExpectations:@[ backgroundExpectation ] timeout:5.0]; OCMVerify([mockEngine notifyLowMemory]); + [mockEngine stopMocking]; } @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegateTest.m b/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegateTest.m index 21501c7421f3f..9891f52cf8c0c 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegateTest.m +++ b/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegateTest.m @@ -11,7 +11,6 @@ FLUTTER_ASSERT_ARC @interface FlutterPluginAppLifeCycleDelegateTest : XCTestCase - @end @implementation FlutterPluginAppLifeCycleDelegateTest @@ -22,51 +21,71 @@ - (void)testCreate { } - (void)testDidEnterBackground { + XCTNSNotificationExpectation* expectation = [[XCTNSNotificationExpectation alloc] + initWithName:UIApplicationDidEnterBackgroundNotification]; FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init]; id plugin = OCMProtocolMock(@protocol(FlutterPlugin)); [delegate addDelegate:plugin]; [[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidEnterBackgroundNotification object:nil]; + + [self waitForExpectations:@[ expectation ] timeout:5.0]; OCMVerify([plugin applicationDidEnterBackground:[UIApplication sharedApplication]]); } - (void)testWillEnterForeground { + XCTNSNotificationExpectation* expectation = [[XCTNSNotificationExpectation alloc] + initWithName:UIApplicationWillEnterForegroundNotification]; + FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init]; id plugin = OCMProtocolMock(@protocol(FlutterPlugin)); [delegate addDelegate:plugin]; [[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationWillEnterForegroundNotification object:nil]; + [self waitForExpectations:@[ expectation ] timeout:5.0]; OCMVerify([plugin applicationWillEnterForeground:[UIApplication sharedApplication]]); } -- (void)skip_testWillResignActive { +- (void)testWillResignActive { + XCTNSNotificationExpectation* expectation = + [[XCTNSNotificationExpectation alloc] initWithName:UIApplicationWillResignActiveNotification]; + FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init]; id plugin = OCMProtocolMock(@protocol(FlutterPlugin)); [delegate addDelegate:plugin]; [[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationWillResignActiveNotification object:nil]; + [self waitForExpectations:@[ expectation ] timeout:5.0]; OCMVerify([plugin applicationWillResignActive:[UIApplication sharedApplication]]); } -- (void)skip_testDidBecomeActive { +- (void)testDidBecomeActive { + XCTNSNotificationExpectation* expectation = + [[XCTNSNotificationExpectation alloc] initWithName:UIApplicationDidBecomeActiveNotification]; + FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init]; id plugin = OCMProtocolMock(@protocol(FlutterPlugin)); [delegate addDelegate:plugin]; [[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidBecomeActiveNotification object:nil]; + [self waitForExpectations:@[ expectation ] timeout:5.0]; OCMVerify([plugin applicationDidBecomeActive:[UIApplication sharedApplication]]); } - (void)testWillTerminate { + XCTNSNotificationExpectation* expectation = + [[XCTNSNotificationExpectation alloc] initWithName:UIApplicationWillTerminateNotification]; + FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init]; id plugin = OCMProtocolMock(@protocol(FlutterPlugin)); [delegate addDelegate:plugin]; [[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationWillTerminateNotification object:nil]; + [self waitForExpectations:@[ expectation ] timeout:5.0]; OCMVerify([plugin applicationWillTerminate:[UIApplication sharedApplication]]); } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.m b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.m index 4e7a3b610819c..06f53c39ff7cb 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.m +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.m @@ -885,9 +885,8 @@ - (void)testFlutterTokenizerCanParseLines { - (void)testFlutterTextInputPluginRetainsFlutterTextInputView { FlutterTextInputPlugin* myInputPlugin; - id myEngine = OCMClassMock([FlutterEngine class]); myInputPlugin = [[FlutterTextInputPlugin alloc] init]; - myInputPlugin.textInputDelegate = myEngine; + myInputPlugin.textInputDelegate = engine; __weak UIView* activeView; @autoreleasepool { FlutterMethodCall* setClientCall = [FlutterMethodCall diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm index a70387182e185..83c62f0518a5c 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm @@ -16,6 +16,22 @@ class PointerDataPacket {}; } +/// Sometimes we have to use a custom mock to avoid retain cycles in ocmock. +@interface FlutterEnginePartialMock : FlutterEngine +@property(nonatomic, strong) FlutterBasicMessageChannel* lifecycleChannel; +@property(nonatomic, weak) FlutterViewController* viewController; +@property(nonatomic, assign) BOOL didCallNotifyLowMemory; +@end + +@implementation FlutterEnginePartialMock +@synthesize viewController; +@synthesize lifecycleChannel; + +- (void)notifyLowMemory { + _didCallNotifyLowMemory = YES; +} +@end + @interface FlutterEngine () - (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryURI @@ -87,14 +103,15 @@ - (void)tearDown { - (void)testViewDidDisappearDoesntPauseEngineWhenNotTheViewController { id lifecycleChannel = OCMClassMock([FlutterBasicMessageChannel class]); - OCMStub([self.mockEngine lifecycleChannel]).andReturn(lifecycleChannel); + FlutterEnginePartialMock* mockEngine = [[FlutterEnginePartialMock alloc] init]; + mockEngine.lifecycleChannel = lifecycleChannel; FlutterViewController* viewControllerA = [[FlutterViewController alloc] initWithEngine:self.mockEngine nibName:nil bundle:nil]; FlutterViewController* viewControllerB = [[FlutterViewController alloc] initWithEngine:self.mockEngine nibName:nil bundle:nil]; id viewControllerMock = OCMPartialMock(viewControllerA); OCMStub([viewControllerMock surfaceUpdated:NO]); - OCMStub([self.mockEngine viewController]).andReturn(viewControllerB); + mockEngine.viewController = viewControllerB; [viewControllerA viewDidDisappear:NO]; OCMReject([lifecycleChannel sendMessage:@"AppLifecycleState.paused"]); OCMReject([viewControllerMock surfaceUpdated:[OCMArg any]]); @@ -102,15 +119,21 @@ - (void)testViewDidDisappearDoesntPauseEngineWhenNotTheViewController { - (void)testViewDidDisappearDoesPauseEngineWhenIsTheViewController { id lifecycleChannel = OCMClassMock([FlutterBasicMessageChannel class]); - OCMStub([self.mockEngine lifecycleChannel]).andReturn(lifecycleChannel); - FlutterViewController* viewController = - [[FlutterViewController alloc] initWithEngine:self.mockEngine nibName:nil bundle:nil]; - id viewControllerMock = OCMPartialMock(viewController); - OCMStub([viewControllerMock surfaceUpdated:NO]); - OCMStub([self.mockEngine viewController]).andReturn(viewController); - [viewController viewDidDisappear:NO]; - OCMVerify([lifecycleChannel sendMessage:@"AppLifecycleState.paused"]); - OCMVerify([viewControllerMock surfaceUpdated:NO]); + FlutterEnginePartialMock* mockEngine = [[FlutterEnginePartialMock alloc] init]; + mockEngine.lifecycleChannel = lifecycleChannel; + __weak FlutterViewController* weakViewController; + @autoreleasepool { + FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:mockEngine + nibName:nil + bundle:nil]; + weakViewController = viewController; + id viewControllerMock = OCMPartialMock(viewController); + OCMStub([viewControllerMock surfaceUpdated:NO]); + [viewController viewDidDisappear:NO]; + OCMVerify([lifecycleChannel sendMessage:@"AppLifecycleState.paused"]); + OCMVerify([viewControllerMock surfaceUpdated:NO]); + } + XCTAssertNil(weakViewController); } - (void)testBinaryMessenger { @@ -528,15 +551,16 @@ - (void)testHideOverlay { } - (void)testNotifyLowMemory { - FlutterViewController* viewController = - [[FlutterViewController alloc] initWithEngine:self.mockEngine nibName:nil bundle:nil]; - OCMStub([self.mockEngine viewController]).andReturn(viewController); + FlutterEnginePartialMock* mockEngine = [[FlutterEnginePartialMock alloc] init]; + FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:mockEngine + nibName:nil + bundle:nil]; id viewControllerMock = OCMPartialMock(viewController); OCMStub([viewControllerMock surfaceUpdated:NO]); - [viewController beginAppearanceTransition:NO animated:NO]; [viewController endAppearanceTransition]; - OCMVerify([self.mockEngine notifyLowMemory]); + XCTAssertTrue(mockEngine.didCallNotifyLowMemory); + [viewControllerMock stopMocking]; } - (void)testValidKeyUpEvent API_AVAILABLE(ios(13.4)) { diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm b/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm index 41f8072afd858..260a7eb19a115 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm @@ -970,5 +970,6 @@ - (void)testAccessibilityMessageAfterDeletion { }); latch.Wait(); OCMVerify([messenger cleanupConnection:connection]); + [engine stopMocking]; } @end