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