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 // The framework for these tests is that each test sets up |treedata0_| 16 // and |treedata1_| and then calls GetTreeSerializer, which creates a 17 // serializer for a tree that's initially in state |treedata0_|, but then 18 // changes to state |treedata1_|. This allows each test to check the 19 // updates created by AXTreeSerializer or unit-test its private 20 // member functions. 21 class AXTreeSerializerTest : public testing::Test { 22 public: 23 AXTreeSerializerTest() {} 24 virtual ~AXTreeSerializerTest() {} 25 26 protected: 27 void CreateTreeSerializer(); 28 29 AXTreeUpdate treedata0_; 30 AXTreeUpdate treedata1_; 31 scoped_ptr<AXSerializableTree> tree0_; 32 scoped_ptr<AXSerializableTree> tree1_; 33 scoped_ptr<AXTreeSource<AXNode> > tree0_source_; 34 scoped_ptr<AXTreeSource<AXNode> > tree1_source_; 35 scoped_ptr<AXTreeSerializer<AXNode> > serializer_; 36 37 private: 38 DISALLOW_COPY_AND_ASSIGN(AXTreeSerializerTest); 39 }; 40 41 void AXTreeSerializerTest::CreateTreeSerializer() { 42 if (serializer_) 43 return; 44 45 tree0_.reset(new AXSerializableTree(treedata0_)); 46 tree1_.reset(new AXSerializableTree(treedata1_)); 47 48 // Serialize tree0 so that AXTreeSerializer thinks that its client 49 // is totally in sync. 50 tree0_source_.reset(tree0_->CreateTreeSource()); 51 serializer_.reset(new AXTreeSerializer<AXNode>(tree0_source_.get())); 52 AXTreeUpdate unused_update; 53 serializer_->SerializeChanges(tree0_->GetRoot(), &unused_update); 54 55 // Pretend that tree0_ turned into tree1_. The next call to 56 // AXTreeSerializer will force it to consider these changes to 57 // the tree and send them as part of the next update. 58 tree1_source_.reset(tree1_->CreateTreeSource()); 59 serializer_->ChangeTreeSourceForTesting(tree1_source_.get()); 60 } 61 62 // In this test, one child is added to the root. Only the root and 63 // new child should be added. 64 TEST_F(AXTreeSerializerTest, UpdateContainsOnlyChangedNodes) { 65 // (1 (2 3)) 66 treedata0_.nodes.resize(3); 67 treedata0_.nodes[0].id = 1; 68 treedata0_.nodes[0].role = AX_ROLE_ROOT_WEB_AREA; 69 treedata0_.nodes[0].child_ids.push_back(2); 70 treedata0_.nodes[0].child_ids.push_back(3); 71 treedata0_.nodes[1].id = 2; 72 treedata0_.nodes[2].id = 3; 73 74 // (1 (4 2 3)) 75 treedata1_.nodes.resize(4); 76 treedata1_.nodes[0].id = 1; 77 treedata1_.nodes[0].role = AX_ROLE_ROOT_WEB_AREA; 78 treedata1_.nodes[0].child_ids.push_back(4); 79 treedata1_.nodes[0].child_ids.push_back(2); 80 treedata1_.nodes[0].child_ids.push_back(3); 81 treedata1_.nodes[1].id = 2; 82 treedata1_.nodes[2].id = 3; 83 treedata1_.nodes[3].id = 4; 84 85 CreateTreeSerializer(); 86 AXTreeUpdate update; 87 serializer_->SerializeChanges(tree1_->GetFromId(1), &update); 88 89 // The update should only touch nodes 1 and 4 - nodes 2 and 3 are unchanged 90 // and shouldn't be affected. 91 EXPECT_EQ(0, update.node_id_to_clear); 92 ASSERT_EQ(static_cast<size_t>(2), update.nodes.size()); 93 EXPECT_EQ(1, update.nodes[0].id); 94 EXPECT_EQ(4, update.nodes[1].id); 95 } 96 97 // When the root changes, the whole tree is updated, even if some of it 98 // is unaffected. 99 TEST_F(AXTreeSerializerTest, NewRootUpdatesEntireTree) { 100 // (1 (2 (3 (4)))) 101 treedata0_.nodes.resize(4); 102 treedata0_.nodes[0].id = 1; 103 treedata0_.nodes[0].role = AX_ROLE_ROOT_WEB_AREA; 104 treedata0_.nodes[0].child_ids.push_back(2); 105 treedata0_.nodes[1].id = 2; 106 treedata0_.nodes[1].child_ids.push_back(3); 107 treedata0_.nodes[2].id = 3; 108 treedata0_.nodes[2].child_ids.push_back(4); 109 treedata0_.nodes[3].id = 4; 110 111 // (5 (2 (3 (4)))) 112 treedata1_.nodes.resize(4); 113 treedata1_.nodes[0].id = 5; 114 treedata1_.nodes[0].role = AX_ROLE_ROOT_WEB_AREA; 115 treedata1_.nodes[0].child_ids.push_back(2); 116 treedata1_.nodes[1].id = 2; 117 treedata1_.nodes[1].child_ids.push_back(3); 118 treedata1_.nodes[2].id = 3; 119 treedata1_.nodes[2].child_ids.push_back(4); 120 treedata1_.nodes[3].id = 4; 121 122 CreateTreeSerializer(); 123 AXTreeUpdate update; 124 serializer_->SerializeChanges(tree1_->GetFromId(4), &update); 125 126 // The update should delete the subtree rooted at node id=1, and 127 // then include all four nodes in the update, even though the 128 // subtree rooted at id=2 didn't actually change. 129 EXPECT_EQ(1, update.node_id_to_clear); 130 ASSERT_EQ(static_cast<size_t>(4), update.nodes.size()); 131 EXPECT_EQ(5, update.nodes[0].id); 132 EXPECT_EQ(2, update.nodes[1].id); 133 EXPECT_EQ(3, update.nodes[2].id); 134 EXPECT_EQ(4, update.nodes[3].id); 135 } 136 137 // When a node is reparented, the subtree including both the old parent 138 // and new parent of the reparented node must be deleted and recreated. 139 TEST_F(AXTreeSerializerTest, ReparentingUpdatesSubtree) { 140 // (1 (2 (3 (4) 5))) 141 treedata0_.nodes.resize(5); 142 treedata0_.nodes[0].id = 1; 143 treedata0_.nodes[0].role = AX_ROLE_ROOT_WEB_AREA; 144 treedata0_.nodes[0].child_ids.push_back(2); 145 treedata0_.nodes[1].id = 2; 146 treedata0_.nodes[1].child_ids.push_back(3); 147 treedata0_.nodes[1].child_ids.push_back(5); 148 treedata0_.nodes[2].id = 3; 149 treedata0_.nodes[2].child_ids.push_back(4); 150 treedata0_.nodes[3].id = 4; 151 treedata0_.nodes[4].id = 5; 152 153 // Node 5 has been reparented from being a child of node 2, 154 // to a child of node 4. 155 // (1 (2 (3 (4 (5))))) 156 treedata1_.nodes.resize(5); 157 treedata1_.nodes[0].id = 1; 158 treedata1_.nodes[0].role = AX_ROLE_ROOT_WEB_AREA; 159 treedata1_.nodes[0].child_ids.push_back(2); 160 treedata1_.nodes[1].id = 2; 161 treedata1_.nodes[1].child_ids.push_back(3); 162 treedata1_.nodes[2].id = 3; 163 treedata1_.nodes[2].child_ids.push_back(4); 164 treedata1_.nodes[3].id = 4; 165 treedata1_.nodes[3].child_ids.push_back(5); 166 treedata1_.nodes[4].id = 5; 167 168 CreateTreeSerializer(); 169 AXTreeUpdate update; 170 serializer_->SerializeChanges(tree1_->GetFromId(4), &update); 171 172 // The update should delete the subtree rooted at node id=2, and 173 // then include nodes 2...5. 174 EXPECT_EQ(2, update.node_id_to_clear); 175 ASSERT_EQ(static_cast<size_t>(4), update.nodes.size()); 176 EXPECT_EQ(2, update.nodes[0].id); 177 EXPECT_EQ(3, update.nodes[1].id); 178 EXPECT_EQ(4, update.nodes[2].id); 179 EXPECT_EQ(5, update.nodes[3].id); 180 } 181 182 } // namespace ui 183