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 "ui/accessibility/ax_tree_serializer.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <memory>
11
12 #include "base/macros.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "testing/gmock/include/gmock/gmock-matchers.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "ui/accessibility/ax_common.h"
17 #include "ui/accessibility/ax_node.h"
18 #include "ui/accessibility/ax_serializable_tree.h"
19
20 using testing::UnorderedElementsAre;
21
22 namespace ui {
23
24 using BasicAXTreeSerializer =
25 AXTreeSerializer<const AXNode*, AXNodeData, AXTreeData>;
26
27 // The framework for these tests is that each test sets up |treedata0_|
28 // and |treedata1_| and then calls GetTreeSerializer, which creates a
29 // serializer for a tree that's initially in state |treedata0_|, but then
30 // changes to state |treedata1_|. This allows each test to check the
31 // updates created by AXTreeSerializer or unit-test its private
32 // member functions.
33 class AXTreeSerializerTest : public testing::Test {
34 public:
AXTreeSerializerTest()35 AXTreeSerializerTest() {}
~AXTreeSerializerTest()36 ~AXTreeSerializerTest() override {}
37
38 protected:
39 void CreateTreeSerializer();
40
41 AXTreeUpdate treedata0_;
42 AXTreeUpdate treedata1_;
43 std::unique_ptr<AXSerializableTree> tree0_;
44 std::unique_ptr<AXSerializableTree> tree1_;
45 std::unique_ptr<AXTreeSource<const AXNode*, AXNodeData, AXTreeData>>
46 tree0_source_;
47 std::unique_ptr<AXTreeSource<const AXNode*, AXNodeData, AXTreeData>>
48 tree1_source_;
49 std::unique_ptr<BasicAXTreeSerializer> serializer_;
50
51 private:
52 DISALLOW_COPY_AND_ASSIGN(AXTreeSerializerTest);
53 };
54
CreateTreeSerializer()55 void AXTreeSerializerTest::CreateTreeSerializer() {
56 if (serializer_)
57 return;
58
59 tree0_ = std::make_unique<AXSerializableTree>(treedata0_);
60 tree1_ = std::make_unique<AXSerializableTree>(treedata1_);
61
62 // Serialize tree0 so that AXTreeSerializer thinks that its client
63 // is totally in sync.
64 tree0_source_.reset(tree0_->CreateTreeSource());
65 serializer_ = std::make_unique<BasicAXTreeSerializer>(tree0_source_.get());
66 AXTreeUpdate unused_update;
67 ASSERT_TRUE(serializer_->SerializeChanges(tree0_->root(), &unused_update));
68
69 // Pretend that tree0_ turned into tree1_. The next call to
70 // AXTreeSerializer will force it to consider these changes to
71 // the tree and send them as part of the next update.
72 tree1_source_.reset(tree1_->CreateTreeSource());
73 serializer_->ChangeTreeSourceForTesting(tree1_source_.get());
74 }
75
76 // In this test, one child is added to the root. Only the root and
77 // new child should be added.
TEST_F(AXTreeSerializerTest,UpdateContainsOnlyChangedNodes)78 TEST_F(AXTreeSerializerTest, UpdateContainsOnlyChangedNodes) {
79 // (1 (2 3))
80 treedata0_.root_id = 1;
81 treedata0_.nodes.resize(3);
82 treedata0_.nodes[0].id = 1;
83 treedata0_.nodes[0].child_ids.push_back(2);
84 treedata0_.nodes[0].child_ids.push_back(3);
85 treedata0_.nodes[1].id = 2;
86 treedata0_.nodes[2].id = 3;
87
88 // (1 (4 2 3))
89 treedata1_.root_id = 1;
90 treedata1_.nodes.resize(4);
91 treedata1_.nodes[0].id = 1;
92 treedata1_.nodes[0].child_ids.push_back(4);
93 treedata1_.nodes[0].child_ids.push_back(2);
94 treedata1_.nodes[0].child_ids.push_back(3);
95 treedata1_.nodes[1].id = 2;
96 treedata1_.nodes[2].id = 3;
97 treedata1_.nodes[3].id = 4;
98
99 CreateTreeSerializer();
100 AXTreeUpdate update;
101 ASSERT_TRUE(serializer_->SerializeChanges(tree1_->GetFromId(1), &update));
102
103 // The update should only touch nodes 1 and 4 - nodes 2 and 3 are unchanged
104 // and shouldn't be affected.
105 EXPECT_EQ(0, update.node_id_to_clear);
106 ASSERT_EQ(2u, update.nodes.size());
107 EXPECT_EQ(1, update.nodes[0].id);
108 EXPECT_EQ(4, update.nodes[1].id);
109 }
110
111 // When the root changes, the whole tree is updated, even if some of it
112 // is unaffected.
TEST_F(AXTreeSerializerTest,NewRootUpdatesEntireTree)113 TEST_F(AXTreeSerializerTest, NewRootUpdatesEntireTree) {
114 // (1 (2 (3 (4))))
115 treedata0_.root_id = 1;
116 treedata0_.nodes.resize(4);
117 treedata0_.nodes[0].id = 1;
118 treedata0_.nodes[0].child_ids.push_back(2);
119 treedata0_.nodes[1].id = 2;
120 treedata0_.nodes[1].child_ids.push_back(3);
121 treedata0_.nodes[2].id = 3;
122 treedata0_.nodes[2].child_ids.push_back(4);
123 treedata0_.nodes[3].id = 4;
124
125 // (5 (2 (3 (4))))
126 treedata1_.root_id = 5;
127 treedata1_.nodes.resize(4);
128 treedata1_.nodes[0].id = 5;
129 treedata1_.nodes[0].child_ids.push_back(2);
130 treedata1_.nodes[1].id = 2;
131 treedata1_.nodes[1].child_ids.push_back(3);
132 treedata1_.nodes[2].id = 3;
133 treedata1_.nodes[2].child_ids.push_back(4);
134 treedata1_.nodes[3].id = 4;
135
136 CreateTreeSerializer();
137 AXTreeUpdate update;
138 ASSERT_TRUE(serializer_->SerializeChanges(tree1_->GetFromId(4), &update));
139
140 // The update should delete the subtree rooted at node id=1, and
141 // then include all four nodes in the update, even though the
142 // subtree rooted at id=2 didn't actually change.
143 EXPECT_EQ(1, update.node_id_to_clear);
144 ASSERT_EQ(4u, update.nodes.size());
145 EXPECT_EQ(5, update.nodes[0].id);
146 EXPECT_EQ(2, update.nodes[1].id);
147 EXPECT_EQ(3, update.nodes[2].id);
148 EXPECT_EQ(4, update.nodes[3].id);
149 }
150
151 // When a node is reparented, the subtree including both the old parent
152 // and new parent of the reparented node must be deleted and recreated.
TEST_F(AXTreeSerializerTest,ReparentingUpdatesSubtree)153 TEST_F(AXTreeSerializerTest, ReparentingUpdatesSubtree) {
154 // (1 (2 (3 (4) 5)))
155 treedata0_.root_id = 1;
156 treedata0_.nodes.resize(5);
157 treedata0_.nodes[0].id = 1;
158 treedata0_.nodes[0].child_ids.push_back(2);
159 treedata0_.nodes[1].id = 2;
160 treedata0_.nodes[1].child_ids.push_back(3);
161 treedata0_.nodes[1].child_ids.push_back(5);
162 treedata0_.nodes[2].id = 3;
163 treedata0_.nodes[2].child_ids.push_back(4);
164 treedata0_.nodes[3].id = 4;
165 treedata0_.nodes[4].id = 5;
166
167 // Node 5 has been reparented from being a child of node 2,
168 // to a child of node 4.
169 // (1 (2 (3 (4 (5)))))
170 treedata1_.root_id = 1;
171 treedata1_.nodes.resize(5);
172 treedata1_.nodes[0].id = 1;
173 treedata1_.nodes[0].child_ids.push_back(2);
174 treedata1_.nodes[1].id = 2;
175 treedata1_.nodes[1].child_ids.push_back(3);
176 treedata1_.nodes[2].id = 3;
177 treedata1_.nodes[2].child_ids.push_back(4);
178 treedata1_.nodes[3].id = 4;
179 treedata1_.nodes[3].child_ids.push_back(5);
180 treedata1_.nodes[4].id = 5;
181
182 CreateTreeSerializer();
183 AXTreeUpdate update;
184 ASSERT_TRUE(serializer_->SerializeChanges(tree1_->GetFromId(4), &update));
185
186 // The update should unserialize without errors.
187 AXTree dst_tree(treedata0_);
188 EXPECT_TRUE(dst_tree.Unserialize(update)) << dst_tree.error();
189
190 // The update should delete the subtree rooted at node id=2, and
191 // then include nodes 2...5.
192 EXPECT_EQ(2, update.node_id_to_clear);
193 ASSERT_EQ(4u, update.nodes.size());
194 EXPECT_EQ(2, update.nodes[0].id);
195 EXPECT_EQ(3, update.nodes[1].id);
196 EXPECT_EQ(4, update.nodes[2].id);
197 EXPECT_EQ(5, update.nodes[3].id);
198 }
199
200 // Similar to ReparentingUpdatesSubtree, except that InvalidateSubtree is
201 // called on id=1 - we need to make sure that the reparenting is still
202 // detected.
TEST_F(AXTreeSerializerTest,ReparentingWithInvalidationUpdatesSubtree)203 TEST_F(AXTreeSerializerTest, ReparentingWithInvalidationUpdatesSubtree) {
204 // (1 (2 (3 (4 (5)))))
205 treedata0_.root_id = 1;
206 treedata0_.nodes.resize(5);
207 treedata0_.nodes[0].id = 1;
208 treedata0_.nodes[0].child_ids.push_back(2);
209 treedata0_.nodes[1].id = 2;
210 treedata0_.nodes[1].child_ids.push_back(3);
211 treedata0_.nodes[2].id = 3;
212 treedata0_.nodes[2].child_ids.push_back(4);
213 treedata0_.nodes[3].id = 4;
214 treedata0_.nodes[3].child_ids.push_back(5);
215 treedata0_.nodes[4].id = 5;
216
217 // Node 5 has been reparented from being a child of node 4,
218 // to a child of node 2.
219 // (1 (2 (3 (4) 5)))
220 treedata1_.root_id = 1;
221 treedata1_.nodes.resize(5);
222 treedata1_.nodes[0].id = 1;
223 treedata1_.nodes[0].child_ids.push_back(2);
224 treedata1_.nodes[1].id = 2;
225 treedata1_.nodes[1].child_ids.push_back(3);
226 treedata1_.nodes[1].child_ids.push_back(5);
227 treedata1_.nodes[2].id = 3;
228 treedata1_.nodes[2].child_ids.push_back(4);
229 treedata1_.nodes[3].id = 4;
230 treedata1_.nodes[4].id = 5;
231
232 CreateTreeSerializer();
233 AXTreeUpdate update;
234 serializer_->InvalidateSubtree(tree1_->GetFromId(1));
235 ASSERT_TRUE(serializer_->SerializeChanges(tree1_->GetFromId(4), &update));
236
237 // The update should unserialize without errors.
238 AXTree dst_tree(treedata0_);
239 EXPECT_TRUE(dst_tree.Unserialize(update)) << dst_tree.error();
240 }
241
242 // A variant of AXTreeSource that returns true for IsValid() for one
243 // particular id.
244 class AXTreeSourceWithInvalidId
245 : public AXTreeSource<const AXNode*, AXNodeData, AXTreeData> {
246 public:
AXTreeSourceWithInvalidId(AXTree * tree,int invalid_id)247 AXTreeSourceWithInvalidId(AXTree* tree, int invalid_id)
248 : tree_(tree),
249 invalid_id_(invalid_id) {}
~AXTreeSourceWithInvalidId()250 ~AXTreeSourceWithInvalidId() override {}
251
252 // AXTreeSource implementation.
GetTreeData(AXTreeData * data) const253 bool GetTreeData(AXTreeData* data) const override {
254 *data = AXTreeData();
255 return true;
256 }
GetRoot() const257 AXNode* GetRoot() const override { return tree_->root(); }
GetFromId(int32_t id) const258 AXNode* GetFromId(int32_t id) const override { return tree_->GetFromId(id); }
GetId(const AXNode * node) const259 int32_t GetId(const AXNode* node) const override { return node->id(); }
GetChildren(const AXNode * node,std::vector<const AXNode * > * out_children) const260 void GetChildren(const AXNode* node,
261 std::vector<const AXNode*>* out_children) const override {
262 *out_children = std::vector<const AXNode*>(node->children().cbegin(),
263 node->children().cend());
264 }
GetParent(const AXNode * node) const265 AXNode* GetParent(const AXNode* node) const override {
266 return node->parent();
267 }
IsIgnored(const AXNode * node) const268 bool IsIgnored(const AXNode* node) const override {
269 return node->IsIgnored();
270 }
IsValid(const AXNode * node) const271 bool IsValid(const AXNode* node) const override {
272 return node != nullptr && node->id() != invalid_id_;
273 }
IsEqual(const AXNode * node1,const AXNode * node2) const274 bool IsEqual(const AXNode* node1, const AXNode* node2) const override {
275 return node1 == node2;
276 }
GetNull() const277 const AXNode* GetNull() const override { return nullptr; }
SerializeNode(const AXNode * node,AXNodeData * out_data) const278 void SerializeNode(const AXNode* node, AXNodeData* out_data) const override {
279 *out_data = node->data();
280 if (node->id() == invalid_id_)
281 out_data->id = -1;
282 }
283
284 private:
285 AXTree* tree_;
286 int invalid_id_;
287
288 DISALLOW_COPY_AND_ASSIGN(AXTreeSourceWithInvalidId);
289 };
290
291 // Test that the serializer skips invalid children.
TEST(AXTreeSerializerInvalidTest,InvalidChild)292 TEST(AXTreeSerializerInvalidTest, InvalidChild) {
293 // (1 (2 3))
294 AXTreeUpdate treedata;
295 treedata.root_id = 1;
296 treedata.nodes.resize(3);
297 treedata.nodes[0].id = 1;
298 treedata.nodes[0].child_ids.push_back(2);
299 treedata.nodes[0].child_ids.push_back(3);
300 treedata.nodes[1].id = 2;
301 treedata.nodes[2].id = 3;
302
303 AXTree tree(treedata);
304 AXTreeSourceWithInvalidId source(&tree, 3);
305
306 BasicAXTreeSerializer serializer(&source);
307 AXTreeUpdate update;
308 ASSERT_TRUE(serializer.SerializeChanges(tree.root(), &update));
309
310 ASSERT_EQ(2U, update.nodes.size());
311 EXPECT_EQ(1, update.nodes[0].id);
312 EXPECT_EQ(2, update.nodes[1].id);
313 }
314
315 // Test that we can set a maximum number of nodes to serialize.
TEST_F(AXTreeSerializerTest,MaximumSerializedNodeCount)316 TEST_F(AXTreeSerializerTest, MaximumSerializedNodeCount) {
317 // (1 (2 (3 4) 5 (6 7)))
318 treedata0_.root_id = 1;
319 treedata0_.nodes.resize(7);
320 treedata0_.nodes[0].id = 1;
321 treedata0_.nodes[0].child_ids.push_back(2);
322 treedata0_.nodes[0].child_ids.push_back(5);
323 treedata0_.nodes[1].id = 2;
324 treedata0_.nodes[1].child_ids.push_back(3);
325 treedata0_.nodes[1].child_ids.push_back(4);
326 treedata0_.nodes[2].id = 3;
327 treedata0_.nodes[3].id = 4;
328 treedata0_.nodes[4].id = 5;
329 treedata0_.nodes[4].child_ids.push_back(6);
330 treedata0_.nodes[4].child_ids.push_back(7);
331 treedata0_.nodes[5].id = 6;
332 treedata0_.nodes[6].id = 7;
333
334 tree0_ = std::make_unique<AXSerializableTree>(treedata0_);
335 tree0_source_.reset(tree0_->CreateTreeSource());
336 serializer_ = std::make_unique<BasicAXTreeSerializer>(tree0_source_.get());
337 serializer_->set_max_node_count(4);
338 AXTreeUpdate update;
339 ASSERT_TRUE(serializer_->SerializeChanges(tree0_->root(), &update));
340 // It actually serializes 5 nodes, not 4 - to be consistent.
341 // It skips the children of node 5.
342 ASSERT_EQ(5u, update.nodes.size());
343 }
344
345 #if !defined(AX_FAIL_FAST_BUILD)
346 // If duplicate ids are encountered, it returns an error and the next
347 // update will re-send the entire tree.
TEST_F(AXTreeSerializerTest,DuplicateIdsReturnsErrorAndFlushes)348 TEST_F(AXTreeSerializerTest, DuplicateIdsReturnsErrorAndFlushes) {
349 // (1 (2 (3 (4) 5)))
350 treedata0_.root_id = 1;
351 treedata0_.nodes.resize(5);
352 treedata0_.nodes[0].id = 1;
353 treedata0_.nodes[0].child_ids.push_back(2);
354 treedata0_.nodes[1].id = 2;
355 treedata0_.nodes[1].child_ids.push_back(3);
356 treedata0_.nodes[1].child_ids.push_back(5);
357 treedata0_.nodes[2].id = 3;
358 treedata0_.nodes[2].child_ids.push_back(4);
359 treedata0_.nodes[3].id = 4;
360 treedata0_.nodes[4].id = 5;
361
362 // (1 (2 (6 (7) 5)))
363 treedata1_.root_id = 1;
364 treedata1_.nodes.resize(5);
365 treedata1_.nodes[0].id = 1;
366 treedata1_.nodes[0].child_ids.push_back(2);
367 treedata1_.nodes[1].id = 2;
368 treedata1_.nodes[1].child_ids.push_back(6);
369 treedata1_.nodes[1].child_ids.push_back(5);
370 treedata1_.nodes[2].id = 6;
371 treedata1_.nodes[2].child_ids.push_back(7);
372 treedata1_.nodes[3].id = 7;
373 treedata1_.nodes[4].id = 5;
374
375 CreateTreeSerializer();
376
377 // Do some open-heart surgery on tree1, giving it a duplicate node.
378 // This could not happen with an AXTree, but could happen with
379 // another AXTreeSource if the structure it wraps is buggy. We want to
380 // fail but not crash when that happens.
381 std::vector<AXNode*> node2_children;
382 node2_children.push_back(tree1_->GetFromId(7));
383 node2_children.push_back(tree1_->GetFromId(6));
384 tree1_->GetFromId(2)->SwapChildren(&node2_children);
385
386 AXTreeUpdate update;
387 ASSERT_FALSE(serializer_->SerializeChanges(tree1_->GetFromId(7), &update));
388
389 // Swap it back, fixing the tree.
390 tree1_->GetFromId(2)->SwapChildren(&node2_children);
391
392 // Now try to serialize again. We should get the whole tree because the
393 // previous failed call to SerializeChanges reset it.
394 update = AXTreeUpdate();
395 serializer_->SerializeChanges(tree1_->GetFromId(7), &update);
396 ASSERT_EQ(5u, update.nodes.size());
397 }
398 #endif // !defined(AX_FAIL_FAST_BUILD)
399
400 // If a tree serializer is reset, that means it doesn't know about
401 // the state of the client tree anymore. The safest thing to do in
402 // that circumstance is to force the client to clear everything.
TEST_F(AXTreeSerializerTest,ResetUpdatesNodeIdToClear)403 TEST_F(AXTreeSerializerTest, ResetUpdatesNodeIdToClear) {
404 // (1 (2 (3 (4 (5)))))
405 treedata0_.root_id = 1;
406 treedata0_.nodes.resize(5);
407 treedata0_.nodes[0].id = 1;
408 treedata0_.nodes[0].child_ids.push_back(2);
409 treedata0_.nodes[1].id = 2;
410 treedata0_.nodes[1].child_ids.push_back(3);
411 treedata0_.nodes[2].id = 3;
412 treedata0_.nodes[2].child_ids.push_back(4);
413 treedata0_.nodes[3].id = 4;
414 treedata0_.nodes[3].child_ids.push_back(5);
415 treedata0_.nodes[4].id = 5;
416
417 // Node 5 has been reparented from being a child of node 4,
418 // to a child of node 2.
419 // (1 (2 (3 (4) 5)))
420 treedata1_.root_id = 1;
421 treedata1_.nodes.resize(5);
422 treedata1_.nodes[0].id = 1;
423 treedata1_.nodes[0].child_ids.push_back(2);
424 treedata1_.nodes[1].id = 2;
425 treedata1_.nodes[1].child_ids.push_back(3);
426 treedata1_.nodes[1].child_ids.push_back(5);
427 treedata1_.nodes[2].id = 3;
428 treedata1_.nodes[2].child_ids.push_back(4);
429 treedata1_.nodes[3].id = 4;
430 treedata1_.nodes[4].id = 5;
431
432 CreateTreeSerializer();
433
434 serializer_->Reset();
435
436 AXTreeUpdate update;
437 ASSERT_TRUE(serializer_->SerializeChanges(tree1_->GetFromId(4), &update));
438
439 // The update should unserialize without errors.
440 AXTree dst_tree(treedata0_);
441 EXPECT_TRUE(dst_tree.Unserialize(update)) << dst_tree.error();
442 }
443
444 // Ensure that calling Reset doesn't cause any problems if
445 // the root changes.
TEST_F(AXTreeSerializerTest,ResetWorksWithNewRootId)446 TEST_F(AXTreeSerializerTest, ResetWorksWithNewRootId) {
447 // (1 (2))
448 treedata0_.root_id = 1;
449 treedata0_.nodes.resize(2);
450 treedata0_.nodes[0].id = 1;
451 treedata0_.nodes[0].child_ids.push_back(2);
452 treedata0_.nodes[1].id = 2;
453
454 // (3 (4))
455 treedata1_.root_id = 3;
456 treedata1_.nodes.resize(2);
457 treedata1_.nodes[0].id = 3;
458 treedata1_.nodes[0].child_ids.push_back(4);
459 treedata1_.nodes[1].id = 4;
460
461 CreateTreeSerializer();
462 serializer_->Reset();
463
464 AXTreeUpdate update;
465 ASSERT_TRUE(serializer_->SerializeChanges(tree1_->GetFromId(4), &update));
466
467 // The update should unserialize without errors.
468 AXTree dst_tree(treedata0_);
469 EXPECT_TRUE(dst_tree.Unserialize(update)) << dst_tree.error();
470 }
471
472 // Wraps an AXTreeSource and provides access to the results of the
473 // SerializerClearedNode callback.
474 class AXTreeSourceTestWrapper
475 : public AXTreeSource<const AXNode*, AXNodeData, AXTreeData> {
476 public:
AXTreeSourceTestWrapper(AXTreeSource<const AXNode *,AXNodeData,AXTreeData> * tree_source)477 explicit AXTreeSourceTestWrapper(
478 AXTreeSource<const AXNode*, AXNodeData, AXTreeData>* tree_source)
479 : tree_source_(tree_source) {}
480 ~AXTreeSourceTestWrapper() override = default;
481
482 // Override SerializerClearedNode and provide a way to access it.
SerializerClearedNode(int32_t node_id)483 void SerializerClearedNode(int32_t node_id) override {
484 cleared_node_ids_.insert(node_id);
485 }
486
ClearClearedNodeIds()487 void ClearClearedNodeIds() { cleared_node_ids_.clear(); }
cleared_node_ids()488 std::set<int32_t>& cleared_node_ids() { return cleared_node_ids_; }
489
490 // The rest of the AXTreeSource implementation just calls through to
491 // tree_source_.
GetTreeData(AXTreeData * data) const492 bool GetTreeData(AXTreeData* data) const override {
493 return tree_source_->GetTreeData(data);
494 }
GetRoot() const495 const AXNode* GetRoot() const override { return tree_source_->GetRoot(); }
GetFromId(int32_t id) const496 const AXNode* GetFromId(int32_t id) const override {
497 return tree_source_->GetFromId(id);
498 }
GetId(const AXNode * node) const499 int32_t GetId(const AXNode* node) const override {
500 return tree_source_->GetId(node);
501 }
GetChildren(const AXNode * node,std::vector<const AXNode * > * out_children) const502 void GetChildren(const AXNode* node,
503 std::vector<const AXNode*>* out_children) const override {
504 return tree_source_->GetChildren(node, out_children);
505 }
GetParent(const AXNode * node) const506 const AXNode* GetParent(const AXNode* node) const override {
507 return tree_source_->GetParent(node);
508 }
IsIgnored(const AXNode * node) const509 bool IsIgnored(const AXNode* node) const override {
510 return tree_source_->IsIgnored(node);
511 }
IsValid(const AXNode * node) const512 bool IsValid(const AXNode* node) const override {
513 return tree_source_->IsValid(node);
514 }
IsEqual(const AXNode * node1,const AXNode * node2) const515 bool IsEqual(const AXNode* node1, const AXNode* node2) const override {
516 return tree_source_->IsEqual(node1, node2);
517 }
GetNull() const518 const AXNode* GetNull() const override { return tree_source_->GetNull(); }
SerializeNode(const AXNode * node,AXNodeData * out_data) const519 void SerializeNode(const AXNode* node, AXNodeData* out_data) const override {
520 tree_source_->SerializeNode(node, out_data);
521 }
522
523 private:
524 AXTreeSource<const AXNode*, AXNodeData, AXTreeData>* tree_source_;
525 std::set<int32_t> cleared_node_ids_;
526 };
527
TEST_F(AXTreeSerializerTest,TestClearedNodesWhenUpdatingRoot)528 TEST_F(AXTreeSerializerTest, TestClearedNodesWhenUpdatingRoot) {
529 // (1 (2 (3 (4))))
530 treedata0_.root_id = 1;
531 treedata0_.nodes.resize(4);
532 treedata0_.nodes[0].id = 1;
533 treedata0_.nodes[0].child_ids.push_back(2);
534 treedata0_.nodes[1].id = 2;
535 treedata0_.nodes[1].child_ids.push_back(3);
536 treedata0_.nodes[2].id = 3;
537 treedata0_.nodes[2].child_ids.push_back(4);
538 treedata0_.nodes[3].id = 4;
539
540 // (5 (2 (3 (4))))
541 treedata1_.root_id = 5;
542 treedata1_.nodes.resize(4);
543 treedata1_.nodes[0].id = 5;
544 treedata1_.nodes[0].child_ids.push_back(2);
545 treedata1_.nodes[1].id = 2;
546 treedata1_.nodes[1].child_ids.push_back(3);
547 treedata1_.nodes[2].id = 3;
548 treedata1_.nodes[2].child_ids.push_back(4);
549 treedata1_.nodes[3].id = 4;
550
551 // Similar sequence to CreateTreeSerializer, but using
552 // AXTreeSourceTestWrapper instead.
553 tree0_ = std::make_unique<AXSerializableTree>(treedata0_);
554 tree1_ = std::make_unique<AXSerializableTree>(treedata1_);
555 tree0_source_.reset(tree0_->CreateTreeSource());
556 AXTreeSourceTestWrapper tree0_source_wrapper(tree0_source_.get());
557 serializer_ = std::make_unique<BasicAXTreeSerializer>(&tree0_source_wrapper);
558 AXTreeUpdate unused_update;
559 ASSERT_TRUE(serializer_->SerializeChanges(tree0_->root(), &unused_update));
560 tree1_source_.reset(tree1_->CreateTreeSource());
561 AXTreeSourceTestWrapper tree1_source_wrapper(tree1_source_.get());
562 serializer_->ChangeTreeSourceForTesting(&tree1_source_wrapper);
563 ASSERT_EQ(4U, serializer_->ClientTreeNodeCount());
564
565 // If we swap out the root, all of the node IDs should have
566 // SerializerClearedNode called on them.
567 tree1_source_wrapper.ClearClearedNodeIds();
568 ASSERT_TRUE(serializer_->SerializeChanges(tree1_->root(), &unused_update));
569 EXPECT_THAT(tree1_source_wrapper.cleared_node_ids(),
570 UnorderedElementsAre(1, 2, 3, 4));
571
572 // Destroy the serializer first so that the AXTreeSources it points to
573 // don't go out of scope first.
574 serializer_.reset();
575 }
576
TEST_F(AXTreeSerializerTest,TestClearedNodesWhenUpdatingBranch)577 TEST_F(AXTreeSerializerTest, TestClearedNodesWhenUpdatingBranch) {
578 // (1 (2 (3 (4))))
579 treedata0_.root_id = 1;
580 treedata0_.nodes.resize(4);
581 treedata0_.nodes[0].id = 1;
582 treedata0_.nodes[0].child_ids.push_back(2);
583 treedata0_.nodes[1].id = 2;
584 treedata0_.nodes[1].child_ids.push_back(3);
585 treedata0_.nodes[2].id = 3;
586 treedata0_.nodes[2].child_ids.push_back(4);
587 treedata0_.nodes[3].id = 4;
588
589 // (1 (2 (5 (6))))
590 treedata1_.root_id = 1;
591 treedata1_.nodes.resize(4);
592 treedata1_.nodes[0].id = 1;
593 treedata1_.nodes[0].child_ids.push_back(2);
594 treedata1_.nodes[1].id = 2;
595 treedata1_.nodes[1].child_ids.push_back(5);
596 treedata1_.nodes[2].id = 5;
597 treedata1_.nodes[2].child_ids.push_back(6);
598 treedata1_.nodes[3].id = 6;
599
600 // Similar sequence to CreateTreeSerializer, but using
601 // AXTreeSourceTestWrapper instead.
602 tree0_ = std::make_unique<AXSerializableTree>(treedata0_);
603 tree1_ = std::make_unique<AXSerializableTree>(treedata1_);
604 tree0_source_.reset(tree0_->CreateTreeSource());
605 AXTreeSourceTestWrapper tree0_source_wrapper(tree0_source_.get());
606 serializer_ = std::make_unique<BasicAXTreeSerializer>(&tree0_source_wrapper);
607 AXTreeUpdate unused_update;
608 ASSERT_TRUE(serializer_->SerializeChanges(tree0_->root(), &unused_update));
609 tree1_source_.reset(tree1_->CreateTreeSource());
610 AXTreeSourceTestWrapper tree1_source_wrapper(tree1_source_.get());
611 serializer_->ChangeTreeSourceForTesting(&tree1_source_wrapper);
612 ASSERT_EQ(4U, serializer_->ClientTreeNodeCount());
613
614 // If we replace one branch with another, we should get calls to
615 // SerializerClearedNode with all of the node IDs no longer in the tree.
616 tree1_source_wrapper.ClearClearedNodeIds();
617 ASSERT_TRUE(
618 serializer_->SerializeChanges(tree1_->GetFromId(2), &unused_update));
619 EXPECT_THAT(tree1_source_wrapper.cleared_node_ids(),
620 UnorderedElementsAre(3, 4));
621
622 // Destroy the serializer first so that the AXTreeSources it points to
623 // don't go out of scope first.
624 serializer_.reset();
625 }
626
627 } // namespace ui
628