Flutter Engine
 
Loading...
Searching...
No Matches
FlutterAppDelegateTest.mm
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 <OCMock/OCMock.h>
6#import <XCTest/XCTest.h>
7
15
17
18@interface FlutterAppDelegateTest : XCTestCase
21@property(strong) id mockMainBundle;
22@property(strong) id mockNavigationChannel;
23@property(strong) FlutterEngine* engine;
24
25// Retain callback until the tests are done.
26// https://github.com/flutter/flutter/issues/74267
27@property(strong) id mockEngineFirstFrameCallback;
28@end
29
30@implementation FlutterAppDelegateTest
31
32- (void)setUp {
33 [super setUp];
34
35 id mockMainBundle = OCMClassMock([NSBundle class]);
36 OCMStub([mockMainBundle mainBundle]).andReturn(mockMainBundle);
37 self.mockMainBundle = mockMainBundle;
38
40 self.appDelegate = appDelegate;
41
43 self.viewController = viewController;
44
45 FlutterMethodChannel* navigationChannel = OCMClassMock([FlutterMethodChannel class]);
46 self.mockNavigationChannel = navigationChannel;
47
48 FlutterEngine* engine = OCMClassMock([FlutterEngine class]);
49 OCMStub([engine navigationChannel]).andReturn(navigationChannel);
50 OCMStub([viewController engine]).andReturn(engine);
51 self.engine = engine;
52
53 id mockEngineFirstFrameCallback = [OCMArg invokeBlockWithArgs:@NO, nil];
54 self.mockEngineFirstFrameCallback = mockEngineFirstFrameCallback;
55 OCMStub([engine waitForFirstFrame:3.0 callback:mockEngineFirstFrameCallback]);
57 return viewController;
58 };
59}
60
61- (void)tearDown {
62 // Explicitly stop mocking the NSBundle class property.
63 [self.mockMainBundle stopMocking];
64 [super tearDown];
65}
66
67- (void)testLaunchUrl {
68 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
69 .andReturn(@YES);
70
71 OCMStub([self.mockNavigationChannel
72 invokeMethod:@"pushRouteInformation"
73 arguments:@{@"location" : @"http://myApp/custom/route?query=test"}])
74 .andReturn(@YES);
75
76 BOOL result =
77 [self.appDelegate application:[UIApplication sharedApplication]
78 openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test"]
79 options:@{}];
80
81 XCTAssertTrue(result);
82 OCMVerifyAll(self.mockNavigationChannel);
83}
84
85- (void)testLaunchUrlWithDeepLinkingNotSet {
86 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
87 .andReturn(nil);
88
89 OCMStub([self.mockNavigationChannel
90 invokeMethod:@"pushRouteInformation"
91 arguments:@{@"location" : @"http://myApp/custom/route?query=test"}])
92 .andReturn(@YES);
93
94 BOOL result =
95 [self.appDelegate application:[UIApplication sharedApplication]
96 openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test"]
97 options:@{}];
98
99 XCTAssertTrue(result);
100 OCMVerifyAll(self.mockNavigationChannel);
101}
102
103- (void)testLaunchUrlWithDeepLinkingDisabled {
104 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
105 .andReturn(@NO);
106
107 BOOL result =
108 [self.appDelegate application:[UIApplication sharedApplication]
109 openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test"]
110 options:@{}];
111 XCTAssertFalse(result);
112 OCMReject([self.mockNavigationChannel invokeMethod:OCMOCK_ANY arguments:OCMOCK_ANY]);
113}
114
115- (void)testLaunchUrlWithQueryParameterAndFragment {
116 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
117 .andReturn(@YES);
118 OCMStub([self.mockNavigationChannel
119 invokeMethod:@"pushRouteInformation"
120 arguments:@{@"location" : @"http://myApp/custom/route?query=test#fragment"}])
121 .andReturn(@YES);
122 BOOL result = [self.appDelegate
123 application:[UIApplication sharedApplication]
124 openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test#fragment"]
125 options:@{}];
126 XCTAssertTrue(result);
127 OCMVerifyAll(self.mockNavigationChannel);
128}
129
130- (void)testLaunchUrlWithFragmentNoQueryParameter {
131 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
132 .andReturn(@YES);
133 OCMStub([self.mockNavigationChannel
134 invokeMethod:@"pushRouteInformation"
135 arguments:@{@"location" : @"http://myApp/custom/route#fragment"}])
136 .andReturn(@YES);
137 BOOL result =
138 [self.appDelegate application:[UIApplication sharedApplication]
139 openURL:[NSURL URLWithString:@"http://myApp/custom/route#fragment"]
140 options:@{}];
141 XCTAssertTrue(result);
142 OCMVerifyAll(self.mockNavigationChannel);
143}
144
145- (void)testReleasesWindowOnDealloc {
146 __weak UIWindow* weakWindow;
147 @autoreleasepool {
148 id mockWindow = OCMClassMock([UIWindow class]);
150 appDelegate.window = mockWindow;
151 weakWindow = mockWindow;
152 XCTAssertNotNil(weakWindow);
153 [mockWindow stopMocking];
154 mockWindow = nil;
155 appDelegate = nil;
156 }
157 // App delegate has released the window.
158 XCTAssertNil(weakWindow);
159}
160
161- (void)testGrabLaunchEngine {
162 // Clear out the mocking of the root view controller.
163 [self.mockMainBundle stopMocking];
164 self.appDelegate.rootFlutterViewControllerGetter = nil;
165 // Working with plugins forces the creation of an engine.
166 XCTAssertFalse([self.appDelegate hasPlugin:@"hello"]);
167 XCTAssertNotNil([self.appDelegate takeLaunchEngine]);
168 XCTAssertNil([self.appDelegate takeLaunchEngine]);
169}
170
171- (void)testGrabLaunchEngineWithoutPlugins {
172 XCTAssertNil([self.appDelegate takeLaunchEngine]);
173}
174
175#pragma mark - Deep linking
176
177- (void)testUniversalLinkPushRouteInformation {
178 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
179 .andReturn(@YES);
180 OCMStub([self.mockNavigationChannel
181 invokeMethod:@"pushRouteInformation"
182 arguments:@{@"location" : @"http://myApp/custom/route?query=test"}])
183 .andReturn(@YES);
184 NSUserActivity* userActivity = [[NSUserActivity alloc] initWithActivityType:@"com.example.test"];
185 userActivity.webpageURL = [NSURL URLWithString:@"http://myApp/custom/route?query=test"];
186 BOOL result = [self.appDelegate
187 application:[UIApplication sharedApplication]
188 continueUserActivity:userActivity
189 restorationHandler:^(NSArray<id<UIUserActivityRestoring>>* __nullable restorableObjects){
190 }];
191 XCTAssertTrue(result);
192 OCMVerifyAll(self.mockNavigationChannel);
193}
194
195- (void)testUseNonDeprecatedOpenURLAPI {
196 OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
197 .andReturn(@YES);
198 NSUserActivity* userActivity = [[NSUserActivity alloc] initWithActivityType:@"com.example.test"];
199 userActivity.webpageURL = [NSURL URLWithString:@"http://myApp/custom/route?query=nonexist"];
200 OCMStub([self.engine sendDeepLinkToFramework:[OCMArg any] completionHandler:[OCMArg any]])
201 .andDo(^(NSInvocation* invocation) {
202 void (^handler)(BOOL success);
203 [invocation getArgument:&handler atIndex:3];
204 handler(NO);
205 });
206 id mockApplication = OCMClassMock([UIApplication class]);
207 OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
208 BOOL result = [self.appDelegate
209 application:[UIApplication sharedApplication]
210 continueUserActivity:userActivity
211 restorationHandler:^(NSArray<id<UIUserActivityRestoring>>* __nullable restorableObjects){
212 }];
213 XCTAssertTrue(result);
214 OCMVerify([mockApplication openURL:[OCMArg any]
215 options:[OCMArg any]
216 completionHandler:[OCMArg any]]);
217}
218
219- (void)testSetGetPluginRegistrant {
220 id mockRegistrant = OCMProtocolMock(@protocol(FlutterPluginRegistrant));
221 self.appDelegate.pluginRegistrant = mockRegistrant;
222 XCTAssertEqual(self.appDelegate.pluginRegistrant, mockRegistrant);
223}
224
225- (void)testSetGetPluginRegistrantSelf {
226 __weak FlutterAppDelegate* appDelegate = self.appDelegate;
227 @autoreleasepool {
229 self.appDelegate = nil;
230 }
231 // A retain cycle would keep this alive.
232 XCTAssertNil(appDelegate);
233}
234
235@end
const gchar FlBinaryMessengerMessageHandler handler
FlutterDesktopBinaryReply callback
FlutterAppLifeCycleProvider UIWindow * window
NSObject< FlutterPluginRegistrant > * pluginRegistrant
FlutterViewController *(^ rootFlutterViewControllerGetter)(void)
FlutterAppDelegate * appDelegate
FlutterViewController * viewController
const uintptr_t id
int BOOL