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 - (NSArray<NSScreen*>*)screens {
126 id mockScreen = OCMClassMock([NSScreen
class]);
127 OCMStub([mockScreen backingScaleFactor]).andReturn(2.0);
128 OCMStub([mockScreen deviceDescription]).andReturn(@{
129 @"NSScreenNumber" : [NSNumber numberWithInt:10]
131 OCMStub([mockScreen frame]).andReturn(NSMakeRect(10, 20, 30, 40));
132 return [NSArray arrayWithObject:mockScreen];
142 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
143 ASSERT_TRUE(engine.running);
148 std::string executable_name = [[engine executableName] UTF8String];
149 ASSERT_FALSE(executable_name.empty());
152 fml::AutoResetWaitableEvent latch;
153 AddNativeCallback(
"NotifyStringValue", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
154 const auto dart_string = tonic::DartConverter<std::string>::FromDart(
155 Dart_GetNativeArgument(args, 0));
156 EXPECT_EQ(executable_name, dart_string);
161 EXPECT_TRUE([engine runWithEntrypoint:
@"executableNameNotNull"]);
166 #ifndef FLUTTER_RELEASE
168 setenv(
"FLUTTER_ENGINE_SWITCHES",
"2", 1);
169 setenv(
"FLUTTER_ENGINE_SWITCH_1",
"abc", 1);
170 setenv(
"FLUTTER_ENGINE_SWITCH_2",
"foo=\"bar, baz\"", 1);
173 std::vector<std::string> switches = engine.switches;
174 ASSERT_EQ(switches.size(), 2UL);
175 EXPECT_EQ(switches[0],
"--abc");
176 EXPECT_EQ(switches[1],
"--foo=\"bar, baz\"");
178 unsetenv(
"FLUTTER_ENGINE_SWITCHES");
179 unsetenv(
"FLUTTER_ENGINE_SWITCH_1");
180 unsetenv(
"FLUTTER_ENGINE_SWITCH_2");
182 #endif // !FLUTTER_RELEASE
186 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
188 NSData* test_message = [@"a message" dataUsingEncoding:NSUTF8StringEncoding];
191 engine.embedderAPI.SendPlatformMessage = MOCK_ENGINE_PROC(
192 SendPlatformMessage, ([&called, test_message](
auto engine,
auto message) {
194 EXPECT_STREQ(message->channel,
"test");
195 EXPECT_EQ(memcmp(message->message, test_message.bytes, message->message_size), 0);
199 [engine.binaryMessenger sendOnChannel:@"test" message:test_message];
205 fml::AutoResetWaitableEvent latch;
206 AddNativeCallback(
"SignalNativeTest",
207 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }));
210 StreamCapture stdout_capture(&std::cout);
214 EXPECT_TRUE([engine runWithEntrypoint:
@"canLogToStdout"]);
215 ASSERT_TRUE(engine.running);
219 stdout_capture.Stop();
222 EXPECT_TRUE(stdout_capture.GetOutput().find(
"Hello logging") != std::string::npos);
229 fml::AutoResetWaitableEvent latch;
230 AddNativeCallback(
"SignalNativeTest", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
232 EXPECT_TRUE(rootLayer.backgroundColor != nil);
233 if (rootLayer.backgroundColor != nil) {
234 NSColor* actualBackgroundColor =
235 [NSColor colorWithCGColor:rootLayer.backgroundColor];
236 EXPECT_EQ(actualBackgroundColor, [NSColor blackColor]);
242 EXPECT_TRUE([engine runWithEntrypoint:
@"backgroundTest"]);
243 ASSERT_TRUE(engine.running);
248 [viewController loadView];
249 viewController.flutterView.frame = CGRectMake(0, 0, 800, 600);
258 fml::AutoResetWaitableEvent latch;
259 AddNativeCallback(
"SignalNativeTest", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
261 EXPECT_TRUE(rootLayer.backgroundColor != nil);
262 if (rootLayer.backgroundColor != nil) {
263 NSColor* actualBackgroundColor =
264 [NSColor colorWithCGColor:rootLayer.backgroundColor];
265 EXPECT_EQ(actualBackgroundColor, [NSColor whiteColor]);
271 EXPECT_TRUE([engine runWithEntrypoint:
@"backgroundTest"]);
272 ASSERT_TRUE(engine.running);
277 [viewController loadView];
278 viewController.flutterView.frame = CGRectMake(0, 0, 800, 600);
287 auto original_init = engine.embedderAPI.Initialize;
288 std::function<void(
const FlutterSemanticsUpdate2*,
void*)> update_semantics_callback;
289 engine.embedderAPI.Initialize = MOCK_ENGINE_PROC(
290 Initialize, ([&update_semantics_callback, &original_init](
291 size_t version,
const FlutterRendererConfig* config,
292 const FlutterProjectArgs* args,
void*
user_data,
auto engine_out) {
293 update_semantics_callback = args->update_semantics_callback2;
294 return original_init(version, config, args,
user_data, engine_out);
296 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
301 [viewController loadView];
303 bool enabled_called =
false;
304 engine.embedderAPI.UpdateSemanticsEnabled =
305 MOCK_ENGINE_PROC(UpdateSemanticsEnabled, ([&enabled_called](
auto engine,
bool enabled) {
306 enabled_called = enabled;
309 engine.semanticsEnabled = YES;
310 EXPECT_TRUE(enabled_called);
312 FlutterSemanticsNode2 root;
314 root.flags =
static_cast<FlutterSemanticsFlag
>(0);
315 root.actions =
static_cast<FlutterSemanticsAction
>(0);
316 root.text_selection_base = -1;
317 root.text_selection_extent = -1;
321 root.increased_value =
"";
322 root.decreased_value =
"";
324 root.child_count = 1;
325 int32_t children[] = {1};
326 root.children_in_traversal_order = children;
327 root.custom_accessibility_actions_count = 0;
329 FlutterSemanticsNode2 child1;
331 child1.flags =
static_cast<FlutterSemanticsFlag
>(0);
332 child1.actions =
static_cast<FlutterSemanticsAction
>(0);
333 child1.text_selection_base = -1;
334 child1.text_selection_extent = -1;
335 child1.label =
"child 1";
338 child1.increased_value =
"";
339 child1.decreased_value =
"";
341 child1.child_count = 0;
342 child1.custom_accessibility_actions_count = 0;
344 FlutterSemanticsUpdate2 update;
345 update.node_count = 2;
346 FlutterSemanticsNode2* nodes[] = {&root, &child1};
347 update.nodes = nodes;
348 update.custom_action_count = 0;
349 update_semantics_callback(&update, (__bridge
void*)engine);
352 EXPECT_EQ([engine.viewController.flutterView.accessibilityChildren count], 1u);
353 NSAccessibilityElement* native_root = engine.viewController.flutterView.accessibilityChildren[0];
354 std::string root_label = [native_root.accessibilityLabel UTF8String];
355 EXPECT_TRUE(root_label ==
"root");
356 EXPECT_EQ(native_root.accessibilityRole, NSAccessibilityGroupRole);
357 EXPECT_EQ([native_root.accessibilityChildren count], 1u);
358 NSAccessibilityElement* native_child1 = native_root.accessibilityChildren[0];
359 std::string child1_value = [native_child1.accessibilityValue UTF8String];
360 EXPECT_TRUE(child1_value ==
"child 1");
361 EXPECT_EQ(native_child1.accessibilityRole, NSAccessibilityStaticTextRole);
362 EXPECT_EQ([native_child1.accessibilityChildren count], 0u);
364 bool semanticsEnabled =
true;
365 engine.embedderAPI.UpdateSemanticsEnabled =
366 MOCK_ENGINE_PROC(UpdateSemanticsEnabled, ([&semanticsEnabled](
auto engine,
bool enabled) {
367 semanticsEnabled = enabled;
370 engine.semanticsEnabled = NO;
371 EXPECT_FALSE(semanticsEnabled);
373 EXPECT_EQ([engine.viewController.flutterView.accessibilityChildren count], 0u);
375 [engine setViewController:nil];
381 auto original_init = engine.embedderAPI.Initialize;
382 std::function<void(
const FlutterSemanticsUpdate2*,
void*)> update_semantics_callback;
383 engine.embedderAPI.Initialize = MOCK_ENGINE_PROC(
384 Initialize, ([&update_semantics_callback, &original_init](
385 size_t version,
const FlutterRendererConfig* config,
386 const FlutterProjectArgs* args,
void*
user_data,
auto engine_out) {
387 update_semantics_callback = args->update_semantics_callback2;
388 return original_init(version, config, args,
user_data, engine_out);
390 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
393 bool enabled_called =
false;
394 engine.embedderAPI.UpdateSemanticsEnabled =
395 MOCK_ENGINE_PROC(UpdateSemanticsEnabled, ([&enabled_called](
auto engine,
bool enabled) {
396 enabled_called = enabled;
399 engine.semanticsEnabled = YES;
400 EXPECT_TRUE(enabled_called);
402 FlutterSemanticsNode2 root;
404 root.flags =
static_cast<FlutterSemanticsFlag
>(0);
405 root.actions =
static_cast<FlutterSemanticsAction
>(0);
406 root.text_selection_base = -1;
407 root.text_selection_extent = -1;
411 root.increased_value =
"";
412 root.decreased_value =
"";
414 root.child_count = 1;
415 int32_t children[] = {1};
416 root.children_in_traversal_order = children;
417 root.custom_accessibility_actions_count = 0;
419 FlutterSemanticsNode2 child1;
421 child1.flags =
static_cast<FlutterSemanticsFlag
>(0);
422 child1.actions =
static_cast<FlutterSemanticsAction
>(0);
423 child1.text_selection_base = -1;
424 child1.text_selection_extent = -1;
425 child1.label =
"child 1";
428 child1.increased_value =
"";
429 child1.decreased_value =
"";
431 child1.child_count = 0;
432 child1.custom_accessibility_actions_count = 0;
434 FlutterSemanticsUpdate2 update;
435 update.node_count = 2;
436 FlutterSemanticsNode2* nodes[] = {&root, &child1};
437 update.nodes = nodes;
438 update.custom_action_count = 0;
441 update_semantics_callback(&update, (__bridge
void*)engine);
444 EXPECT_EQ(engine.viewController, nil);
447 bool semanticsEnabled =
true;
448 engine.embedderAPI.UpdateSemanticsEnabled =
449 MOCK_ENGINE_PROC(UpdateSemanticsEnabled, ([&semanticsEnabled](
auto engine,
bool enabled) {
450 semanticsEnabled = enabled;
453 engine.semanticsEnabled = NO;
454 EXPECT_FALSE(semanticsEnabled);
456 EXPECT_EQ(engine.viewController, nil);
461 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
464 bool enabled_called =
false;
465 engine.embedderAPI.UpdateSemanticsEnabled =
466 MOCK_ENGINE_PROC(UpdateSemanticsEnabled, ([&enabled_called](
auto engine,
bool enabled) {
467 enabled_called = enabled;
470 engine.semanticsEnabled = YES;
471 EXPECT_TRUE(enabled_called);
481 EXPECT_NE(viewController.accessibilityBridge.lock(),
nullptr);
485 fml::AutoResetWaitableEvent latch;
486 bool latch_called =
false;
487 AddNativeCallback(
"SignalNativeTest", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
493 EXPECT_TRUE([engine runWithEntrypoint:
@"nativeCallback"]);
494 ASSERT_TRUE(engine.running);
497 ASSERT_TRUE(latch_called);
501 NSString* fixtures = @(flutter::testing::GetFixturesPath());
503 initWithAssetsPath:fixtures
504 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
510 [viewController loadView];
511 [viewController viewDidLoad];
512 viewController.flutterView.frame = CGRectMake(0, 0, 800, 600);
514 EXPECT_TRUE([engine runWithEntrypoint:
@"canCompositePlatformViews"]);
517 withId:@"factory_id"];
518 [engine.platformViewController
522 @"viewType" : @"factory_id",
527 [engine.testThreadSynchronizer blockUntilFrameAvailable];
529 CALayer* rootLayer = viewController.flutterView.layer;
532 EXPECT_EQ(rootLayer.sublayers.count, 2u);
533 EXPECT_EQ(viewController.flutterView.subviews.count, 1u);
541 NSString* fixtures = @(flutter::testing::GetFixturesPath());
543 initWithAssetsPath:fixtures
544 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
546 project.dartEntrypointArguments = @[ @"arg1", @"arg2" ];
550 auto original_init = engine.embedderAPI.Initialize;
551 engine.embedderAPI.Initialize = MOCK_ENGINE_PROC(
552 Initialize, ([&called, &original_init](
size_t version,
const FlutterRendererConfig* config,
553 const FlutterProjectArgs* args,
void*
user_data,
556 EXPECT_EQ(args->dart_entrypoint_argc, 2);
557 NSString* arg1 = [[NSString alloc] initWithCString:args->dart_entrypoint_argv[0]
558 encoding:NSUTF8StringEncoding];
559 NSString* arg2 = [[NSString alloc] initWithCString:args->dart_entrypoint_argv[1]
560 encoding:NSUTF8StringEncoding];
562 EXPECT_TRUE([arg1 isEqualToString:
@"arg1"]);
563 EXPECT_TRUE([arg2 isEqualToString:
@"arg2"]);
565 return original_init(version, config, args,
user_data, engine_out);
568 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
580 id<FlutterBinaryMessenger> binaryMessenger = nil;
583 NSString* fixtures = @(flutter::testing::GetFixturesPath());
585 initWithAssetsPath:fixtures
586 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
589 allowHeadlessExecution:YES];
596 EXPECT_NE(binaryMessenger, nil);
597 EXPECT_EQ(weakEngine, nil);
604 id<FlutterTextureRegistry> textureRegistry;
607 NSString* fixtures = @(flutter::testing::GetFixturesPath());
609 initWithAssetsPath:fixtures
610 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
613 allowHeadlessExecution:YES];
614 id<FlutterPluginRegistrar> registrar = [engine registrarForPlugin:@"MyPlugin"];
615 textureRegistry = registrar.textures;
620 EXPECT_NE(textureRegistry, nil);
621 EXPECT_EQ(weakEngine, nil);
625 NSString* fixtures = @(flutter::testing::GetFixturesPath());
627 initWithAssetsPath:fixtures
628 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
631 allowHeadlessExecution:YES];
633 EXPECT_EQ([engine valuePublishedByPlugin:
@"NoSuchPlugin"], nil);
637 NSString* fixtures = @(flutter::testing::GetFixturesPath());
639 initWithAssetsPath:fixtures
640 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
643 allowHeadlessExecution:YES];
644 NSString* pluginName =
@"MyPlugin";
646 [engine registrarForPlugin:pluginName];
650 EXPECT_EQ([engine valuePublishedByPlugin:pluginName], [NSNull
null]);
654 NSString* fixtures = @(flutter::testing::GetFixturesPath());
656 initWithAssetsPath:fixtures
657 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
660 allowHeadlessExecution:YES];
661 NSString* pluginName =
@"MyPlugin";
662 id<FlutterPluginRegistrar> registrar = [engine registrarForPlugin:pluginName];
664 NSString* firstValue =
@"A published value";
665 NSArray* secondValue = @[ @"A different published value" ];
667 [registrar publish:firstValue];
668 EXPECT_EQ([engine valuePublishedByPlugin:pluginName], firstValue);
670 [registrar publish:secondValue];
671 EXPECT_EQ([engine valuePublishedByPlugin:pluginName], secondValue);
682 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
684 NSString* channel =
@"_test_";
685 NSData* channel_data = [channel dataUsingEncoding:NSUTF8StringEncoding];
690 engine.embedderAPI.SendPlatformMessage = MOCK_ENGINE_PROC(
691 SendPlatformMessage, ([](
auto engine_,
auto message_) {
692 if (strcmp(message_->channel,
"test/send_message") == 0) {
694 std::string message = R
"|({"method": "a"})|";
695 std::string channel(reinterpret_cast<const char*>(message_->message),
696 message_->message_size);
697 reinterpret_cast<EmbedderEngine*>(engine_)
700 ->HandlePlatformMessage(std::make_unique<PlatformMessage>(
701 channel.c_str(), fml::MallocMapping::Copy(message.c_str(), message.length()),
702 fml::RefPtr<PlatformMessageResponse>()));
707 __block
int record = 0;
717 [engine.binaryMessenger sendOnChannel:@"test/send_message" message:channel_data];
718 EXPECT_EQ(record, 1);
728 [engine.binaryMessenger sendOnChannel:@"test/send_message" message:channel_data];
729 EXPECT_EQ(record, 11);
733 [engine.binaryMessenger sendOnChannel:@"test/send_message" message:channel_data];
734 EXPECT_EQ(record, 21);
741 __block
bool calledAfterClear =
false;
742 __block
bool valueAfterClear;
744 calledAfterClear =
true;
745 NSNumber* valueNumber = [result valueForKey:@"value"];
746 valueAfterClear = [valueNumber boolValue];
750 [engineMock handleMethodCall:methodCallAfterClear result:resultAfterClear];
751 EXPECT_TRUE(calledAfterClear);
752 EXPECT_FALSE(valueAfterClear);
759 __block
bool called =
false;
763 NSNumber* valueNumber = [result valueForKey:@"value"];
764 value = [valueNumber boolValue];
768 [engineMock handleMethodCall:methodCall result:result];
777 binaryMessenger:engine.binaryMessenger
779 __block BOOL didCallCallback = NO;
783 didCallCallback = YES;
785 EXPECT_TRUE([engine runWithEntrypoint:
@"sendFooMessage"]);
788 while (!didCallCallback) {
789 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
797 binaryMessenger:engine.binaryMessenger
799 __block BOOL didCallCallback = NO;
801 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
803 dispatch_async(dispatch_get_main_queue(), ^{
804 didCallCallback = YES;
808 EXPECT_TRUE([engine runWithEntrypoint:
@"sendFooMessage"]);
810 while (!didCallCallback) {
811 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
819 std::thread rasterThread([&threadSynchronizer] {
821 size:CGSizeMake(100, 100)
830 NSString* fixtures = @(flutter::testing::GetFixturesPath());
832 initWithAssetsPath:fixtures
833 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
841 EXPECT_EQ(viewController1.viewId, 0ll);
843 engine = viewController1.
engine;
858 EXPECT_EQ(viewController1.viewId, 0ll);
867 allowHeadlessExecution:NO];
872 EXPECT_EQ(viewController1.viewId, 0ll);
880 EXPECT_EQ(viewController2.viewId, 0ll);
889 EXPECT_EQ(viewController1.viewId, 0ll);
894 __block NSString* nextResponse =
@"exit";
895 __block BOOL triedToTerminate = NO;
898 terminator:^(id sender) {
899 triedToTerminate = TRUE;
902 OCMStub([engineMock terminationHandler]).andReturn(terminationHandler);
905 [engineMock binaryMessenger])
906 .andReturn(binaryMessengerMock);
907 OCMStub([engineMock sendOnChannel:
@"flutter/platform"
909 binaryReply:[OCMArg any]])
910 .andDo((^(NSInvocation* invocation) {
911 [invocation retainArguments];
913 NSData* returnedMessage;
914 [invocation getArgument:&callback atIndex:4];
915 if ([nextResponse isEqualToString:
@"error"]) {
922 NSDictionary* responseDict = @{
@"response" : nextResponse};
926 callback(returnedMessage);
928 __block NSString* calledAfterTerminate =
@"";
930 NSDictionary* resultDict = result;
931 calledAfterTerminate = resultDict[@"response"];
938 triedToTerminate = NO;
939 calledAfterTerminate =
@"";
940 nextResponse =
@"cancel";
941 [engineMock handleMethodCall:methodExitApplication result:appExitResult];
942 EXPECT_STREQ([calledAfterTerminate UTF8String],
"");
943 EXPECT_TRUE(triedToTerminate);
946 terminationHandler.acceptingRequests = YES;
947 triedToTerminate = NO;
948 calledAfterTerminate =
@"";
949 nextResponse =
@"exit";
950 [engineMock handleMethodCall:methodExitApplication result:appExitResult];
951 EXPECT_STREQ([calledAfterTerminate UTF8String],
"exit");
952 EXPECT_TRUE(triedToTerminate);
954 triedToTerminate = NO;
955 calledAfterTerminate =
@"";
956 nextResponse =
@"cancel";
957 [engineMock handleMethodCall:methodExitApplication result:appExitResult];
958 EXPECT_STREQ([calledAfterTerminate UTF8String],
"cancel");
959 EXPECT_FALSE(triedToTerminate);
962 triedToTerminate = NO;
963 calledAfterTerminate =
@"";
964 nextResponse =
@"error";
965 [engineMock handleMethodCall:methodExitApplication result:appExitResult];
966 EXPECT_STREQ([calledAfterTerminate UTF8String],
"");
967 EXPECT_TRUE(triedToTerminate);
971 id<NSApplicationDelegate> previousDelegate = [[NSApplication sharedApplication] delegate];
973 [NSApplication sharedApplication].delegate = plainDelegate;
980 EXPECT_EQ([[[NSApplication sharedApplication] delegate] applicationShouldTerminate:NSApp],
983 [NSApplication sharedApplication].delegate = previousDelegate;
987 __block BOOL announced = NO;
990 OCMStub([engineMock announceAccessibilityMessage:[OCMArg any]
991 withPriority:NSAccessibilityPriorityMedium])
992 .andDo((^(NSInvocation* invocation) {
994 [invocation retainArguments];
996 [invocation getArgument:&message atIndex:2];
997 EXPECT_EQ(message,
@"error message");
1000 NSDictionary<NSString*, id>* annotatedEvent =
1001 @{
@"type" :
@"announce",
1002 @"data" : @{
@"message" :
@"error message"}};
1004 [engineMock handleAccessibilityEvent:annotatedEvent];
1006 EXPECT_TRUE(announced);
1016 .andDo((^(NSInvocation* invocation) {
1020 .andDo((^(NSInvocation* invocation) {
1024 .andDo((^(NSInvocation* invocation) {
1028 .andDo((^(NSInvocation* invocation) {
1032 .andDo((^(NSInvocation* invocation) {
1036 __block NSApplicationOcclusionState visibility = NSApplicationOcclusionStateVisible;
1037 id mockApplication = OCMPartialMock([NSApplication sharedApplication]);
1038 OCMStub((NSApplicationOcclusionState)[mockApplication occlusionState])
1039 .andDo(^(NSInvocation* invocation) {
1040 [invocation setReturnValue:&visibility];
1043 NSNotification* willBecomeActive =
1044 [[NSNotification alloc] initWithName:NSApplicationWillBecomeActiveNotification
1047 NSNotification* willResignActive =
1048 [[NSNotification alloc] initWithName:NSApplicationWillResignActiveNotification
1052 NSNotification* didChangeOcclusionState;
1053 didChangeOcclusionState =
1054 [[NSNotification alloc] initWithName:NSApplicationDidChangeOcclusionStateNotification
1058 [engineMock handleDidChangeOcclusionState:didChangeOcclusionState];
1061 [engineMock handleWillBecomeActive:willBecomeActive];
1064 [engineMock handleWillResignActive:willResignActive];
1068 [engineMock handleDidChangeOcclusionState:didChangeOcclusionState];
1071 [engineMock handleWillBecomeActive:willBecomeActive];
1074 [engineMock handleWillResignActive:willResignActive];
1077 [mockApplication stopMocking];
1081 id<NSApplicationDelegate> previousDelegate = [[NSApplication sharedApplication] delegate];
1083 [NSApplication sharedApplication].delegate = fakeAppDelegate;
1088 [[engine registrarForPlugin:@"TestPlugin"] addApplicationDelegate:plugin];
1090 EXPECT_TRUE([fakeAppDelegate hasDelegate:plugin]);
1092 [NSApplication sharedApplication].delegate = previousDelegate;
1096 id<NSApplicationDelegate> previousDelegate = [[NSApplication sharedApplication] delegate];
1098 [NSApplication sharedApplication].delegate = fakeAppDelegate;
1105 [[engine registrarForPlugin:@"TestPlugin"] addApplicationDelegate:plugin];
1106 EXPECT_TRUE([fakeAppDelegate hasDelegate:plugin]);
1111 EXPECT_FALSE([fakeAppDelegate hasDelegate:plugin]);
1113 [NSApplication sharedApplication].delegate = previousDelegate;
1119 auto original_update_displays = engine.embedderAPI.NotifyDisplayUpdate;
1120 engine.embedderAPI.NotifyDisplayUpdate = MOCK_ENGINE_PROC(
1121 NotifyDisplayUpdate, ([&updated, &original_update_displays](
1122 auto engine,
auto update_type,
auto* displays,
auto display_count) {
1124 return original_update_displays(engine, update_type, displays, display_count);
1127 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
1128 EXPECT_TRUE(updated);
1131 [[NSNotificationCenter defaultCenter]
1132 postNotificationName:NSApplicationDidChangeScreenParametersNotification
1134 EXPECT_TRUE(updated);
1140 auto original_set_viewport_metrics = engine.embedderAPI.SendWindowMetricsEvent;
1141 engine.embedderAPI.SendWindowMetricsEvent = MOCK_ENGINE_PROC(
1142 SendWindowMetricsEvent,
1143 ([&updated, &original_set_viewport_metrics](
auto engine,
auto* window_metrics) {
1145 return original_set_viewport_metrics(engine, window_metrics);
1148 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
1151 [[NSNotificationCenter defaultCenter] postNotificationName:NSWindowDidChangeScreenNotification
1154 EXPECT_FALSE(updated);
1159 [viewController loadView];
1160 viewController.flutterView.frame = CGRectMake(0, 0, 800, 600);
1162 [[NSNotificationCenter defaultCenter] postNotificationName:NSWindowDidChangeScreenNotification
1164 EXPECT_TRUE(updated);
1168 NSString* fixtures = @(testing::GetFixturesPath());
1170 initWithAssetsPath:fixtures
1171 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
1172 project.rootIsolateCreateCallback = FlutterEngineTest::IsolateCreateCallback;
1175 allowHeadlessExecution:true];
1177 auto original_update_displays = engine.embedderAPI.NotifyDisplayUpdate;
1178 engine.embedderAPI.NotifyDisplayUpdate = MOCK_ENGINE_PROC(
1179 NotifyDisplayUpdate, ([&updated, &original_update_displays](
1180 auto engine,
auto update_type,
auto* displays,
auto display_count) {
1181 EXPECT_EQ(display_count, 1UL);
1182 EXPECT_EQ(displays->display_id, 10UL);
1183 EXPECT_EQ(displays->width, 60UL);
1184 EXPECT_EQ(displays->height, 80UL);
1185 EXPECT_EQ(displays->device_pixel_ratio, 2UL);
1187 return original_update_displays(engine, update_type, displays, display_count);
1189 EXPECT_TRUE([engine runWithEntrypoint:
@"main"]);
1190 EXPECT_TRUE(updated);