Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit bee48ca

Browse files
committed
Move more logic into test setup, remove infoPlistGetter helper
1 parent 22dd1da commit bee48ca

File tree

3 files changed

+102
-103
lines changed

3 files changed

+102
-103
lines changed

shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -132,17 +132,11 @@ - (void)userNotificationCenter:(UNUserNotificationCenter*)center
132132
}
133133
}
134134

135-
static BOOL IsDeepLinkingEnabled(NSDictionary* infoDictionary) {
136-
NSNumber* isEnabled = [infoDictionary objectForKey:@"FlutterDeepLinkingEnabled"];
137-
if (isEnabled) {
138-
return [isEnabled boolValue];
139-
} else {
140-
return NO;
141-
}
142-
}
143-
144-
- (BOOL)openURL:(NSURL*)url infoPlistGetter:(NSDictionary* (^)())infoPlistGetter {
145-
if (!IsDeepLinkingEnabled(infoPlistGetter())) {
135+
- (BOOL)openURL:(NSURL*)url {
136+
NSNumber* isDeepLinkingEnabled =
137+
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"];
138+
if (!isDeepLinkingEnabled.boolValue) {
139+
// Not set or NO.
146140
return NO;
147141
} else {
148142
FlutterViewController* flutterViewController = [self rootFlutterViewController];
@@ -179,10 +173,7 @@ - (BOOL)application:(UIApplication*)application
179173
if ([_lifeCycleDelegate application:application openURL:url options:options]) {
180174
return YES;
181175
}
182-
return [self openURL:url
183-
infoPlistGetter:^NSDictionary*() {
184-
return [[NSBundle mainBundle] infoDictionary];
185-
}];
176+
return [self openURL:url];
186177
}
187178

188179
- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url {
@@ -233,10 +224,7 @@ - (BOOL)application:(UIApplication*)application
233224
if (userActivity.activityType == NSUserActivityTypeBrowsingWeb) {
234225
return NO;
235226
}
236-
return [self openURL:userActivity.webpageURL
237-
infoPlistGetter:^NSDictionary*() {
238-
return [[NSBundle mainBundle] infoDictionary];
239-
}];
227+
return [self openURL:userActivity.webpageURL];
240228
}
241229

242230
#pragma mark - FlutterPluginRegistry methods. All delegating to the rootViewController

shell/platform/darwin/ios/framework/Source/FlutterAppDelegateTest.mm

Lines changed: 95 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -14,132 +14,145 @@
1414
FLUTTER_ASSERT_ARC
1515

1616
@interface FlutterAppDelegateTest : XCTestCase
17+
@property(strong) FlutterAppDelegate* appDelegate;
18+
19+
@property(strong) id mockMainBundle;
20+
@property(strong) id mockNavigationChannel;
21+
22+
// Retain callback until the tests are done.
23+
// https://github.com/flutter/flutter/issues/74267
24+
@property(strong) id mockEngineFirstFrameCallback;
1725
@end
1826

1927
@implementation FlutterAppDelegateTest
2028

21-
- (void)testLaunchUrl {
29+
- (void)setUp {
30+
[super setUp];
31+
32+
id mockMainBundle = OCMClassMock([NSBundle class]);
33+
OCMStub([mockMainBundle mainBundle]).andReturn(mockMainBundle);
34+
self.mockMainBundle = mockMainBundle;
35+
2236
FlutterAppDelegate* appDelegate = [[FlutterAppDelegate alloc] init];
37+
self.appDelegate = appDelegate;
38+
2339
FlutterViewController* viewController = OCMClassMock([FlutterViewController class]);
24-
FlutterEngine* engine = OCMClassMock([FlutterEngine class]);
2540
FlutterMethodChannel* navigationChannel = OCMClassMock([FlutterMethodChannel class]);
41+
self.mockNavigationChannel = navigationChannel;
42+
43+
FlutterEngine* engine = OCMClassMock([FlutterEngine class]);
2644
OCMStub([engine navigationChannel]).andReturn(navigationChannel);
2745
OCMStub([viewController engine]).andReturn(engine);
28-
// Set blockNoInvoker to a strong local to retain to end of scope.
29-
id blockNoInvoker = [OCMArg invokeBlockWithArgs:@NO, nil];
30-
OCMStub([engine waitForFirstFrame:3.0 callback:blockNoInvoker]);
46+
47+
id mockEngineFirstFrameCallback = [OCMArg invokeBlockWithArgs:@NO, nil];
48+
self.mockEngineFirstFrameCallback = mockEngineFirstFrameCallback;
49+
OCMStub([engine waitForFirstFrame:3.0 callback:mockEngineFirstFrameCallback]);
3150
appDelegate.rootFlutterViewControllerGetter = ^{
3251
return viewController;
3352
};
34-
NSURL* url = [NSURL URLWithString:@"http://myApp/custom/route?query=test"];
35-
BOOL result = [appDelegate openURL:url
36-
infoPlistGetter:^NSDictionary*() {
37-
return @{@"FlutterDeepLinkingEnabled" : @YES};
38-
}];
53+
}
54+
55+
- (void)tearDown {
56+
// Explicitly stop mocking the NSBundle class property.
57+
[self.mockMainBundle stopMocking];
58+
[super tearDown];
59+
}
60+
61+
- (void)testLaunchUrl {
62+
OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
63+
.andReturn(@YES);
64+
65+
BOOL result =
66+
[self.appDelegate application:[UIApplication sharedApplication]
67+
openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test"]
68+
options:@{}];
3969
XCTAssertTrue(result);
40-
OCMVerify([navigationChannel invokeMethod:@"pushRoute" arguments:@"/custom/route?query=test"]);
70+
OCMVerify([self.mockNavigationChannel invokeMethod:@"pushRoute"
71+
arguments:@"/custom/route?query=test"]);
72+
}
73+
74+
- (void)testLaunchUrlWithDeepLinkingNotSet {
75+
OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
76+
.andReturn(nil);
77+
78+
BOOL result =
79+
[self.appDelegate application:[UIApplication sharedApplication]
80+
openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test"]
81+
options:@{}];
82+
XCTAssertFalse(result);
83+
OCMReject([self.mockNavigationChannel invokeMethod:OCMOCK_ANY arguments:OCMOCK_ANY]);
84+
}
85+
86+
- (void)testLaunchUrlWithDeepLinkingDisabled {
87+
OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
88+
.andReturn(@NO);
89+
90+
BOOL result =
91+
[self.appDelegate application:[UIApplication sharedApplication]
92+
openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test"]
93+
options:@{}];
94+
XCTAssertFalse(result);
95+
OCMReject([self.mockNavigationChannel invokeMethod:OCMOCK_ANY arguments:OCMOCK_ANY]);
4196
}
4297

4398
- (void)testLaunchUrlWithQueryParameterAndFragment {
44-
FlutterAppDelegate* appDelegate = [[FlutterAppDelegate alloc] init];
45-
FlutterViewController* viewController = OCMClassMock([FlutterViewController class]);
46-
FlutterEngine* engine = OCMClassMock([FlutterEngine class]);
47-
FlutterMethodChannel* navigationChannel = OCMClassMock([FlutterMethodChannel class]);
48-
OCMStub([engine navigationChannel]).andReturn(navigationChannel);
49-
OCMStub([viewController engine]).andReturn(engine);
50-
// Set blockNoInvoker to a strong local to retain to end of scope.
51-
id blockNoInvoker = [OCMArg invokeBlockWithArgs:@NO, nil];
52-
OCMStub([engine waitForFirstFrame:3.0 callback:blockNoInvoker]);
53-
appDelegate.rootFlutterViewControllerGetter = ^{
54-
return viewController;
55-
};
56-
NSURL* url = [NSURL URLWithString:@"http://myApp/custom/route?query=test#fragment"];
57-
BOOL result = [appDelegate openURL:url
58-
infoPlistGetter:^NSDictionary*() {
59-
return @{@"FlutterDeepLinkingEnabled" : @YES};
60-
}];
99+
OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
100+
.andReturn(@YES);
101+
102+
BOOL result = [self.appDelegate
103+
application:[UIApplication sharedApplication]
104+
openURL:[NSURL URLWithString:@"http://myApp/custom/route?query=test#fragment"]
105+
options:@{}];
61106
XCTAssertTrue(result);
62-
OCMVerify([navigationChannel invokeMethod:@"pushRoute"
63-
arguments:@"/custom/route?query=test#fragment"]);
107+
OCMVerify([self.mockNavigationChannel invokeMethod:@"pushRoute"
108+
arguments:@"/custom/route?query=test#fragment"]);
64109
}
65110

66111
- (void)testLaunchUrlWithFragmentNoQueryParameter {
67-
FlutterAppDelegate* appDelegate = [[FlutterAppDelegate alloc] init];
68-
FlutterViewController* viewController = OCMClassMock([FlutterViewController class]);
69-
FlutterEngine* engine = OCMClassMock([FlutterEngine class]);
70-
FlutterMethodChannel* navigationChannel = OCMClassMock([FlutterMethodChannel class]);
71-
OCMStub([engine navigationChannel]).andReturn(navigationChannel);
72-
OCMStub([viewController engine]).andReturn(engine);
73-
// Set blockNoInvoker to a strong local to retain to end of scope.
74-
id blockNoInvoker = [OCMArg invokeBlockWithArgs:@NO, nil];
75-
OCMStub([engine waitForFirstFrame:3.0 callback:blockNoInvoker]);
76-
appDelegate.rootFlutterViewControllerGetter = ^{
77-
return viewController;
78-
};
79-
NSURL* url = [NSURL URLWithString:@"http://myApp/custom/route#fragment"];
80-
BOOL result = [appDelegate openURL:url
81-
infoPlistGetter:^NSDictionary*() {
82-
return @{@"FlutterDeepLinkingEnabled" : @YES};
83-
}];
112+
OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
113+
.andReturn(@YES);
114+
115+
BOOL result =
116+
[self.appDelegate application:[UIApplication sharedApplication]
117+
openURL:[NSURL URLWithString:@"http://myApp/custom/route#fragment"]
118+
options:@{}];
84119
XCTAssertTrue(result);
85-
OCMVerify([navigationChannel invokeMethod:@"pushRoute" arguments:@"/custom/route#fragment"]);
120+
OCMVerify([self.mockNavigationChannel invokeMethod:@"pushRoute"
121+
arguments:@"/custom/route#fragment"]);
86122
}
87123

88124
#pragma mark - Deep linking
89125

90126
- (void)testUniversalLinkWebBrowserUrl {
91-
FlutterAppDelegate* appDelegate = [[FlutterAppDelegate alloc] init];
92-
FlutterViewController* viewController = OCMClassMock([FlutterViewController class]);
93-
FlutterEngine* engine = OCMClassMock([FlutterEngine class]);
94-
FlutterMethodChannel* navigationChannel = OCMClassMock([FlutterMethodChannel class]);
95-
OCMStub([engine navigationChannel]).andReturn(navigationChannel);
96-
OCMStub([viewController engine]).andReturn(engine);
97-
// Set blockArg to a strong local to retain to end of scope.
98-
id blockArg = [OCMArg invokeBlockWithArgs:@NO, nil];
99-
OCMStub([engine waitForFirstFrame:3.0 callback:blockArg]);
100-
appDelegate.rootFlutterViewControllerGetter = ^{
101-
return viewController;
102-
};
127+
OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
128+
.andReturn(@YES);
129+
103130
NSUserActivity* userActivity =
104131
[[NSUserActivity alloc] initWithActivityType:NSUserActivityTypeBrowsingWeb];
105132
userActivity.webpageURL = [NSURL URLWithString:@"http://myApp/custom/route?query=test"];
106-
BOOL result = [appDelegate
133+
BOOL result = [self.appDelegate
107134
application:[UIApplication sharedApplication]
108135
continueUserActivity:userActivity
109136
restorationHandler:^(NSArray<id<UIUserActivityRestoring>>* __nullable restorableObjects){
110137
}];
111138
XCTAssertFalse(result);
112-
OCMReject([navigationChannel invokeMethod:OCMOCK_ANY arguments:OCMOCK_ANY]);
139+
OCMReject([self.mockNavigationChannel invokeMethod:OCMOCK_ANY arguments:OCMOCK_ANY]);
113140
}
114141

115142
- (void)testUniversalLinkPushRoute {
116-
id mockBundle = OCMClassMock([NSBundle class]);
117-
OCMStub([mockBundle mainBundle]).andReturn(mockBundle);
118-
OCMStub([mockBundle infoDictionary]).andReturn(@{@"FlutterDeepLinkingEnabled" : @YES});
143+
OCMStub([self.mockMainBundle objectForInfoDictionaryKey:@"FlutterDeepLinkingEnabled"])
144+
.andReturn(@YES);
119145

120-
FlutterAppDelegate* appDelegate = [[FlutterAppDelegate alloc] init];
121-
FlutterViewController* viewController = OCMClassMock([FlutterViewController class]);
122-
FlutterEngine* engine = OCMClassMock([FlutterEngine class]);
123-
FlutterMethodChannel* navigationChannel = OCMClassMock([FlutterMethodChannel class]);
124-
OCMStub([engine navigationChannel]).andReturn(navigationChannel);
125-
OCMStub([viewController engine]).andReturn(engine);
126-
// Set blockArg to a strong local to retain to end of scope.
127-
id blockArg = [OCMArg invokeBlockWithArgs:@NO, nil];
128-
OCMStub([engine waitForFirstFrame:3.0 callback:blockArg]);
129-
appDelegate.rootFlutterViewControllerGetter = ^{
130-
return viewController;
131-
};
132-
NSURL* url = [NSURL URLWithString:@"http://myApp/custom/route?query=test"];
133146
NSUserActivity* userActivity = [[NSUserActivity alloc] initWithActivityType:@"com.example.test"];
134-
userActivity.webpageURL = url;
135-
BOOL result = [appDelegate
147+
userActivity.webpageURL = [NSURL URLWithString:@"http://myApp/custom/route?query=test"];
148+
BOOL result = [self.appDelegate
136149
application:[UIApplication sharedApplication]
137150
continueUserActivity:userActivity
138151
restorationHandler:^(NSArray<id<UIUserActivityRestoring>>* __nullable restorableObjects){
139152
}];
140153
XCTAssertTrue(result);
141-
OCMVerify([navigationChannel invokeMethod:@"pushRoute" arguments:@"/custom/route?query=test"]);
142-
[mockBundle stopMocking];
154+
OCMVerify([self.mockNavigationChannel invokeMethod:@"pushRoute"
155+
arguments:@"/custom/route?query=test"]);
143156
}
144157

145158
@end

shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Test.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,4 @@
77
@interface FlutterAppDelegate (Test)
88
@property(nonatomic, copy) FlutterViewController* (^rootFlutterViewControllerGetter)(void);
99

10-
- (BOOL)openURL:(NSURL*)url infoPlistGetter:(NSDictionary* (^)())infoPlistGetter;
11-
1210
@end

0 commit comments

Comments
 (0)