Flutter iOS Embedder
FlutterDartProjectTest.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #import <OCMock/OCMock.h>
6 #import <XCTest/XCTest.h>
7 
8 #include "flutter/common/constants.h"
11 
13 
14 @interface FlutterDartProjectTest : XCTestCase
15 @end
16 
17 @implementation FlutterDartProjectTest
18 
19 - (void)setUp {
20 }
21 
22 - (void)tearDown {
23 }
24 
25 - (void)testOldGenHeapSizeSetting {
26  FlutterDartProject* project = [[FlutterDartProject alloc] init];
27  int64_t old_gen_heap_size =
28  std::round([NSProcessInfo processInfo].physicalMemory * .48 / flutter::kMegaByteSizeInBytes);
29  XCTAssertEqual(project.settings.old_gen_heap_size, old_gen_heap_size);
30 }
31 
32 - (void)testResourceCacheMaxBytesThresholdSetting {
33  FlutterDartProject* project = [[FlutterDartProject alloc] init];
34  CGFloat scale = [UIScreen mainScreen].scale;
35  CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width * scale;
36  CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height * scale;
37  size_t resource_cache_max_bytes_threshold = screenWidth * screenHeight * 12 * 4;
38  XCTAssertEqual(project.settings.resource_cache_max_bytes_threshold,
39  resource_cache_max_bytes_threshold);
40 }
41 
42 - (void)testMainBundleSettingsAreCorrectlyParsed {
43  NSBundle* mainBundle = [NSBundle mainBundle];
44  NSDictionary* appTransportSecurity =
45  [mainBundle objectForInfoDictionaryKey:@"NSAppTransportSecurity"];
46  XCTAssertTrue([FlutterDartProject allowsArbitraryLoads:appTransportSecurity]);
47  XCTAssertEqualObjects(
48  @"[[\"invalid-site.com\",true,false],[\"sub.invalid-site.com\",false,false]]",
49  [FlutterDartProject domainNetworkPolicy:appTransportSecurity]);
50 }
51 
52 - (void)testLeakDartVMSettingsAreCorrectlyParsed {
53  // The FLTLeakDartVM's value is defined in Info.plist
54  NSBundle* mainBundle = [NSBundle mainBundle];
55  NSNumber* leakDartVM = [mainBundle objectForInfoDictionaryKey:@"FLTLeakDartVM"];
56  XCTAssertEqual(leakDartVM.boolValue, NO);
57 
58  auto settings = FLTDefaultSettingsForBundle();
59  // Check settings.leak_vm value is same as the value defined in Info.plist.
60  XCTAssertEqual(settings.leak_vm, NO);
61 }
62 
63 - (void)testFLTFrameworkBundleInternalWhenBundleIsNotPresent {
64  NSBundle* found =
65  FLTFrameworkBundleInternal(@"doesNotExist", NSBundle.mainBundle.privateFrameworksURL);
66  XCTAssertNil(found);
67 }
68 
69 - (void)testFLTFrameworkBundleInternalWhenBundleIsPresent {
70  NSString* presentBundleID = @"io.flutter.flutter";
71  NSBundle* found =
72  FLTFrameworkBundleInternal(presentBundleID, NSBundle.mainBundle.privateFrameworksURL);
73  XCTAssertNotNil(found);
74 }
75 
76 - (void)testFLTGetApplicationBundleWhenCurrentTargetIsNotExtension {
77  NSBundle* bundle = FLTGetApplicationBundle();
78  XCTAssertEqual(bundle, [NSBundle mainBundle]);
79 }
80 
81 - (void)testFLTGetApplicationBundleWhenCurrentTargetIsExtension {
82  id mockMainBundle = OCMPartialMock([NSBundle mainBundle]);
83  NSURL* url = [[NSBundle mainBundle].bundleURL URLByAppendingPathComponent:@"foo/ext.appex"];
84  OCMStub([mockMainBundle bundleURL]).andReturn(url);
85  NSBundle* bundle = FLTGetApplicationBundle();
86  [mockMainBundle stopMocking];
87  XCTAssertEqualObjects(bundle.bundleURL, [NSBundle mainBundle].bundleURL);
88 }
89 
90 - (void)testFLTAssetsURLFromBundle {
91  {
92  // Found asset path in info.plist
93  id mockBundle = OCMClassMock([NSBundle class]);
94  OCMStub([mockBundle objectForInfoDictionaryKey:@"FLTAssetsPath"]).andReturn(@"foo/assets");
95  NSString* resultAssetsPath = @"path/to/foo/assets";
96  OCMStub([mockBundle pathForResource:@"foo/assets" ofType:nil]).andReturn(resultAssetsPath);
97  NSString* path = FLTAssetsPathFromBundle(mockBundle);
98  XCTAssertEqualObjects(path, @"path/to/foo/assets");
99  }
100  {
101  // Found asset path in info.plist, is not overriden by main bundle
102  id mockBundle = OCMClassMock([NSBundle class]);
103  id mockMainBundle = OCMPartialMock(NSBundle.mainBundle);
104  OCMStub([mockBundle objectForInfoDictionaryKey:@"FLTAssetsPath"]).andReturn(@"foo/assets");
105  OCMStub([mockMainBundle objectForInfoDictionaryKey:@"FLTAssetsPath"]).andReturn(nil);
106  NSString* resultAssetsPath = @"path/to/foo/assets";
107  OCMStub([mockBundle pathForResource:@"foo/assets" ofType:nil]).andReturn(resultAssetsPath);
108  NSString* path = FLTAssetsPathFromBundle(mockBundle);
109  XCTAssertEqualObjects(path, @"path/to/foo/assets");
110  [mockMainBundle stopMocking];
111  }
112  {
113  // No asset path in info.plist, defaults to main bundle
114  id mockBundle = OCMClassMock([NSBundle class]);
115  id mockMainBundle = OCMPartialMock([NSBundle mainBundle]);
116  NSString* resultAssetsPath = @"path/to/foo/assets";
117  OCMStub([mockBundle pathForResource:@"Frameworks/App.framework/flutter_assets" ofType:nil])
118  .andReturn(nil);
119  OCMStub([mockMainBundle pathForResource:@"Frameworks/App.framework/flutter_assets" ofType:nil])
120  .andReturn(resultAssetsPath);
121  NSString* path = FLTAssetsPathFromBundle(mockBundle);
122  XCTAssertEqualObjects(path, @"path/to/foo/assets");
123  [mockMainBundle stopMocking];
124  }
125 }
126 
127 - (void)testFLTAssetPathReturnsTheCorrectValue {
128  {
129  // Found assets path in info.plist
130  id mockBundle = OCMClassMock([NSBundle class]);
131  OCMStub([mockBundle objectForInfoDictionaryKey:@"FLTAssetsPath"]).andReturn(@"foo/assets");
132  XCTAssertEqualObjects(FLTAssetPath(mockBundle), @"foo/assets");
133  }
134  {
135  // No assets path in info.plist, use default value
136  id mockBundle = OCMClassMock([NSBundle class]);
137  OCMStub([mockBundle objectForInfoDictionaryKey:@"FLTAssetsPath"]).andReturn(nil);
138  XCTAssertEqualObjects(FLTAssetPath(mockBundle), kDefaultAssetPath);
139  }
140 }
141 
142 - (void)testLookUpForAssets {
143  {
144  id mockBundle = OCMPartialMock([NSBundle mainBundle]);
145  // Found assets path in info.plist
146  OCMStub([mockBundle objectForInfoDictionaryKey:@"FLTAssetsPath"]).andReturn(@"foo/assets");
147  NSString* assetsPath = [FlutterDartProject lookupKeyForAsset:@"bar"];
148  // This is testing public API, changing this assert is likely to break plugins.
149  XCTAssertEqualObjects(assetsPath, @"foo/assets/bar");
150  [mockBundle stopMocking];
151  }
152  {
153  id mockBundle = OCMPartialMock([NSBundle mainBundle]);
154  // No assets path in info.plist, use default value
155  OCMStub([mockBundle objectForInfoDictionaryKey:@"FLTAssetsPath"]).andReturn(nil);
156  NSString* assetsPath = [FlutterDartProject lookupKeyForAsset:@"bar"];
157  // This is testing public API, changing this assert is likely to break plugins.
158  XCTAssertEqualObjects(assetsPath, @"Frameworks/App.framework/flutter_assets/bar");
159  [mockBundle stopMocking];
160  }
161 }
162 
163 - (void)testLookUpForAssetsFromBundle {
164  {
165  id mockBundle = OCMClassMock([NSBundle class]);
166  // Found assets path in info.plist
167  OCMStub([mockBundle objectForInfoDictionaryKey:@"FLTAssetsPath"]).andReturn(@"foo/assets");
168  NSString* assetsPath = [FlutterDartProject lookupKeyForAsset:@"bar" fromBundle:mockBundle];
169  // This is testing public API, changing this assert is likely to break plugins.
170  XCTAssertEqualObjects(assetsPath, @"foo/assets/bar");
171  }
172  {
173  // No assets path in info.plist, use default value
174  id mockBundle = OCMClassMock([NSBundle class]);
175  OCMStub([mockBundle objectForInfoDictionaryKey:@"FLTAssetsPath"]).andReturn(nil);
176  NSString* assetsPath = [FlutterDartProject lookupKeyForAsset:@"bar" fromBundle:mockBundle];
177  // This is testing public API, changing this assert is likely to break plugins.
178  XCTAssertEqualObjects(assetsPath, @"Frameworks/App.framework/flutter_assets/bar");
179  }
180 }
181 
182 - (void)testLookUpForAssetsFromPackage {
183  {
184  id mockBundle = OCMPartialMock([NSBundle mainBundle]);
185  // Found assets path in info.plist
186  OCMStub([mockBundle objectForInfoDictionaryKey:@"FLTAssetsPath"]).andReturn(@"foo/assets");
187  NSString* assetsPath = [FlutterDartProject lookupKeyForAsset:@"bar" fromPackage:@"bar_package"];
188  // This is testing public API, changing this assert is likely to break plugins.
189  XCTAssertEqualObjects(assetsPath, @"foo/assets/packages/bar_package/bar");
190  [mockBundle stopMocking];
191  }
192  {
193  id mockBundle = OCMPartialMock([NSBundle mainBundle]);
194  // No assets path in info.plist, use default value
195  OCMStub([mockBundle objectForInfoDictionaryKey:@"FLTAssetsPath"]).andReturn(nil);
196  NSString* assetsPath = [FlutterDartProject lookupKeyForAsset:@"bar" fromPackage:@"bar_package"];
197  // This is testing public API, changing this assert is likely to break plugins.
198  XCTAssertEqualObjects(assetsPath,
199  @"Frameworks/App.framework/flutter_assets/packages/bar_package/bar");
200  [mockBundle stopMocking];
201  }
202 }
203 
204 - (void)testLookUpForAssetsFromPackageFromBundle {
205  {
206  id mockBundle = OCMClassMock([NSBundle class]);
207  // Found assets path in info.plist
208  OCMStub([mockBundle objectForInfoDictionaryKey:@"FLTAssetsPath"]).andReturn(@"foo/assets");
209  NSString* assetsPath = [FlutterDartProject lookupKeyForAsset:@"bar"
210  fromPackage:@"bar_package"
211  fromBundle:mockBundle];
212  // This is testing public API, changing this assert is likely to break plugins.
213  XCTAssertEqualObjects(assetsPath, @"foo/assets/packages/bar_package/bar");
214  }
215  {
216  id mockBundle = OCMClassMock([NSBundle class]);
217  // No assets path in info.plist, use default value
218  OCMStub([mockBundle objectForInfoDictionaryKey:@"FLTAssetsPath"]).andReturn(nil);
219  NSString* assetsPath = [FlutterDartProject lookupKeyForAsset:@"bar"
220  fromPackage:@"bar_package"
221  fromBundle:mockBundle];
222  // This is testing public API, changing this assert is likely to break plugins.
223  XCTAssertEqualObjects(assetsPath,
224  @"Frameworks/App.framework/flutter_assets/packages/bar_package/bar");
225  }
226 }
227 
228 - (void)testRequestsWarningWhenImpellerOptOut {
229  auto settings = FLTDefaultSettingsForBundle();
230  XCTAssertEqual(settings.warn_on_impeller_opt_out, YES);
231 }
232 
233 - (void)testEnableImpellerSettingIsCorrectlyParsed {
234  id mockMainBundle = OCMPartialMock([NSBundle mainBundle]);
235  OCMStub([mockMainBundle objectForInfoDictionaryKey:@"FLTEnableImpeller"]).andReturn(@"YES");
236 
237  auto settings = FLTDefaultSettingsForBundle();
238  // Check settings.enable_impeller value is same as the value defined in Info.plist.
239  XCTAssertEqual(settings.enable_impeller, YES);
240  [mockMainBundle stopMocking];
241 }
242 
243 - (void)testEnableImpellerSettingIsCorrectlyOverriddenByCommandLine {
244  id mockMainBundle = OCMPartialMock([NSBundle mainBundle]);
245  OCMStub([mockMainBundle objectForInfoDictionaryKey:@"FLTEnableImpeller"]).andReturn(@"NO");
246  id mockProcessInfo = OCMPartialMock([NSProcessInfo processInfo]);
247  NSArray* arguments = @[ @"process_name", @"--enable-impeller" ];
248  OCMStub([mockProcessInfo arguments]).andReturn(arguments);
249 
250  auto settings = FLTDefaultSettingsForBundle(nil, mockProcessInfo);
251  // Check settings.enable_impeller value is same as the value on command line.
252  XCTAssertEqual(settings.enable_impeller, YES);
253  [mockMainBundle stopMocking];
254 }
255 
256 - (void)testEnableDartAssertsCommandLineArgument {
257  id mockMainBundle = OCMPartialMock([NSBundle mainBundle]);
258  OCMStub([mockMainBundle objectForInfoDictionaryKey:@"FLTEnableDartAsserts"]).andReturn(@"YES");
259  id mockProcessInfo = OCMPartialMock([NSProcessInfo processInfo]);
260  NSArray* arguments = @[ @"process_name" ];
261  OCMStub([mockProcessInfo arguments]).andReturn(arguments);
262 
263  auto settings = FLTDefaultSettingsForBundle(nil, mockProcessInfo);
264 
265  XCTAssertEqual(settings.dart_flags.size(), 1u);
266  XCTAssertEqual(settings.dart_flags[0], "--enable-asserts");
267  [mockMainBundle stopMocking];
268 }
269 
270 - (void)testEnableTraceSystraceSettingIsCorrectlyParsed {
271  NSBundle* mainBundle = [NSBundle mainBundle];
272  NSNumber* enableTraceSystrace = [mainBundle objectForInfoDictionaryKey:@"FLTTraceSystrace"];
273  XCTAssertNotNil(enableTraceSystrace);
274  XCTAssertEqual(enableTraceSystrace.boolValue, NO);
275  auto settings = FLTDefaultSettingsForBundle();
276  XCTAssertEqual(settings.trace_systrace, NO);
277 }
278 
279 - (void)testEnableDartProflingSettingIsCorrectlyParsed {
280  NSBundle* mainBundle = [NSBundle mainBundle];
281  NSNumber* enableTraceSystrace = [mainBundle objectForInfoDictionaryKey:@"FLTEnableDartProfiling"];
282  XCTAssertNotNil(enableTraceSystrace);
283  XCTAssertEqual(enableTraceSystrace.boolValue, NO);
284  auto settings = FLTDefaultSettingsForBundle();
285  XCTAssertEqual(settings.trace_systrace, NO);
286 }
287 
288 - (void)testEmptySettingsAreCorrect {
289  XCTAssertFalse([FlutterDartProject allowsArbitraryLoads:[[NSDictionary alloc] init]]);
290  XCTAssertEqualObjects(@"", [FlutterDartProject domainNetworkPolicy:[[NSDictionary alloc] init]]);
291 }
292 
293 - (void)testAllowsArbitraryLoads {
294  XCTAssertFalse([FlutterDartProject allowsArbitraryLoads:@{@"NSAllowsArbitraryLoads" : @false}]);
295  XCTAssertTrue([FlutterDartProject allowsArbitraryLoads:@{@"NSAllowsArbitraryLoads" : @true}]);
296 }
297 
298 - (void)testProperlyFormedExceptionDomains {
299  NSDictionary* domainInfoOne = @{
300  @"NSIncludesSubdomains" : @false,
301  @"NSExceptionAllowsInsecureHTTPLoads" : @true,
302  @"NSExceptionMinimumTLSVersion" : @"4.0"
303  };
304  NSDictionary* domainInfoTwo = @{
305  @"NSIncludesSubdomains" : @true,
306  @"NSExceptionAllowsInsecureHTTPLoads" : @false,
307  @"NSExceptionMinimumTLSVersion" : @"4.0"
308  };
309  NSDictionary* domainInfoThree = @{
310  @"NSIncludesSubdomains" : @false,
311  @"NSExceptionAllowsInsecureHTTPLoads" : @true,
312  @"NSExceptionMinimumTLSVersion" : @"4.0"
313  };
314  NSDictionary* exceptionDomains = @{
315  @"domain.name" : domainInfoOne,
316  @"sub.domain.name" : domainInfoTwo,
317  @"sub.two.domain.name" : domainInfoThree
318  };
319  NSDictionary* appTransportSecurity = @{@"NSExceptionDomains" : exceptionDomains};
320  XCTAssertEqualObjects(@"[[\"domain.name\",false,true],[\"sub.domain.name\",true,false],"
321  @"[\"sub.two.domain.name\",false,true]]",
322  [FlutterDartProject domainNetworkPolicy:appTransportSecurity]);
323 }
324 
325 - (void)testExceptionDomainsWithMissingInfo {
326  NSDictionary* domainInfoOne = @{@"NSExceptionMinimumTLSVersion" : @"4.0"};
327  NSDictionary* domainInfoTwo = @{
328  @"NSIncludesSubdomains" : @true,
329  };
330  NSDictionary* domainInfoThree = @{};
331  NSDictionary* exceptionDomains = @{
332  @"domain.name" : domainInfoOne,
333  @"sub.domain.name" : domainInfoTwo,
334  @"sub.two.domain.name" : domainInfoThree
335  };
336  NSDictionary* appTransportSecurity = @{@"NSExceptionDomains" : exceptionDomains};
337  XCTAssertEqualObjects(@"[[\"domain.name\",false,false],[\"sub.domain.name\",true,false],"
338  @"[\"sub.two.domain.name\",false,false]]",
339  [FlutterDartProject domainNetworkPolicy:appTransportSecurity]);
340 }
341 
342 @end
FLTFrameworkBundleInternal
NSBundle * FLTFrameworkBundleInternal(NSString *flutterFrameworkBundleID, NSURL *searchURL)
Definition: FlutterNSBundleUtils.mm:17
+[FlutterDartProject lookupKeyForAsset:fromPackage:fromBundle:]
NSString * lookupKeyForAsset:fromPackage:fromBundle:(NSString *asset,[fromPackage] NSString *package,[fromBundle] nullable NSBundle *bundle)
Definition: FlutterDartProject.mm:391
kDefaultAssetPath
NS_ASSUME_NONNULL_BEGIN NSString *const kDefaultAssetPath
Definition: FlutterNSBundleUtils.mm:13
+[FlutterDartProject lookupKeyForAsset:]
NSString * lookupKeyForAsset:(NSString *asset)
Definition: FlutterDartProject.mm:378
FlutterDartProjectTest
Definition: FlutterDartProjectTest.mm:14
FlutterMacros.h
FLTAssetPath
NSString * FLTAssetPath(NSBundle *bundle)
Definition: FlutterNSBundleUtils.mm:60
FLTGetApplicationBundle
NSBundle * FLTGetApplicationBundle()
Definition: FlutterNSBundleUtils.mm:35
FlutterDartProject_Internal.h
+[FlutterDartProject lookupKeyForAsset:fromPackage:]
NSString * lookupKeyForAsset:fromPackage:(NSString *asset,[fromPackage] NSString *package)
Definition: FlutterDartProject.mm:387
-[FlutterDartProject settings]
const flutter::Settings & settings()
FLTDefaultSettingsForBundle
flutter::Settings FLTDefaultSettingsForBundle(NSBundle *bundle, NSProcessInfo *processInfoOrNil)
Definition: FlutterDartProject.mm:47
FLTAssetsPathFromBundle
NSString * FLTAssetsPathFromBundle(NSBundle *bundle)
Definition: FlutterNSBundleUtils.mm:64
FlutterDartProject
Definition: FlutterDartProject.mm:252
+[FlutterDartProject lookupKeyForAsset:fromBundle:]
NSString * lookupKeyForAsset:fromBundle:(NSString *asset,[fromBundle] nullable NSBundle *bundle)
Definition: FlutterDartProject.mm:382
FLUTTER_ASSERT_ARC
Definition: FlutterChannelKeyResponder.mm:13