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/test_dart_native_resolver.h"
29 #include "gtest/gtest.h"
50 - (nonnull NSView*)createWithViewIdentifier:(int64_t)viewId arguments:(nullable id)args {
51 return viewId == 42 ? [[NSView alloc] init] : nil;
60 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication* _Nonnull)sender {
62 return NSTerminateCancel;
70 @property(nonatomic, strong, readonly) NSPointerArray* registeredDelegates;
73 - (BOOL)hasDelegate:(nonnull NSObject<FlutterAppLifecycleDelegate>*)delegate;
86 std::vector<void*> _delegates;
89 - (void)addApplicationLifecycleDelegate:(nonnull NSObject<FlutterAppLifecycleDelegate>*)delegate {
90 _delegates.push_back((__bridge
void*)delegate);
93 - (void)removeApplicationLifecycleDelegate:
94 (nonnull NSObject<FlutterAppLifecycleDelegate>*)delegate {
95 auto delegateIndex = std::find(_delegates.begin(), _delegates.end(), (__bridge
void*)delegate);
96 NSAssert(delegateIndex != _delegates.end(),
97 @"Attempting to unregister a delegate that was not registered.");
98 _delegates.erase(delegateIndex);
102 return std::find(_delegates.begin(), _delegates.end(), (__bridge
void*)delegate) !=
114 + (void)registerWithRegistrar:(id<FlutterPluginRegistrar>)registrar {
124 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
125 EXPECT_TRUE(engine.running);
130 std::string executable_name = [[engine executableName] UTF8String];
131 ASSERT_FALSE(executable_name.empty());
134 fml::AutoResetWaitableEvent latch;
135 AddNativeCallback(
"NotifyStringValue", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
136 const auto dart_string = tonic::DartConverter<std::string>::FromDart(
137 Dart_GetNativeArgument(args, 0));
138 EXPECT_EQ(executable_name, dart_string);
143 EXPECT_TRUE([engine runWithEntrypoint:
@"executableNameNotNull"]);
148 #ifndef FLUTTER_RELEASE
150 setenv(
"FLUTTER_ENGINE_SWITCHES",
"2", 1);
151 setenv(
"FLUTTER_ENGINE_SWITCH_1",
"abc", 1);
152 setenv(
"FLUTTER_ENGINE_SWITCH_2",
"foo=\"bar, baz\"", 1);
155 std::vector<std::string> switches = engine.switches;
156 ASSERT_EQ(switches.size(), 2UL);
157 EXPECT_EQ(switches[0],
"--abc");
158 EXPECT_EQ(switches[1],
"--foo=\"bar, baz\"");
160 unsetenv(
"FLUTTER_ENGINE_SWITCHES");
161 unsetenv(
"FLUTTER_ENGINE_SWITCH_1");
162 unsetenv(
"FLUTTER_ENGINE_SWITCH_2");
164 #endif // !FLUTTER_RELEASE
168 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
170 NSData* test_message = [@"a message" dataUsingEncoding:NSUTF8StringEncoding];
173 engine.embedderAPI.SendPlatformMessage = MOCK_ENGINE_PROC(
174 SendPlatformMessage, ([&called, test_message](
auto engine,
auto message) {
176 EXPECT_STREQ(message->channel,
"test");
177 EXPECT_EQ(memcmp(message->message, test_message.bytes, message->message_size), 0);
181 [engine.binaryMessenger sendOnChannel:@"test" message:test_message];
187 fml::AutoResetWaitableEvent latch;
188 AddNativeCallback(
"SignalNativeTest",
189 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
192 std::stringstream buffer;
193 std::streambuf* old_buffer = std::cout.rdbuf();
194 std::cout.rdbuf(buffer.rdbuf());
198 EXPECT_TRUE([engine runWithEntrypoint:
@"canLogToStdout"]);
199 EXPECT_TRUE(engine.running);
204 std::cout.rdbuf(old_buffer);
207 std::string logs = buffer.str();
208 EXPECT_TRUE(logs.find(
"Hello logging") != std::string::npos);
216 fml::AutoResetWaitableEvent latch;
217 AddNativeCallback(
"SignalNativeTest", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
219 EXPECT_TRUE(rootLayer.backgroundColor != nil);
220 if (rootLayer.backgroundColor != nil) {
221 NSColor* actualBackgroundColor =
222 [NSColor colorWithCGColor:rootLayer.backgroundColor];
223 EXPECT_EQ(actualBackgroundColor, [NSColor blackColor]);
229 EXPECT_TRUE([engine runWithEntrypoint:
@"backgroundTest"]);
230 EXPECT_TRUE(engine.running);
235 [viewController loadView];
236 viewController.flutterView.frame = CGRectMake(0, 0, 800, 600);
246 fml::AutoResetWaitableEvent latch;
247 AddNativeCallback(
"SignalNativeTest", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
249 EXPECT_TRUE(rootLayer.backgroundColor != nil);
250 if (rootLayer.backgroundColor != nil) {
251 NSColor* actualBackgroundColor =
252 [NSColor colorWithCGColor:rootLayer.backgroundColor];
253 EXPECT_EQ(actualBackgroundColor, [NSColor whiteColor]);
259 EXPECT_TRUE([engine runWithEntrypoint:
@"backgroundTest"]);
260 EXPECT_TRUE(engine.running);
265 [viewController loadView];
266 viewController.flutterView.frame = CGRectMake(0, 0, 800, 600);
275 auto original_init = engine.embedderAPI.Initialize;
276 std::function<void(
const FlutterSemanticsUpdate2*,
void*)> update_semantics_callback;
277 engine.embedderAPI.Initialize = MOCK_ENGINE_PROC(
278 Initialize, ([&update_semantics_callback, &original_init](
279 size_t version,
const FlutterRendererConfig* config,
280 const FlutterProjectArgs* args,
void*
user_data,
auto engine_out) {
281 update_semantics_callback = args->update_semantics_callback2;
282 return original_init(version, config, args,
user_data, engine_out);
284 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
289 [viewController loadView];
291 bool enabled_called =
false;
292 engine.embedderAPI.UpdateSemanticsEnabled =
293 MOCK_ENGINE_PROC(UpdateSemanticsEnabled, ([&enabled_called](
auto engine,
bool enabled) {
294 enabled_called = enabled;
297 engine.semanticsEnabled = YES;
298 EXPECT_TRUE(enabled_called);
300 FlutterSemanticsNode2 root;
302 root.flags =
static_cast<FlutterSemanticsFlag
>(0);
303 root.actions =
static_cast<FlutterSemanticsAction
>(0);
304 root.text_selection_base = -1;
305 root.text_selection_extent = -1;
309 root.increased_value =
"";
310 root.decreased_value =
"";
312 root.child_count = 1;
313 int32_t children[] = {1};
314 root.children_in_traversal_order = children;
315 root.custom_accessibility_actions_count = 0;
317 FlutterSemanticsNode2 child1;
319 child1.flags =
static_cast<FlutterSemanticsFlag
>(0);
320 child1.actions =
static_cast<FlutterSemanticsAction
>(0);
321 child1.text_selection_base = -1;
322 child1.text_selection_extent = -1;
323 child1.label =
"child 1";
326 child1.increased_value =
"";
327 child1.decreased_value =
"";
329 child1.child_count = 0;
330 child1.custom_accessibility_actions_count = 0;
332 FlutterSemanticsUpdate2 update;
333 update.node_count = 2;
334 FlutterSemanticsNode2* nodes[] = {&root, &child1};
335 update.nodes = nodes;
336 update.custom_action_count = 0;
337 update_semantics_callback(&update, (__bridge
void*)engine);
340 EXPECT_EQ([engine.viewController.flutterView.accessibilityChildren count], 1u);
341 NSAccessibilityElement* native_root = engine.viewController.flutterView.accessibilityChildren[0];
342 std::string root_label = [native_root.accessibilityLabel UTF8String];
343 EXPECT_TRUE(root_label ==
"root");
344 EXPECT_EQ(native_root.accessibilityRole, NSAccessibilityGroupRole);
345 EXPECT_EQ([native_root.accessibilityChildren count], 1u);
346 NSAccessibilityElement* native_child1 = native_root.accessibilityChildren[0];
347 std::string child1_value = [native_child1.accessibilityValue UTF8String];
348 EXPECT_TRUE(child1_value ==
"child 1");
349 EXPECT_EQ(native_child1.accessibilityRole, NSAccessibilityStaticTextRole);
350 EXPECT_EQ([native_child1.accessibilityChildren count], 0u);
352 bool semanticsEnabled =
true;
353 engine.embedderAPI.UpdateSemanticsEnabled =
354 MOCK_ENGINE_PROC(UpdateSemanticsEnabled, ([&semanticsEnabled](
auto engine,
bool enabled) {
355 semanticsEnabled = enabled;
358 engine.semanticsEnabled = NO;
359 EXPECT_FALSE(semanticsEnabled);
361 EXPECT_EQ([engine.viewController.flutterView.accessibilityChildren count], 0u);
363 [engine setViewController:nil];
369 auto original_init = engine.embedderAPI.Initialize;
370 std::function<void(
const FlutterSemanticsUpdate2*,
void*)> update_semantics_callback;
371 engine.embedderAPI.Initialize = MOCK_ENGINE_PROC(
372 Initialize, ([&update_semantics_callback, &original_init](
373 size_t version,
const FlutterRendererConfig* config,
374 const FlutterProjectArgs* args,
void*
user_data,
auto engine_out) {
375 update_semantics_callback = args->update_semantics_callback2;
376 return original_init(version, config, args,
user_data, engine_out);
378 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
381 bool enabled_called =
false;
382 engine.embedderAPI.UpdateSemanticsEnabled =
383 MOCK_ENGINE_PROC(UpdateSemanticsEnabled, ([&enabled_called](
auto engine,
bool enabled) {
384 enabled_called = enabled;
387 engine.semanticsEnabled = YES;
388 EXPECT_TRUE(enabled_called);
390 FlutterSemanticsNode2 root;
392 root.flags =
static_cast<FlutterSemanticsFlag
>(0);
393 root.actions =
static_cast<FlutterSemanticsAction
>(0);
394 root.text_selection_base = -1;
395 root.text_selection_extent = -1;
399 root.increased_value =
"";
400 root.decreased_value =
"";
402 root.child_count = 1;
403 int32_t children[] = {1};
404 root.children_in_traversal_order = children;
405 root.custom_accessibility_actions_count = 0;
407 FlutterSemanticsNode2 child1;
409 child1.flags =
static_cast<FlutterSemanticsFlag
>(0);
410 child1.actions =
static_cast<FlutterSemanticsAction
>(0);
411 child1.text_selection_base = -1;
412 child1.text_selection_extent = -1;
413 child1.label =
"child 1";
416 child1.increased_value =
"";
417 child1.decreased_value =
"";
419 child1.child_count = 0;
420 child1.custom_accessibility_actions_count = 0;
422 FlutterSemanticsUpdate2 update;
423 update.node_count = 2;
424 FlutterSemanticsNode2* nodes[] = {&root, &child1};
425 update.nodes = nodes;
426 update.custom_action_count = 0;
429 update_semantics_callback(&update, (__bridge
void*)engine);
432 EXPECT_EQ(engine.viewController, nil);
435 bool semanticsEnabled =
true;
436 engine.embedderAPI.UpdateSemanticsEnabled =
437 MOCK_ENGINE_PROC(UpdateSemanticsEnabled, ([&semanticsEnabled](
auto engine,
bool enabled) {
438 semanticsEnabled = enabled;
441 engine.semanticsEnabled = NO;
442 EXPECT_FALSE(semanticsEnabled);
444 EXPECT_EQ(engine.viewController, nil);
449 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
452 bool enabled_called =
false;
453 engine.embedderAPI.UpdateSemanticsEnabled =
454 MOCK_ENGINE_PROC(UpdateSemanticsEnabled, ([&enabled_called](
auto engine,
bool enabled) {
455 enabled_called = enabled;
458 engine.semanticsEnabled = YES;
459 EXPECT_TRUE(enabled_called);
469 EXPECT_NE(viewController.accessibilityBridge.lock(),
nullptr);
473 fml::AutoResetWaitableEvent latch;
474 bool latch_called =
false;
475 AddNativeCallback(
"SignalNativeTest", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
481 EXPECT_TRUE([engine runWithEntrypoint:
@"nativeCallback"]);
482 EXPECT_TRUE(engine.running);
485 ASSERT_TRUE(latch_called);
489 NSString* fixtures = @(flutter::testing::GetFixturesPath());
491 initWithAssetsPath:fixtures
492 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
498 [viewController loadView];
499 viewController.flutterView.frame = CGRectMake(0, 0, 800, 600);
501 EXPECT_TRUE([engine runWithEntrypoint:
@"canCompositePlatformViews"]);
504 withId:@"factory_id"];
505 [engine.platformViewController
509 @"viewType" : @"factory_id",
514 [engine.testThreadSynchronizer blockUntilFrameAvailable];
516 CALayer* rootLayer = viewController.flutterView.layer;
519 EXPECT_EQ(rootLayer.sublayers.count, 2u);
520 EXPECT_EQ(viewController.flutterView.subviews.count, 1u);
528 NSString* fixtures = @(flutter::testing::GetFixturesPath());
530 initWithAssetsPath:fixtures
531 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
533 project.dartEntrypointArguments = @[ @"arg1", @"arg2" ];
537 auto original_init = engine.embedderAPI.Initialize;
538 engine.embedderAPI.Initialize = MOCK_ENGINE_PROC(
539 Initialize, ([&called, &original_init](
size_t version,
const FlutterRendererConfig* config,
540 const FlutterProjectArgs* args,
void*
user_data,
543 EXPECT_EQ(args->dart_entrypoint_argc, 2);
544 NSString* arg1 = [[NSString alloc] initWithCString:args->dart_entrypoint_argv[0]
545 encoding:NSUTF8StringEncoding];
546 NSString* arg2 = [[NSString alloc] initWithCString:args->dart_entrypoint_argv[1]
547 encoding:NSUTF8StringEncoding];
549 EXPECT_TRUE([arg1 isEqualToString:
@"arg1"]);
550 EXPECT_TRUE([arg2 isEqualToString:
@"arg2"]);
552 return original_init(version, config, args,
user_data, engine_out);
555 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
567 id<FlutterBinaryMessenger> binaryMessenger = nil;
570 NSString* fixtures = @(flutter::testing::GetFixturesPath());
572 initWithAssetsPath:fixtures
573 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
576 allowHeadlessExecution:YES];
583 EXPECT_NE(binaryMessenger, nil);
584 EXPECT_EQ(weakEngine, nil);
591 id<FlutterTextureRegistry> textureRegistry;
594 NSString* fixtures = @(flutter::testing::GetFixturesPath());
596 initWithAssetsPath:fixtures
597 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
600 allowHeadlessExecution:YES];
601 id<FlutterPluginRegistrar> registrar = [engine registrarForPlugin:@"MyPlugin"];
602 textureRegistry = registrar.textures;
607 EXPECT_NE(textureRegistry, nil);
608 EXPECT_EQ(weakEngine, nil);
612 NSString* fixtures = @(flutter::testing::GetFixturesPath());
614 initWithAssetsPath:fixtures
615 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
618 allowHeadlessExecution:YES];
620 EXPECT_EQ([engine valuePublishedByPlugin:
@"NoSuchPlugin"], nil);
624 NSString* fixtures = @(flutter::testing::GetFixturesPath());
626 initWithAssetsPath:fixtures
627 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
630 allowHeadlessExecution:YES];
631 NSString* pluginName =
@"MyPlugin";
633 [engine registrarForPlugin:pluginName];
637 EXPECT_EQ([engine valuePublishedByPlugin:pluginName], [NSNull
null]);
641 NSString* fixtures = @(flutter::testing::GetFixturesPath());
643 initWithAssetsPath:fixtures
644 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
647 allowHeadlessExecution:YES];
648 NSString* pluginName =
@"MyPlugin";
649 id<FlutterPluginRegistrar> registrar = [engine registrarForPlugin:pluginName];
651 NSString* firstValue =
@"A published value";
652 NSArray* secondValue = @[ @"A different published value" ];
654 [registrar publish:firstValue];
655 EXPECT_EQ([engine valuePublishedByPlugin:pluginName], firstValue);
657 [registrar publish:secondValue];
658 EXPECT_EQ([engine valuePublishedByPlugin:pluginName], secondValue);
669 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
671 NSString* channel =
@"_test_";
672 NSData* channel_data = [channel dataUsingEncoding:NSUTF8StringEncoding];
677 engine.embedderAPI.SendPlatformMessage = MOCK_ENGINE_PROC(
678 SendPlatformMessage, ([](
auto engine_,
auto message_) {
679 if (strcmp(message_->channel,
"test/send_message") == 0) {
681 std::string message = R
"|({"method": "a"})|";
682 std::string channel(reinterpret_cast<const char*>(message_->message),
683 message_->message_size);
684 reinterpret_cast<EmbedderEngine*>(engine_)
687 ->HandlePlatformMessage(std::make_unique<PlatformMessage>(
688 channel.c_str(), fml::MallocMapping::Copy(message.c_str(), message.length()),
689 fml::RefPtr<PlatformMessageResponse>()));
694 __block
int record = 0;
704 [engine.binaryMessenger sendOnChannel:@"test/send_message" message:channel_data];
705 EXPECT_EQ(record, 1);
715 [engine.binaryMessenger sendOnChannel:@"test/send_message" message:channel_data];
716 EXPECT_EQ(record, 11);
720 [engine.binaryMessenger sendOnChannel:@"test/send_message" message:channel_data];
721 EXPECT_EQ(record, 21);
728 __block
bool calledAfterClear =
false;
729 __block
bool valueAfterClear;
731 calledAfterClear =
true;
732 NSNumber* valueNumber = [result valueForKey:@"value"];
733 valueAfterClear = [valueNumber boolValue];
737 [engineMock handleMethodCall:methodCallAfterClear result:resultAfterClear];
738 EXPECT_TRUE(calledAfterClear);
739 EXPECT_FALSE(valueAfterClear);
746 __block
bool called =
false;
750 NSNumber* valueNumber = [result valueForKey:@"value"];
751 value = [valueNumber boolValue];
755 [engineMock handleMethodCall:methodCall result:result];
764 binaryMessenger:engine.binaryMessenger
766 __block BOOL didCallCallback = NO;
770 didCallCallback = YES;
772 EXPECT_TRUE([engine runWithEntrypoint:
@"sendFooMessage"]);
775 while (!didCallCallback) {
776 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
784 binaryMessenger:engine.binaryMessenger
786 __block BOOL didCallCallback = NO;
788 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
790 dispatch_async(dispatch_get_main_queue(), ^{
791 didCallCallback = YES;
795 EXPECT_TRUE([engine runWithEntrypoint:
@"sendFooMessage"]);
797 while (!didCallCallback) {
798 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
806 std::thread rasterThread([&threadSynchronizer] {
808 size:CGSizeMake(100, 100)
817 NSString* fixtures = @(flutter::testing::GetFixturesPath());
819 initWithAssetsPath:fixtures
820 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
828 EXPECT_EQ(viewController1.viewId, 0ll);
830 engine = viewController1.
engine;
845 EXPECT_EQ(viewController1.viewId, 0ll);
854 allowHeadlessExecution:NO];
859 EXPECT_EQ(viewController1.viewId, 0ll);
867 EXPECT_EQ(viewController2.viewId, 0ll);
876 EXPECT_EQ(viewController1.viewId, 0ll);
881 __block NSString* nextResponse =
@"exit";
882 __block BOOL triedToTerminate = NO;
885 terminator:^(id sender) {
886 triedToTerminate = TRUE;
889 OCMStub([engineMock terminationHandler]).andReturn(terminationHandler);
892 [engineMock binaryMessenger])
893 .andReturn(binaryMessengerMock);
894 OCMStub([engineMock sendOnChannel:
@"flutter/platform"
896 binaryReply:[OCMArg any]])
897 .andDo((^(NSInvocation* invocation) {
898 [invocation retainArguments];
900 NSData* returnedMessage;
901 [invocation getArgument:&callback atIndex:4];
902 if ([nextResponse isEqualToString:
@"error"]) {
909 NSDictionary* responseDict = @{
@"response" : nextResponse};
913 callback(returnedMessage);
915 __block NSString* calledAfterTerminate =
@"";
917 NSDictionary* resultDict = result;
918 calledAfterTerminate = resultDict[@"response"];
925 triedToTerminate = NO;
926 calledAfterTerminate =
@"";
927 nextResponse =
@"cancel";
928 [engineMock handleMethodCall:methodExitApplication result:appExitResult];
929 EXPECT_STREQ([calledAfterTerminate UTF8String],
"");
930 EXPECT_TRUE(triedToTerminate);
933 terminationHandler.acceptingRequests = YES;
934 triedToTerminate = NO;
935 calledAfterTerminate =
@"";
936 nextResponse =
@"exit";
937 [engineMock handleMethodCall:methodExitApplication result:appExitResult];
938 EXPECT_STREQ([calledAfterTerminate UTF8String],
"exit");
939 EXPECT_TRUE(triedToTerminate);
941 triedToTerminate = NO;
942 calledAfterTerminate =
@"";
943 nextResponse =
@"cancel";
944 [engineMock handleMethodCall:methodExitApplication result:appExitResult];
945 EXPECT_STREQ([calledAfterTerminate UTF8String],
"cancel");
946 EXPECT_FALSE(triedToTerminate);
949 triedToTerminate = NO;
950 calledAfterTerminate =
@"";
951 nextResponse =
@"error";
952 [engineMock handleMethodCall:methodExitApplication result:appExitResult];
953 EXPECT_STREQ([calledAfterTerminate UTF8String],
"");
954 EXPECT_TRUE(triedToTerminate);
958 id<NSApplicationDelegate> previousDelegate = [[NSApplication sharedApplication] delegate];
960 [NSApplication sharedApplication].delegate = plainDelegate;
967 EXPECT_EQ([[[NSApplication sharedApplication] delegate] applicationShouldTerminate:NSApp],
970 [NSApplication sharedApplication].delegate = previousDelegate;
974 __block BOOL announced = NO;
977 OCMStub([engineMock announceAccessibilityMessage:[OCMArg any]
978 withPriority:NSAccessibilityPriorityMedium])
979 .andDo((^(NSInvocation* invocation) {
981 [invocation retainArguments];
983 [invocation getArgument:&message atIndex:2];
984 EXPECT_EQ(message,
@"error message");
987 NSDictionary<NSString*, id>* annotatedEvent =
988 @{
@"type" :
@"announce",
989 @"data" : @{
@"message" :
@"error message"}};
991 [engineMock handleAccessibilityEvent:annotatedEvent];
993 EXPECT_TRUE(announced);
1003 .andDo((^(NSInvocation* invocation) {
1007 .andDo((^(NSInvocation* invocation) {
1011 .andDo((^(NSInvocation* invocation) {
1015 .andDo((^(NSInvocation* invocation) {
1019 .andDo((^(NSInvocation* invocation) {
1023 __block NSApplicationOcclusionState visibility = NSApplicationOcclusionStateVisible;
1024 id mockApplication = OCMPartialMock([NSApplication sharedApplication]);
1025 OCMStub((NSApplicationOcclusionState)[mockApplication occlusionState])
1026 .andDo(^(NSInvocation* invocation) {
1027 [invocation setReturnValue:&visibility];
1030 NSNotification* willBecomeActive =
1031 [[NSNotification alloc] initWithName:NSApplicationWillBecomeActiveNotification
1034 NSNotification* willResignActive =
1035 [[NSNotification alloc] initWithName:NSApplicationWillResignActiveNotification
1039 NSNotification* didChangeOcclusionState;
1040 didChangeOcclusionState =
1041 [[NSNotification alloc] initWithName:NSApplicationDidChangeOcclusionStateNotification
1045 [engineMock handleDidChangeOcclusionState:didChangeOcclusionState];
1048 [engineMock handleWillBecomeActive:willBecomeActive];
1051 [engineMock handleWillResignActive:willResignActive];
1055 [engineMock handleDidChangeOcclusionState:didChangeOcclusionState];
1058 [engineMock handleWillBecomeActive:willBecomeActive];
1061 [engineMock handleWillResignActive:willResignActive];
1064 [mockApplication stopMocking];
1068 id<NSApplicationDelegate> previousDelegate = [[NSApplication sharedApplication] delegate];
1070 [NSApplication sharedApplication].delegate = fakeAppDelegate;
1075 [[engine registrarForPlugin:@"TestPlugin"] addApplicationDelegate:plugin];
1077 EXPECT_TRUE([fakeAppDelegate hasDelegate:plugin]);
1079 [NSApplication sharedApplication].delegate = previousDelegate;
1083 id<NSApplicationDelegate> previousDelegate = [[NSApplication sharedApplication] delegate];
1085 [NSApplication sharedApplication].delegate = fakeAppDelegate;
1092 [[engine registrarForPlugin:@"TestPlugin"] addApplicationDelegate:plugin];
1093 EXPECT_TRUE([fakeAppDelegate hasDelegate:plugin]);
1098 EXPECT_FALSE([fakeAppDelegate hasDelegate:plugin]);
1100 [NSApplication sharedApplication].delegate = previousDelegate;