1 // Copyright 2016 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/accessibility/ax_tree_combiner.h"
6
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "ui/accessibility/ax_enums.mojom.h"
9
10 namespace ui {
11
TEST(CombineAXTreesTest,RenumberOneTree)12 TEST(CombineAXTreesTest, RenumberOneTree) {
13 AXTreeID tree_id_1 = AXTreeID::CreateNewAXTreeID();
14
15 AXTreeUpdate tree;
16 tree.has_tree_data = true;
17 tree.tree_data.tree_id = tree_id_1;
18 tree.root_id = 2;
19 tree.nodes.resize(3);
20 tree.nodes[0].id = 2;
21 tree.nodes[0].child_ids.push_back(4);
22 tree.nodes[0].child_ids.push_back(6);
23 tree.nodes[1].id = 4;
24 tree.nodes[2].id = 6;
25
26 AXTreeCombiner combiner;
27 combiner.AddTree(tree, true);
28 combiner.Combine();
29
30 const AXTreeUpdate& combined = combiner.combined();
31
32 EXPECT_EQ(1, combined.root_id);
33 ASSERT_EQ(3U, combined.nodes.size());
34 EXPECT_EQ(1, combined.nodes[0].id);
35 ASSERT_EQ(2U, combined.nodes[0].child_ids.size());
36 EXPECT_EQ(2, combined.nodes[0].child_ids[0]);
37 EXPECT_EQ(3, combined.nodes[0].child_ids[1]);
38 EXPECT_EQ(2, combined.nodes[1].id);
39 EXPECT_EQ(3, combined.nodes[2].id);
40 }
41
TEST(CombineAXTreesTest,EmbedChildTree)42 TEST(CombineAXTreesTest, EmbedChildTree) {
43 AXTreeID tree_id_1 = AXTreeID::CreateNewAXTreeID();
44 AXTreeID tree_id_2 = AXTreeID::CreateNewAXTreeID();
45
46 AXTreeUpdate parent_tree;
47 parent_tree.root_id = 1;
48 parent_tree.has_tree_data = true;
49 parent_tree.tree_data.tree_id = tree_id_1;
50 parent_tree.nodes.resize(3);
51 parent_tree.nodes[0].id = 1;
52 parent_tree.nodes[0].child_ids.push_back(2);
53 parent_tree.nodes[0].child_ids.push_back(3);
54 parent_tree.nodes[1].id = 2;
55 parent_tree.nodes[1].role = ax::mojom::Role::kButton;
56 parent_tree.nodes[2].id = 3;
57 parent_tree.nodes[2].role = ax::mojom::Role::kIframe;
58 parent_tree.nodes[2].AddStringAttribute(
59 ax::mojom::StringAttribute::kChildTreeId, tree_id_2.ToString());
60
61 AXTreeUpdate child_tree;
62 child_tree.root_id = 1;
63 child_tree.has_tree_data = true;
64 child_tree.tree_data.parent_tree_id = tree_id_1;
65 child_tree.tree_data.tree_id = tree_id_2;
66 child_tree.nodes.resize(3);
67 child_tree.nodes[0].id = 1;
68 child_tree.nodes[0].child_ids.push_back(2);
69 child_tree.nodes[0].child_ids.push_back(3);
70 child_tree.nodes[1].id = 2;
71 child_tree.nodes[1].role = ax::mojom::Role::kCheckBox;
72 child_tree.nodes[2].id = 3;
73 child_tree.nodes[2].role = ax::mojom::Role::kRadioButton;
74
75 AXTreeCombiner combiner;
76 combiner.AddTree(parent_tree, true);
77 combiner.AddTree(child_tree, false);
78 combiner.Combine();
79
80 const AXTreeUpdate& combined = combiner.combined();
81
82 EXPECT_EQ(1, combined.root_id);
83 ASSERT_EQ(6U, combined.nodes.size());
84 EXPECT_EQ(1, combined.nodes[0].id);
85 ASSERT_EQ(2U, combined.nodes[0].child_ids.size());
86 EXPECT_EQ(2, combined.nodes[0].child_ids[0]);
87 EXPECT_EQ(3, combined.nodes[0].child_ids[1]);
88 EXPECT_EQ(2, combined.nodes[1].id);
89 EXPECT_EQ(ax::mojom::Role::kButton, combined.nodes[1].role);
90 EXPECT_EQ(3, combined.nodes[2].id);
91 EXPECT_EQ(ax::mojom::Role::kIframe, combined.nodes[2].role);
92 EXPECT_EQ(1U, combined.nodes[2].child_ids.size());
93 EXPECT_EQ(4, combined.nodes[2].child_ids[0]);
94 EXPECT_EQ(4, combined.nodes[3].id);
95 EXPECT_EQ(5, combined.nodes[4].id);
96 EXPECT_EQ(ax::mojom::Role::kCheckBox, combined.nodes[4].role);
97 EXPECT_EQ(6, combined.nodes[5].id);
98 EXPECT_EQ(ax::mojom::Role::kRadioButton, combined.nodes[5].role);
99 }
100
TEST(CombineAXTreesTest,MapAllIdAttributes)101 TEST(CombineAXTreesTest, MapAllIdAttributes) {
102 AXTreeID tree_id_1 = AXTreeID::CreateNewAXTreeID();
103
104 // This is a nonsensical accessibility tree, the goal is to make sure
105 // that all attributes that reference IDs of other nodes are remapped.
106
107 AXTreeUpdate tree;
108 tree.has_tree_data = true;
109 tree.tree_data.tree_id = tree_id_1;
110 tree.root_id = 11;
111 tree.nodes.resize(2);
112 tree.nodes[0].id = 11;
113 tree.nodes[0].child_ids.push_back(22);
114 tree.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kTableHeaderId, 22);
115 tree.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kTableRowHeaderId, 22);
116 tree.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kTableColumnHeaderId,
117 22);
118 tree.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kActivedescendantId,
119 22);
120 std::vector<int32_t> ids { 22 };
121 tree.nodes[0].AddIntListAttribute(
122 ax::mojom::IntListAttribute::kIndirectChildIds, ids);
123 tree.nodes[0].AddIntListAttribute(ax::mojom::IntListAttribute::kControlsIds,
124 ids);
125 tree.nodes[0].AddIntListAttribute(
126 ax::mojom::IntListAttribute::kDescribedbyIds, ids);
127 tree.nodes[0].AddIntListAttribute(ax::mojom::IntListAttribute::kFlowtoIds,
128 ids);
129 tree.nodes[0].AddIntListAttribute(ax::mojom::IntListAttribute::kLabelledbyIds,
130 ids);
131 tree.nodes[1].id = 22;
132
133 AXTreeCombiner combiner;
134 combiner.AddTree(tree, true);
135 combiner.Combine();
136
137 const AXTreeUpdate& combined = combiner.combined();
138
139 EXPECT_EQ(1, combined.root_id);
140 ASSERT_EQ(2U, combined.nodes.size());
141 EXPECT_EQ(1, combined.nodes[0].id);
142 ASSERT_EQ(1U, combined.nodes[0].child_ids.size());
143 EXPECT_EQ(2, combined.nodes[0].child_ids[0]);
144 EXPECT_EQ(2, combined.nodes[1].id);
145
146 EXPECT_EQ(2, combined.nodes[0].GetIntAttribute(
147 ax::mojom::IntAttribute::kTableHeaderId));
148 EXPECT_EQ(2, combined.nodes[0].GetIntAttribute(
149 ax::mojom::IntAttribute::kTableRowHeaderId));
150 EXPECT_EQ(2, combined.nodes[0].GetIntAttribute(
151 ax::mojom::IntAttribute::kTableColumnHeaderId));
152 EXPECT_EQ(2, combined.nodes[0].GetIntAttribute(
153 ax::mojom::IntAttribute::kActivedescendantId));
154 EXPECT_EQ(2, combined.nodes[0].GetIntListAttribute(
155 ax::mojom::IntListAttribute::kIndirectChildIds)[0]);
156 EXPECT_EQ(2, combined.nodes[0].GetIntListAttribute(
157 ax::mojom::IntListAttribute::kControlsIds)[0]);
158 EXPECT_EQ(2, combined.nodes[0].GetIntListAttribute(
159 ax::mojom::IntListAttribute::kDescribedbyIds)[0]);
160 EXPECT_EQ(2, combined.nodes[0].GetIntListAttribute(
161 ax::mojom::IntListAttribute::kFlowtoIds)[0]);
162 EXPECT_EQ(2, combined.nodes[0].GetIntListAttribute(
163 ax::mojom::IntListAttribute::kLabelledbyIds)[0]);
164 }
165
TEST(CombineAXTreesTest,FocusedTree)166 TEST(CombineAXTreesTest, FocusedTree) {
167 AXTreeID tree_id_1 = AXTreeID::CreateNewAXTreeID();
168 AXTreeID tree_id_2 = AXTreeID::CreateNewAXTreeID();
169
170 AXTreeUpdate parent_tree;
171 parent_tree.has_tree_data = true;
172 parent_tree.tree_data.tree_id = tree_id_1;
173 parent_tree.tree_data.focused_tree_id = tree_id_2;
174 parent_tree.tree_data.focus_id = 2;
175 parent_tree.root_id = 1;
176 parent_tree.nodes.resize(3);
177 parent_tree.nodes[0].id = 1;
178 parent_tree.nodes[0].child_ids.push_back(2);
179 parent_tree.nodes[0].child_ids.push_back(3);
180 parent_tree.nodes[1].id = 2;
181 parent_tree.nodes[1].role = ax::mojom::Role::kButton;
182 parent_tree.nodes[2].id = 3;
183 parent_tree.nodes[2].role = ax::mojom::Role::kIframe;
184 parent_tree.nodes[2].AddStringAttribute(
185 ax::mojom::StringAttribute::kChildTreeId, tree_id_2.ToString());
186
187 AXTreeUpdate child_tree;
188 child_tree.has_tree_data = true;
189 child_tree.tree_data.parent_tree_id = tree_id_1;
190 child_tree.tree_data.tree_id = tree_id_2;
191 child_tree.tree_data.focus_id = 3;
192 child_tree.root_id = 1;
193 child_tree.nodes.resize(3);
194 child_tree.nodes[0].id = 1;
195 child_tree.nodes[0].child_ids.push_back(2);
196 child_tree.nodes[0].child_ids.push_back(3);
197 child_tree.nodes[1].id = 2;
198 child_tree.nodes[1].role = ax::mojom::Role::kCheckBox;
199 child_tree.nodes[2].id = 3;
200 child_tree.nodes[2].role = ax::mojom::Role::kRadioButton;
201
202 AXTreeCombiner combiner;
203 combiner.AddTree(parent_tree, true);
204 combiner.AddTree(child_tree, false);
205 combiner.Combine();
206
207 const AXTreeUpdate& combined = combiner.combined();
208
209 ASSERT_EQ(6U, combined.nodes.size());
210 EXPECT_EQ(6, combined.tree_data.focus_id);
211 }
212
TEST(CombineAXTreesTest,EmptyTree)213 TEST(CombineAXTreesTest, EmptyTree) {
214 AXTreeUpdate tree;
215
216 AXTreeCombiner combiner;
217 combiner.AddTree(tree, true);
218 combiner.Combine();
219
220 const AXTreeUpdate& combined = combiner.combined();
221 ASSERT_EQ(0U, combined.nodes.size());
222 }
223
224 } // namespace ui
225