| Flutter iOS Embedder |

FlutterPluginAppLifeCycleDelegateTest.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
8 #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h"
9 #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h"
10 #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterSceneLifeCycle.h"
11 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate_internal.h"
12 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSharedApplication.h"
13
14 FLUTTER_ASSERT_ARC
15
16 @protocol TestFlutterPluginWithSceneEvents <NSObject,
17 FlutterApplicationLifeCycleDelegate,
18 FlutterSceneLifeCycleDelegate>
19 @end
20
21 @interface FakeTestFlutterPluginWithSceneEvents : NSObject <TestFlutterPluginWithSceneEvents>
22 @end
23
24 @implementation FakeTestFlutterPluginWithSceneEvents
25 - (BOOL)application:(UIApplication*)application
26 didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
27 return NO;
28 }
29
30 - (BOOL)application:(UIApplication*)application
31 openURL:(NSURL*)url
32 options:(NSDictionary<UIApplicationOpenURLOptionsKey, id>*)options {
33 return YES;
34 }
35
36 - (BOOL)application:(UIApplication*)application
37 continueUserActivity:(NSUserActivity*)userActivity
38 restorationHandler:(void (^)(NSArray*))restorationHandler {
39 return YES;
40 }
41
42 - (BOOL)application:(UIApplication*)application
43 performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem
44 completionHandler:(void (^)(BOOL succeeded))completionHandler
45 API_AVAILABLE(ios(9.0)) {
46 return YES;
47 }
48 @end
49
50 @interface FakePlugin : NSObject <FlutterApplicationLifeCycleDelegate>
51 @end
52
53 @implementation FakePlugin
54 - (BOOL)application:(UIApplication*)application
55 openURL:(NSURL*)url
56 options:(NSDictionary<UIApplicationOpenURLOptionsKey, id>*)options {
57 return YES;
58 }
59
60 - (BOOL)application:(UIApplication*)application
61 continueUserActivity:(NSUserActivity*)userActivity
62 restorationHandler:(void (^)(NSArray*))restorationHandler {
63 return YES;
64 }
65
66 - (BOOL)application:(UIApplication*)application
67 performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem
68 completionHandler:(void (^)(BOOL succeeded))completionHandler
69 API_AVAILABLE(ios(9.0)) {
70 return YES;
71 }
72
73 - (BOOL)application:(UIApplication*)application
74 didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
75 return YES;
76 }
77
78 - (BOOL)application:(UIApplication*)application
79 willFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
80 return YES;
81 }
82 @end
83
84 @interface FlutterPluginAppLifeCycleDelegateTest : XCTestCase
85 @end
86
87 @implementation FlutterPluginAppLifeCycleDelegateTest
88
89 - (void)testCreate {
90 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
91 XCTAssertNotNil(delegate);
92 }
93
94 - (void)testSceneWillConnectFallback {
95 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
96 id plugin = [[FakePlugin alloc] init];
97 id mockPlugin = OCMPartialMock(plugin);
98 [delegate addDelegate:mockPlugin];
99
100 id mockOptions = OCMClassMock([UISceneConnectionOptions class]);
101 id mockShortcutItem = OCMClassMock([UIApplicationShortcutItem class]);
102 OCMStub([mockOptions shortcutItem]).andReturn(mockShortcutItem);
103 OCMStub([mockOptions sourceApplication]).andReturn(@"bundle_id");
104 id urlContext = OCMClassMock([UIOpenURLContext class]);
105 NSURL* url = [NSURL URLWithString:@"http://example.com"];
106 OCMStub([urlContext URL]).andReturn(url);
107 NSSet<UIOpenURLContext*>* urlContexts = [NSSet setWithObjects:urlContext, nil];
108 OCMStub([mockOptions URLContexts]).andReturn(urlContexts);
109
110 NSDictionary<UIApplicationOpenURLOptionsKey, id>* expectedApplicationOptions = @{
111 UIApplicationLaunchOptionsShortcutItemKey : mockShortcutItem,
112 UIApplicationLaunchOptionsSourceApplicationKey : @"bundle_id",
113 UIApplicationLaunchOptionsURLKey : url,
114 };
115
116 [delegate sceneWillConnectFallback:mockOptions];
117 OCMVerify([mockPlugin application:[UIApplication sharedApplication]
118 didFinishLaunchingWithOptions:expectedApplicationOptions]);
119 }
120
121 - (void)testSceneWillConnectFallbackSkippedSupportsScenes {
122 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
123 id plugin = [[FakeTestFlutterPluginWithSceneEvents alloc] init];
124 id mockPlugin = OCMPartialMock(plugin);
125 [delegate addDelegate:mockPlugin];
126
127 id mockOptions = OCMClassMock([UISceneConnectionOptions class]);
128 id mockShortcutItem = OCMClassMock([UIApplicationShortcutItem class]);
129 OCMStub([mockOptions shortcutItem]).andReturn(mockShortcutItem);
130 OCMStub([mockOptions sourceApplication]).andReturn(@"bundle_id");
131 id urlContext = OCMClassMock([UIOpenURLContext class]);
132 NSURL* url = [NSURL URLWithString:@"http://example.com"];
133 OCMStub([urlContext URL]).andReturn(url);
134 NSSet<UIOpenURLContext*>* urlContexts = [NSSet setWithObjects:urlContext, nil];
135 OCMStub([mockOptions URLContexts]).andReturn(urlContexts);
136
137 [delegate sceneWillConnectFallback:mockOptions];
138 OCMReject([mockPlugin application:[OCMArg any] didFinishLaunchingWithOptions:[OCMArg any]]);
139 }
140
141 - (void)testSceneWillConnectFallbackSkippedNoOptions {
142 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
143 id plugin = [[FakePlugin alloc] init];
144 id mockPlugin = OCMPartialMock(plugin);
145 [delegate addDelegate:mockPlugin];
146
147 id mockOptions = OCMClassMock([UISceneConnectionOptions class]);
148
149 [delegate sceneWillConnectFallback:mockOptions];
150 OCMReject([mockPlugin application:[OCMArg any] didFinishLaunchingWithOptions:[OCMArg any]]);
151 }
152
153 - (void)testDidEnterBackground {
154 XCTNSNotificationExpectation* expectation = [[XCTNSNotificationExpectation alloc]
155 initWithName:UIApplicationDidEnterBackgroundNotification];
156 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
157 id plugin = OCMProtocolMock(@protocol(FlutterPlugin));
158 [delegate addDelegate:plugin];
159 [[NSNotificationCenter defaultCenter]
160 postNotificationName:UIApplicationDidEnterBackgroundNotification
161 object:nil];
162
163 [self waitForExpectations:@[ expectation ] timeout:5.0];
164 OCMVerify([plugin applicationDidEnterBackground:[UIApplication sharedApplication]]);
165 }
166
167 - (void)testDidEnterBackgroundWithUIScene {
168 XCTNSNotificationExpectation* expectation = [[XCTNSNotificationExpectation alloc]
169 initWithName:UIApplicationDidEnterBackgroundNotification];
170 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
171 id mockApplication = OCMClassMock([FlutterSharedApplication class]);
172 OCMStub([mockApplication hasSceneDelegate]).andReturn(YES);
173 id plugin = OCMProtocolMock(@protocol(FlutterPlugin));
174 [delegate addDelegate:plugin];
175 [[NSNotificationCenter defaultCenter]
176 postNotificationName:UIApplicationDidEnterBackgroundNotification
177 object:nil];
178
179 [self waitForExpectations:@[ expectation ] timeout:5.0];
180 OCMReject([plugin applicationDidEnterBackground:[OCMArg any]]);
181 }
182
183 - (void)testSceneDidEnterBackgroundFallback {
184 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
185 id plugin = OCMProtocolMock(@protocol(FlutterPlugin));
186 [delegate addDelegate:plugin];
187
188 [delegate sceneDidEnterBackgroundFallback];
189 OCMVerify([plugin applicationDidEnterBackground:[UIApplication sharedApplication]]);
190 }
191
192 - (void)testUnnecessarySceneDidEnterBackgroundFallback {
193 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
194 id plugin = OCMProtocolMock(@protocol(TestFlutterPluginWithSceneEvents));
195 [delegate addDelegate:plugin];
196
197 [delegate sceneDidEnterBackgroundFallback];
198 OCMReject([plugin applicationDidEnterBackground:[OCMArg any]]);
199 }
200
201 - (void)testWillEnterForeground {
202 XCTNSNotificationExpectation* expectation = [[XCTNSNotificationExpectation alloc]
203 initWithName:UIApplicationWillEnterForegroundNotification];
204
205 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
206 id plugin = OCMProtocolMock(@protocol(FlutterPlugin));
207 [delegate addDelegate:plugin];
208 [[NSNotificationCenter defaultCenter]
209 postNotificationName:UIApplicationWillEnterForegroundNotification
210 object:nil];
211 [self waitForExpectations:@[ expectation ] timeout:5.0];
212 OCMVerify([plugin applicationWillEnterForeground:[UIApplication sharedApplication]]);
213 }
214
215 - (void)testWillEnterForegroundWithUIScene {
216 XCTNSNotificationExpectation* expectation = [[XCTNSNotificationExpectation alloc]
217 initWithName:UIApplicationWillEnterForegroundNotification];
218 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
219 id mockApplication = OCMClassMock([FlutterSharedApplication class]);
220 OCMStub([mockApplication hasSceneDelegate]).andReturn(YES);
221 id plugin = OCMProtocolMock(@protocol(FlutterPlugin));
222 [delegate addDelegate:plugin];
223 [[NSNotificationCenter defaultCenter]
224 postNotificationName:UIApplicationWillEnterForegroundNotification
225 object:nil];
226
227 [self waitForExpectations:@[ expectation ] timeout:5.0];
228 OCMReject([plugin applicationWillEnterForeground:[OCMArg any]]);
229 }
230
231 - (void)testSceneWillEnterForegroundFallback {
232 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
233 id plugin = OCMProtocolMock(@protocol(FlutterPlugin));
234 [delegate addDelegate:plugin];
235
236 [delegate sceneWillEnterForegroundFallback];
237 OCMVerify([plugin applicationWillEnterForeground:[UIApplication sharedApplication]]);
238 }
239
240 - (void)testUnnecessarySceneWillEnterForegroundFallback {
241 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
242 id plugin = OCMProtocolMock(@protocol(TestFlutterPluginWithSceneEvents));
243 [delegate addDelegate:plugin];
244
245 [delegate sceneWillEnterForegroundFallback];
246 OCMReject([plugin applicationWillEnterForeground:[OCMArg any]]);
247 }
248
249 - (void)testWillResignActive {
250 XCTNSNotificationExpectation* expectation =
251 [[XCTNSNotificationExpectation alloc] initWithName:UIApplicationWillResignActiveNotification];
252
253 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
254 id plugin = OCMProtocolMock(@protocol(FlutterPlugin));
255 [delegate addDelegate:plugin];
256 [[NSNotificationCenter defaultCenter]
257 postNotificationName:UIApplicationWillResignActiveNotification
258 object:nil];
259 [self waitForExpectations:@[ expectation ] timeout:5.0];
260 OCMVerify([plugin applicationWillResignActive:[UIApplication sharedApplication]]);
261 }
262
263 - (void)testWillResignActiveWithUIScene {
264 XCTNSNotificationExpectation* expectation =
265 [[XCTNSNotificationExpectation alloc] initWithName:UIApplicationWillResignActiveNotification];
266 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
267 id mockApplication = OCMClassMock([FlutterSharedApplication class]);
268 OCMStub([mockApplication hasSceneDelegate]).andReturn(YES);
269 id plugin = OCMProtocolMock(@protocol(FlutterPlugin));
270 [delegate addDelegate:plugin];
271 [[NSNotificationCenter defaultCenter]
272 postNotificationName:UIApplicationWillResignActiveNotification
273 object:nil];
274
275 [self waitForExpectations:@[ expectation ] timeout:5.0];
276 OCMReject([plugin applicationWillResignActive:[OCMArg any]]);
277 }
278
279 - (void)testSceneWillResignActiveFallback {
280 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
281 id plugin = OCMProtocolMock(@protocol(FlutterPlugin));
282 [delegate addDelegate:plugin];
283
284 [delegate sceneWillResignActiveFallback];
285 OCMVerify([plugin applicationWillResignActive:[UIApplication sharedApplication]]);
286 }
287
288 - (void)testUnnecessarySceneWillResignActiveFallback {
289 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
290 id plugin = OCMProtocolMock(@protocol(TestFlutterPluginWithSceneEvents));
291 [delegate addDelegate:plugin];
292
293 [delegate sceneWillResignActiveFallback];
294 OCMReject([plugin applicationWillResignActive:[OCMArg any]]);
295 }
296
297 - (void)testDidBecomeActive {
298 XCTNSNotificationExpectation* expectation =
299 [[XCTNSNotificationExpectation alloc] initWithName:UIApplicationDidBecomeActiveNotification];
300
301 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
302 id plugin = OCMProtocolMock(@protocol(FlutterPlugin));
303 [delegate addDelegate:plugin];
304 [[NSNotificationCenter defaultCenter]
305 postNotificationName:UIApplicationDidBecomeActiveNotification
306 object:nil];
307 [self waitForExpectations:@[ expectation ] timeout:5.0];
308 OCMVerify([plugin applicationDidBecomeActive:[UIApplication sharedApplication]]);
309 }
310
311 - (void)testDidBecomeActiveWithUIScene {
312 XCTNSNotificationExpectation* expectation =
313 [[XCTNSNotificationExpectation alloc] initWithName:UIApplicationDidBecomeActiveNotification];
314 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
315 id mockApplication = OCMClassMock([FlutterSharedApplication class]);
316 OCMStub([mockApplication hasSceneDelegate]).andReturn(YES);
317 id plugin = OCMProtocolMock(@protocol(FlutterPlugin));
318 [delegate addDelegate:plugin];
319 [[NSNotificationCenter defaultCenter]
320 postNotificationName:UIApplicationDidBecomeActiveNotification
321 object:nil];
322
323 [self waitForExpectations:@[ expectation ] timeout:5.0];
324 OCMReject([plugin applicationDidBecomeActive:[OCMArg any]]);
325 }
326
327 - (void)testSceneDidBecomeActiveFallback {
328 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
329 id plugin = OCMProtocolMock(@protocol(FlutterPlugin));
330 [delegate addDelegate:plugin];
331
332 [delegate sceneDidBecomeActiveFallback];
333 OCMVerify([plugin applicationDidBecomeActive:[UIApplication sharedApplication]]);
334 }
335
336 - (void)testUnnecessarySceneDidBecomeActiveFallback {
337 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
338 id plugin = OCMProtocolMock(@protocol(TestFlutterPluginWithSceneEvents));
339 [delegate addDelegate:plugin];
340
341 [delegate sceneDidBecomeActiveFallback];
342 OCMReject([plugin applicationDidBecomeActive:[OCMArg any]]);
343 }
344
345 - (void)testSceneFallbackOpenURLContexts {
346 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
347 id plugin = [[FakePlugin alloc] init];
348 id mockPlugin = OCMPartialMock(plugin);
349 [delegate addDelegate:mockPlugin];
350
351 id urlContext = OCMClassMock([UIOpenURLContext class]);
352 NSURL* url = [NSURL URLWithString:@"http://example.com"];
353 OCMStub([urlContext URL]).andReturn(url);
354 NSSet<UIOpenURLContext*>* urlContexts = [NSSet setWithObjects:urlContext, nil];
355
356 NSDictionary<UIApplicationOpenURLOptionsKey, id>* expectedApplicationOptions = @{
357 UIApplicationOpenURLOptionsOpenInPlaceKey : @(NO),
358 };
359
360 [delegate sceneFallbackOpenURLContexts:urlContexts];
361 OCMVerify([mockPlugin application:[UIApplication sharedApplication]
362 openURL:url
363 options:expectedApplicationOptions]);
364 }
365
366 - (void)testConvertURLOptions {
367 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
368 id plugin = [[FakePlugin alloc] init];
369 id mockPlugin = OCMPartialMock(plugin);
370 [delegate addDelegate:mockPlugin];
371
372 NSString* bundleId = @"app.bundle.id";
373 id annotation = @{@"key" : @"value"};
374 id eventAttribution = OCMClassMock([UIEventAttribution class]);
375
376 UIOpenURLContext* urlContext = OCMClassMock([UIOpenURLContext class]);
377 NSURL* url = [NSURL URLWithString:@"http://example.com"];
378 OCMStub([urlContext URL]).andReturn(url);
379 id sceneOptions = OCMClassMock([UISceneOpenURLOptions class]);
380 OCMStub([sceneOptions sourceApplication]).andReturn(bundleId);
381 OCMStub([sceneOptions annotation]).andReturn(annotation);
382 OCMStub([sceneOptions openInPlace]).andReturn(YES);
383 OCMStub([sceneOptions eventAttribution]).andReturn(eventAttribution);
384
385 OCMStub([urlContext options]).andReturn(sceneOptions);
386 NSSet<UIOpenURLContext*>* urlContexts = [NSSet setWithObjects:urlContext, nil];
387
388 [delegate sceneFallbackOpenURLContexts:urlContexts];
389
390 NSDictionary<UIApplicationOpenURLOptionsKey, id>* expectedApplicationOptions = @{
391 UIApplicationOpenURLOptionsSourceApplicationKey : bundleId,
392 UIApplicationOpenURLOptionsAnnotationKey : annotation,
393 UIApplicationOpenURLOptionsOpenInPlaceKey : @(YES),
394 UIApplicationOpenURLOptionsEventAttributionKey : eventAttribution,
395 };
396
397 OCMVerify([mockPlugin application:[UIApplication sharedApplication]
398 openURL:url
399 options:expectedApplicationOptions]);
400 }
401
402 - (void)testUnnecessarySceneFallbackOpenURLContexts {
403 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
404 id plugin = [[FakeTestFlutterPluginWithSceneEvents alloc] init];
405 id mockPlugin = OCMPartialMock(plugin);
406 [delegate addDelegate:mockPlugin];
407
408 id urlContext = OCMClassMock([UIOpenURLContext class]);
409 NSSet<UIOpenURLContext*>* urlContexts = [NSSet setWithObjects:urlContext, nil];
410
411 [delegate sceneFallbackOpenURLContexts:urlContexts];
412 OCMReject([mockPlugin application:[OCMArg any] openURL:[OCMArg any] options:[OCMArg any]]);
413 }
414
415 - (void)testSceneFallbackContinueUserActivity {
416 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
417 id plugin = [[FakePlugin alloc] init];
418 id mockPlugin = OCMPartialMock(plugin);
419 [delegate addDelegate:mockPlugin];
420
421 id userActivity = OCMClassMock([NSUserActivity class]);
422
423 [delegate sceneFallbackContinueUserActivity:userActivity];
424 OCMVerify([mockPlugin application:[UIApplication sharedApplication]
425 continueUserActivity:userActivity
426 restorationHandler:[OCMArg any]]);
427 }
428
429 - (void)testUnnecessarySceneFallbackContinueUserActivity {
430 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
431 id plugin = [[FakeTestFlutterPluginWithSceneEvents alloc] init];
432 id mockPlugin = OCMPartialMock(plugin);
433 [delegate addDelegate:mockPlugin];
434
435 id userActivity = OCMClassMock([NSUserActivity class]);
436
437 [delegate sceneFallbackContinueUserActivity:userActivity];
438 OCMReject([mockPlugin application:[UIApplication sharedApplication]
439 continueUserActivity:userActivity
440 restorationHandler:[OCMArg any]]);
441 }
442
443 - (void)testSceneFallbackPerformActionForShortcutItem {
444 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
445 FakePlugin* plugin = [[FakePlugin alloc] init];
446 FakePlugin* mockPlugin = OCMPartialMock(plugin);
447 [delegate addDelegate:mockPlugin];
448
449 id shortcut = OCMClassMock([UIApplicationShortcutItem class]);
450 id handler = ^(BOOL succeeded) {
451 };
452
453 [delegate sceneFallbackPerformActionForShortcutItem:shortcut completionHandler:handler];
454 OCMVerify([mockPlugin application:[UIApplication sharedApplication]
455 performActionForShortcutItem:shortcut
456 completionHandler:handler]);
457 }
458
459 - (void)testUnnecessarySceneFallbackPerformActionForShortcutItem {
460 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
461 FakeTestFlutterPluginWithSceneEvents* plugin =
462 [[FakeTestFlutterPluginWithSceneEvents alloc] init];
463 FakeTestFlutterPluginWithSceneEvents* mockPlugin = OCMPartialMock(plugin);
464 [delegate addDelegate:mockPlugin];
465
466 id shortcut = OCMClassMock([UIApplicationShortcutItem class]);
467 [delegate sceneFallbackPerformActionForShortcutItem:shortcut
468 completionHandler:^(BOOL succeeded){
469 }];
470 OCMReject([mockPlugin application:[OCMArg any]
471 performActionForShortcutItem:[OCMArg any]
472 completionHandler:[OCMArg any]]);
473 }
474
475 - (void)testWillTerminate {
476 XCTNSNotificationExpectation* expectation =
477 [[XCTNSNotificationExpectation alloc] initWithName:UIApplicationWillTerminateNotification];
478
479 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
480 id plugin = OCMProtocolMock(@protocol(FlutterPlugin));
481 [delegate addDelegate:plugin];
482 [[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationWillTerminateNotification
483 object:nil];
484 [self waitForExpectations:@[ expectation ] timeout:5.0];
485 OCMVerify([plugin applicationWillTerminate:[UIApplication sharedApplication]]);
486 }
487
488 - (void)testReleasesPluginOnDealloc {
489 __weak id<FlutterApplicationLifeCycleDelegate> weakPlugin;
490 __weak FlutterPluginAppLifeCycleDelegate* weakDelegate;
491 @autoreleasepool {
492 FakePlugin* fakePlugin = [[FakePlugin alloc] init];
493 weakPlugin = fakePlugin;
494 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
495 [delegate addDelegate:fakePlugin];
496 weakDelegate = delegate;
497 }
498 XCTAssertNil(weakPlugin);
499 XCTAssertNil(weakDelegate);
500 }
501
502 - (void)testApplicationWillFinishLaunchingSceneFallbackForwards {
503 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
504 id plugin = [[FakePlugin alloc] init];
505 id mockPlugin = OCMPartialMock(plugin);
506 [delegate addDelegate:mockPlugin];
507 id mockApplication = OCMClassMock([UIApplication class]);
508 NSDictionary* options = @{};
509
510 [delegate sceneFallbackWillFinishLaunchingApplication:mockApplication];
511 OCMVerify(times(1), [mockPlugin application:mockApplication
512 willFinishLaunchingWithOptions:options]);
513 }
514
515 - (void)testApplicationWillFinishLaunchingSceneFallbackNoForwardAfterWillLaunch {
516 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
517 id plugin = [[FakePlugin alloc] init];
518 id mockPlugin = OCMPartialMock(plugin);
519 [delegate addDelegate:mockPlugin];
520 id mockApplication = OCMClassMock([UIApplication class]);
521 NSDictionary* options = @{@"key" : @"value"};
522
523 [delegate application:mockApplication willFinishLaunchingWithOptions:options];
524 [delegate sceneFallbackWillFinishLaunchingApplication:mockApplication];
525 OCMVerify(times(1), [mockPlugin application:mockApplication
526 willFinishLaunchingWithOptions:options]);
527 }
528
529 - (void)testApplicationWillFinishLaunchingSceneFallbackNoForwardAfterDidLaunch {
530 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
531 id plugin = [[FakePlugin alloc] init];
532 id mockPlugin = OCMPartialMock(plugin);
533 [delegate addDelegate:mockPlugin];
534 id mockApplication = OCMClassMock([UIApplication class]);
535 NSDictionary* options = @{@"key" : @"value"};
536
537 [delegate application:mockApplication didFinishLaunchingWithOptions:options];
538 [delegate sceneFallbackWillFinishLaunchingApplication:mockApplication];
539 OCMVerify(times(0), [mockPlugin application:mockApplication
540 willFinishLaunchingWithOptions:options]);
541 }
542
543 - (void)testApplicationDidFinishLaunchingSceneFallbackForwards {
544 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
545 id plugin = [[FakePlugin alloc] init];
546 id mockPlugin = OCMPartialMock(plugin);
547 [delegate addDelegate:mockPlugin];
548 id mockApplication = OCMClassMock([UIApplication class]);
549 NSDictionary* options = @{};
550
551 [delegate sceneFallbackDidFinishLaunchingApplication:mockApplication];
552 OCMVerify(times(1), [mockPlugin application:mockApplication
553 didFinishLaunchingWithOptions:options]);
554 }
555
556 - (void)testApplicationDidFinishLaunchingSceneFallbackNoForward {
557 FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
558 id plugin = [[FakePlugin alloc] init];
559 id mockPlugin = OCMPartialMock(plugin);
560 [delegate addDelegate:mockPlugin];
561 id mockApplication = OCMClassMock([UIApplication class]);
562 NSDictionary* options = @{@"key" : @"value"};
563
564 [delegate application:mockApplication didFinishLaunchingWithOptions:options];
565 [delegate sceneFallbackDidFinishLaunchingApplication:mockApplication];
566 OCMVerify(times(1), [mockPlugin application:mockApplication
567 didFinishLaunchingWithOptions:options]);
568 }
569
570 @end
FlutterMacros.h
FlutterPluginAppLifeCycleDelegate.h
FlutterPluginAppLifeCycleDelegate_internal.h
FlutterSceneLifeCycle.h
FlutterSharedApplication.h
API_AVAILABLE
UITextSmartQuotesType smartQuotesType API_AVAILABLE(ios(11.0))
FakePlugin
Definition: FlutterPluginAppLifeCycleDelegateTest.mm:50
FakeTestFlutterPluginWithSceneEvents
Definition: FlutterPluginAppLifeCycleDelegateTest.mm:21
FlutterPluginAppLifeCycleDelegate
Definition: FlutterPluginAppLifeCycleDelegate.h:16
-[FlutterPluginAppLifeCycleDelegate application:didFinishLaunchingWithOptions:]
BOOL application:didFinishLaunchingWithOptions:(UIApplication *application,[didFinishLaunchingWithOptions] NSDictionary *launchOptions)
Definition: FlutterPluginAppLifeCycleDelegate.mm:146
-[FlutterPluginAppLifeCycleDelegate application:willFinishLaunchingWithOptions:]
BOOL application:willFinishLaunchingWithOptions:(UIApplication *application,[willFinishLaunchingWithOptions] NSDictionary *launchOptions)
Definition: FlutterPluginAppLifeCycleDelegate.mm:220
-[FlutterPluginAppLifeCycleDelegate addDelegate:]
void addDelegate:(NSObject< FlutterApplicationLifeCycleDelegate > *delegate)
Definition: FlutterPluginAppLifeCycleDelegate.mm:114
FlutterPluginAppLifeCycleDelegateTest
Definition: FlutterPluginAppLifeCycleDelegateTest.mm:85
FlutterSharedApplication
Definition: FlutterSharedApplication.h:13
FLUTTER_ASSERT_ARC
Definition: FlutterChannelKeyResponder.mm:13
FlutterApplicationLifeCycleDelegate-p
Definition: FlutterPlugin.h:26
FlutterPlugin-p
Definition: FlutterPlugin.h:190
FlutterSceneLifeCycleDelegate-p
Definition: FlutterSceneLifeCycle.h:31
TestFlutterPluginWithSceneEvents-p
Definition: FlutterEngineTest.mm:24