Home | History | Annotate | Download | only in accessibility
      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