IndexedDBFactory now ForceCloses databases.
[chromium-blink-merge.git] / content / browser / accessibility / browser_accessibility_manager_unittest.cc
blobdadc810bd0280995fcfb59b2121475549163d01c
1 // Copyright (c) 2012 The Chromium 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.
5 #include "base/strings/string16.h"
6 #include "base/strings/utf_string_conversions.h"
7 #include "content/browser/accessibility/browser_accessibility.h"
8 #include "content/browser/accessibility/browser_accessibility_manager.h"
9 #include "content/common/accessibility_messages.h"
10 #include "testing/gtest/include/gtest/gtest.h"
12 namespace content {
13 namespace {
15 // Subclass of BrowserAccessibility that counts the number of instances.
16 class CountedBrowserAccessibility : public BrowserAccessibility {
17 public:
18 CountedBrowserAccessibility() {
19 global_obj_count_++;
20 native_ref_count_ = 1;
22 virtual ~CountedBrowserAccessibility() {
23 global_obj_count_--;
26 virtual void NativeAddReference() OVERRIDE {
27 native_ref_count_++;
30 virtual void NativeReleaseReference() OVERRIDE {
31 native_ref_count_--;
32 if (native_ref_count_ == 0)
33 delete this;
36 int native_ref_count_;
37 static int global_obj_count_;
40 int CountedBrowserAccessibility::global_obj_count_ = 0;
42 // Factory that creates a CountedBrowserAccessibility.
43 class CountedBrowserAccessibilityFactory
44 : public BrowserAccessibilityFactory {
45 public:
46 virtual ~CountedBrowserAccessibilityFactory() {}
47 virtual BrowserAccessibility* Create() OVERRIDE {
48 return new CountedBrowserAccessibility();
52 class TestBrowserAccessibilityDelegate
53 : public BrowserAccessibilityDelegate {
54 public:
55 TestBrowserAccessibilityDelegate()
56 : got_fatal_error_(false) {}
58 virtual void SetAccessibilityFocus(int acc_obj_id) OVERRIDE {}
59 virtual void AccessibilityDoDefaultAction(int acc_obj_id) OVERRIDE {}
60 virtual void AccessibilityScrollToMakeVisible(
61 int acc_obj_id, gfx::Rect subfocus) OVERRIDE {}
62 virtual void AccessibilityScrollToPoint(
63 int acc_obj_id, gfx::Point point) OVERRIDE {}
64 virtual void AccessibilitySetTextSelection(
65 int acc_obj_id, int start_offset, int end_offset) OVERRIDE {}
66 virtual bool HasFocus() const OVERRIDE {
67 return false;
69 virtual gfx::Rect GetViewBounds() const OVERRIDE {
70 return gfx::Rect();
72 virtual gfx::Point GetLastTouchEventLocation() const OVERRIDE {
73 return gfx::Point();
75 virtual void FatalAccessibilityTreeError() OVERRIDE {
76 got_fatal_error_ = true;
79 bool got_fatal_error() const { return got_fatal_error_; }
80 void reset_got_fatal_error() { got_fatal_error_ = false; }
82 private:
83 bool got_fatal_error_;
86 } // anonymous namespace
88 TEST(BrowserAccessibilityManagerTest, TestNoLeaks) {
89 // Create ui::AXNodeData objects for a simple document tree,
90 // representing the accessibility information used to initialize
91 // BrowserAccessibilityManager.
92 ui::AXNodeData button;
93 button.id = 2;
94 button.SetName("Button");
95 button.role = ui::AX_ROLE_BUTTON;
96 button.state = 0;
98 ui::AXNodeData checkbox;
99 checkbox.id = 3;
100 checkbox.SetName("Checkbox");
101 checkbox.role = ui::AX_ROLE_CHECK_BOX;
102 checkbox.state = 0;
104 ui::AXNodeData root;
105 root.id = 1;
106 root.SetName("Document");
107 root.role = ui::AX_ROLE_ROOT_WEB_AREA;
108 root.state = 0;
109 root.child_ids.push_back(2);
110 root.child_ids.push_back(3);
112 // Construct a BrowserAccessibilityManager with this
113 // ui::AXNodeData tree and a factory for an instance-counting
114 // BrowserAccessibility, and ensure that exactly 3 instances were
115 // created. Note that the manager takes ownership of the factory.
116 CountedBrowserAccessibility::global_obj_count_ = 0;
117 BrowserAccessibilityManager* manager =
118 BrowserAccessibilityManager::Create(
119 root,
120 NULL,
121 new CountedBrowserAccessibilityFactory());
122 manager->UpdateNodesForTesting(button, checkbox);
124 ASSERT_EQ(3, CountedBrowserAccessibility::global_obj_count_);
126 // Delete the manager and test that all 3 instances are deleted.
127 delete manager;
128 ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
130 // Construct a manager again, and this time save references to two of
131 // the three nodes in the tree.
132 manager =
133 BrowserAccessibilityManager::Create(
134 root,
135 NULL,
136 new CountedBrowserAccessibilityFactory());
137 manager->UpdateNodesForTesting(button, checkbox);
138 ASSERT_EQ(3, CountedBrowserAccessibility::global_obj_count_);
140 CountedBrowserAccessibility* root_accessible =
141 static_cast<CountedBrowserAccessibility*>(manager->GetRoot());
142 root_accessible->NativeAddReference();
143 CountedBrowserAccessibility* child1_accessible =
144 static_cast<CountedBrowserAccessibility*>(
145 root_accessible->PlatformGetChild(1));
146 child1_accessible->NativeAddReference();
148 // Now delete the manager, and only one of the three nodes in the tree
149 // should be released.
150 delete manager;
151 ASSERT_EQ(2, CountedBrowserAccessibility::global_obj_count_);
153 // Release each of our references and make sure that each one results in
154 // the instance being deleted as its reference count hits zero.
155 root_accessible->NativeReleaseReference();
156 ASSERT_EQ(1, CountedBrowserAccessibility::global_obj_count_);
157 child1_accessible->NativeReleaseReference();
158 ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
161 TEST(BrowserAccessibilityManagerTest, TestReuseBrowserAccessibilityObjects) {
162 // Make sure that changes to a subtree reuse as many objects as possible.
164 // Tree 1:
166 // root
167 // child1
168 // child2
169 // child3
171 ui::AXNodeData tree1_child1;
172 tree1_child1.id = 2;
173 tree1_child1.SetName("Child1");
174 tree1_child1.role = ui::AX_ROLE_BUTTON;
175 tree1_child1.state = 0;
177 ui::AXNodeData tree1_child2;
178 tree1_child2.id = 3;
179 tree1_child2.SetName("Child2");
180 tree1_child2.role = ui::AX_ROLE_BUTTON;
181 tree1_child2.state = 0;
183 ui::AXNodeData tree1_child3;
184 tree1_child3.id = 4;
185 tree1_child3.SetName("Child3");
186 tree1_child3.role = ui::AX_ROLE_BUTTON;
187 tree1_child3.state = 0;
189 ui::AXNodeData tree1_root;
190 tree1_root.id = 1;
191 tree1_root.SetName("Document");
192 tree1_root.role = ui::AX_ROLE_ROOT_WEB_AREA;
193 tree1_root.state = 0;
194 tree1_root.child_ids.push_back(2);
195 tree1_root.child_ids.push_back(3);
196 tree1_root.child_ids.push_back(4);
198 // Tree 2:
200 // root
201 // child0 <-- inserted
202 // child1
203 // child2
204 // <-- child3 deleted
206 ui::AXNodeData tree2_child0;
207 tree2_child0.id = 5;
208 tree2_child0.SetName("Child0");
209 tree2_child0.role = ui::AX_ROLE_BUTTON;
210 tree2_child0.state = 0;
212 ui::AXNodeData tree2_root;
213 tree2_root.id = 1;
214 tree2_root.SetName("DocumentChanged");
215 tree2_root.role = ui::AX_ROLE_ROOT_WEB_AREA;
216 tree2_root.state = 0;
217 tree2_root.child_ids.push_back(5);
218 tree2_root.child_ids.push_back(2);
219 tree2_root.child_ids.push_back(3);
221 // Construct a BrowserAccessibilityManager with tree1.
222 CountedBrowserAccessibility::global_obj_count_ = 0;
223 BrowserAccessibilityManager* manager =
224 BrowserAccessibilityManager::Create(
225 tree1_root,
226 NULL,
227 new CountedBrowserAccessibilityFactory());
228 manager->UpdateNodesForTesting(tree1_child1, tree1_child2, tree1_child3);
229 ASSERT_EQ(4, CountedBrowserAccessibility::global_obj_count_);
231 // Save references to all of the objects.
232 CountedBrowserAccessibility* root_accessible =
233 static_cast<CountedBrowserAccessibility*>(manager->GetRoot());
234 root_accessible->NativeAddReference();
235 CountedBrowserAccessibility* child1_accessible =
236 static_cast<CountedBrowserAccessibility*>(
237 root_accessible->PlatformGetChild(0));
238 child1_accessible->NativeAddReference();
239 CountedBrowserAccessibility* child2_accessible =
240 static_cast<CountedBrowserAccessibility*>(
241 root_accessible->PlatformGetChild(1));
242 child2_accessible->NativeAddReference();
243 CountedBrowserAccessibility* child3_accessible =
244 static_cast<CountedBrowserAccessibility*>(
245 root_accessible->PlatformGetChild(2));
246 child3_accessible->NativeAddReference();
248 // Check the index in parent.
249 EXPECT_EQ(0, child1_accessible->index_in_parent());
250 EXPECT_EQ(1, child2_accessible->index_in_parent());
251 EXPECT_EQ(2, child3_accessible->index_in_parent());
253 // Process a notification containing the changed subtree.
254 std::vector<AccessibilityHostMsg_EventParams> params;
255 params.push_back(AccessibilityHostMsg_EventParams());
256 AccessibilityHostMsg_EventParams* msg = &params[0];
257 msg->event_type = ui::AX_EVENT_CHILDREN_CHANGED;
258 msg->nodes.push_back(tree2_root);
259 msg->nodes.push_back(tree2_child0);
260 msg->id = tree2_root.id;
261 manager->OnAccessibilityEvents(params);
263 // There should be 5 objects now: the 4 from the new tree, plus the
264 // reference to child3 we kept.
265 EXPECT_EQ(5, CountedBrowserAccessibility::global_obj_count_);
267 // Check that our references to the root, child1, and child2 are still valid,
268 // but that the reference to child3 is now invalid.
269 EXPECT_TRUE(root_accessible->instance_active());
270 EXPECT_TRUE(child1_accessible->instance_active());
271 EXPECT_TRUE(child2_accessible->instance_active());
272 EXPECT_FALSE(child3_accessible->instance_active());
274 // Check that the index in parent has been updated.
275 EXPECT_EQ(1, child1_accessible->index_in_parent());
276 EXPECT_EQ(2, child2_accessible->index_in_parent());
278 // Release our references. The object count should only decrease by 1
279 // for child3.
280 root_accessible->NativeReleaseReference();
281 child1_accessible->NativeReleaseReference();
282 child2_accessible->NativeReleaseReference();
283 child3_accessible->NativeReleaseReference();
285 EXPECT_EQ(4, CountedBrowserAccessibility::global_obj_count_);
287 // Delete the manager and make sure all memory is cleaned up.
288 delete manager;
289 ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
292 TEST(BrowserAccessibilityManagerTest, TestReuseBrowserAccessibilityObjects2) {
293 // Similar to the test above, but with a more complicated tree.
295 // Tree 1:
297 // root
298 // container
299 // child1
300 // grandchild1
301 // child2
302 // grandchild2
303 // child3
304 // grandchild3
306 ui::AXNodeData tree1_grandchild1;
307 tree1_grandchild1.id = 4;
308 tree1_grandchild1.SetName("GrandChild1");
309 tree1_grandchild1.role = ui::AX_ROLE_BUTTON;
310 tree1_grandchild1.state = 0;
312 ui::AXNodeData tree1_child1;
313 tree1_child1.id = 3;
314 tree1_child1.SetName("Child1");
315 tree1_child1.role = ui::AX_ROLE_BUTTON;
316 tree1_child1.state = 0;
317 tree1_child1.child_ids.push_back(4);
319 ui::AXNodeData tree1_grandchild2;
320 tree1_grandchild2.id = 6;
321 tree1_grandchild2.SetName("GrandChild1");
322 tree1_grandchild2.role = ui::AX_ROLE_BUTTON;
323 tree1_grandchild2.state = 0;
325 ui::AXNodeData tree1_child2;
326 tree1_child2.id = 5;
327 tree1_child2.SetName("Child2");
328 tree1_child2.role = ui::AX_ROLE_BUTTON;
329 tree1_child2.state = 0;
330 tree1_child2.child_ids.push_back(6);
332 ui::AXNodeData tree1_grandchild3;
333 tree1_grandchild3.id = 8;
334 tree1_grandchild3.SetName("GrandChild3");
335 tree1_grandchild3.role = ui::AX_ROLE_BUTTON;
336 tree1_grandchild3.state = 0;
338 ui::AXNodeData tree1_child3;
339 tree1_child3.id = 7;
340 tree1_child3.SetName("Child3");
341 tree1_child3.role = ui::AX_ROLE_BUTTON;
342 tree1_child3.state = 0;
343 tree1_child3.child_ids.push_back(8);
345 ui::AXNodeData tree1_container;
346 tree1_container.id = 2;
347 tree1_container.SetName("Container");
348 tree1_container.role = ui::AX_ROLE_GROUP;
349 tree1_container.state = 0;
350 tree1_container.child_ids.push_back(3);
351 tree1_container.child_ids.push_back(5);
352 tree1_container.child_ids.push_back(7);
354 ui::AXNodeData tree1_root;
355 tree1_root.id = 1;
356 tree1_root.SetName("Document");
357 tree1_root.role = ui::AX_ROLE_ROOT_WEB_AREA;
358 tree1_root.state = 0;
359 tree1_root.child_ids.push_back(2);
361 // Tree 2:
363 // root
364 // container
365 // child0 <-- inserted
366 // grandchild0 <--
367 // child1
368 // grandchild1
369 // child2
370 // grandchild2
371 // <-- child3 (and grandchild3) deleted
373 ui::AXNodeData tree2_grandchild0;
374 tree2_grandchild0.id = 9;
375 tree2_grandchild0.SetName("GrandChild0");
376 tree2_grandchild0.role = ui::AX_ROLE_BUTTON;
377 tree2_grandchild0.state = 0;
379 ui::AXNodeData tree2_child0;
380 tree2_child0.id = 10;
381 tree2_child0.SetName("Child0");
382 tree2_child0.role = ui::AX_ROLE_BUTTON;
383 tree2_child0.state = 0;
384 tree2_child0.child_ids.push_back(9);
386 ui::AXNodeData tree2_container;
387 tree2_container.id = 2;
388 tree2_container.SetName("Container");
389 tree2_container.role = ui::AX_ROLE_GROUP;
390 tree2_container.state = 0;
391 tree2_container.child_ids.push_back(10);
392 tree2_container.child_ids.push_back(3);
393 tree2_container.child_ids.push_back(5);
395 // Construct a BrowserAccessibilityManager with tree1.
396 CountedBrowserAccessibility::global_obj_count_ = 0;
397 BrowserAccessibilityManager* manager =
398 BrowserAccessibilityManager::Create(
399 tree1_root,
400 NULL,
401 new CountedBrowserAccessibilityFactory());
402 manager->UpdateNodesForTesting(tree1_container,
403 tree1_child1, tree1_grandchild1,
404 tree1_child2, tree1_grandchild2,
405 tree1_child3, tree1_grandchild3);
406 ASSERT_EQ(8, CountedBrowserAccessibility::global_obj_count_);
408 // Save references to some objects.
409 CountedBrowserAccessibility* root_accessible =
410 static_cast<CountedBrowserAccessibility*>(manager->GetRoot());
411 root_accessible->NativeAddReference();
412 CountedBrowserAccessibility* container_accessible =
413 static_cast<CountedBrowserAccessibility*>(
414 root_accessible->PlatformGetChild(0));
415 container_accessible->NativeAddReference();
416 CountedBrowserAccessibility* child2_accessible =
417 static_cast<CountedBrowserAccessibility*>(
418 container_accessible->PlatformGetChild(1));
419 child2_accessible->NativeAddReference();
420 CountedBrowserAccessibility* child3_accessible =
421 static_cast<CountedBrowserAccessibility*>(
422 container_accessible->PlatformGetChild(2));
423 child3_accessible->NativeAddReference();
425 // Check the index in parent.
426 EXPECT_EQ(1, child2_accessible->index_in_parent());
427 EXPECT_EQ(2, child3_accessible->index_in_parent());
429 // Process a notification containing the changed subtree rooted at
430 // the container.
431 std::vector<AccessibilityHostMsg_EventParams> params;
432 params.push_back(AccessibilityHostMsg_EventParams());
433 AccessibilityHostMsg_EventParams* msg = &params[0];
434 msg->event_type = ui::AX_EVENT_CHILDREN_CHANGED;
435 msg->nodes.push_back(tree2_container);
436 msg->nodes.push_back(tree2_child0);
437 msg->nodes.push_back(tree2_grandchild0);
438 msg->id = tree2_container.id;
439 manager->OnAccessibilityEvents(params);
441 // There should be 9 objects now: the 8 from the new tree, plus the
442 // reference to child3 we kept.
443 EXPECT_EQ(9, CountedBrowserAccessibility::global_obj_count_);
445 // Check that our references to the root and container and child2 are
446 // still valid, but that the reference to child3 is now invalid.
447 EXPECT_TRUE(root_accessible->instance_active());
448 EXPECT_TRUE(container_accessible->instance_active());
449 EXPECT_TRUE(child2_accessible->instance_active());
450 EXPECT_FALSE(child3_accessible->instance_active());
452 // Ensure that we retain the parent of the detached subtree.
453 EXPECT_EQ(root_accessible, container_accessible->parent());
454 EXPECT_EQ(0, container_accessible->index_in_parent());
456 // Check that the index in parent has been updated.
457 EXPECT_EQ(2, child2_accessible->index_in_parent());
459 // Release our references. The object count should only decrease by 1
460 // for child3.
461 root_accessible->NativeReleaseReference();
462 container_accessible->NativeReleaseReference();
463 child2_accessible->NativeReleaseReference();
464 child3_accessible->NativeReleaseReference();
466 EXPECT_EQ(8, CountedBrowserAccessibility::global_obj_count_);
468 // Delete the manager and make sure all memory is cleaned up.
469 delete manager;
470 ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
473 TEST(BrowserAccessibilityManagerTest, TestMoveChildUp) {
474 // Tree 1:
476 // 1
477 // 2
478 // 3
479 // 4
481 ui::AXNodeData tree1_4;
482 tree1_4.id = 4;
483 tree1_4.state = 0;
485 ui::AXNodeData tree1_3;
486 tree1_3.id = 3;
487 tree1_3.state = 0;
488 tree1_3.child_ids.push_back(4);
490 ui::AXNodeData tree1_2;
491 tree1_2.id = 2;
492 tree1_2.state = 0;
494 ui::AXNodeData tree1_1;
495 tree1_1.id = 1;
496 tree1_1.role = ui::AX_ROLE_ROOT_WEB_AREA;
497 tree1_1.state = 0;
498 tree1_1.child_ids.push_back(2);
499 tree1_1.child_ids.push_back(3);
501 // Tree 2:
503 // 1
504 // 4 <-- moves up a level and gains child
505 // 6 <-- new
506 // 5 <-- new
508 ui::AXNodeData tree2_6;
509 tree2_6.id = 6;
510 tree2_6.state = 0;
512 ui::AXNodeData tree2_5;
513 tree2_5.id = 5;
514 tree2_5.state = 0;
516 ui::AXNodeData tree2_4;
517 tree2_4.id = 4;
518 tree2_4.state = 0;
519 tree2_4.child_ids.push_back(6);
521 ui::AXNodeData tree2_1;
522 tree2_1.id = 1;
523 tree2_1.state = 0;
524 tree2_1.child_ids.push_back(4);
525 tree2_1.child_ids.push_back(5);
527 // Construct a BrowserAccessibilityManager with tree1.
528 CountedBrowserAccessibility::global_obj_count_ = 0;
529 BrowserAccessibilityManager* manager =
530 BrowserAccessibilityManager::Create(
531 tree1_1,
532 NULL,
533 new CountedBrowserAccessibilityFactory());
534 manager->UpdateNodesForTesting(tree1_2, tree1_3, tree1_4);
535 ASSERT_EQ(4, CountedBrowserAccessibility::global_obj_count_);
537 // Process a notification containing the changed subtree.
538 std::vector<AccessibilityHostMsg_EventParams> params;
539 params.push_back(AccessibilityHostMsg_EventParams());
540 AccessibilityHostMsg_EventParams* msg = &params[0];
541 msg->event_type = ui::AX_EVENT_CHILDREN_CHANGED;
542 msg->nodes.push_back(tree2_1);
543 msg->nodes.push_back(tree2_4);
544 msg->nodes.push_back(tree2_5);
545 msg->nodes.push_back(tree2_6);
546 msg->id = tree2_1.id;
547 manager->OnAccessibilityEvents(params);
549 // There should be 4 objects now.
550 EXPECT_EQ(4, CountedBrowserAccessibility::global_obj_count_);
552 // Delete the manager and make sure all memory is cleaned up.
553 delete manager;
554 ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
557 // Crashes on Windows. http://crbug.com/304130
558 #if defined(OS_WIN)
559 #define MAYBE_TestFatalError DISABLED_TestFatalError
560 #else
561 #define MAYBE_TestFatalError TestFatalError
562 #endif
563 TEST(BrowserAccessibilityManagerTest, MAYBE_TestFatalError) {
564 // Test that BrowserAccessibilityManager raises a fatal error
565 // (which will crash the renderer) if the same id is used in
566 // two places in the tree.
568 ui::AXNodeData root;
569 root.id = 1;
570 root.role = ui::AX_ROLE_ROOT_WEB_AREA;
571 root.child_ids.push_back(2);
572 root.child_ids.push_back(2);
574 CountedBrowserAccessibilityFactory* factory =
575 new CountedBrowserAccessibilityFactory();
576 scoped_ptr<TestBrowserAccessibilityDelegate> delegate(
577 new TestBrowserAccessibilityDelegate());
578 scoped_ptr<BrowserAccessibilityManager> manager;
579 ASSERT_FALSE(delegate->got_fatal_error());
580 manager.reset(BrowserAccessibilityManager::Create(
581 root,
582 delegate.get(),
583 factory));
584 ASSERT_TRUE(delegate->got_fatal_error());
586 ui::AXNodeData root2;
587 root2.id = 1;
588 root2.role = ui::AX_ROLE_ROOT_WEB_AREA;
589 root2.child_ids.push_back(2);
590 root2.child_ids.push_back(3);
592 ui::AXNodeData child1;
593 child1.id = 2;
594 child1.child_ids.push_back(4);
595 child1.child_ids.push_back(5);
597 ui::AXNodeData child2;
598 child2.id = 3;
599 child2.child_ids.push_back(6);
600 child2.child_ids.push_back(5); // Duplicate
602 delegate->reset_got_fatal_error();
603 factory = new CountedBrowserAccessibilityFactory();
604 manager.reset(BrowserAccessibilityManager::Create(
605 root2,
606 delegate.get(),
607 factory));
608 ASSERT_FALSE(delegate->got_fatal_error());
609 manager->UpdateNodesForTesting(child1, child2);
610 ASSERT_TRUE(delegate->got_fatal_error());
613 TEST(BrowserAccessibilityManagerTest, BoundsForRange) {
614 ui::AXNodeData root;
615 root.id = 1;
616 root.role = ui::AX_ROLE_ROOT_WEB_AREA;
618 ui::AXNodeData static_text;
619 static_text.id = 2;
620 static_text.SetValue("Hello, world.");
621 static_text.role = ui::AX_ROLE_STATIC_TEXT;
622 static_text.location = gfx::Rect(100, 100, 29, 18);
623 root.child_ids.push_back(2);
625 ui::AXNodeData inline_text1;
626 inline_text1.id = 3;
627 inline_text1.SetValue("Hello, ");
628 inline_text1.role = ui::AX_ROLE_INLINE_TEXT_BOX;
629 inline_text1.location = gfx::Rect(100, 100, 29, 9);
630 inline_text1.AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
631 blink::WebAXTextDirectionLR);
632 std::vector<int32> character_offsets1;
633 character_offsets1.push_back(6); // 0
634 character_offsets1.push_back(11); // 1
635 character_offsets1.push_back(16); // 2
636 character_offsets1.push_back(21); // 3
637 character_offsets1.push_back(26); // 4
638 character_offsets1.push_back(29); // 5
639 character_offsets1.push_back(29); // 6 (note that the space has no width)
640 inline_text1.AddIntListAttribute(
641 ui::AX_ATTR_CHARACTER_OFFSETS, character_offsets1);
642 static_text.child_ids.push_back(3);
644 ui::AXNodeData inline_text2;
645 inline_text2.id = 4;
646 inline_text2.SetValue("world.");
647 inline_text2.role = ui::AX_ROLE_INLINE_TEXT_BOX;
648 inline_text2.location = gfx::Rect(100, 109, 28, 9);
649 inline_text2.AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
650 blink::WebAXTextDirectionLR);
651 std::vector<int32> character_offsets2;
652 character_offsets2.push_back(5);
653 character_offsets2.push_back(10);
654 character_offsets2.push_back(15);
655 character_offsets2.push_back(20);
656 character_offsets2.push_back(25);
657 character_offsets2.push_back(28);
658 inline_text2.AddIntListAttribute(
659 ui::AX_ATTR_CHARACTER_OFFSETS, character_offsets2);
660 static_text.child_ids.push_back(4);
662 scoped_ptr<BrowserAccessibilityManager> manager(
663 BrowserAccessibilityManager::Create(
664 root,
665 NULL,
666 new CountedBrowserAccessibilityFactory()));
667 manager->UpdateNodesForTesting(static_text, inline_text1, inline_text2);
669 BrowserAccessibility* root_accessible = manager->GetRoot();
670 BrowserAccessibility* static_text_accessible =
671 root_accessible->PlatformGetChild(0);
673 EXPECT_EQ(gfx::Rect(100, 100, 6, 9).ToString(),
674 static_text_accessible->GetLocalBoundsForRange(0, 1).ToString());
676 EXPECT_EQ(gfx::Rect(100, 100, 26, 9).ToString(),
677 static_text_accessible->GetLocalBoundsForRange(0, 5).ToString());
679 EXPECT_EQ(gfx::Rect(100, 109, 5, 9).ToString(),
680 static_text_accessible->GetLocalBoundsForRange(7, 1).ToString());
682 EXPECT_EQ(gfx::Rect(100, 109, 25, 9).ToString(),
683 static_text_accessible->GetLocalBoundsForRange(7, 5).ToString());
685 EXPECT_EQ(gfx::Rect(100, 100, 29, 18).ToString(),
686 static_text_accessible->GetLocalBoundsForRange(5, 3).ToString());
688 EXPECT_EQ(gfx::Rect(100, 100, 29, 18).ToString(),
689 static_text_accessible->GetLocalBoundsForRange(0, 13).ToString());
691 // Test range that's beyond the text.
692 EXPECT_EQ(gfx::Rect(100, 100, 29, 18).ToString(),
693 static_text_accessible->GetLocalBoundsForRange(-1, 999).ToString());
695 // Test that we can call bounds for range on the parent element, too,
696 // and it still works.
697 EXPECT_EQ(gfx::Rect(100, 100, 29, 18).ToString(),
698 root_accessible->GetLocalBoundsForRange(0, 13).ToString());
701 TEST(BrowserAccessibilityManagerTest, BoundsForRangeBiDi) {
702 // In this example, we assume that the string "123abc" is rendered with
703 // "123" going left-to-right and "abc" going right-to-left. In other
704 // words, on-screen it would look like "123cba". This is possible to
705 // acheive if the source string had unicode control characters
706 // to switch directions. This test doesn't worry about how, though - it just
707 // tests that if something like that were to occur, GetLocalBoundsForRange
708 // returns the correct bounds for different ranges.
710 ui::AXNodeData root;
711 root.id = 1;
712 root.role = ui::AX_ROLE_ROOT_WEB_AREA;
714 ui::AXNodeData static_text;
715 static_text.id = 2;
716 static_text.SetValue("123abc");
717 static_text.role = ui::AX_ROLE_STATIC_TEXT;
718 static_text.location = gfx::Rect(100, 100, 60, 20);
719 root.child_ids.push_back(2);
721 ui::AXNodeData inline_text1;
722 inline_text1.id = 3;
723 inline_text1.SetValue("123");
724 inline_text1.role = ui::AX_ROLE_INLINE_TEXT_BOX;
725 inline_text1.location = gfx::Rect(100, 100, 30, 20);
726 inline_text1.AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
727 blink::WebAXTextDirectionLR);
728 std::vector<int32> character_offsets1;
729 character_offsets1.push_back(10); // 0
730 character_offsets1.push_back(20); // 1
731 character_offsets1.push_back(30); // 2
732 inline_text1.AddIntListAttribute(
733 ui::AX_ATTR_CHARACTER_OFFSETS, character_offsets1);
734 static_text.child_ids.push_back(3);
736 ui::AXNodeData inline_text2;
737 inline_text2.id = 4;
738 inline_text2.SetValue("abc");
739 inline_text2.role = ui::AX_ROLE_INLINE_TEXT_BOX;
740 inline_text2.location = gfx::Rect(130, 100, 30, 20);
741 inline_text2.AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
742 blink::WebAXTextDirectionRL);
743 std::vector<int32> character_offsets2;
744 character_offsets2.push_back(10);
745 character_offsets2.push_back(20);
746 character_offsets2.push_back(30);
747 inline_text2.AddIntListAttribute(
748 ui::AX_ATTR_CHARACTER_OFFSETS, character_offsets2);
749 static_text.child_ids.push_back(4);
751 scoped_ptr<BrowserAccessibilityManager> manager(
752 BrowserAccessibilityManager::Create(
753 root,
754 NULL,
755 new CountedBrowserAccessibilityFactory()));
756 manager->UpdateNodesForTesting(static_text, inline_text1, inline_text2);
758 BrowserAccessibility* root_accessible = manager->GetRoot();
759 BrowserAccessibility* static_text_accessible =
760 root_accessible->PlatformGetChild(0);
762 EXPECT_EQ(gfx::Rect(100, 100, 60, 20).ToString(),
763 static_text_accessible->GetLocalBoundsForRange(0, 6).ToString());
765 EXPECT_EQ(gfx::Rect(100, 100, 10, 20).ToString(),
766 static_text_accessible->GetLocalBoundsForRange(0, 1).ToString());
768 EXPECT_EQ(gfx::Rect(100, 100, 30, 20).ToString(),
769 static_text_accessible->GetLocalBoundsForRange(0, 3).ToString());
771 EXPECT_EQ(gfx::Rect(150, 100, 10, 20).ToString(),
772 static_text_accessible->GetLocalBoundsForRange(3, 1).ToString());
774 EXPECT_EQ(gfx::Rect(130, 100, 30, 20).ToString(),
775 static_text_accessible->GetLocalBoundsForRange(3, 3).ToString());
777 // This range is only two characters, but because of the direction switch
778 // the bounds are as wide as four characters.
779 EXPECT_EQ(gfx::Rect(120, 100, 40, 20).ToString(),
780 static_text_accessible->GetLocalBoundsForRange(2, 2).ToString());
783 #if defined(OS_WIN)
784 #define MAYBE_BoundsForRangeOnParentElement \
785 DISABLED_BoundsForRangeOnParentElement
786 #else
787 #define MAYBE_BoundsForRangeOnParentElement BoundsForRangeOnParentElement
788 #endif
789 TEST(BrowserAccessibilityManagerTest, MAYBE_BoundsForRangeOnParentElement) {
790 ui::AXNodeData root;
791 root.id = 1;
792 root.role = ui::AX_ROLE_ROOT_WEB_AREA;
793 root.child_ids.push_back(2);
795 ui::AXNodeData div;
796 div.id = 2;
797 div.role = ui::AX_ROLE_DIV;
798 div.location = gfx::Rect(100, 100, 100, 20);
799 div.child_ids.push_back(3);
800 div.child_ids.push_back(4);
801 div.child_ids.push_back(5);
803 ui::AXNodeData static_text1;
804 static_text1.id = 3;
805 static_text1.SetValue("AB");
806 static_text1.role = ui::AX_ROLE_STATIC_TEXT;
807 static_text1.location = gfx::Rect(100, 100, 40, 20);
808 static_text1.child_ids.push_back(6);
810 ui::AXNodeData img;
811 img.id = 4;
812 img.role = ui::AX_ROLE_IMAGE;
813 img.location = gfx::Rect(140, 100, 20, 20);
815 ui::AXNodeData static_text2;
816 static_text2.id = 5;
817 static_text2.SetValue("CD");
818 static_text2.role = ui::AX_ROLE_STATIC_TEXT;
819 static_text2.location = gfx::Rect(160, 100, 40, 20);
820 static_text2.child_ids.push_back(7);
822 ui::AXNodeData inline_text1;
823 inline_text1.id = 6;
824 inline_text1.SetValue("AB");
825 inline_text1.role = ui::AX_ROLE_INLINE_TEXT_BOX;
826 inline_text1.location = gfx::Rect(100, 100, 40, 20);
827 inline_text1.AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
828 blink::WebAXTextDirectionLR);
829 std::vector<int32> character_offsets1;
830 character_offsets1.push_back(20); // 0
831 character_offsets1.push_back(40); // 1
832 inline_text1.AddIntListAttribute(
833 ui::AX_ATTR_CHARACTER_OFFSETS, character_offsets1);
835 ui::AXNodeData inline_text2;
836 inline_text2.id = 7;
837 inline_text2.SetValue("CD");
838 inline_text2.role = ui::AX_ROLE_INLINE_TEXT_BOX;
839 inline_text2.location = gfx::Rect(160, 100, 40, 20);
840 inline_text2.AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
841 blink::WebAXTextDirectionLR);
842 std::vector<int32> character_offsets2;
843 character_offsets2.push_back(20); // 0
844 character_offsets2.push_back(40); // 1
845 inline_text2.AddIntListAttribute(
846 ui::AX_ATTR_CHARACTER_OFFSETS, character_offsets2);
848 scoped_ptr<BrowserAccessibilityManager> manager(
849 BrowserAccessibilityManager::Create(
850 root,
851 NULL,
852 new CountedBrowserAccessibilityFactory()));
853 manager->UpdateNodesForTesting(
854 div, static_text1, img, static_text2, inline_text1, inline_text2);
856 BrowserAccessibility* root_accessible = manager->GetRoot();
858 EXPECT_EQ(gfx::Rect(100, 100, 20, 20).ToString(),
859 root_accessible->GetLocalBoundsForRange(0, 1).ToString());
861 EXPECT_EQ(gfx::Rect(100, 100, 40, 20).ToString(),
862 root_accessible->GetLocalBoundsForRange(0, 2).ToString());
864 EXPECT_EQ(gfx::Rect(100, 100, 80, 20).ToString(),
865 root_accessible->GetLocalBoundsForRange(0, 3).ToString());
867 EXPECT_EQ(gfx::Rect(120, 100, 60, 20).ToString(),
868 root_accessible->GetLocalBoundsForRange(1, 2).ToString());
870 EXPECT_EQ(gfx::Rect(120, 100, 80, 20).ToString(),
871 root_accessible->GetLocalBoundsForRange(1, 3).ToString());
873 EXPECT_EQ(gfx::Rect(100, 100, 100, 20).ToString(),
874 root_accessible->GetLocalBoundsForRange(0, 4).ToString());
877 } // namespace content