Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ui / accessibility / ax_tree_unittest.cc
1 // Copyright 2013 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 "base/memory/scoped_ptr.h"
6 #include "base/strings/string_number_conversions.h"
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "ui/accessibility/ax_node.h"
9 #include "ui/accessibility/ax_serializable_tree.h"
10 #include "ui/accessibility/ax_tree.h"
11 #include "ui/accessibility/ax_tree_serializer.h"
12
13 namespace ui {
14
15 namespace {
16
17 class FakeAXTreeDelegate : public AXTreeDelegate {
18  public:
19   virtual void OnNodeWillBeDeleted(AXNode* node) OVERRIDE {
20     deleted_ids_.push_back(node->id());
21   }
22
23   virtual void OnNodeCreated(AXNode* node) OVERRIDE {
24     created_ids_.push_back(node->id());
25   }
26
27   virtual void OnNodeChanged(AXNode* node) OVERRIDE {
28     changed_ids_.push_back(node->id());
29   }
30
31   virtual void OnNodeCreationFinished(AXNode* node) OVERRIDE {
32     creation_finished_ids_.push_back(node->id());
33   }
34
35   virtual void OnNodeChangeFinished(AXNode* node) OVERRIDE {
36     change_finished_ids_.push_back(node->id());
37   }
38
39   virtual void OnRootChanged(AXNode* new_root) OVERRIDE {
40     new_root_ids_.push_back(new_root->id());
41   }
42
43   const std::vector<int32>& deleted_ids() { return deleted_ids_; }
44   const std::vector<int32>& created_ids() { return created_ids_; }
45   const std::vector<int32>& creation_finished_ids() {
46     return creation_finished_ids_;
47   }
48   const std::vector<int32>& new_root_ids() { return new_root_ids_; }
49
50  private:
51   std::vector<int32> deleted_ids_;
52   std::vector<int32> created_ids_;
53   std::vector<int32> creation_finished_ids_;
54   std::vector<int32> changed_ids_;
55   std::vector<int32> change_finished_ids_;
56   std::vector<int32> new_root_ids_;
57 };
58
59 }  // namespace
60
61 TEST(AXTreeTest, SerializeSimpleAXTree) {
62   AXNodeData root;
63   root.id = 1;
64   root.role = AX_ROLE_ROOT_WEB_AREA;
65   root.state = (1 << AX_STATE_FOCUSABLE) | (1 << AX_STATE_FOCUSED);
66   root.location = gfx::Rect(0, 0, 800, 600);
67   root.child_ids.push_back(2);
68   root.child_ids.push_back(3);
69
70   AXNodeData button;
71   button.id = 2;
72   button.role = AX_ROLE_BUTTON;
73   button.state = 0;
74   button.location = gfx::Rect(20, 20, 200, 30);
75
76   AXNodeData checkbox;
77   checkbox.id = 3;
78   checkbox.role = AX_ROLE_CHECK_BOX;
79   checkbox.state = 0;
80   checkbox.location = gfx::Rect(20, 50, 200, 30);
81
82   AXTreeUpdate initial_state;
83   initial_state.nodes.push_back(root);
84   initial_state.nodes.push_back(button);
85   initial_state.nodes.push_back(checkbox);
86   AXSerializableTree src_tree(initial_state);
87
88   scoped_ptr<AXTreeSource<const AXNode*> > tree_source(
89       src_tree.CreateTreeSource());
90   AXTreeSerializer<const AXNode*> serializer(tree_source.get());
91   AXTreeUpdate update;
92   serializer.SerializeChanges(src_tree.GetRoot(), &update);
93
94   AXTree dst_tree;
95   ASSERT_TRUE(dst_tree.Unserialize(update));
96
97   const AXNode* root_node = dst_tree.GetRoot();
98   ASSERT_TRUE(root_node != NULL);
99   EXPECT_EQ(root.id, root_node->id());
100   EXPECT_EQ(root.role, root_node->data().role);
101
102   ASSERT_EQ(2, root_node->child_count());
103
104   const AXNode* button_node = root_node->ChildAtIndex(0);
105   EXPECT_EQ(button.id, button_node->id());
106   EXPECT_EQ(button.role, button_node->data().role);
107
108   const AXNode* checkbox_node = root_node->ChildAtIndex(1);
109   EXPECT_EQ(checkbox.id, checkbox_node->id());
110   EXPECT_EQ(checkbox.role, checkbox_node->data().role);
111
112   EXPECT_EQ(
113       "id=1 root_web_area FOCUSABLE FOCUSED (0, 0)-(800, 600) child_ids=2,3\n"
114       "  id=2 button (20, 20)-(200, 30)\n"
115       "  id=3 check_box (20, 50)-(200, 30)\n",
116       dst_tree.ToString());
117 }
118
119 TEST(AXTreeTest, SerializeAXTreeUpdate) {
120   AXNodeData list;
121   list.id = 3;
122   list.role = AX_ROLE_LIST;
123   list.state = 0;
124   list.child_ids.push_back(4);
125   list.child_ids.push_back(5);
126   list.child_ids.push_back(6);
127
128   AXNodeData list_item_2;
129   list_item_2.id = 5;
130   list_item_2.role = AX_ROLE_LIST_ITEM;
131   list_item_2.state = 0;
132
133   AXNodeData list_item_3;
134   list_item_3.id = 6;
135   list_item_3.role = AX_ROLE_LIST_ITEM;
136   list_item_3.state = 0;
137
138   AXNodeData button;
139   button.id = 7;
140   button.role = AX_ROLE_BUTTON;
141   button.state = 0;
142
143   AXTreeUpdate update;
144   update.nodes.push_back(list);
145   update.nodes.push_back(list_item_2);
146   update.nodes.push_back(list_item_3);
147   update.nodes.push_back(button);
148
149   EXPECT_EQ(
150       "id=3 list (0, 0)-(0, 0) child_ids=4,5,6\n"
151       "  id=5 list_item (0, 0)-(0, 0)\n"
152       "  id=6 list_item (0, 0)-(0, 0)\n"
153       "id=7 button (0, 0)-(0, 0)\n",
154       update.ToString());
155 }
156
157 TEST(AXTreeTest, DeleteUnknownSubtreeFails) {
158   AXNodeData root;
159   root.id = 1;
160   root.role = AX_ROLE_ROOT_WEB_AREA;
161
162   AXTreeUpdate initial_state;
163   initial_state.nodes.push_back(root);
164   AXTree tree(initial_state);
165
166   // This should fail because we're asking it to delete
167   // a subtree rooted at id=2, which doesn't exist.
168   AXTreeUpdate update;
169   update.node_id_to_clear = 2;
170   update.nodes.resize(1);
171   update.nodes[0].id = 1;
172   update.nodes[0].id = AX_ROLE_ROOT_WEB_AREA;
173   EXPECT_FALSE(tree.Unserialize(update));
174   ASSERT_EQ("Bad node_id_to_clear: 2", tree.error());
175 }
176
177 TEST(AXTreeTest, LeaveOrphanedDeletedSubtreeFails) {
178   AXTreeUpdate initial_state;
179   initial_state.nodes.resize(3);
180   initial_state.nodes[0].id = 1;
181   initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
182   initial_state.nodes[0].child_ids.push_back(2);
183   initial_state.nodes[0].child_ids.push_back(3);
184   initial_state.nodes[1].id = 2;
185   initial_state.nodes[2].id = 3;
186   AXTree tree(initial_state);
187
188   // This should fail because we delete a subtree rooted at id=2
189   // but never update it.
190   AXTreeUpdate update;
191   update.node_id_to_clear = 2;
192   update.nodes.resize(1);
193   update.nodes[0].id = 3;
194   EXPECT_FALSE(tree.Unserialize(update));
195   ASSERT_EQ("Nodes left pending by the update: 2", tree.error());
196 }
197
198 TEST(AXTreeTest, LeaveOrphanedNewChildFails) {
199   AXTreeUpdate initial_state;
200   initial_state.nodes.resize(1);
201   initial_state.nodes[0].id = 1;
202   initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
203   AXTree tree(initial_state);
204
205   // This should fail because we add a new child to the root node
206   // but never update it.
207   AXTreeUpdate update;
208   update.nodes.resize(1);
209   update.nodes[0].id = 1;
210   update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
211   update.nodes[0].child_ids.push_back(2);
212   EXPECT_FALSE(tree.Unserialize(update));
213   ASSERT_EQ("Nodes left pending by the update: 2", tree.error());
214 }
215
216 TEST(AXTreeTest, DuplicateChildIdFails) {
217   AXTreeUpdate initial_state;
218   initial_state.nodes.resize(1);
219   initial_state.nodes[0].id = 1;
220   initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
221   AXTree tree(initial_state);
222
223   // This should fail because a child id appears twice.
224   AXTreeUpdate update;
225   update.nodes.resize(2);
226   update.nodes[0].id = 1;
227   update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
228   update.nodes[0].child_ids.push_back(2);
229   update.nodes[0].child_ids.push_back(2);
230   update.nodes[1].id = 2;
231   EXPECT_FALSE(tree.Unserialize(update));
232   ASSERT_EQ("Node 1 has duplicate child id 2", tree.error());
233 }
234
235 TEST(AXTreeTest, InvalidReparentingFails) {
236   AXTreeUpdate initial_state;
237   initial_state.nodes.resize(3);
238   initial_state.nodes[0].id = 1;
239   initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
240   initial_state.nodes[0].child_ids.push_back(2);
241   initial_state.nodes[1].id = 2;
242   initial_state.nodes[1].child_ids.push_back(3);
243   initial_state.nodes[2].id = 3;
244
245   AXTree tree(initial_state);
246
247   // This should fail because node 3 is reparented from node 2 to node 1
248   // without deleting node 1's subtree first.
249   AXTreeUpdate update;
250   update.nodes.resize(3);
251   update.nodes[0].id = 1;
252   update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
253   update.nodes[0].child_ids.push_back(3);
254   update.nodes[0].child_ids.push_back(2);
255   update.nodes[1].id = 2;
256   update.nodes[2].id = 3;
257   EXPECT_FALSE(tree.Unserialize(update));
258   ASSERT_EQ("Node 3 reparented from 2 to 1", tree.error());
259 }
260
261 TEST(AXTreeTest, TreeDelegateIsCalled) {
262   AXTreeUpdate initial_state;
263   initial_state.nodes.resize(1);
264   initial_state.nodes[0].id = 1;
265   initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
266
267   AXTree tree(initial_state);
268   AXTreeUpdate update;
269   update.node_id_to_clear = 1;
270   update.nodes.resize(2);
271   update.nodes[0].id = 2;
272   update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
273   update.nodes[0].child_ids.push_back(3);
274   update.nodes[1].id = 3;
275
276   FakeAXTreeDelegate fake_delegate;
277   tree.SetDelegate(&fake_delegate);
278
279   EXPECT_TRUE(tree.Unserialize(update));
280
281   ASSERT_EQ(1U, fake_delegate.deleted_ids().size());
282   EXPECT_EQ(1, fake_delegate.deleted_ids()[0]);
283
284   ASSERT_EQ(2U, fake_delegate.created_ids().size());
285   EXPECT_EQ(2, fake_delegate.created_ids()[0]);
286   EXPECT_EQ(3, fake_delegate.created_ids()[1]);
287
288   ASSERT_EQ(2U, fake_delegate.creation_finished_ids().size());
289   EXPECT_EQ(2, fake_delegate.creation_finished_ids()[0]);
290   EXPECT_EQ(3, fake_delegate.creation_finished_ids()[1]);
291
292   ASSERT_EQ(1U, fake_delegate.new_root_ids().size());
293   EXPECT_EQ(2, fake_delegate.new_root_ids()[0]);
294
295   tree.SetDelegate(NULL);
296 }
297
298 }  // namespace ui