| 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
8 #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h"
9 #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterSceneDelegate.h"
10 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSceneLifeCycle_Internal.h"
11 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSceneLifeCycle_Test.h"
12 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h"
13
14 FLUTTER_ASSERT_ARC
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
34 - (void)flutterViewAccessibilityDidCall {
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 =
195 [[FlutterPluginSceneLifeCycleDelegate alloc] init];
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
FlutterEngine.h
FlutterSceneDelegate.h
FlutterSceneLifeCycle_Internal.h
FlutterSceneLifeCycle_Test.h
FlutterView.h
FakeDelegate
Definition: FlutterViewTest.mm:16
FakeDelegate::callbackCalled
BOOL callbackCalled
Definition: FlutterViewTest.mm:17
FlutterEngine
Definition: FlutterEngine.h:61
FlutterPluginSceneLifeCycleDelegate
Definition: FlutterSceneLifeCycle.h:149
FlutterPluginSceneLifeCycleDelegate::flutterManagedEngines
NSPointerArray * flutterManagedEngines
Definition: FlutterSceneLifeCycle_Test.h:14
FlutterSceneDelegate
Definition: FlutterSceneDelegate.h:21
FlutterView
Definition: FlutterView.h:50
-[FlutterView screen]
UIScreen * screen()
Definition: FlutterView.mm:42
FlutterViewTest
Definition: FlutterViewTest.mm:41
FLUTTER_ASSERT_ARC
Definition: FlutterChannelKeyResponder.mm:13
FlutterViewEngineDelegate-p
Definition: FlutterView.h:14
FlutterViewEngineDelegate-p::platformViewsController
FlutterPlatformViewsController * platformViewsController
Definition: FlutterView.h:16
-[FlutterViewEngineDelegate-p flutterViewAccessibilityDidCall]
void flutterViewAccessibilityDidCall()