15 #include "flutter/fml/synchronization/waitable_event.h"
16 #include "flutter/lib/ui/window/platform_message.h"
25 #include "flutter/shell/platform/embedder/embedder.h"
26 #include "flutter/shell/platform/embedder/embedder_engine.h"
27 #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
28 #include "flutter/testing/stream_capture.h"
29 #include "flutter/testing/test_dart_native_resolver.h"
30 #include "gtest/gtest.h"
51 - (nonnull NSView*)createWithViewIdentifier:(int64_t)viewId arguments:(nullable id)args {
52 return viewId == 42 ? [[NSView alloc] init] : nil;
61 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication* _Nonnull)sender {
63 return NSTerminateCancel;
71 @property(nonatomic, strong, readonly) NSPointerArray* registeredDelegates;
74 - (BOOL)hasDelegate:(nonnull NSObject<FlutterAppLifecycleDelegate>*)delegate;
87 std::vector<void*> _delegates;
90 - (void)addApplicationLifecycleDelegate:(nonnull NSObject<FlutterAppLifecycleDelegate>*)delegate {
91 _delegates.push_back((__bridge
void*)delegate);
94 - (void)removeApplicationLifecycleDelegate:
95 (nonnull NSObject<FlutterAppLifecycleDelegate>*)delegate {
96 auto delegateIndex = std::find(_delegates.begin(), _delegates.end(), (__bridge
void*)delegate);
97 NSAssert(delegateIndex != _delegates.end(),
98 @"Attempting to unregister a delegate that was not registered.");
99 _delegates.erase(delegateIndex);
103 return std::find(_delegates.begin(), _delegates.end(), (__bridge
void*)delegate) !=
115 + (void)registerWithRegistrar:(id<FlutterPluginRegistrar>)registrar {
125 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
126 ASSERT_TRUE(engine.running);
131 std::string executable_name = [[engine executableName] UTF8String];
132 ASSERT_FALSE(executable_name.empty());
135 fml::AutoResetWaitableEvent latch;
136 AddNativeCallback(
"NotifyStringValue", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
137 const auto dart_string = tonic::DartConverter<std::string>::FromDart(
138 Dart_GetNativeArgument(args, 0));
139 EXPECT_EQ(executable_name, dart_string);
144 EXPECT_TRUE([engine runWithEntrypoint:
@"executableNameNotNull"]);
149 #ifndef FLUTTER_RELEASE
151 setenv(
"FLUTTER_ENGINE_SWITCHES",
"2", 1);
152 setenv(
"FLUTTER_ENGINE_SWITCH_1",
"abc", 1);
153 setenv(
"FLUTTER_ENGINE_SWITCH_2",
"foo=\"bar, baz\"", 1);
156 std::vector<std::string> switches = engine.switches;
157 ASSERT_EQ(switches.size(), 2UL);
158 EXPECT_EQ(switches[0],
"--abc");
159 EXPECT_EQ(switches[1],
"--foo=\"bar, baz\"");
161 unsetenv(
"FLUTTER_ENGINE_SWITCHES");
162 unsetenv(
"FLUTTER_ENGINE_SWITCH_1");
163 unsetenv(
"FLUTTER_ENGINE_SWITCH_2");
165 #endif // !FLUTTER_RELEASE
169 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
171 NSData* test_message = [@"a message" dataUsingEncoding:NSUTF8StringEncoding];
174 engine.embedderAPI.SendPlatformMessage = MOCK_ENGINE_PROC(
175 SendPlatformMessage, ([&called, test_message](
auto engine,
auto message) {
177 EXPECT_STREQ(message->channel,
"test");
178 EXPECT_EQ(memcmp(message->message, test_message.bytes, message->message_size), 0);
182 [engine.binaryMessenger sendOnChannel:@"test" message:test_message];
188 fml::AutoResetWaitableEvent latch;
189 AddNativeCallback(
"SignalNativeTest",
190 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
193 StreamCapture stdout_capture(&std::cout);
197 EXPECT_TRUE([engine runWithEntrypoint:
@"canLogToStdout"]);
198 ASSERT_TRUE(engine.running);
202 stdout_capture.Stop();
205 EXPECT_TRUE(stdout_capture.GetOutput().find(
"Hello logging") != std::string::npos);
213 fml::AutoResetWaitableEvent latch;
214 AddNativeCallback(
"SignalNativeTest", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
216 EXPECT_TRUE(rootLayer.backgroundColor != nil);
217 if (rootLayer.backgroundColor != nil) {
218 NSColor* actualBackgroundColor =
219 [NSColor colorWithCGColor:rootLayer.backgroundColor];
220 EXPECT_EQ(actualBackgroundColor, [NSColor blackColor]);
226 EXPECT_TRUE([engine runWithEntrypoint:
@"backgroundTest"]);
227 ASSERT_TRUE(engine.running);
232 [viewController loadView];
233 viewController.flutterView.frame = CGRectMake(0, 0, 800, 600);
243 fml::AutoResetWaitableEvent latch;
244 AddNativeCallback(
"SignalNativeTest", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
246 EXPECT_TRUE(rootLayer.backgroundColor != nil);
247 if (rootLayer.backgroundColor != nil) {
248 NSColor* actualBackgroundColor =
249 [NSColor colorWithCGColor:rootLayer.backgroundColor];
250 EXPECT_EQ(actualBackgroundColor, [NSColor whiteColor]);
256 EXPECT_TRUE([engine runWithEntrypoint:
@"backgroundTest"]);
257 ASSERT_TRUE(engine.running);
262 [viewController loadView];
263 viewController.flutterView.frame = CGRectMake(0, 0, 800, 600);
272 auto original_init = engine.embedderAPI.Initialize;
273 std::function<void(
const FlutterSemanticsUpdate2*,
void*)> update_semantics_callback;
274 engine.embedderAPI.Initialize = MOCK_ENGINE_PROC(
275 Initialize, ([&update_semantics_callback, &original_init](
276 size_t version,
const FlutterRendererConfig* config,
277 const FlutterProjectArgs* args,
void*
user_data,
auto engine_out) {
278 update_semantics_callback = args->update_semantics_callback2;
279 return original_init(version, config, args,
user_data, engine_out);
281 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
286 [viewController loadView];
288 bool enabled_called =
false;
289 engine.embedderAPI.UpdateSemanticsEnabled =
290 MOCK_ENGINE_PROC(UpdateSemanticsEnabled, ([&enabled_called](
auto engine,
bool enabled) {
291 enabled_called = enabled;
294 engine.semanticsEnabled = YES;
295 EXPECT_TRUE(enabled_called);
297 FlutterSemanticsNode2 root;
299 root.flags =
static_cast<FlutterSemanticsFlag
>(0);
300 root.actions =
static_cast<FlutterSemanticsAction
>(0);
301 root.text_selection_base = -1;
302 root.text_selection_extent = -1;
306 root.increased_value =
"";
307 root.decreased_value =
"";
309 root.child_count = 1;
310 int32_t children[] = {1};
311 root.children_in_traversal_order = children;
312 root.custom_accessibility_actions_count = 0;
314 FlutterSemanticsNode2 child1;
316 child1.flags =
static_cast<FlutterSemanticsFlag
>(0);
317 child1.actions =
static_cast<FlutterSemanticsAction
>(0);
318 child1.text_selection_base = -1;
319 child1.text_selection_extent = -1;
320 child1.label =
"child 1";
323 child1.increased_value =
"";
324 child1.decreased_value =
"";
326 child1.child_count = 0;
327 child1.custom_accessibility_actions_count = 0;
329 FlutterSemanticsUpdate2 update;
330 update.node_count = 2;
331 FlutterSemanticsNode2* nodes[] = {&root, &child1};
332 update.nodes = nodes;
333 update.custom_action_count = 0;
334 update_semantics_callback(&update, (__bridge
void*)engine);
337 EXPECT_EQ([engine.viewController.flutterView.accessibilityChildren count], 1u);
338 NSAccessibilityElement* native_root = engine.viewController.flutterView.accessibilityChildren[0];
339 std::string root_label = [native_root.accessibilityLabel UTF8String];
340 EXPECT_TRUE(root_label ==
"root");
341 EXPECT_EQ(native_root.accessibilityRole, NSAccessibilityGroupRole);
342 EXPECT_EQ([native_root.accessibilityChildren count], 1u);
343 NSAccessibilityElement* native_child1 = native_root.accessibilityChildren[0];
344 std::string child1_value = [native_child1.accessibilityValue UTF8String];
345 EXPECT_TRUE(child1_value ==
"child 1");
346 EXPECT_EQ(native_child1.accessibilityRole, NSAccessibilityStaticTextRole);
347 EXPECT_EQ([native_child1.accessibilityChildren count], 0u);
349 bool semanticsEnabled =
true;
350 engine.embedderAPI.UpdateSemanticsEnabled =
351 MOCK_ENGINE_PROC(UpdateSemanticsEnabled, ([&semanticsEnabled](
auto engine,
bool enabled) {
352 semanticsEnabled = enabled;
355 engine.semanticsEnabled = NO;
356 EXPECT_FALSE(semanticsEnabled);
358 EXPECT_EQ([engine.viewController.flutterView.accessibilityChildren count], 0u);
360 [engine setViewController:nil];
366 auto original_init = engine.embedderAPI.Initialize;
367 std::function<void(
const FlutterSemanticsUpdate2*,
void*)> update_semantics_callback;
368 engine.embedderAPI.Initialize = MOCK_ENGINE_PROC(
369 Initialize, ([&update_semantics_callback, &original_init](
370 size_t version,
const FlutterRendererConfig* config,
371 const FlutterProjectArgs* args,
void*
user_data,
auto engine_out) {
372 update_semantics_callback = args->update_semantics_callback2;
373 return original_init(version, config, args,
user_data, engine_out);
375 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
378 bool enabled_called =
false;
379 engine.embedderAPI.UpdateSemanticsEnabled =
380 MOCK_ENGINE_PROC(UpdateSemanticsEnabled, ([&enabled_called](
auto engine,
bool enabled) {
381 enabled_called = enabled;
384 engine.semanticsEnabled = YES;
385 EXPECT_TRUE(enabled_called);
387 FlutterSemanticsNode2 root;
389 root.flags =
static_cast<FlutterSemanticsFlag
>(0);
390 root.actions =
static_cast<FlutterSemanticsAction
>(0);
391 root.text_selection_base = -1;
392 root.text_selection_extent = -1;
396 root.increased_value =
"";
397 root.decreased_value =
"";
399 root.child_count = 1;
400 int32_t children[] = {1};
401 root.children_in_traversal_order = children;
402 root.custom_accessibility_actions_count = 0;
404 FlutterSemanticsNode2 child1;
406 child1.flags =
static_cast<FlutterSemanticsFlag
>(0);
407 child1.actions =
static_cast<FlutterSemanticsAction
>(0);
408 child1.text_selection_base = -1;
409 child1.text_selection_extent = -1;
410 child1.label =
"child 1";
413 child1.increased_value =
"";
414 child1.decreased_value =
"";
416 child1.child_count = 0;
417 child1.custom_accessibility_actions_count = 0;
419 FlutterSemanticsUpdate2 update;
420 update.node_count = 2;
421 FlutterSemanticsNode2* nodes[] = {&root, &child1};
422 update.nodes = nodes;
423 update.custom_action_count = 0;
426 update_semantics_callback(&update, (__bridge
void*)engine);
429 EXPECT_EQ(engine.viewController, nil);
432 bool semanticsEnabled =
true;
433 engine.embedderAPI.UpdateSemanticsEnabled =
434 MOCK_ENGINE_PROC(UpdateSemanticsEnabled, ([&semanticsEnabled](
auto engine,
bool enabled) {
435 semanticsEnabled = enabled;
438 engine.semanticsEnabled = NO;
439 EXPECT_FALSE(semanticsEnabled);
441 EXPECT_EQ(engine.viewController, nil);
446 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
449 bool enabled_called =
false;
450 engine.embedderAPI.UpdateSemanticsEnabled =
451 MOCK_ENGINE_PROC(UpdateSemanticsEnabled, ([&enabled_called](
auto engine,
bool enabled) {
452 enabled_called = enabled;
455 engine.semanticsEnabled = YES;
456 EXPECT_TRUE(enabled_called);
466 EXPECT_NE(viewController.accessibilityBridge.lock(),
nullptr);
470 fml::AutoResetWaitableEvent latch;
471 bool latch_called =
false;
472 AddNativeCallback(
"SignalNativeTest", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
478 EXPECT_TRUE([engine runWithEntrypoint:
@"nativeCallback"]);
479 ASSERT_TRUE(engine.running);
482 ASSERT_TRUE(latch_called);
486 NSString* fixtures = @(flutter::testing::GetFixturesPath());
488 initWithAssetsPath:fixtures
489 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
495 [viewController loadView];
496 viewController.flutterView.frame = CGRectMake(0, 0, 800, 600);
498 EXPECT_TRUE([engine runWithEntrypoint:
@"canCompositePlatformViews"]);
501 withId:@"factory_id"];
502 [engine.platformViewController
506 @"viewType" : @"factory_id",
511 [engine.testThreadSynchronizer blockUntilFrameAvailable];
513 CALayer* rootLayer = viewController.flutterView.layer;
516 EXPECT_EQ(rootLayer.sublayers.count, 2u);
517 EXPECT_EQ(viewController.flutterView.subviews.count, 1u);
525 NSString* fixtures = @(flutter::testing::GetFixturesPath());
527 initWithAssetsPath:fixtures
528 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
530 project.dartEntrypointArguments = @[ @"arg1", @"arg2" ];
534 auto original_init = engine.embedderAPI.Initialize;
535 engine.embedderAPI.Initialize = MOCK_ENGINE_PROC(
536 Initialize, ([&called, &original_init](
size_t version,
const FlutterRendererConfig* config,
537 const FlutterProjectArgs* args,
void*
user_data,
540 EXPECT_EQ(args->dart_entrypoint_argc, 2);
541 NSString* arg1 = [[NSString alloc] initWithCString:args->dart_entrypoint_argv[0]
542 encoding:NSUTF8StringEncoding];
543 NSString* arg2 = [[NSString alloc] initWithCString:args->dart_entrypoint_argv[1]
544 encoding:NSUTF8StringEncoding];
546 EXPECT_TRUE([arg1 isEqualToString:
@"arg1"]);
547 EXPECT_TRUE([arg2 isEqualToString:
@"arg2"]);
549 return original_init(version, config, args,
user_data, engine_out);
552 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
564 id<FlutterBinaryMessenger> binaryMessenger = nil;
567 NSString* fixtures = @(flutter::testing::GetFixturesPath());
569 initWithAssetsPath:fixtures
570 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
573 allowHeadlessExecution:YES];
580 EXPECT_NE(binaryMessenger, nil);
581 EXPECT_EQ(weakEngine, nil);
588 id<FlutterTextureRegistry> textureRegistry;
591 NSString* fixtures = @(flutter::testing::GetFixturesPath());
593 initWithAssetsPath:fixtures
594 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
597 allowHeadlessExecution:YES];
598 id<FlutterPluginRegistrar> registrar = [engine registrarForPlugin:@"MyPlugin"];
599 textureRegistry = registrar.textures;
604 EXPECT_NE(textureRegistry, nil);
605 EXPECT_EQ(weakEngine, nil);
609 NSString* fixtures = @(flutter::testing::GetFixturesPath());
611 initWithAssetsPath:fixtures
612 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
615 allowHeadlessExecution:YES];
617 EXPECT_EQ([engine valuePublishedByPlugin:
@"NoSuchPlugin"], nil);
621 NSString* fixtures = @(flutter::testing::GetFixturesPath());
623 initWithAssetsPath:fixtures
624 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
627 allowHeadlessExecution:YES];
628 NSString* pluginName =
@"MyPlugin";
630 [engine registrarForPlugin:pluginName];
634 EXPECT_EQ([engine valuePublishedByPlugin:pluginName], [NSNull
null]);
638 NSString* fixtures = @(flutter::testing::GetFixturesPath());
640 initWithAssetsPath:fixtures
641 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
644 allowHeadlessExecution:YES];
645 NSString* pluginName =
@"MyPlugin";
646 id<FlutterPluginRegistrar> registrar = [engine registrarForPlugin:pluginName];
648 NSString* firstValue =
@"A published value";
649 NSArray* secondValue = @[ @"A different published value" ];
651 [registrar publish:firstValue];
652 EXPECT_EQ([engine valuePublishedByPlugin:pluginName], firstValue);
654 [registrar publish:secondValue];
655 EXPECT_EQ([engine valuePublishedByPlugin:pluginName], secondValue);
666 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
668 NSString* channel =
@"_test_";
669 NSData* channel_data = [channel dataUsingEncoding:NSUTF8StringEncoding];
674 engine.embedderAPI.SendPlatformMessage = MOCK_ENGINE_PROC(
675 SendPlatformMessage, ([](
auto engine_,
auto message_) {
676 if (strcmp(message_->channel,
"test/send_message") == 0) {
678 std::string message = R
"|({"method": "a"})|";
679 std::string channel(reinterpret_cast<const char*>(message_->message),
680 message_->message_size);
681 reinterpret_cast<EmbedderEngine*>(engine_)
684 ->HandlePlatformMessage(std::make_unique<PlatformMessage>(
685 channel.c_str(), fml::MallocMapping::Copy(message.c_str(), message.length()),
686 fml::RefPtr<PlatformMessageResponse>()));
691 __block
int record = 0;
701 [engine.binaryMessenger sendOnChannel:@"test/send_message" message:channel_data];
702 EXPECT_EQ(record, 1);
712 [engine.binaryMessenger sendOnChannel:@"test/send_message" message:channel_data];
713 EXPECT_EQ(record, 11);
717 [engine.binaryMessenger sendOnChannel:@"test/send_message" message:channel_data];
718 EXPECT_EQ(record, 21);
725 __block
bool calledAfterClear =
false;
726 __block
bool valueAfterClear;
728 calledAfterClear =
true;
729 NSNumber* valueNumber = [result valueForKey:@"value"];
730 valueAfterClear = [valueNumber boolValue];
734 [engineMock handleMethodCall:methodCallAfterClear result:resultAfterClear];
735 EXPECT_TRUE(calledAfterClear);
736 EXPECT_FALSE(valueAfterClear);
743 __block
bool called =
false;
747 NSNumber* valueNumber = [result valueForKey:@"value"];
748 value = [valueNumber boolValue];
752 [engineMock handleMethodCall:methodCall result:result];
761 binaryMessenger:engine.binaryMessenger
763 __block BOOL didCallCallback = NO;
767 didCallCallback = YES;
769 EXPECT_TRUE([engine runWithEntrypoint:
@"sendFooMessage"]);
772 while (!didCallCallback) {
773 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
781 binaryMessenger:engine.binaryMessenger
783 __block BOOL didCallCallback = NO;
785 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
787 dispatch_async(dispatch_get_main_queue(), ^{
788 didCallCallback = YES;
792 EXPECT_TRUE([engine runWithEntrypoint:
@"sendFooMessage"]);
794 while (!didCallCallback) {
795 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
803 std::thread rasterThread([&threadSynchronizer] {
805 size:CGSizeMake(100, 100)
814 NSString* fixtures = @(flutter::testing::GetFixturesPath());
816 initWithAssetsPath:fixtures
817 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
825 EXPECT_EQ(viewController1.viewId, 0ll);
827 engine = viewController1.
engine;
842 EXPECT_EQ(viewController1.viewId, 0ll);
851 allowHeadlessExecution:NO];
856 EXPECT_EQ(viewController1.viewId, 0ll);
864 EXPECT_EQ(viewController2.viewId, 0ll);
873 EXPECT_EQ(viewController1.viewId, 0ll);
878 __block NSString* nextResponse =
@"exit";
879 __block BOOL triedToTerminate = NO;
882 terminator:^(id sender) {
883 triedToTerminate = TRUE;
886 OCMStub([engineMock terminationHandler]).andReturn(terminationHandler);
889 [engineMock binaryMessenger])
890 .andReturn(binaryMessengerMock);
891 OCMStub([engineMock sendOnChannel:
@"flutter/platform"
893 binaryReply:[OCMArg any]])
894 .andDo((^(NSInvocation* invocation) {
895 [invocation retainArguments];
897 NSData* returnedMessage;
898 [invocation getArgument:&callback atIndex:4];
899 if ([nextResponse isEqualToString:
@"error"]) {
906 NSDictionary* responseDict = @{
@"response" : nextResponse};
910 callback(returnedMessage);
912 __block NSString* calledAfterTerminate =
@"";
914 NSDictionary* resultDict = result;
915 calledAfterTerminate = resultDict[@"response"];
922 triedToTerminate = NO;
923 calledAfterTerminate =
@"";
924 nextResponse =
@"cancel";
925 [engineMock handleMethodCall:methodExitApplication result:appExitResult];
926 EXPECT_STREQ([calledAfterTerminate UTF8String],
"");
927 EXPECT_TRUE(triedToTerminate);
930 terminationHandler.acceptingRequests = YES;
931 triedToTerminate = NO;
932 calledAfterTerminate =
@"";
933 nextResponse =
@"exit";
934 [engineMock handleMethodCall:methodExitApplication result:appExitResult];
935 EXPECT_STREQ([calledAfterTerminate UTF8String],
"exit");
936 EXPECT_TRUE(triedToTerminate);
938 triedToTerminate = NO;
939 calledAfterTerminate =
@"";
940 nextResponse =
@"cancel";
941 [engineMock handleMethodCall:methodExitApplication result:appExitResult];
942 EXPECT_STREQ([calledAfterTerminate UTF8String],
"cancel");
943 EXPECT_FALSE(triedToTerminate);
946 triedToTerminate = NO;
947 calledAfterTerminate =
@"";
948 nextResponse =
@"error";
949 [engineMock handleMethodCall:methodExitApplication result:appExitResult];
950 EXPECT_STREQ([calledAfterTerminate UTF8String],
"");
951 EXPECT_TRUE(triedToTerminate);
955 id<NSApplicationDelegate> previousDelegate = [[NSApplication sharedApplication] delegate];
957 [NSApplication sharedApplication].delegate = plainDelegate;
964 EXPECT_EQ([[[NSApplication sharedApplication] delegate] applicationShouldTerminate:NSApp],
967 [NSApplication sharedApplication].delegate = previousDelegate;
971 __block BOOL announced = NO;
974 OCMStub([engineMock announceAccessibilityMessage:[OCMArg any]
975 withPriority:NSAccessibilityPriorityMedium])
976 .andDo((^(NSInvocation* invocation) {
978 [invocation retainArguments];
980 [invocation getArgument:&message atIndex:2];
981 EXPECT_EQ(message,
@"error message");
984 NSDictionary<NSString*, id>* annotatedEvent =
985 @{
@"type" :
@"announce",
986 @"data" : @{
@"message" :
@"error message"}};
988 [engineMock handleAccessibilityEvent:annotatedEvent];
990 EXPECT_TRUE(announced);
1000 .andDo((^(NSInvocation* invocation) {
1004 .andDo((^(NSInvocation* invocation) {
1008 .andDo((^(NSInvocation* invocation) {
1012 .andDo((^(NSInvocation* invocation) {
1016 .andDo((^(NSInvocation* invocation) {
1020 __block NSApplicationOcclusionState visibility = NSApplicationOcclusionStateVisible;
1021 id mockApplication = OCMPartialMock([NSApplication sharedApplication]);
1022 OCMStub((NSApplicationOcclusionState)[mockApplication occlusionState])
1023 .andDo(^(NSInvocation* invocation) {
1024 [invocation setReturnValue:&visibility];
1027 NSNotification* willBecomeActive =
1028 [[NSNotification alloc] initWithName:NSApplicationWillBecomeActiveNotification
1031 NSNotification* willResignActive =
1032 [[NSNotification alloc] initWithName:NSApplicationWillResignActiveNotification
1036 NSNotification* didChangeOcclusionState;
1037 didChangeOcclusionState =
1038 [[NSNotification alloc] initWithName:NSApplicationDidChangeOcclusionStateNotification
1042 [engineMock handleDidChangeOcclusionState:didChangeOcclusionState];
1045 [engineMock handleWillBecomeActive:willBecomeActive];
1048 [engineMock handleWillResignActive:willResignActive];
1052 [engineMock handleDidChangeOcclusionState:didChangeOcclusionState];
1055 [engineMock handleWillBecomeActive:willBecomeActive];
1058 [engineMock handleWillResignActive:willResignActive];
1061 [mockApplication stopMocking];
1065 id<NSApplicationDelegate> previousDelegate = [[NSApplication sharedApplication] delegate];
1067 [NSApplication sharedApplication].delegate = fakeAppDelegate;
1072 [[engine registrarForPlugin:@"TestPlugin"] addApplicationDelegate:plugin];
1074 EXPECT_TRUE([fakeAppDelegate hasDelegate:plugin]);
1076 [NSApplication sharedApplication].delegate = previousDelegate;
1080 id<NSApplicationDelegate> previousDelegate = [[NSApplication sharedApplication] delegate];
1082 [NSApplication sharedApplication].delegate = fakeAppDelegate;
1089 [[engine registrarForPlugin:@"TestPlugin"] addApplicationDelegate:plugin];
1090 EXPECT_TRUE([fakeAppDelegate hasDelegate:plugin]);
1095 EXPECT_FALSE([fakeAppDelegate hasDelegate:plugin]);
1097 [NSApplication sharedApplication].delegate = previousDelegate;