5 #import <Foundation/Foundation.h>
6 #import <OCMock/OCMock.h>
7 #import <XCTest/XCTest.h>
9 #import <objc/runtime.h>
11 #import "flutter/common/settings.h"
12 #include "flutter/fml/synchronization/sync_switch.h"
36 XCTFail(
"FakeBinaryMessageRelay should not be deallocated");
58 - (void)testInfoPlist {
60 NSURL* flutterFrameworkURL =
61 [NSBundle.mainBundle.privateFrameworksURL URLByAppendingPathComponent:@"Flutter.framework"];
62 NSBundle* flutterBundle = [NSBundle bundleWithURL:flutterFrameworkURL];
63 XCTAssertEqualObjects(flutterBundle.bundleIdentifier,
@"io.flutter.flutter");
65 NSDictionary<NSString*, id>* infoDictionary = flutterBundle.infoDictionary;
68 NSError* regexError = NULL;
69 NSRegularExpression* osVersionRegex =
70 [NSRegularExpression regularExpressionWithPattern:@"((0|[1-9]\\d*)\\.)*(0|[1-9]\\d*)"
71 options:NSRegularExpressionCaseInsensitive
73 XCTAssertNil(regexError);
76 NSString* testString =
@"9";
77 NSUInteger versionMatches =
78 [osVersionRegex numberOfMatchesInString:testString
79 options:NSMatchingAnchored
80 range:NSMakeRange(0, testString.length)];
81 XCTAssertEqual(versionMatches, 1UL);
83 versionMatches = [osVersionRegex numberOfMatchesInString:testString
84 options:NSMatchingAnchored
85 range:NSMakeRange(0, testString.length)];
86 XCTAssertEqual(versionMatches, 1UL);
87 testString =
@"9.0.1";
88 versionMatches = [osVersionRegex numberOfMatchesInString:testString
89 options:NSMatchingAnchored
90 range:NSMakeRange(0, testString.length)];
91 XCTAssertEqual(versionMatches, 1UL);
93 versionMatches = [osVersionRegex numberOfMatchesInString:testString
94 options:NSMatchingAnchored
95 range:NSMakeRange(0, testString.length)];
96 XCTAssertEqual(versionMatches, 0UL);
99 NSString* minimumOSVersion = infoDictionary[@"MinimumOSVersion"];
100 versionMatches = [osVersionRegex numberOfMatchesInString:minimumOSVersion
101 options:NSMatchingAnchored
102 range:NSMakeRange(0, minimumOSVersion.length)];
103 XCTAssertEqual(versionMatches, 1UL);
106 XCTAssertEqual(((NSString*)infoDictionary[
@"FlutterEngine"]).length, 40UL);
111 XCTAssertTrue(((NSString*)infoDictionary[
@"ClangVersion"]).length > 15UL);
114 - (void)testDeallocated {
120 XCTAssertNotNil(weakEngine);
122 XCTAssertNil(weakEngine);
125 - (void)testSendMessageBeforeRun {
129 XCTAssertThrows([
engine.binaryMessenger
131 message:[
@"bar" dataUsingEncoding:NSUTF8StringEncoding]
135 - (void)testSetMessageHandlerBeforeRun {
139 XCTAssertThrows([
engine.binaryMessenger
140 setMessageHandlerOnChannel:
@"foo"
146 - (void)testNilSetMessageHandlerBeforeRun {
150 XCTAssertNoThrow([
engine.binaryMessenger setMessageHandlerOnChannel:
@"foo"
151 binaryMessageHandler:nil]);
154 - (void)testNotifyPluginOfDealloc {
156 OCMStub([plugin detachFromEngineForRegistrar:[OCMArg any]]);
161 [registrar publish:plugin];
164 OCMVerify([plugin detachFromEngineForRegistrar:[OCMArg any]]);
167 - (void)testSetBinaryMessengerToSameBinaryMessenger {
181 - (void)testRunningInitialRouteSendsNavigationMessage {
194 NSData* encodedSetInitialRouteMethod =
196 OCMVerify([mockBinaryMessenger sendOnChannel:
@"flutter/navigation"
197 message:encodedSetInitialRouteMethod]);
200 - (void)testInitialRouteSettingsSendsNavigationMessage {
204 settings.route =
"test";
214 NSData* encodedSetInitialRouteMethod =
216 OCMVerify([mockBinaryMessenger sendOnChannel:
@"flutter/navigation"
217 message:encodedSetInitialRouteMethod]);
220 - (void)testPlatformViewsControllerRenderingMetalBackend {
228 - (void)testPlatformViewsControllerRenderingSoftware {
230 settings.enable_software_rendering =
true;
239 - (void)testWaitForFirstFrameTimeout {
242 XCTestExpectation* timeoutFirstFrame = [
self expectationWithDescription:@"timeoutFirstFrame"];
245 if (timeoutFirstFrame) {
246 [timeoutFirstFrame fulfill];
249 [
self waitForExpectationsWithTimeout:5 handler:nil];
259 XCTAssertNotNil(spawn);
262 - (void)testDeallocNotification {
263 XCTestExpectation* deallocNotification = [
self expectationWithDescription:@"deallocNotification"];
264 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
265 id<NSObject> observer;
268 observer = [center addObserverForName:kFlutterEngineWillDealloc
270 queue:[NSOperationQueue mainQueue]
271 usingBlock:^(NSNotification* note) {
272 [deallocNotification fulfill];
275 [
self waitForExpectationsWithTimeout:1 handler:nil];
276 [center removeObserver:observer];
279 - (void)testSetHandlerAfterRun {
281 XCTestExpectation* gotMessage = [
self expectationWithDescription:@"gotMessage"];
282 dispatch_async(dispatch_get_main_queue(), ^{
284 fml::AutoResetWaitableEvent latch;
286 flutter::Shell& shell =
engine.shell;
287 engine.shell.GetTaskRunners().GetUITaskRunner()->PostTask([&latch, &shell] {
288 flutter::Engine::Delegate& delegate = shell;
289 auto message = std::make_unique<flutter::PlatformMessage>(
"foo",
nullptr);
290 delegate.OnEngineHandlePlatformMessage(std::move(message));
294 [registrar.messenger setMessageHandlerOnChannel:@"foo"
295 binaryMessageHandler:^(NSData* message, FlutterBinaryReply reply) {
296 [gotMessage fulfill];
299 [
self waitForExpectationsWithTimeout:1 handler:nil];
302 - (void)testThreadPrioritySetCorrectly {
303 XCTestExpectation* prioritiesSet = [
self expectationWithDescription:@"prioritiesSet"];
304 prioritiesSet.expectedFulfillmentCount = 3;
306 IMP mockSetThreadPriority =
307 imp_implementationWithBlock(^(NSThread* thread,
double threadPriority) {
308 if ([thread.name hasSuffix:
@".ui"]) {
309 XCTAssertEqual(threadPriority, 1.0);
310 [prioritiesSet fulfill];
311 }
else if ([thread.name hasSuffix:
@".raster"]) {
312 XCTAssertEqual(threadPriority, 1.0);
313 [prioritiesSet fulfill];
314 }
else if ([thread.name hasSuffix:
@".io"]) {
315 XCTAssertEqual(threadPriority, 0.5);
316 [prioritiesSet fulfill];
319 Method method = class_getInstanceMethod([NSThread
class],
@selector(setThreadPriority:));
320 IMP originalSetThreadPriority = method_getImplementation(method);
321 method_setImplementation(method, mockSetThreadPriority);
325 [
self waitForExpectationsWithTimeout:1 handler:nil];
327 method_setImplementation(method, originalSetThreadPriority);
330 - (void)testCanEnableDisableEmbedderAPIThroughInfoPlist {
334 settings.enable_software_rendering =
true;
337 XCTAssertFalse(
engine.enableEmbedderAPI);
341 id mockMainBundle = OCMPartialMock([NSBundle mainBundle]);
342 OCMStub([mockMainBundle objectForInfoDictionaryKey:
@"FLTEnableIOSEmbedderAPI"])
345 settings.enable_software_rendering =
true;
348 XCTAssertTrue(
engine.enableEmbedderAPI);
352 - (void)testFlutterTextInputViewDidResignFirstResponderWillCallTextInputClientConnectionClosed {
357 [engine flutterTextInputView:nil didResignFirstResponderWithTextInputClient:1];
362 OCMVerify([mockBinaryMessenger sendOnChannel:
@"flutter/textinput" message:encodedMethodCall]);
365 - (void)testFlutterEngineUpdatesDisplays {
367 id mockEngine = OCMPartialMock(
engine);
370 OCMVerify(times(1), [mockEngine updateDisplays]);
371 engine.viewController = nil;
372 OCMVerify(times(2), [mockEngine updateDisplays]);
375 - (void)testLifeCycleNotificationDidEnterBackground {
379 NSNotification* sceneNotification =
380 [NSNotification notificationWithName:UISceneDidEnterBackgroundNotification
383 NSNotification* applicationNotification =
384 [NSNotification notificationWithName:UIApplicationDidEnterBackgroundNotification
387 id mockEngine = OCMPartialMock(
engine);
388 [[NSNotificationCenter defaultCenter] postNotification:sceneNotification];
389 [[NSNotificationCenter defaultCenter] postNotification:applicationNotification];
390 #if APPLICATION_EXTENSION_API_ONLY
391 OCMVerify(times(1), [mockEngine sceneDidEnterBackground:[OCMArg any]]);
393 OCMVerify(times(1), [mockEngine applicationDidEnterBackground:[OCMArg any]]);
395 XCTAssertTrue(
engine.isGpuDisabled);
396 bool switch_value =
false;
397 [engine
shell].GetIsGpuDisabledSyncSwitch()->Execute(
398 fml::SyncSwitch::Handlers().SetIfTrue([&] { switch_value =
true; }).SetIfFalse([&] {
399 switch_value =
false;
401 XCTAssertTrue(switch_value);
404 - (void)testLifeCycleNotificationWillEnterForeground {
408 NSNotification* sceneNotification =
409 [NSNotification notificationWithName:UISceneWillEnterForegroundNotification
412 NSNotification* applicationNotification =
413 [NSNotification notificationWithName:UIApplicationWillEnterForegroundNotification
416 id mockEngine = OCMPartialMock(
engine);
417 [[NSNotificationCenter defaultCenter] postNotification:sceneNotification];
418 [[NSNotificationCenter defaultCenter] postNotification:applicationNotification];
419 #if APPLICATION_EXTENSION_API_ONLY
420 OCMVerify(times(1), [mockEngine sceneWillEnterForeground:[OCMArg any]]);
422 OCMVerify(times(1), [mockEngine applicationWillEnterForeground:[OCMArg any]]);
424 XCTAssertFalse(
engine.isGpuDisabled);
425 bool switch_value =
true;
426 [engine
shell].GetIsGpuDisabledSyncSwitch()->Execute(
427 fml::SyncSwitch::Handlers().SetIfTrue([&] { switch_value =
true; }).SetIfFalse([&] {
428 switch_value =
false;
430 XCTAssertFalse(switch_value);