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