| Flutter iOS Embedder |

SemanticsObjectTest.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/common/framework/Headers/FlutterMacros.h"
9 #import "flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.h"
10 #import "flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTestMocks.h"
11
12 FLUTTER_ASSERT_ARC
13
14 @interface SemanticsObjectTest : XCTestCase
15 @end
16
17 @implementation SemanticsObjectTest
18
19 - (void)testCreate {
20 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
21 new flutter::MockAccessibilityBridge());
22 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
23 SemanticsObject* object = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
24 XCTAssertNotNil(object);
25 }
26
27 - (void)testSetChildren {
28 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
29 new flutter::MockAccessibilityBridge());
30 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
31 SemanticsObject* parent = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
32 SemanticsObject* child = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
33 parent.children = @[ child ];
34 XCTAssertEqual(parent, child.parent);
35 parent.children = @[];
36 XCTAssertNil(child.parent);
37 }
38
39 - (void)testAccessibilityHitTestFocusAtLeaf {
40 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
41 new flutter::MockAccessibilityBridge());
42 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
43 SemanticsObject* object0 = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
44 SemanticsObject* object1 = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
45 SemanticsObject* object2 = [[SemanticsObject alloc] initWithBridge:bridge uid:2];
46 SemanticsObject* object3 = [[SemanticsObject alloc] initWithBridge:bridge uid:3];
47 object0.children = @[ object1 ];
48 object0.childrenInHitTestOrder = @[ object1 ];
49 object1.children = @[ object2, object3 ];
50 object1.childrenInHitTestOrder = @[ object2, object3 ];
51
52 flutter::SemanticsNode node0;
53 node0.id = 0;
54 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
55 node0.label = "0";
56 [object0 setSemanticsNode:&node0];
57
58 flutter::SemanticsNode node1;
59 node1.id = 1;
60 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
61 node1.label = "1";
62 [object1 setSemanticsNode:&node1];
63
64 flutter::SemanticsNode node2;
65 node2.id = 2;
66 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
67 node2.label = "2";
68 [object2 setSemanticsNode:&node2];
69
70 flutter::SemanticsNode node3;
71 node3.id = 3;
72 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
73 node3.label = "3";
74 [object3 setSemanticsNode:&node3];
75
76 CGPoint point = CGPointMake(10, 10);
77 id hitTestResult = [object0 _accessibilityHitTest:point withEvent:nil];
78
79 // Focus to object2 because it's the first object in hit test order
80 XCTAssertEqual(hitTestResult, object2);
81 }
82
83 - (void)testAccessibilityHitTestNoFocusableItem {
84 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
85 new flutter::MockAccessibilityBridge());
86 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
87 SemanticsObject* object0 = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
88 SemanticsObject* object1 = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
89 SemanticsObject* object2 = [[SemanticsObject alloc] initWithBridge:bridge uid:2];
90 SemanticsObject* object3 = [[SemanticsObject alloc] initWithBridge:bridge uid:3];
91 object0.children = @[ object1 ];
92 object0.childrenInHitTestOrder = @[ object1 ];
93 object1.children = @[ object2, object3 ];
94 object1.childrenInHitTestOrder = @[ object2, object3 ];
95
96 flutter::SemanticsNode node0;
97 node0.id = 0;
98 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
99 [object0 setSemanticsNode:&node0];
100
101 flutter::SemanticsNode node1;
102 node1.id = 1;
103 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
104 [object1 setSemanticsNode:&node1];
105
106 flutter::SemanticsNode node2;
107 node2.id = 2;
108 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
109 [object2 setSemanticsNode:&node2];
110
111 flutter::SemanticsNode node3;
112 node3.id = 3;
113 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
114 [object3 setSemanticsNode:&node3];
115
116 CGPoint point = CGPointMake(10, 10);
117 id hitTestResult = [object0 _accessibilityHitTest:point withEvent:nil];
118
119 XCTAssertNil(hitTestResult);
120 }
121
122 - (void)testAccessibilityScrollToVisible {
123 fml::WeakPtrFactory<flutter::MockAccessibilityBridge> factory(
124 new flutter::MockAccessibilityBridge());
125 fml::WeakPtr<flutter::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
126 SemanticsObject* object3 = [[SemanticsObject alloc] initWithBridge:bridge uid:3];
127
128 flutter::SemanticsNode node3;
129 node3.id = 3;
130 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
131 [object3 setSemanticsNode:&node3];
132
133 [object3 accessibilityScrollToVisible];
134
135 XCTAssertTrue(bridge->observations.size() == 1);
136 XCTAssertTrue(bridge->observations[0].id == 3);
137 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
138 }
139
140 - (void)testAccessibilityScrollToVisibleWithChild {
141 fml::WeakPtrFactory<flutter::MockAccessibilityBridge> factory(
142 new flutter::MockAccessibilityBridge());
143 fml::WeakPtr<flutter::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
144 SemanticsObject* object3 = [[SemanticsObject alloc] initWithBridge:bridge uid:3];
145
146 flutter::SemanticsNode node3;
147 node3.id = 3;
148 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
149 [object3 setSemanticsNode:&node3];
150
151 [object3 accessibilityScrollToVisibleWithChild:object3];
152
153 XCTAssertTrue(bridge->observations.size() == 1);
154 XCTAssertTrue(bridge->observations[0].id == 3);
155 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
156 }
157
158 - (void)testAccessibilityHitTestOutOfRect {
159 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
160 new flutter::MockAccessibilityBridge());
161 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
162 SemanticsObject* object0 = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
163 SemanticsObject* object1 = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
164 SemanticsObject* object2 = [[SemanticsObject alloc] initWithBridge:bridge uid:2];
165 SemanticsObject* object3 = [[SemanticsObject alloc] initWithBridge:bridge uid:3];
166 object0.children = @[ object1 ];
167 object0.childrenInHitTestOrder = @[ object1 ];
168 object1.children = @[ object2, object3 ];
169 object1.childrenInHitTestOrder = @[ object2, object3 ];
170
171 flutter::SemanticsNode node0;
172 node0.id = 0;
173 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
174 node0.label = "0";
175 [object0 setSemanticsNode:&node0];
176
177 flutter::SemanticsNode node1;
178 node1.id = 1;
179 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
180 node1.label = "1";
181 [object1 setSemanticsNode:&node1];
182
183 flutter::SemanticsNode node2;
184 node2.id = 2;
185 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
186 node2.label = "2";
187 [object2 setSemanticsNode:&node2];
188
189 flutter::SemanticsNode node3;
190 node3.id = 3;
191 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
192 node3.label = "3";
193 [object3 setSemanticsNode:&node3];
194
195 CGPoint point = CGPointMake(300, 300);
196 id hitTestResult = [object0 _accessibilityHitTest:point withEvent:nil];
197
198 XCTAssertNil(hitTestResult);
199 }
200
201 - (void)testReplaceChildAtIndex {
202 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
203 new flutter::MockAccessibilityBridge());
204 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
205 SemanticsObject* parent = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
206 SemanticsObject* child1 = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
207 SemanticsObject* child2 = [[SemanticsObject alloc] initWithBridge:bridge uid:2];
208 parent.children = @[ child1 ];
209 [parent replaceChildAtIndex:0 withChild:child2];
210 XCTAssertNil(child1.parent);
211 XCTAssertEqual(parent, child2.parent);
212 XCTAssertEqualObjects(parent.children, @[ child2 ]);
213 }
214
215 - (void)testPlainSemanticsObjectWithLabelHasStaticTextTrait {
216 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
217 new flutter::MockAccessibilityBridge());
218 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
219 flutter::SemanticsNode node;
220 node.label = "foo";
221 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
222 [object setSemanticsNode:&node];
223 XCTAssertEqual([object accessibilityTraits], UIAccessibilityTraitStaticText);
224 }
225
226 - (void)testNodeWithImplicitScrollIsAnAccessibilityElementWhenItisHidden {
227 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
228 new flutter::MockAccessibilityBridge());
229 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
230 flutter::SemanticsNode node;
231 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling) |
232 static_cast<int32_t>(flutter::SemanticsFlags::kIsHidden);
233 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
234 [object setSemanticsNode:&node];
235 XCTAssertEqual(object.isAccessibilityElement, YES);
236 }
237
238 - (void)testNodeWithImplicitScrollIsNotAnAccessibilityElementWhenItisNotHidden {
239 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
240 new flutter::MockAccessibilityBridge());
241 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
242 flutter::SemanticsNode node;
243 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
244 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
245 [object setSemanticsNode:&node];
246 XCTAssertEqual(object.isAccessibilityElement, NO);
247 }
248
249 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait {
250 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
251 new flutter::MockAccessibilityBridge());
252 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
253 flutter::SemanticsNode node;
254 node.label = "foo";
255 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
256 SemanticsObject* child1 = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
257 object.children = @[ child1 ];
258 [object setSemanticsNode:&node];
259 XCTAssertEqual([object accessibilityTraits], UIAccessibilityTraitNone);
260 }
261
262 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait1 {
263 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
264 new flutter::MockAccessibilityBridge());
265 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
266 flutter::SemanticsNode node;
267 node.label = "foo";
268 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsTextField);
269 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
270 [object setSemanticsNode:&node];
271 XCTAssertEqual([object accessibilityTraits], UIAccessibilityTraitNone);
272 }
273
274 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait2 {
275 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
276 new flutter::MockAccessibilityBridge());
277 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
278 flutter::SemanticsNode node;
279 node.label = "foo";
280 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsButton);
281 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
282 [object setSemanticsNode:&node];
283 XCTAssertEqual([object accessibilityTraits], UIAccessibilityTraitButton);
284 }
285
286 - (void)testVerticalFlutterScrollableSemanticsObject {
287 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
288 new flutter::MockAccessibilityBridge());
289 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
290
291 float transformScale = 0.5f;
292 float screenScale = [[bridge->view() window] screen].scale;
293 float effectivelyScale = transformScale / screenScale;
294 float x = 10;
295 float y = 10;
296 float w = 100;
297 float h = 200;
298 float scrollExtentMax = 500.0;
299 float scrollPosition = 150.0;
300
301 flutter::SemanticsNode node;
302 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
303 node.actions = flutter::kVerticalScrollSemanticsActions;
304 node.rect = SkRect::MakeXYWH(x, y, w, h);
305 node.scrollExtentMax = scrollExtentMax;
306 node.scrollPosition = scrollPosition;
307 node.transform = {
308 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
309 FlutterScrollableSemanticsObject* scrollable =
310 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
311 [scrollable setSemanticsNode:&node];
312 [scrollable accessibilityBridgeDidFinishUpdate];
313 UIScrollView* scrollView = [scrollable nativeAccessibility];
314 XCTAssertTrue(
315 CGRectEqualToRect(scrollView.frame, CGRectMake(x * effectivelyScale, y * effectivelyScale,
316 w * effectivelyScale, h * effectivelyScale)));
317 XCTAssertTrue(CGSizeEqualToSize(
318 scrollView.contentSize,
319 CGSizeMake(w * effectivelyScale, (h + scrollExtentMax) * effectivelyScale)));
320 XCTAssertTrue(CGPointEqualToPoint(scrollView.contentOffset,
321 CGPointMake(0, scrollPosition * effectivelyScale)));
322 }
323
324 - (void)testVerticalFlutterScrollableSemanticsObjectNoWindowDoesNotCrash {
325 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
326 new flutter::MockAccessibilityBridgeNoWindow());
327 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
328
329 float transformScale = 0.5f;
330 float x = 10;
331 float y = 10;
332 float w = 100;
333 float h = 200;
334 float scrollExtentMax = 500.0;
335 float scrollPosition = 150.0;
336
337 flutter::SemanticsNode node;
338 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
339 node.actions = flutter::kVerticalScrollSemanticsActions;
340 node.rect = SkRect::MakeXYWH(x, y, w, h);
341 node.scrollExtentMax = scrollExtentMax;
342 node.scrollPosition = scrollPosition;
343 node.transform = {
344 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
345 FlutterScrollableSemanticsObject* scrollable =
346 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
347 [scrollable setSemanticsNode:&node];
348 [scrollable accessibilityBridgeDidFinishUpdate];
349 XCTAssertNoThrow([scrollable accessibilityBridgeDidFinishUpdate]);
350 }
351
352 - (void)testHorizontalFlutterScrollableSemanticsObject {
353 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
354 new flutter::MockAccessibilityBridge());
355 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
356
357 float transformScale = 0.5f;
358 float screenScale = [[bridge->view() window] screen].scale;
359 float effectivelyScale = transformScale / screenScale;
360 float x = 10;
361 float y = 10;
362 float w = 100;
363 float h = 200;
364 float scrollExtentMax = 500.0;
365 float scrollPosition = 150.0;
366
367 flutter::SemanticsNode node;
368 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
369 node.actions = flutter::kHorizontalScrollSemanticsActions;
370 node.rect = SkRect::MakeXYWH(x, y, w, h);
371 node.scrollExtentMax = scrollExtentMax;
372 node.scrollPosition = scrollPosition;
373 node.transform = {
374 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
375 FlutterScrollableSemanticsObject* scrollable =
376 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
377 [scrollable setSemanticsNode:&node];
378 [scrollable accessibilityBridgeDidFinishUpdate];
379 UIScrollView* scrollView = [scrollable nativeAccessibility];
380 XCTAssertTrue(
381 CGRectEqualToRect(scrollView.frame, CGRectMake(x * effectivelyScale, y * effectivelyScale,
382 w * effectivelyScale, h * effectivelyScale)));
383 XCTAssertTrue(CGSizeEqualToSize(
384 scrollView.contentSize,
385 CGSizeMake((w + scrollExtentMax) * effectivelyScale, h * effectivelyScale)));
386 XCTAssertTrue(CGPointEqualToPoint(scrollView.contentOffset,
387 CGPointMake(scrollPosition * effectivelyScale, 0)));
388 }
389
390 - (void)testCanHandleInfiniteScrollExtent {
391 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
392 new flutter::MockAccessibilityBridge());
393 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
394
395 float transformScale = 0.5f;
396 float screenScale = [[bridge->view() window] screen].scale;
397 float effectivelyScale = transformScale / screenScale;
398 float x = 10;
399 float y = 10;
400 float w = 100;
401 float h = 200;
402 float scrollExtentMax = INFINITY;
403 float scrollPosition = 150.0;
404
405 flutter::SemanticsNode node;
406 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
407 node.actions = flutter::kVerticalScrollSemanticsActions;
408 node.rect = SkRect::MakeXYWH(x, y, w, h);
409 node.scrollExtentMax = scrollExtentMax;
410 node.scrollPosition = scrollPosition;
411 node.transform = {
412 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
413 FlutterScrollableSemanticsObject* scrollable =
414 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
415 [scrollable setSemanticsNode:&node];
416 [scrollable accessibilityBridgeDidFinishUpdate];
417 UIScrollView* scrollView = [scrollable nativeAccessibility];
418 XCTAssertTrue(
419 CGRectEqualToRect(scrollView.frame, CGRectMake(x * effectivelyScale, y * effectivelyScale,
420 w * effectivelyScale, h * effectivelyScale)));
421 XCTAssertTrue(CGSizeEqualToSize(
422 scrollView.contentSize,
423 CGSizeMake(w * effectivelyScale,
424 (h + kScrollExtentMaxForInf + scrollPosition) * effectivelyScale)));
425 XCTAssertTrue(CGPointEqualToPoint(scrollView.contentOffset,
426 CGPointMake(0, scrollPosition * effectivelyScale)));
427 }
428
429 - (void)testCanHandleNaNScrollExtentAndScrollPoisition {
430 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
431 new flutter::MockAccessibilityBridge());
432 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
433
434 float transformScale = 0.5f;
435 float screenScale = [[bridge->view() window] screen].scale;
436 float effectivelyScale = transformScale / screenScale;
437 float x = 10;
438 float y = 10;
439 float w = 100;
440 float h = 200;
441 float scrollExtentMax = std::nan("");
442 float scrollPosition = std::nan("");
443
444 flutter::SemanticsNode node;
445 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
446 node.actions = flutter::kVerticalScrollSemanticsActions;
447 node.rect = SkRect::MakeXYWH(x, y, w, h);
448 node.scrollExtentMax = scrollExtentMax;
449 node.scrollPosition = scrollPosition;
450 node.transform = {
451 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
452 FlutterScrollableSemanticsObject* scrollable =
453 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
454 [scrollable setSemanticsNode:&node];
455 [scrollable accessibilityBridgeDidFinishUpdate];
456 UIScrollView* scrollView = [scrollable nativeAccessibility];
457 XCTAssertTrue(
458 CGRectEqualToRect(scrollView.frame, CGRectMake(x * effectivelyScale, y * effectivelyScale,
459 w * effectivelyScale, h * effectivelyScale)));
460 // Content size equal to the scrollable size.
461 XCTAssertTrue(CGSizeEqualToSize(scrollView.contentSize,
462 CGSizeMake(w * effectivelyScale, h * effectivelyScale)));
463 XCTAssertTrue(CGPointEqualToPoint(scrollView.contentOffset, CGPointMake(0, 0)));
464 }
465
466 - (void)testFlutterScrollableSemanticsObjectIsNotHittestable {
467 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
468 new flutter::MockAccessibilityBridge());
469 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
470
471 flutter::SemanticsNode node;
472 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
473 node.actions = flutter::kHorizontalScrollSemanticsActions;
474 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
475 node.scrollExtentMax = 100.0;
476 node.scrollPosition = 0.0;
477
478 FlutterScrollableSemanticsObject* scrollable =
479 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
480 [scrollable setSemanticsNode:&node];
481 [scrollable accessibilityBridgeDidFinishUpdate];
482 UIScrollView* scrollView = [scrollable nativeAccessibility];
483 XCTAssertEqual([scrollView hitTest:CGPointMake(10, 10) withEvent:nil], nil);
484 }
485
486 - (void)testFlutterScrollableSemanticsObjectIsHiddenWhenVoiceOverIsRunning {
487 flutter::MockAccessibilityBridge* mock = new flutter::MockAccessibilityBridge();
488 mock->isVoiceOverRunningValue = false;
489 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
490 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
491
492 flutter::SemanticsNode node;
493 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
494 node.actions = flutter::kHorizontalScrollSemanticsActions;
495 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
496 node.scrollExtentMax = 100.0;
497 node.scrollPosition = 0.0;
498
499 FlutterScrollableSemanticsObject* scrollable =
500 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
501 [scrollable setSemanticsNode:&node];
502 [scrollable accessibilityBridgeDidFinishUpdate];
503 UIScrollView* scrollView = [scrollable nativeAccessibility];
504 XCTAssertTrue(scrollView.isAccessibilityElement);
505 mock->isVoiceOverRunningValue = true;
506 XCTAssertFalse(scrollView.isAccessibilityElement);
507 }
508
509 - (void)testFlutterScrollableSemanticsObjectWithLabelValueHintIsNotHiddenWhenVoiceOverIsRunning {
510 flutter::MockAccessibilityBridge* mock = new flutter::MockAccessibilityBridge();
511 mock->isVoiceOverRunningValue = true;
512 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
513 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
514
515 flutter::SemanticsNode node;
516 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
517 node.actions = flutter::kHorizontalScrollSemanticsActions;
518 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
519 node.label = "label";
520 node.value = "value";
521 node.hint = "hint";
522 node.scrollExtentMax = 100.0;
523 node.scrollPosition = 0.0;
524
525 FlutterScrollableSemanticsObject* scrollable =
526 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
527 [scrollable setSemanticsNode:&node];
528 [scrollable accessibilityBridgeDidFinishUpdate];
529 UIScrollView* scrollView = [scrollable nativeAccessibility];
530 XCTAssertTrue(scrollView.isAccessibilityElement);
531 XCTAssertTrue(
532 [scrollView.accessibilityLabel isEqualToString:NSLocalizedString(@"label", @"test")]);
533 XCTAssertTrue(
534 [scrollView.accessibilityValue isEqualToString:NSLocalizedString(@"value", @"test")]);
535 XCTAssertTrue([scrollView.accessibilityHint isEqualToString:NSLocalizedString(@"hint", @"test")]);
536 }
537
538 - (void)testFlutterSemanticsObjectMergeTooltipToLabel {
539 flutter::MockAccessibilityBridge* mock = new flutter::MockAccessibilityBridge();
540 mock->isVoiceOverRunningValue = true;
541 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
542 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
543
544 flutter::SemanticsNode node;
545 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
546 node.label = "label";
547 node.tooltip = "tooltip";
548 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
549 [object setSemanticsNode:&node];
550 XCTAssertTrue(object.isAccessibilityElement);
551 XCTAssertTrue([object.accessibilityLabel isEqualToString:@"label\ntooltip"]);
552 }
553
554 - (void)testFlutterSemanticsObjectAttributedStringsDoNotCrashWhenEmpty {
555 flutter::MockAccessibilityBridge* mock = new flutter::MockAccessibilityBridge();
556 mock->isVoiceOverRunningValue = true;
557 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
558 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
559
560 flutter::SemanticsNode node;
561 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
562 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
563 [object setSemanticsNode:&node];
564 XCTAssertTrue(object.accessibilityAttributedLabel == nil);
565 }
566
567 - (void)testFlutterScrollableSemanticsObjectReturnsParentContainerIfNoChildren {
568 flutter::MockAccessibilityBridge* mock = new flutter::MockAccessibilityBridge();
569 mock->isVoiceOverRunningValue = true;
570 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
571 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
572
573 flutter::SemanticsNode parent;
574 parent.id = 0;
575 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
576 parent.label = "label";
577 parent.value = "value";
578 parent.hint = "hint";
579
580 flutter::SemanticsNode node;
581 node.id = 1;
582 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
583 node.actions = flutter::kHorizontalScrollSemanticsActions;
584 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
585 node.label = "label";
586 node.value = "value";
587 node.hint = "hint";
588 node.scrollExtentMax = 100.0;
589 node.scrollPosition = 0.0;
590 parent.childrenInTraversalOrder.push_back(1);
591
592 FlutterSemanticsObject* parentObject = [[FlutterSemanticsObject alloc] initWithBridge:bridge
593 uid:0];
594 [parentObject setSemanticsNode:&parent];
595
596 FlutterScrollableSemanticsObject* scrollable =
597 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:1];
598 [scrollable setSemanticsNode:&node];
599 UIScrollView* scrollView = [scrollable nativeAccessibility];
600
601 parentObject.children = @[ scrollable ];
602 [parentObject accessibilityBridgeDidFinishUpdate];
603 [scrollable accessibilityBridgeDidFinishUpdate];
604 XCTAssertTrue(scrollView.isAccessibilityElement);
605 SemanticsObjectContainer* container =
606 static_cast<SemanticsObjectContainer*>(scrollable.accessibilityContainer);
607 XCTAssertEqual(container.semanticsObject, parentObject);
608 }
609
610 - (void)testFlutterScrollableSemanticsObjectHidesScrollBar {
611 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
612 new flutter::MockAccessibilityBridge());
613 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
614
615 flutter::SemanticsNode node;
616 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
617 node.actions = flutter::kHorizontalScrollSemanticsActions;
618 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
619 node.scrollExtentMax = 100.0;
620 node.scrollPosition = 0.0;
621
622 FlutterScrollableSemanticsObject* scrollable =
623 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
624 [scrollable setSemanticsNode:&node];
625 [scrollable accessibilityBridgeDidFinishUpdate];
626 UIScrollView* scrollView = [scrollable nativeAccessibility];
627
628 XCTAssertFalse(scrollView.showsHorizontalScrollIndicator);
629 XCTAssertFalse(scrollView.showsVerticalScrollIndicator);
630 }
631
632 - (void)testSemanticsObjectBuildsAttributedString {
633 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
634 new flutter::MockAccessibilityBridge());
635 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
636 flutter::SemanticsNode node;
637 node.label = "label";
638 std::shared_ptr<flutter::SpellOutStringAttribute> attribute =
639 std::make_shared<flutter::SpellOutStringAttribute>();
640 attribute->start = 1;
641 attribute->end = 2;
642 attribute->type = flutter::StringAttributeType::kSpellOut;
643 node.labelAttributes.push_back(attribute);
644 node.value = "value";
645 attribute = std::make_shared<flutter::SpellOutStringAttribute>();
646 attribute->start = 2;
647 attribute->end = 3;
648 attribute->type = flutter::StringAttributeType::kSpellOut;
649 node.valueAttributes.push_back(attribute);
650 node.hint = "hint";
651 std::shared_ptr<flutter::LocaleStringAttribute> local_attribute =
652 std::make_shared<flutter::LocaleStringAttribute>();
653 local_attribute->start = 3;
654 local_attribute->end = 4;
655 local_attribute->type = flutter::StringAttributeType::kLocale;
656 local_attribute->locale = "en-MX";
657 node.hintAttributes.push_back(local_attribute);
658 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
659 [object setSemanticsNode:&node];
660 NSMutableAttributedString* expectedAttributedLabel =
661 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"label", @"test")];
662 NSDictionary* attributeDict = @{
663 UIAccessibilitySpeechAttributeSpellOut : @YES,
664 };
665 [expectedAttributedLabel setAttributes:attributeDict range:NSMakeRange(1, 1)];
666 XCTAssertTrue(
667 [object.accessibilityAttributedLabel isEqualToAttributedString:expectedAttributedLabel]);
668
669 NSMutableAttributedString* expectedAttributedValue =
670 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"value", @"test")];
671 attributeDict = @{
672 UIAccessibilitySpeechAttributeSpellOut : @YES,
673 };
674 [expectedAttributedValue setAttributes:attributeDict range:NSMakeRange(2, 1)];
675 XCTAssertTrue(
676 [object.accessibilityAttributedValue isEqualToAttributedString:expectedAttributedValue]);
677
678 NSMutableAttributedString* expectedAttributedHint =
679 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"hint", @"test")];
680 attributeDict = @{
681 UIAccessibilitySpeechAttributeLanguage : @"en-MX",
682 };
683 [expectedAttributedHint setAttributes:attributeDict range:NSMakeRange(3, 1)];
684 XCTAssertTrue(
685 [object.accessibilityAttributedHint isEqualToAttributedString:expectedAttributedHint]);
686 }
687
688 - (void)testShouldTriggerAnnouncement {
689 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
690 new flutter::MockAccessibilityBridge());
691 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
692 SemanticsObject* object = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
693
694 // Handle nil with no node set.
695 XCTAssertFalse([object nodeShouldTriggerAnnouncement:nil]);
696
697 // Handle initial setting of node with liveRegion
698 flutter::SemanticsNode node;
699 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsLiveRegion);
700 node.label = "foo";
701 XCTAssertTrue([object nodeShouldTriggerAnnouncement:&node]);
702
703 // Handle nil with node set.
704 [object setSemanticsNode:&node];
705 XCTAssertFalse([object nodeShouldTriggerAnnouncement:nil]);
706
707 // Handle new node, still has live region, same label.
708 XCTAssertFalse([object nodeShouldTriggerAnnouncement:&node]);
709
710 // Handle update node with new label, still has live region.
711 flutter::SemanticsNode updatedNode;
712 updatedNode.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsLiveRegion);
713 updatedNode.label = "bar";
714 XCTAssertTrue([object nodeShouldTriggerAnnouncement:&updatedNode]);
715
716 // Handle dropping the live region flag.
717 updatedNode.flags = 0;
718 XCTAssertFalse([object nodeShouldTriggerAnnouncement:&updatedNode]);
719
720 // Handle adding the flag when the label has not changed.
721 updatedNode.label = "foo";
722 [object setSemanticsNode:&updatedNode];
723 XCTAssertTrue([object nodeShouldTriggerAnnouncement:&node]);
724 }
725
726 - (void)testShouldDispatchShowOnScreenActionForHeader {
727 fml::WeakPtrFactory<flutter::MockAccessibilityBridge> factory(
728 new flutter::MockAccessibilityBridge());
729 fml::WeakPtr<flutter::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
730 SemanticsObject* object = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
731
732 // Handle initial setting of node with header.
733 flutter::SemanticsNode node;
734 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsHeader);
735 node.label = "foo";
736
737 [object setSemanticsNode:&node];
738
739 // Simulate accessibility focus.
740 [object accessibilityElementDidBecomeFocused];
741
742 XCTAssertTrue(bridge->observations.size() == 1);
743 XCTAssertTrue(bridge->observations[0].id == 1);
744 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
745 }
746
747 - (void)testShouldDispatchShowOnScreenActionForHidden {
748 fml::WeakPtrFactory<flutter::MockAccessibilityBridge> factory(
749 new flutter::MockAccessibilityBridge());
750 fml::WeakPtr<flutter::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
751 SemanticsObject* object = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
752
753 // Handle initial setting of node with hidden.
754 flutter::SemanticsNode node;
755 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsHidden);
756 node.label = "foo";
757
758 [object setSemanticsNode:&node];
759
760 // Simulate accessibility focus.
761 [object accessibilityElementDidBecomeFocused];
762
763 XCTAssertTrue(bridge->observations.size() == 1);
764 XCTAssertTrue(bridge->observations[0].id == 1);
765 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
766 }
767
768 - (void)testFlutterSwitchSemanticsObjectMatchesUISwitch {
769 fml::WeakPtrFactory<flutter::MockAccessibilityBridge> factory(
770 new flutter::MockAccessibilityBridge());
771 fml::WeakPtr<flutter::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
772 FlutterSwitchSemanticsObject* object = [[FlutterSwitchSemanticsObject alloc] initWithBridge:bridge
773 uid:1];
774
775 // Handle initial setting of node with header.
776 flutter::SemanticsNode node;
777 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasToggledState) |
778 static_cast<int32_t>(flutter::SemanticsFlags::kIsToggled) |
779 static_cast<int32_t>(flutter::SemanticsFlags::kIsEnabled);
780 node.label = "foo";
781 [object setSemanticsNode:&node];
782 // Create ab real UISwitch to compare the FlutterSwitchSemanticsObject with.
783 UISwitch* nativeSwitch = [[UISwitch alloc] init];
784 nativeSwitch.on = YES;
785
786 XCTAssertEqual(object.accessibilityTraits, nativeSwitch.accessibilityTraits);
787 XCTAssertEqualObjects(object.accessibilityValue, nativeSwitch.accessibilityValue);
788
789 // Set the toggled to false;
790 flutter::SemanticsNode update;
791 update.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasToggledState) |
792 static_cast<int32_t>(flutter::SemanticsFlags::kIsEnabled);
793 update.label = "foo";
794 [object setSemanticsNode:&update];
795
796 nativeSwitch.on = NO;
797
798 XCTAssertEqual(object.accessibilityTraits, nativeSwitch.accessibilityTraits);
799 XCTAssertEqualObjects(object.accessibilityValue, nativeSwitch.accessibilityValue);
800 }
801
802 - (void)testFlutterSemanticsObjectOfRadioButton {
803 fml::WeakPtrFactory<flutter::MockAccessibilityBridge> factory(
804 new flutter::MockAccessibilityBridge());
805 fml::WeakPtr<flutter::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
806 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
807
808 // Handle initial setting of node with header.
809 flutter::SemanticsNode node;
810 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsInMutuallyExclusiveGroup) |
811 static_cast<int32_t>(flutter::SemanticsFlags::kHasCheckedState) |
812 static_cast<int32_t>(flutter::SemanticsFlags::kHasEnabledState) |
813 static_cast<int32_t>(flutter::SemanticsFlags::kIsEnabled);
814 node.label = "foo";
815 [object setSemanticsNode:&node];
816 XCTAssertTrue((object.accessibilityTraits & UIAccessibilityTraitButton) > 0);
817 XCTAssertNil(object.accessibilityValue);
818 }
819
820 - (void)testFlutterSwitchSemanticsObjectMatchesUISwitchDisabled {
821 fml::WeakPtrFactory<flutter::MockAccessibilityBridge> factory(
822 new flutter::MockAccessibilityBridge());
823 fml::WeakPtr<flutter::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
824 FlutterSwitchSemanticsObject* object = [[FlutterSwitchSemanticsObject alloc] initWithBridge:bridge
825 uid:1];
826
827 // Handle initial setting of node with header.
828 flutter::SemanticsNode node;
829 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasToggledState) |
830 static_cast<int32_t>(flutter::SemanticsFlags::kIsToggled);
831 node.label = "foo";
832 [object setSemanticsNode:&node];
833 // Create ab real UISwitch to compare the FlutterSwitchSemanticsObject with.
834 UISwitch* nativeSwitch = [[UISwitch alloc] init];
835 nativeSwitch.on = YES;
836 nativeSwitch.enabled = NO;
837
838 XCTAssertEqual(object.accessibilityTraits, nativeSwitch.accessibilityTraits);
839 XCTAssertEqualObjects(object.accessibilityValue, nativeSwitch.accessibilityValue);
840 }
841
842 - (void)testSemanticsObjectDeallocated {
843 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
844 new flutter::MockAccessibilityBridge());
845 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
846 SemanticsObject* parent = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
847 SemanticsObject* child = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
848 parent.children = @[ child ];
849 // Validate SemanticsObject deallocation does not crash.
850 // https://github.com/flutter/flutter/issues/66032
851 __weak SemanticsObject* weakObject = parent;
852 parent = nil;
853 XCTAssertNil(weakObject);
854 }
855
856 - (void)testFlutterSemanticsObjectReturnsNilContainerWhenBridgeIsNotAlive {
857 FlutterSemanticsObject* parentObject;
858 FlutterScrollableSemanticsObject* scrollable;
859 FlutterSemanticsObject* object2;
860
861 flutter::SemanticsNode parent;
862 parent.id = 0;
863 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
864 parent.label = "label";
865 parent.value = "value";
866 parent.hint = "hint";
867
868 flutter::SemanticsNode node;
869 node.id = 1;
870 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
871 node.actions = flutter::kHorizontalScrollSemanticsActions;
872 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
873 node.label = "label";
874 node.value = "value";
875 node.hint = "hint";
876 node.scrollExtentMax = 100.0;
877 node.scrollPosition = 0.0;
878 parent.childrenInTraversalOrder.push_back(1);
879
880 flutter::SemanticsNode node2;
881 node2.id = 2;
882 node2.rect = SkRect::MakeXYWH(0, 0, 100, 200);
883 node2.label = "label";
884 node2.value = "value";
885 node2.hint = "hint";
886 node2.scrollExtentMax = 100.0;
887 node2.scrollPosition = 0.0;
888 parent.childrenInTraversalOrder.push_back(2);
889
890 {
891 flutter::MockAccessibilityBridge* mock = new flutter::MockAccessibilityBridge();
892 mock->isVoiceOverRunningValue = true;
893 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
894 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
895
896 parentObject = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
897 [parentObject setSemanticsNode:&parent];
898
899 scrollable = [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:1];
900 [scrollable setSemanticsNode:&node];
901 [scrollable accessibilityBridgeDidFinishUpdate];
902
903 object2 = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:2];
904 [object2 setSemanticsNode:&node2];
905
906 parentObject.children = @[ scrollable, object2 ];
907 [parentObject accessibilityBridgeDidFinishUpdate];
908 [scrollable accessibilityBridgeDidFinishUpdate];
909 [object2 accessibilityBridgeDidFinishUpdate];
910
911 // Returns the correct container if the bridge is alive.
912 SemanticsObjectContainer* container =
913 static_cast<SemanticsObjectContainer*>(scrollable.accessibilityContainer);
914 XCTAssertEqual(container.semanticsObject, parentObject);
915 SemanticsObjectContainer* container2 =
916 static_cast<SemanticsObjectContainer*>(object2.accessibilityContainer);
917 XCTAssertEqual(container2.semanticsObject, parentObject);
918 }
919 // The bridge pointer went out of scope and was deallocated.
920
921 XCTAssertNil(scrollable.accessibilityContainer);
922 XCTAssertNil(object2.accessibilityContainer);
923 }
924
925 @end
FLUTTER_ASSERT_ARC
#define FLUTTER_ASSERT_ARC
Definition: FlutterMacros.h:44
-[SemanticsObject accessibilityScrollToVisible]
BOOL accessibilityScrollToVisible()
-[SemanticsObject replaceChildAtIndex:withChild:]
void replaceChildAtIndex:withChild:(NSInteger index,[withChild] SemanticsObject *child)
Definition: SemanticsObject.mm:393
SemanticsObject::parent
SemanticsObject * parent
Definition: SemanticsObject.h:41
SemanticsObjectTestMocks.h
SemanticsObjectContainer::semanticsObject
SemanticsObject * semanticsObject
Definition: SemanticsObject.h:234
-[SemanticsObject accessibilityScrollToVisibleWithChild:]
BOOL accessibilityScrollToVisibleWithChild:(id child)
-[SemanticsObject setSemanticsNode:]
void setSemanticsNode:(const flutter::SemanticsNode *NS_REQUIRES_SUPER)
Definition: SemanticsObject.mm:352
FlutterMacros.h
FlutterSemanticsObject
Definition: SemanticsObject.h:154
SemanticsObject::childrenInHitTestOrder
NSArray< SemanticsObject * > * childrenInHitTestOrder
Definition: SemanticsObject.h:73
kScrollExtentMaxForInf
constexpr float kScrollExtentMaxForInf
Definition: SemanticsObject.h:17
-[SemanticsObject _accessibilityHitTest:withEvent:]
id _accessibilityHitTest:withEvent:(CGPoint point,[withEvent] UIEvent *event)
FlutterSwitchSemanticsObject
Definition: SemanticsObject.h:182
SemanticsObject::children
NSArray< SemanticsObject * > * children
Definition: SemanticsObject.h:67
SemanticsObject::nativeAccessibility
id nativeAccessibility
Definition: SemanticsObject.h:82
SemanticsObject.h
-[SemanticsObject accessibilityBridgeDidFinishUpdate]
void accessibilityBridgeDidFinishUpdate()
Definition: SemanticsObject.mm:356
SemanticsObjectContainer
Definition: SemanticsObject.h:226
SemanticsObjectTest
Definition: SemanticsObjectTest.mm:14
FlutterScrollableSemanticsObject
Definition: SemanticsObject.h:188
SemanticsObject
Definition: SemanticsObject.h:30