Flutter iOS Embedder
FlutterViewTest.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 
13 
15 
16 @interface FakeDelegate : NSObject <FlutterViewEngineDelegate>
17 @property(nonatomic) BOOL callbackCalled;
18 @end
19 
20 @implementation FakeDelegate
21 
22 @synthesize platformViewsController = _platformViewsController;
23 
24 - (instancetype)init {
25  _callbackCalled = NO;
26  return self;
27 }
28 
29 - (flutter::Rasterizer::Screenshot)takeScreenshot:(flutter::Rasterizer::ScreenshotType)type
30  asBase64Encoded:(BOOL)base64Encode {
31  return {};
32 }
33 
35  _callbackCalled = YES;
36 }
37 
38 @end
39 
40 @interface FlutterViewTest : XCTestCase
41 @end
42 
43 @implementation FlutterViewTest
44 
45 - (void)testFlutterViewEnableSemanticsWhenIsAccessibilityElementIsCalled {
46  FakeDelegate* delegate = [[FakeDelegate alloc] init];
47  FlutterView* view = [[FlutterView alloc] initWithDelegate:delegate opaque:NO enableWideGamut:NO];
48  delegate.callbackCalled = NO;
49  XCTAssertFalse(view.isAccessibilityElement);
50  XCTAssertTrue(delegate.callbackCalled);
51 }
52 
53 - (void)testFlutterViewBackgroundColorIsNil {
54  FakeDelegate* delegate = [[FakeDelegate alloc] init];
55  FlutterView* view = [[FlutterView alloc] initWithDelegate:delegate opaque:NO enableWideGamut:NO];
56  XCTAssertNil(view.backgroundColor);
57 }
58 
59 - (void)testLayerScalesMatchScreenAfterLayoutSubviews {
60  FakeDelegate* delegate = [[FakeDelegate alloc] init];
61  FlutterView* view = [[FlutterView alloc] initWithDelegate:delegate opaque:NO enableWideGamut:NO];
62  view.layer.contentsScale = CGFloat(-99.0);
63  view.layer.rasterizationScale = CGFloat(-99.0);
64  UIScreen* screen = [view screen];
65  XCTAssertNotEqual(view.layer.contentsScale, screen.scale);
66  XCTAssertNotEqual(view.layer.rasterizationScale, screen.scale);
67  [view layoutSubviews];
68  XCTAssertEqual(view.layer.contentsScale, screen.scale);
69  XCTAssertEqual(view.layer.rasterizationScale, screen.scale);
70 }
71 
72 - (void)testViewWillMoveToWindow {
73  NSDictionary* mocks = [self createWindowMocks];
74  FlutterView* view = (FlutterView*)mocks[@"view"];
75  id mockLifecycleDelegate = mocks[@"mockLifecycleDelegate"];
76  FlutterPluginSceneLifeCycleDelegate* lifecycleDelegate =
77  (FlutterPluginSceneLifeCycleDelegate*)mocks[@"lifecycleDelegate"];
78  id mockEngine = mocks[@"mockEngine"];
79  id mockWindow = mocks[@"mockWindow"];
80 
81  [view willMoveToWindow:mockWindow];
82  OCMVerify(times(1), [mockLifecycleDelegate addFlutterManagedEngine:mockEngine]);
83  XCTAssertEqual(lifecycleDelegate.flutterManagedEngines.count, 1.0);
84 }
85 
86 - (void)testViewWillMoveToSameWindow {
87  NSDictionary* mocks = [self createWindowMocks];
88  FlutterView* view = (FlutterView*)mocks[@"view"];
89  id mockLifecycleDelegate = mocks[@"mockLifecycleDelegate"];
90  FlutterPluginSceneLifeCycleDelegate* lifecycleDelegate =
91  (FlutterPluginSceneLifeCycleDelegate*)mocks[@"lifecycleDelegate"];
92  id mockEngine = mocks[@"mockEngine"];
93  id mockWindow = mocks[@"mockWindow"];
94 
95  [view willMoveToWindow:mockWindow];
96  [view willMoveToWindow:mockWindow];
97 
98  OCMVerify(times(2), [mockLifecycleDelegate addFlutterManagedEngine:mockEngine]);
99  XCTAssertEqual(lifecycleDelegate.flutterManagedEngines.count, 1.0);
100 }
101 
102 - (void)testMultipleViewsWillMoveToSameWindow {
103  NSDictionary* mocks = [self createWindowMocks];
104  FlutterView* view1 = (FlutterView*)mocks[@"view"];
105  id mockLifecycleDelegate = mocks[@"mockLifecycleDelegate"];
106  FlutterPluginSceneLifeCycleDelegate* lifecycleDelegate =
107  (FlutterPluginSceneLifeCycleDelegate*)mocks[@"lifecycleDelegate"];
108  id mockEngine1 = mocks[@"mockEngine"];
109  id mockWindow1 = mocks[@"mockWindow"];
110 
111  id mockEngine2 = OCMClassMock([FlutterEngine class]);
112  FlutterView* view2 = [[FlutterView alloc] initWithDelegate:mockEngine2
113  opaque:NO
114  enableWideGamut:NO];
115 
116  [view1 willMoveToWindow:mockWindow1];
117  [view2 willMoveToWindow:mockWindow1];
118  [view1 willMoveToWindow:mockWindow1];
119  OCMVerify(times(2), [mockLifecycleDelegate addFlutterManagedEngine:mockEngine1]);
120  OCMVerify(times(1), [mockLifecycleDelegate addFlutterManagedEngine:mockEngine2]);
121  XCTAssertEqual(lifecycleDelegate.flutterManagedEngines.count, 2.0);
122 }
123 
124 - (void)testMultipleViewsWillMoveToDifferentWindow {
125  NSDictionary* mocks = [self createWindowMocks];
126  FlutterView* view1 = (FlutterView*)mocks[@"view"];
127  id mockLifecycleDelegate1 = mocks[@"mockLifecycleDelegate"];
128  FlutterPluginSceneLifeCycleDelegate* lifecycleDelegate1 =
129  (FlutterPluginSceneLifeCycleDelegate*)mocks[@"lifecycleDelegate"];
130  id mockEngine1 = mocks[@"mockEngine"];
131  id mockWindow1 = mocks[@"mockWindow"];
132 
133  NSDictionary* mocks2 = [self createWindowMocks];
134  FlutterView* view2 = (FlutterView*)mocks2[@"view"];
135  id mockLifecycleDelegate2 = mocks2[@"mockLifecycleDelegate"];
136  FlutterPluginSceneLifeCycleDelegate* lifecycleDelegate2 =
137  (FlutterPluginSceneLifeCycleDelegate*)mocks2[@"lifecycleDelegate"];
138  id mockEngine2 = mocks2[@"mockEngine"];
139  id mockWindow2 = mocks2[@"mockWindow"];
140 
141  [view1 willMoveToWindow:mockWindow1];
142  [view2 willMoveToWindow:mockWindow2];
143  [view1 willMoveToWindow:mockWindow1];
144  OCMVerify(times(2), [mockLifecycleDelegate1 addFlutterManagedEngine:mockEngine1]);
145  OCMVerify(times(1), [mockLifecycleDelegate2 addFlutterManagedEngine:mockEngine2]);
146  XCTAssertEqual(lifecycleDelegate1.flutterManagedEngines.count, 1.0);
147  XCTAssertEqual(lifecycleDelegate2.flutterManagedEngines.count, 1.0);
148 }
149 
150 - (void)testViewRemovedFromWindowAndAddedToNewScene {
151  NSDictionary* mocks = [self createWindowMocks];
152  FlutterView* view = (FlutterView*)mocks[@"view"];
153  id mockLifecycleDelegate = mocks[@"mockLifecycleDelegate"];
154  FlutterPluginSceneLifeCycleDelegate* lifecycleDelegate =
155  (FlutterPluginSceneLifeCycleDelegate*)mocks[@"lifecycleDelegate"];
156  id mockEngine = mocks[@"mockEngine"];
157  id mockWindow = mocks[@"mockWindow"];
158 
159  NSDictionary* mocks2 = [self createWindowMocks];
160  id mockWindow2 = mocks2[@"mockWindow"];
161  id mockLifecycleDelegate2 = mocks2[@"mockLifecycleDelegate"];
162  FlutterPluginSceneLifeCycleDelegate* lifecycleDelegate2 =
163  (FlutterPluginSceneLifeCycleDelegate*)mocks2[@"lifecycleDelegate"];
164 
165  id mockView = OCMPartialMock(view);
166 
167  [mockView willMoveToWindow:mockWindow];
168  OCMVerify(times(1), [mockLifecycleDelegate addFlutterManagedEngine:mockEngine]);
169  XCTAssertEqual(lifecycleDelegate.flutterManagedEngines.count, 1.0);
170 
171  OCMStub([mockView window]).andReturn(mockWindow);
172  [mockView willMoveToWindow:nil];
173  XCTAssertEqual(lifecycleDelegate.flutterManagedEngines.count, 1.0);
174 
175  OCMStub([mockView window]).andReturn(nil);
176  [mockView willMoveToWindow:mockWindow2];
177  OCMVerify(times(1), [mockLifecycleDelegate removeFlutterManagedEngine:mockEngine]);
178  XCTAssertEqual(lifecycleDelegate.flutterManagedEngines.count, 0.0);
179  OCMVerify(times(1), [mockLifecycleDelegate2 addFlutterManagedEngine:mockEngine]);
180  XCTAssertEqual(lifecycleDelegate2.flutterManagedEngines.count, 1.0);
181 }
182 
183 - (NSDictionary*)createWindowMocks {
184  id mockEngine = OCMClassMock([FlutterEngine class]);
185  FlutterView* view = [[FlutterView alloc] initWithDelegate:mockEngine
186  opaque:NO
187  enableWideGamut:NO];
188  id mockWindow = OCMClassMock([UIWindow class]);
189  id mockWindowScene = OCMClassMock([UIWindowScene class]);
190 
191  FlutterSceneDelegate* sceneDelegate = [[FlutterSceneDelegate alloc] init];
192  id mockSceneDelegate = OCMPartialMock(sceneDelegate);
193 
194  FlutterPluginSceneLifeCycleDelegate* lifecycleDelegate =
196  id mockLifecycleDelegate = OCMPartialMock(lifecycleDelegate);
197 
198  OCMStub([mockWindow windowScene]).andReturn(mockWindowScene);
199  OCMStub([mockWindowScene delegate]).andReturn(mockSceneDelegate);
200  OCMStub([mockSceneDelegate sceneLifeCycleDelegate]).andReturn(mockLifecycleDelegate);
201 
202  return @{
203  @"view" : view,
204  @"mockLifecycleDelegate" : mockLifecycleDelegate,
205  @"lifecycleDelegate" : lifecycleDelegate,
206  @"mockEngine" : mockEngine,
207  @"mockWindow" : mockWindow,
208  };
209 }
210 
211 @end
UIScreen * screen()
Definition: FlutterView.mm:38
FlutterPlatformViewsController * platformViewsController
Definition: FlutterView.h:16