Flutter iOS Embedder
FlutterPlatformPluginTest.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 
14 
16 
17 @interface FlutterPlatformPluginTest : XCTestCase
18 @end
19 
20 @interface FlutterPlatformPlugin ()
21 - (BOOL)isLiveTextInputAvailable;
22 - (void)searchWeb:(NSString*)searchTerm;
23 - (void)showLookUpViewController:(NSString*)term;
24 - (void)showShareViewController:(NSString*)content;
25 - (void)playSystemSound:(NSString*)soundType;
26 @end
27 
28 @interface UIViewController ()
29 - (void)presentViewController:(UIViewController*)viewControllerToPresent
30  animated:(BOOL)flag
31  completion:(void (^)(void))completion;
32 @end
33 
34 @implementation FlutterPlatformPluginTest
35 
36 - (void)testSearchWebInvokedWithEscapedTerm {
37  id mockApplication = OCMClassMock([UIApplication class]);
38  OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
39 
40  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
41  [engine runWithEntrypoint:nil];
42 
43  XCTestExpectation* invokeExpectation =
44  [self expectationWithDescription:@"Web search launched with escaped search term"];
45 
46  FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
47  FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
48 
49  FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"SearchWeb.invoke"
50  arguments:@"Testing Word!"];
51 
52  FlutterResult result = ^(id result) {
53  OCMVerify([mockPlugin searchWeb:@"Testing Word!"]);
54  OCMVerify([mockApplication openURL:[NSURL URLWithString:@"x-web-search://?Testing%20Word!"]
55  options:@{}
56  completionHandler:nil]);
57  [invokeExpectation fulfill];
58  };
59 
60  [mockPlugin handleMethodCall:methodCall result:result];
61  [self waitForExpectationsWithTimeout:1 handler:nil];
62  [mockApplication stopMocking];
63 }
64 
65 - (void)testSearchWebSkippedIfAppExtension {
66  id mockBundle = OCMPartialMock([NSBundle mainBundle]);
67  OCMStub([mockBundle objectForInfoDictionaryKey:@"NSExtension"]).andReturn(@{
68  @"NSExtensionPointIdentifier" : @"com.apple.share-services"
69  });
70  id mockApplication = OCMClassMock([UIApplication class]);
71  OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
72  OCMReject([mockApplication openURL:OCMOCK_ANY options:OCMOCK_ANY completionHandler:OCMOCK_ANY]);
73  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
74  [engine runWithEntrypoint:nil];
75 
76  XCTestExpectation* invokeExpectation =
77  [self expectationWithDescription:@"Web search launched with non escaped search term"];
78 
79  FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
80  FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
81 
82  FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"SearchWeb.invoke"
83  arguments:@"Test"];
84 
85  FlutterResult result = ^(id result) {
86  OCMVerify([mockPlugin searchWeb:@"Test"]);
87 
88  [invokeExpectation fulfill];
89  };
90 
91  [mockPlugin handleMethodCall:methodCall result:result];
92  [self waitForExpectationsWithTimeout:1 handler:nil];
93  [mockBundle stopMocking];
94  [mockApplication stopMocking];
95 }
96 
97 - (void)testLookUpCallInitiated {
98  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
99  [engine runWithEntrypoint:nil];
100 
101  XCTestExpectation* presentExpectation =
102  [self expectationWithDescription:@"Look Up view controller presented"];
103 
104  FlutterViewController* engineViewController = [[FlutterViewController alloc] initWithEngine:engine
105  nibName:nil
106  bundle:nil];
107  FlutterViewController* mockEngineViewController = OCMPartialMock(engineViewController);
108 
109  FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
110  FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
111 
112  FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"LookUp.invoke"
113  arguments:@"Test"];
114  FlutterResult result = ^(id result) {
115  OCMVerify([mockEngineViewController
116  presentViewController:[OCMArg isKindOfClass:[UIReferenceLibraryViewController class]]
117  animated:YES
118  completion:nil]);
119  [presentExpectation fulfill];
120  };
121  [mockPlugin handleMethodCall:methodCall result:result];
122  [self waitForExpectationsWithTimeout:2 handler:nil];
123 }
124 
125 - (void)testShareScreenInvoked {
126  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
127  [engine runWithEntrypoint:nil];
128 
129  XCTestExpectation* presentExpectation =
130  [self expectationWithDescription:@"Share view controller presented"];
131 
132  FlutterViewController* engineViewController = [[FlutterViewController alloc] initWithEngine:engine
133  nibName:nil
134  bundle:nil];
135  FlutterViewController* mockEngineViewController = OCMPartialMock(engineViewController);
136  OCMStub([mockEngineViewController
137  presentViewController:[OCMArg isKindOfClass:[UIActivityViewController class]]
138  animated:YES
139  completion:nil]);
140 
141  FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
142  FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
143 
144  FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"Share.invoke"
145  arguments:@"Test"];
146  FlutterResult result = ^(id result) {
147  OCMVerify([mockEngineViewController
148  presentViewController:[OCMArg isKindOfClass:[UIActivityViewController class]]
149  animated:YES
150  completion:nil]);
151  [presentExpectation fulfill];
152  };
153  [mockPlugin handleMethodCall:methodCall result:result];
154  [self waitForExpectationsWithTimeout:1 handler:nil];
155 }
156 
157 - (void)testShareScreenInvokedOnIPad {
158  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
159  [engine runWithEntrypoint:nil];
160 
161  XCTestExpectation* presentExpectation =
162  [self expectationWithDescription:@"Share view controller presented on iPad"];
163 
164  FlutterViewController* engineViewController = [[FlutterViewController alloc] initWithEngine:engine
165  nibName:nil
166  bundle:nil];
167  FlutterViewController* mockEngineViewController = OCMPartialMock(engineViewController);
168  OCMStub([mockEngineViewController
169  presentViewController:[OCMArg isKindOfClass:[UIActivityViewController class]]
170  animated:YES
171  completion:nil]);
172 
173  id mockTraitCollection = OCMClassMock([UITraitCollection class]);
174  OCMStub([mockTraitCollection userInterfaceIdiom]).andReturn(UIUserInterfaceIdiomPad);
175 
176  FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
177  FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
178 
179  FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"Share.invoke"
180  arguments:@"Test"];
181  FlutterResult result = ^(id result) {
182  OCMVerify([mockEngineViewController
183  presentViewController:[OCMArg isKindOfClass:[UIActivityViewController class]]
184  animated:YES
185  completion:nil]);
186  [presentExpectation fulfill];
187  };
188  [mockPlugin handleMethodCall:methodCall result:result];
189  [self waitForExpectationsWithTimeout:1 handler:nil];
190 }
191 
192 - (void)testClipboardHasCorrectStrings {
193  [UIPasteboard generalPasteboard].string = nil;
194  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
195  FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
196 
197  XCTestExpectation* setStringExpectation = [self expectationWithDescription:@"setString"];
198  FlutterResult resultSet = ^(id result) {
199  [setStringExpectation fulfill];
200  };
201  FlutterMethodCall* methodCallSet =
202  [FlutterMethodCall methodCallWithMethodName:@"Clipboard.setData"
203  arguments:@{@"text" : @"some string"}];
204  [plugin handleMethodCall:methodCallSet result:resultSet];
205  [self waitForExpectationsWithTimeout:1 handler:nil];
206 
207  XCTestExpectation* hasStringsExpectation = [self expectationWithDescription:@"hasStrings"];
208  FlutterResult result = ^(id result) {
209  XCTAssertTrue([result[@"value"] boolValue]);
210  [hasStringsExpectation fulfill];
211  };
212  FlutterMethodCall* methodCall =
213  [FlutterMethodCall methodCallWithMethodName:@"Clipboard.hasStrings" arguments:nil];
214  [plugin handleMethodCall:methodCall result:result];
215  [self waitForExpectationsWithTimeout:1 handler:nil];
216 
217  XCTestExpectation* getDataExpectation = [self expectationWithDescription:@"getData"];
218  FlutterResult getDataResult = ^(id result) {
219  XCTAssertEqualObjects(result[@"text"], @"some string");
220  [getDataExpectation fulfill];
221  };
222  FlutterMethodCall* methodCallGetData =
223  [FlutterMethodCall methodCallWithMethodName:@"Clipboard.getData" arguments:@"text/plain"];
224  [plugin handleMethodCall:methodCallGetData result:getDataResult];
225  [self waitForExpectationsWithTimeout:1 handler:nil];
226 }
227 
228 - (void)testClipboardSetDataToNullDoNotCrash {
229  [UIPasteboard generalPasteboard].string = nil;
230  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
231  FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
232 
233  XCTestExpectation* setStringExpectation = [self expectationWithDescription:@"setData"];
234  FlutterResult resultSet = ^(id result) {
235  [setStringExpectation fulfill];
236  };
237  FlutterMethodCall* methodCallSet =
238  [FlutterMethodCall methodCallWithMethodName:@"Clipboard.setData"
239  arguments:@{@"text" : [NSNull null]}];
240  [plugin handleMethodCall:methodCallSet result:resultSet];
241 
242  XCTestExpectation* getDataExpectation = [self expectationWithDescription:@"getData"];
243  FlutterResult result = ^(id result) {
244  XCTAssertEqualObjects(result[@"text"], @"null");
245  [getDataExpectation fulfill];
246  };
247  FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"Clipboard.getData"
248  arguments:@"text/plain"];
249  [plugin handleMethodCall:methodCall result:result];
250  [self waitForExpectationsWithTimeout:1 handler:nil];
251 }
252 
253 - (void)testPopSystemNavigator {
254  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
255  [engine runWithEntrypoint:nil];
256  FlutterViewController* flutterViewController =
257  [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
258  UINavigationController* navigationController =
259  [[UINavigationController alloc] initWithRootViewController:flutterViewController];
260  UITabBarController* tabBarController = [[UITabBarController alloc] init];
261  tabBarController.viewControllers = @[ navigationController ];
262  FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
263 
264  id navigationControllerMock = OCMPartialMock(navigationController);
265  OCMStub([navigationControllerMock popViewControllerAnimated:YES]);
266  // Set some string to the pasteboard.
267  XCTestExpectation* navigationPopCalled = [self expectationWithDescription:@"SystemNavigator.pop"];
268  FlutterResult resultSet = ^(id result) {
269  [navigationPopCalled fulfill];
270  };
271  FlutterMethodCall* methodCallSet =
272  [FlutterMethodCall methodCallWithMethodName:@"SystemNavigator.pop" arguments:@(YES)];
273  [plugin handleMethodCall:methodCallSet result:resultSet];
274  [self waitForExpectationsWithTimeout:1 handler:nil];
275  OCMVerify([navigationControllerMock popViewControllerAnimated:YES]);
276 
277  [flutterViewController deregisterNotifications];
278 }
279 
280 - (void)testWhetherDeviceHasLiveTextInputInvokeCorrectly {
281  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
282  XCTestExpectation* invokeExpectation =
283  [self expectationWithDescription:@"isLiveTextInputAvailableInvoke"];
284  FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
285  FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
286  FlutterMethodCall* methodCall =
287  [FlutterMethodCall methodCallWithMethodName:@"LiveText.isLiveTextInputAvailable"
288  arguments:nil];
289  FlutterResult result = ^(id result) {
290  OCMVerify([mockPlugin isLiveTextInputAvailable]);
291  [invokeExpectation fulfill];
292  };
293  [mockPlugin handleMethodCall:methodCall result:result];
294  [self waitForExpectationsWithTimeout:1 handler:nil];
295 }
296 
297 - (void)testSystemSoundPlay {
298  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
299  XCTestExpectation* invokeExpectation =
300  [self expectationWithDescription:@"SystemSound.play invoked"];
301  FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
302  FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
303 
304  FlutterMethodCall* methodCall =
305  [FlutterMethodCall methodCallWithMethodName:@"SystemSound.play"
306  arguments:@"SystemSoundType.click"];
307  FlutterResult result = ^(id result) {
308  OCMVerify([mockPlugin playSystemSound:@"SystemSoundType.click"]);
309  [invokeExpectation fulfill];
310  };
311  [mockPlugin handleMethodCall:methodCall result:result];
312  [self waitForExpectationsWithTimeout:1 handler:nil];
313 }
314 
315 - (void)testViewControllerBasedStatusBarHiddenUpdate {
316  id bundleMock = OCMPartialMock([NSBundle mainBundle]);
317  OCMStub([bundleMock objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"])
318  .andReturn(@YES);
319  {
320  // Enabling system UI overlays to update status bar.
321  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
322  [engine runWithEntrypoint:nil];
323  FlutterViewController* flutterViewController =
324  [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
325  XCTAssertFalse(flutterViewController.prefersStatusBarHidden);
326 
327  // Update to hidden.
328  FlutterPlatformPlugin* plugin = [engine platformPlugin];
329 
330  XCTestExpectation* enableSystemUIOverlaysCalled =
331  [self expectationWithDescription:@"setEnabledSystemUIOverlays"];
332  FlutterResult resultSet = ^(id result) {
333  [enableSystemUIOverlaysCalled fulfill];
334  };
335  FlutterMethodCall* methodCallSet =
336  [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIOverlays"
337  arguments:@[ @"SystemUiOverlay.bottom" ]];
338  [plugin handleMethodCall:methodCallSet result:resultSet];
339  [self waitForExpectationsWithTimeout:1 handler:nil];
340  XCTAssertTrue(flutterViewController.prefersStatusBarHidden);
341 
342  // Update to shown.
343  XCTestExpectation* enableSystemUIOverlaysCalled2 =
344  [self expectationWithDescription:@"setEnabledSystemUIOverlays"];
345  FlutterResult resultSet2 = ^(id result) {
346  [enableSystemUIOverlaysCalled2 fulfill];
347  };
348  FlutterMethodCall* methodCallSet2 =
349  [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIOverlays"
350  arguments:@[ @"SystemUiOverlay.top" ]];
351  [plugin handleMethodCall:methodCallSet2 result:resultSet2];
352  [self waitForExpectationsWithTimeout:1 handler:nil];
353  XCTAssertFalse(flutterViewController.prefersStatusBarHidden);
354 
355  [flutterViewController deregisterNotifications];
356  }
357  {
358  // Enable system UI mode to update status bar.
359  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
360  [engine runWithEntrypoint:nil];
361  FlutterViewController* flutterViewController =
362  [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
363  XCTAssertFalse(flutterViewController.prefersStatusBarHidden);
364 
365  // Update to hidden.
366  FlutterPlatformPlugin* plugin = [engine platformPlugin];
367 
368  XCTestExpectation* enableSystemUIModeCalled =
369  [self expectationWithDescription:@"setEnabledSystemUIMode"];
370  FlutterResult resultSet = ^(id result) {
371  [enableSystemUIModeCalled fulfill];
372  };
373  FlutterMethodCall* methodCallSet =
374  [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIMode"
375  arguments:@"SystemUiMode.immersive"];
376  [plugin handleMethodCall:methodCallSet result:resultSet];
377  [self waitForExpectationsWithTimeout:1 handler:nil];
378  XCTAssertTrue(flutterViewController.prefersStatusBarHidden);
379 
380  // Update to shown.
381  XCTestExpectation* enableSystemUIModeCalled2 =
382  [self expectationWithDescription:@"setEnabledSystemUIMode"];
383  FlutterResult resultSet2 = ^(id result) {
384  [enableSystemUIModeCalled2 fulfill];
385  };
386  FlutterMethodCall* methodCallSet2 =
387  [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIMode"
388  arguments:@"SystemUiMode.edgeToEdge"];
389  [plugin handleMethodCall:methodCallSet2 result:resultSet2];
390  [self waitForExpectationsWithTimeout:1 handler:nil];
391  XCTAssertFalse(flutterViewController.prefersStatusBarHidden);
392 
393  [flutterViewController deregisterNotifications];
394  }
395  [bundleMock stopMocking];
396 }
397 
398 - (void)testStatusBarHiddenUpdate {
399  id bundleMock = OCMPartialMock([NSBundle mainBundle]);
400  OCMStub([bundleMock objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"])
401  .andReturn(@NO);
402  id mockApplication = OCMClassMock([UIApplication class]);
403  OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
404 
405  // Enabling system UI overlays to update status bar.
406  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
407  [engine runWithEntrypoint:nil];
408  FlutterViewController* flutterViewController =
409  [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
410 
411  // Update the visibility of the status bar to hidden.
412  FlutterPlatformPlugin* plugin = [engine platformPlugin];
413 
414  XCTestExpectation* systemOverlaysBottomExpectation =
415  [self expectationWithDescription:@"setEnabledSystemUIOverlays"];
416  FlutterResult systemOverlaysBottomResult = ^(id result) {
417  [systemOverlaysBottomExpectation fulfill];
418  };
419  FlutterMethodCall* setSystemOverlaysBottomCall =
420  [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIOverlays"
421  arguments:@[ @"SystemUiOverlay.bottom" ]];
422  [plugin handleMethodCall:setSystemOverlaysBottomCall result:systemOverlaysBottomResult];
423  [self waitForExpectationsWithTimeout:1 handler:nil];
424  OCMVerify([mockApplication setStatusBarHidden:YES]);
425 
426  // Update the visibility of the status bar to shown.
427  XCTestExpectation* systemOverlaysTopExpectation =
428  [self expectationWithDescription:@"setEnabledSystemUIOverlays"];
429  FlutterResult systemOverlaysTopResult = ^(id result) {
430  [systemOverlaysTopExpectation fulfill];
431  };
432  FlutterMethodCall* setSystemOverlaysTopCall =
433  [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIOverlays"
434  arguments:@[ @"SystemUiOverlay.top" ]];
435  [plugin handleMethodCall:setSystemOverlaysTopCall result:systemOverlaysTopResult];
436  [self waitForExpectationsWithTimeout:1 handler:nil];
437  OCMVerify([mockApplication setStatusBarHidden:NO]);
438 
439  [flutterViewController deregisterNotifications];
440  [mockApplication stopMocking];
441  [bundleMock stopMocking];
442 }
443 
444 - (void)testStatusBarHiddenNotUpdatedInAppExtension {
445  id bundleMock = OCMPartialMock([NSBundle mainBundle]);
446  OCMStub([bundleMock objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"])
447  .andReturn(@NO);
448  OCMStub([bundleMock objectForInfoDictionaryKey:@"NSExtension"]).andReturn(@{
449  @"NSExtensionPointIdentifier" : @"com.apple.share-services"
450  });
451  id mockApplication = OCMClassMock([UIApplication class]);
452  OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
453  OCMReject([mockApplication setStatusBarHidden:OCMOCK_ANY]);
454 
455  // Enabling system UI overlays to update status bar.
456  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
457  [engine runWithEntrypoint:nil];
458  FlutterViewController* flutterViewController =
459  [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
460 
461  // Update the visibility of the status bar to hidden does not occur with extensions.
462  FlutterPlatformPlugin* plugin = [engine platformPlugin];
463 
464  XCTestExpectation* systemOverlaysBottomExpectation =
465  [self expectationWithDescription:@"setEnabledSystemUIOverlays"];
466  FlutterResult systemOverlaysBottomResult = ^(id result) {
467  [systemOverlaysBottomExpectation fulfill];
468  };
469  FlutterMethodCall* setSystemOverlaysBottomCall =
470  [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIOverlays"
471  arguments:@[ @"SystemUiOverlay.bottom" ]];
472  [plugin handleMethodCall:setSystemOverlaysBottomCall result:systemOverlaysBottomResult];
473  [self waitForExpectationsWithTimeout:1 handler:nil];
474  OCMReject([mockApplication setStatusBarHidden:YES]);
475 
476  // Update the visibility of the status bar to shown does not occur with extensions.
477  XCTestExpectation* systemOverlaysTopExpectation =
478  [self expectationWithDescription:@"setEnabledSystemUIOverlays"];
479  FlutterResult systemOverlaysTopResult = ^(id result) {
480  [systemOverlaysTopExpectation fulfill];
481  };
482  FlutterMethodCall* setSystemOverlaysTopCall =
483  [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIOverlays"
484  arguments:@[ @"SystemUiOverlay.top" ]];
485  [plugin handleMethodCall:setSystemOverlaysTopCall result:systemOverlaysTopResult];
486  [self waitForExpectationsWithTimeout:1 handler:nil];
487  OCMReject([mockApplication setStatusBarHidden:NO]);
488 
489  [flutterViewController deregisterNotifications];
490  [mockApplication stopMocking];
491  [bundleMock stopMocking];
492 }
493 
494 - (void)testStatusBarStyle {
495  id bundleMock = OCMPartialMock([NSBundle mainBundle]);
496  OCMStub([bundleMock objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"])
497  .andReturn(@NO);
498  id mockApplication = OCMClassMock([UIApplication class]);
499  OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
500 
501  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
502  [engine runWithEntrypoint:nil];
503  FlutterViewController* flutterViewController =
504  [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
505  XCTAssertFalse(flutterViewController.prefersStatusBarHidden);
506 
507  FlutterPlatformPlugin* plugin = [engine platformPlugin];
508 
509  XCTestExpectation* enableSystemUIModeCalled =
510  [self expectationWithDescription:@"setSystemUIOverlayStyle"];
511  FlutterResult resultSet = ^(id result) {
512  [enableSystemUIModeCalled fulfill];
513  };
514  FlutterMethodCall* methodCallSet =
515  [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setSystemUIOverlayStyle"
516  arguments:@{@"statusBarBrightness" : @"Brightness.dark"}];
517  [plugin handleMethodCall:methodCallSet result:resultSet];
518  [self waitForExpectationsWithTimeout:1 handler:nil];
519 
520  OCMVerify([mockApplication setStatusBarStyle:UIStatusBarStyleLightContent]);
521 
522  [flutterViewController deregisterNotifications];
523  [mockApplication stopMocking];
524  [bundleMock stopMocking];
525 }
526 
527 - (void)testStatusBarStyleNotUpdatedInAppExtension {
528  id bundleMock = OCMPartialMock([NSBundle mainBundle]);
529  OCMStub([bundleMock objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"])
530  .andReturn(@NO);
531  OCMStub([bundleMock objectForInfoDictionaryKey:@"NSExtension"]).andReturn(@{
532  @"NSExtensionPointIdentifier" : @"com.apple.share-services"
533  });
534  id mockApplication = OCMClassMock([UIApplication class]);
535  OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
536  OCMReject([mockApplication setStatusBarHidden:OCMOCK_ANY]);
537 
538  FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
539  [engine runWithEntrypoint:nil];
540  FlutterViewController* flutterViewController =
541  [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
542  XCTAssertFalse(flutterViewController.prefersStatusBarHidden);
543 
544  FlutterPlatformPlugin* plugin = [engine platformPlugin];
545 
546  XCTestExpectation* enableSystemUIModeCalled =
547  [self expectationWithDescription:@"setSystemUIOverlayStyle"];
548  FlutterResult resultSet = ^(id result) {
549  [enableSystemUIModeCalled fulfill];
550  };
551  FlutterMethodCall* methodCallSet =
552  [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setSystemUIOverlayStyle"
553  arguments:@{@"statusBarBrightness" : @"Brightness.dark"}];
554  [plugin handleMethodCall:methodCallSet result:resultSet];
555  [self waitForExpectationsWithTimeout:1 handler:nil];
556 
557  [flutterViewController deregisterNotifications];
558  [mockApplication stopMocking];
559  [bundleMock stopMocking];
560 }
561 
562 @end
void(^ FlutterResult)(id _Nullable result)
BOOL runWithEntrypoint:(nullable NSString *entrypoint)
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
void handleMethodCall:result:(FlutterMethodCall *call,[result] FlutterResult result)