1 // Copyright 2018 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.
4
5 #include "ui/views/accessibility/ax_tree_source_views.h"
6
7 #include <memory>
8 #include <utility>
9 #include <vector>
10
11 #include "base/strings/utf_string_conversions.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "ui/accessibility/ax_tree_data.h"
14 #include "ui/accessibility/platform/ax_unique_id.h"
15 #include "ui/gfx/geometry/rect_f.h"
16 #include "ui/views/accessibility/ax_aura_obj_cache.h"
17 #include "ui/views/accessibility/ax_aura_obj_wrapper.h"
18 #include "ui/views/accessibility/view_accessibility.h"
19 #include "ui/views/controls/label.h"
20 #include "ui/views/controls/textfield/textfield.h"
21 #include "ui/views/test/views_test_base.h"
22 #include "ui/views/widget/widget.h"
23
24 namespace views {
25 namespace {
26
27 // TestAXTreeSourceViews provides a root with a default tree ID.
28 class TestAXTreeSourceViews : public AXTreeSourceViews {
29 public:
TestAXTreeSourceViews(AXAuraObjWrapper * root,AXAuraObjCache * cache)30 TestAXTreeSourceViews(AXAuraObjWrapper* root, AXAuraObjCache* cache)
31 : AXTreeSourceViews(root, ui::AXTreeID::CreateNewAXTreeID(), cache) {}
32 TestAXTreeSourceViews(const TestAXTreeSourceViews&) = delete;
33 TestAXTreeSourceViews& operator=(const TestAXTreeSourceViews&) = delete;
34 ~TestAXTreeSourceViews() override = default;
35 };
36
37 class AXTreeSourceViewsTest : public ViewsTestBase {
38 public:
39 AXTreeSourceViewsTest() = default;
40 AXTreeSourceViewsTest(const AXTreeSourceViewsTest&) = delete;
41 AXTreeSourceViewsTest& operator=(const AXTreeSourceViewsTest&) = delete;
42 ~AXTreeSourceViewsTest() override = default;
43
44 // testing::Test:
SetUp()45 void SetUp() override {
46 ViewsTestBase::SetUp();
47 widget_ = std::make_unique<Widget>();
48 Widget::InitParams params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
49 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
50 params.bounds = gfx::Rect(11, 22, 333, 444);
51 params.context = GetContext();
52 widget_->Init(std::move(params));
53 widget_->SetContentsView(std::make_unique<View>());
54
55 label1_ = new Label(base::ASCIIToUTF16("Label 1"));
56 label1_->SetBounds(1, 1, 111, 111);
57 widget_->GetContentsView()->AddChildView(label1_);
58
59 label2_ = new Label(base::ASCIIToUTF16("Label 2"));
60 label2_->SetBounds(2, 2, 222, 222);
61 widget_->GetContentsView()->AddChildView(label2_);
62
63 textfield_ = new Textfield();
64 textfield_->SetBounds(222, 2, 20, 200);
65 widget_->GetContentsView()->AddChildView(textfield_);
66 }
67
TearDown()68 void TearDown() override {
69 widget_.reset();
70 ViewsTestBase::TearDown();
71 }
72
73 std::unique_ptr<Widget> widget_;
74 Label* label1_ = nullptr; // Owned by views hierarchy.
75 Label* label2_ = nullptr; // Owned by views hierarchy.
76 Textfield* textfield_ = nullptr; // Owned by views hierarchy.
77 };
78
TEST_F(AXTreeSourceViewsTest,Basics)79 TEST_F(AXTreeSourceViewsTest, Basics) {
80 AXAuraObjCache cache;
81
82 // Start the tree at the Widget's contents view.
83 AXAuraObjWrapper* root = cache.GetOrCreate(widget_->GetContentsView());
84 TestAXTreeSourceViews tree(root, &cache);
85 EXPECT_EQ(root, tree.GetRoot());
86
87 // The root has no parent.
88 EXPECT_FALSE(tree.GetParent(root));
89
90 // The root has the right children.
91 std::vector<AXAuraObjWrapper*> children;
92 tree.GetChildren(root, &children);
93 ASSERT_EQ(3u, children.size());
94
95 // The labels are the children.
96 AXAuraObjWrapper* label1 = children[0];
97 AXAuraObjWrapper* label2 = children[1];
98 AXAuraObjWrapper* textfield = children[2];
99 EXPECT_EQ(label1, cache.GetOrCreate(label1_));
100 EXPECT_EQ(label2, cache.GetOrCreate(label2_));
101 EXPECT_EQ(textfield, cache.GetOrCreate(textfield_));
102
103 // The parents is correct.
104 EXPECT_EQ(root, tree.GetParent(label1));
105 EXPECT_EQ(root, tree.GetParent(label2));
106 EXPECT_EQ(root, tree.GetParent(textfield));
107
108 // IDs match the ones in the cache.
109 EXPECT_EQ(root->GetUniqueId(), tree.GetId(root));
110 EXPECT_EQ(label1->GetUniqueId(), tree.GetId(label1));
111 EXPECT_EQ(label2->GetUniqueId(), tree.GetId(label2));
112 EXPECT_EQ(textfield->GetUniqueId(), tree.GetId(textfield));
113
114 // Reverse ID lookups work.
115 EXPECT_EQ(root, tree.GetFromId(root->GetUniqueId()));
116 EXPECT_EQ(label1, tree.GetFromId(label1->GetUniqueId()));
117 EXPECT_EQ(label2, tree.GetFromId(label2->GetUniqueId()));
118 EXPECT_EQ(textfield, tree.GetFromId(textfield->GetUniqueId()));
119
120 // Validity.
121 EXPECT_TRUE(tree.IsValid(root));
122 EXPECT_FALSE(tree.IsValid(nullptr));
123
124 // Comparisons.
125 EXPECT_TRUE(tree.IsEqual(label1, label1));
126 EXPECT_FALSE(tree.IsEqual(label1, label2));
127 EXPECT_FALSE(tree.IsEqual(label1, nullptr));
128 EXPECT_FALSE(tree.IsEqual(nullptr, label1));
129
130 // Null pointers is the null value.
131 EXPECT_EQ(nullptr, tree.GetNull());
132 }
133
TEST_F(AXTreeSourceViewsTest,GetTreeDataWithFocus)134 TEST_F(AXTreeSourceViewsTest, GetTreeDataWithFocus) {
135 AXAuraObjCache cache;
136 TestAXTreeSourceViews tree(cache.GetOrCreate(widget_.get()), &cache);
137 textfield_->RequestFocus();
138
139 ui::AXTreeData tree_data;
140 tree.GetTreeData(&tree_data);
141 EXPECT_TRUE(tree_data.loaded);
142 EXPECT_EQ(cache.GetID(textfield_), tree_data.focus_id);
143 }
144
TEST_F(AXTreeSourceViewsTest,IgnoredView)145 TEST_F(AXTreeSourceViewsTest, IgnoredView) {
146 View* ignored_view = new View();
147 ignored_view->GetViewAccessibility().OverrideIsIgnored(true);
148 widget_->GetContentsView()->AddChildView(ignored_view);
149
150 AXAuraObjCache cache;
151 TestAXTreeSourceViews tree(cache.GetOrCreate(widget_.get()), &cache);
152 EXPECT_TRUE(tree.IsValid(cache.GetOrCreate(ignored_view)));
153 }
154
155 } // namespace
156 } // namespace views
157