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
13namespace ui {
14
15TEST(AXTreeTest, SerializeSimpleAXTree) {
16  AXNodeData root;
17  root.id = 1;
18  root.role = AX_ROLE_ROOT_WEB_AREA;
19  root.child_ids.push_back(2);
20  root.child_ids.push_back(3);
21
22  AXNodeData button;
23  button.id = 2;
24  button.role = AX_ROLE_BUTTON;
25  button.state = 0;
26
27  AXNodeData checkbox;
28  checkbox.id = 3;
29  checkbox.role = AX_ROLE_CHECK_BOX;
30
31  AXTreeUpdate initial_state;
32  initial_state.nodes.push_back(root);
33  initial_state.nodes.push_back(button);
34  initial_state.nodes.push_back(checkbox);
35  AXSerializableTree src_tree(initial_state);
36
37  scoped_ptr<AXTreeSource<AXNode> > tree_source(
38      src_tree.CreateTreeSource());
39  AXTreeSerializer<AXNode> serializer(tree_source.get());
40  AXTreeUpdate update;
41  serializer.SerializeChanges(src_tree.GetRoot(), &update);
42
43  AXTree dst_tree;
44  ASSERT_TRUE(dst_tree.Unserialize(update));
45
46  AXNode* root_node = dst_tree.GetRoot();
47  ASSERT_TRUE(root_node != NULL);
48  EXPECT_EQ(root.id, root_node->id());
49  EXPECT_EQ(root.role, root_node->data().role);
50
51  ASSERT_EQ(2, root_node->child_count());
52
53  AXNode* button_node = root_node->ChildAtIndex(0);
54  EXPECT_EQ(button.id, button_node->id());
55  EXPECT_EQ(button.role, button_node->data().role);
56
57  AXNode* checkbox_node = root_node->ChildAtIndex(1);
58  EXPECT_EQ(checkbox.id, checkbox_node->id());
59  EXPECT_EQ(checkbox.role, checkbox_node->data().role);
60}
61
62TEST(AXTreeTest, DeleteUnknownSubtreeFails) {
63  AXNodeData root;
64  root.id = 1;
65  root.role = AX_ROLE_ROOT_WEB_AREA;
66
67  AXTreeUpdate initial_state;
68  initial_state.nodes.push_back(root);
69  AXTree tree(initial_state);
70
71  // This should fail because we're asking it to delete
72  // a subtree rooted at id=2, which doesn't exist.
73  AXTreeUpdate update;
74  update.node_id_to_clear = 2;
75  update.nodes.resize(1);
76  update.nodes[0].id = 1;
77  update.nodes[0].id = AX_ROLE_ROOT_WEB_AREA;
78  EXPECT_FALSE(tree.Unserialize(update));
79  ASSERT_EQ("Bad node_id_to_clear: 2", tree.error());
80}
81
82TEST(AXTreeTest, LeaveOrphanedDeletedSubtreeFails) {
83  AXTreeUpdate initial_state;
84  initial_state.nodes.resize(3);
85  initial_state.nodes[0].id = 1;
86  initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
87  initial_state.nodes[0].child_ids.push_back(2);
88  initial_state.nodes[0].child_ids.push_back(3);
89  initial_state.nodes[1].id = 2;
90  initial_state.nodes[2].id = 3;
91  AXTree tree(initial_state);
92
93  // This should fail because we delete a subtree rooted at id=2
94  // but never update it.
95  AXTreeUpdate update;
96  update.node_id_to_clear = 2;
97  update.nodes.resize(1);
98  update.nodes[0].id = 3;
99  EXPECT_FALSE(tree.Unserialize(update));
100  ASSERT_EQ("Nodes left pending by the update: 2", tree.error());
101}
102
103TEST(AXTreeTest, LeaveOrphanedNewChildFails) {
104  AXTreeUpdate initial_state;
105  initial_state.nodes.resize(1);
106  initial_state.nodes[0].id = 1;
107  initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
108  AXTree tree(initial_state);
109
110  // This should fail because we add a new child to the root node
111  // but never update it.
112  AXTreeUpdate update;
113  update.nodes.resize(1);
114  update.nodes[0].id = 1;
115  update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
116  update.nodes[0].child_ids.push_back(2);
117  EXPECT_FALSE(tree.Unserialize(update));
118  ASSERT_EQ("Nodes left pending by the update: 2", tree.error());
119}
120
121TEST(AXTreeTest, DuplicateChildIdFails) {
122  AXTreeUpdate initial_state;
123  initial_state.nodes.resize(1);
124  initial_state.nodes[0].id = 1;
125  initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
126  AXTree tree(initial_state);
127
128  // This should fail because a child id appears twice.
129  AXTreeUpdate update;
130  update.nodes.resize(2);
131  update.nodes[0].id = 1;
132  update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
133  update.nodes[0].child_ids.push_back(2);
134  update.nodes[0].child_ids.push_back(2);
135  update.nodes[1].id = 2;
136  EXPECT_FALSE(tree.Unserialize(update));
137  ASSERT_EQ("Node 1 has duplicate child id 2", tree.error());
138}
139
140TEST(AXTreeTest, InvalidReparentingFails) {
141  AXTreeUpdate initial_state;
142  initial_state.nodes.resize(3);
143  initial_state.nodes[0].id = 1;
144  initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
145  initial_state.nodes[0].child_ids.push_back(2);
146  initial_state.nodes[1].id = 2;
147  initial_state.nodes[1].child_ids.push_back(3);
148  initial_state.nodes[2].id = 3;
149
150  AXTree tree(initial_state);
151
152  // This should fail because node 3 is reparented from node 2 to node 1
153  // without deleting node 1's subtree first.
154  AXTreeUpdate update;
155  update.nodes.resize(3);
156  update.nodes[0].id = 1;
157  update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
158  update.nodes[0].child_ids.push_back(3);
159  update.nodes[0].child_ids.push_back(2);
160  update.nodes[1].id = 2;
161  update.nodes[2].id = 3;
162  EXPECT_FALSE(tree.Unserialize(update));
163  ASSERT_EQ("Node 3 reparented from 2 to 1", tree.error());
164}
165
166}  // namespace ui
167