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)testEnableDartAssertsCommandLineArgument {
229  id mockMainBundle = OCMPartialMock([NSBundle mainBundle]);
230  OCMStub([mockMainBundle objectForInfoDictionaryKey:@"FLTEnableDartAsserts"]).andReturn(@"YES");
231  id mockProcessInfo = OCMPartialMock([NSProcessInfo processInfo]);
232  NSArray* arguments = @[ @"process_name" ];
233  OCMStub([mockProcessInfo arguments]).andReturn(arguments);
234 
235  auto settings = FLTDefaultSettingsForBundle(nil, mockProcessInfo);
236 
237  XCTAssertEqual(settings.dart_flags.size(), 1u);
238  XCTAssertEqual(settings.dart_flags[0], "--enable-asserts");
239  [mockMainBundle stopMocking];
240 }
241 
242 - (void)testEnableFlutterGPUCommandLineArgument {
243  id mockMainBundle = OCMPartialMock([NSBundle mainBundle]);
244  OCMStub([mockMainBundle objectForInfoDictionaryKey:@"FLTEnableFlutterGPU"]).andReturn(@"YES");
245  id mockProcessInfo = OCMPartialMock([NSProcessInfo processInfo]);
246  NSArray* arguments = @[ @"process_name" ];
247  OCMStub([mockProcessInfo arguments]).andReturn(arguments);
248 
249  auto settings = FLTDefaultSettingsForBundle(nil, mockProcessInfo);
250 
251  XCTAssertTrue(settings.enable_flutter_gpu);
252  [mockMainBundle stopMocking];
253 }
254 
255 - (void)testEnableTraceSystraceSettingIsCorrectlyParsed {
256  NSBundle* mainBundle = [NSBundle mainBundle];
257  NSNumber* enableTraceSystrace = [mainBundle objectForInfoDictionaryKey:@"FLTTraceSystrace"];
258  XCTAssertNotNil(enableTraceSystrace);
259  XCTAssertEqual(enableTraceSystrace.boolValue, NO);
260  auto settings = FLTDefaultSettingsForBundle();
261  XCTAssertEqual(settings.trace_systrace, NO);
262 }
263 
264 - (void)testEnableDartProflingSettingIsCorrectlyParsed {
265  NSBundle* mainBundle = [NSBundle mainBundle];
266  NSNumber* enableTraceSystrace = [mainBundle objectForInfoDictionaryKey:@"FLTEnableDartProfiling"];
267  XCTAssertNotNil(enableTraceSystrace);
268  XCTAssertEqual(enableTraceSystrace.boolValue, NO);
269  auto settings = FLTDefaultSettingsForBundle();
270  XCTAssertEqual(settings.trace_systrace, NO);
271 }
272 
273 - (void)testEmptySettingsAreCorrect {
274  XCTAssertFalse([FlutterDartProject allowsArbitraryLoads:[[NSDictionary alloc] init]]);
275  XCTAssertEqualObjects(@"", [FlutterDartProject domainNetworkPolicy:[[NSDictionary alloc] init]]);
276 }
277 
278 - (void)testAllowsArbitraryLoads {
279  XCTAssertFalse([FlutterDartProject allowsArbitraryLoads:@{@"NSAllowsArbitraryLoads" : @false}]);
280  XCTAssertTrue([FlutterDartProject allowsArbitraryLoads:@{@"NSAllowsArbitraryLoads" : @true}]);
281 }
282 
283 - (void)testProperlyFormedExceptionDomains {
284  NSDictionary* domainInfoOne = @{
285  @"NSIncludesSubdomains" : @false,
286  @"NSExceptionAllowsInsecureHTTPLoads" : @true,
287  @"NSExceptionMinimumTLSVersion" : @"4.0"
288  };
289  NSDictionary* domainInfoTwo = @{
290  @"NSIncludesSubdomains" : @true,
291  @"NSExceptionAllowsInsecureHTTPLoads" : @false,
292  @"NSExceptionMinimumTLSVersion" : @"4.0"
293  };
294  NSDictionary* domainInfoThree = @{
295  @"NSIncludesSubdomains" : @false,
296  @"NSExceptionAllowsInsecureHTTPLoads" : @true,
297  @"NSExceptionMinimumTLSVersion" : @"4.0"
298  };
299  NSDictionary* exceptionDomains = @{
300  @"domain.name" : domainInfoOne,
301  @"sub.domain.name" : domainInfoTwo,
302  @"sub.two.domain.name" : domainInfoThree
303  };
304  NSDictionary* appTransportSecurity = @{@"NSExceptionDomains" : exceptionDomains};
305  XCTAssertEqualObjects(@"[[\"domain.name\",false,true],[\"sub.domain.name\",true,false],"
306  @"[\"sub.two.domain.name\",false,true]]",
307  [FlutterDartProject domainNetworkPolicy:appTransportSecurity]);
308 }
309 
310 - (void)testExceptionDomainsWithMissingInfo {
311  NSDictionary* domainInfoOne = @{@"NSExceptionMinimumTLSVersion" : @"4.0"};
312  NSDictionary* domainInfoTwo = @{
313  @"NSIncludesSubdomains" : @true,
314  };
315  NSDictionary* domainInfoThree = @{};
316  NSDictionary* exceptionDomains = @{
317  @"domain.name" : domainInfoOne,
318  @"sub.domain.name" : domainInfoTwo,
319  @"sub.two.domain.name" : domainInfoThree
320  };
321  NSDictionary* appTransportSecurity = @{@"NSExceptionDomains" : exceptionDomains};
322  XCTAssertEqualObjects(@"[[\"domain.name\",false,false],[\"sub.domain.name\",true,false],"
323  @"[\"sub.two.domain.name\",false,false]]",
324  [FlutterDartProject domainNetworkPolicy:appTransportSecurity]);
325 }
326 
327 @end
flutter::Settings FLTDefaultSettingsForBundle(NSBundle *bundle, NSProcessInfo *processInfoOrNil)
NSBundle * FLTFrameworkBundleInternal(NSString *flutterFrameworkBundleID, NSURL *searchURL)
NSString * FLTAssetPath(NSBundle *bundle)
NSBundle * FLTGetApplicationBundle()
NSString * FLTAssetsPathFromBundle(NSBundle *bundle)
NS_ASSUME_NONNULL_BEGIN NSString *const kDefaultAssetPath
NSString * lookupKeyForAsset:fromBundle:(NSString *asset,[fromBundle] nullable NSBundle *bundle)
NSString * lookupKeyForAsset:fromPackage:(NSString *asset,[fromPackage] NSString *package)
NSString * lookupKeyForAsset:fromPackage:fromBundle:(NSString *asset,[fromPackage] NSString *package,[fromBundle] nullable NSBundle *bundle)
const flutter::Settings & settings()
NSString * lookupKeyForAsset:(NSString *asset)