15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved.
25c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Use of this source code is governed by a BSD-style license that can be
35c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// found in the LICENSE file.
45c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
55c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include <vector>
65c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ash/test/ash_test_base.h"
85c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/strings/utf_string_conversions.h"
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/ui/ash/accessibility/ax_tree_source_ash.h"
105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "testing/gtest/include/gtest/gtest.h"
115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/accessibility/ax_enums.h"
125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/accessibility/ax_node.h"
135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/accessibility/ax_serializable_tree.h"
145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/accessibility/ax_tree_serializer.h"
155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/accessibility/ax_tree_update.h"
165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/aura/window.h"
175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/views/accessibility/ax_aura_obj_cache.h"
185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/views/controls/textfield/textfield.h"
205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/views/test/views_test_base.h"
215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/views/widget/widget.h"
225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing views::AXAuraObjCache;
245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing views::AXAuraObjWrapper;
255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing views::Textfield;
265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing views::View;
275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing views::Widget;
285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Helper to count the number of nodes in a tree.
305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liusize_t GetSize(AXAuraObjWrapper* tree) {
315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  size_t count = 1;
325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  std::vector<AXAuraObjWrapper*> out_children;
345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  tree->GetChildren(&out_children);
355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (size_t i = 0; i < out_children.size(); ++i)
375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    count += GetSize(out_children[i]);
385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return count;
405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class AXTreeSourceAshTest : public ash::test::AshTestBase {
435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu public:
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AXTreeSourceAshTest() {}
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual ~AXTreeSourceAshTest() {}
465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void SetUp() OVERRIDE {
485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    AshTestBase::SetUp();
495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    widget_ = new Widget();
515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    Widget::InitParams init_params(Widget::InitParams::TYPE_POPUP);
525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    init_params.parent = CurrentContext();
535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    widget_->Init(init_params);
545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    content_ = new View();
565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    widget_->SetContentsView(content_);
575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    textfield_ = new Textfield();
595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    textfield_->SetText(base::ASCIIToUTF16("Value"));
605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    content_->AddChildView(textfield_);
615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu protected:
645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  Widget* widget_;
655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  View* content_;
665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  Textfield* textfield_;
675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu private:
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(AXTreeSourceAshTest);
705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu};
715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST_F(AXTreeSourceAshTest, Accessors) {
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AXTreeSourceAsh ax_tree;
745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ASSERT_TRUE(ax_tree.GetRoot());
755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // ID's should start at 1 and there should be a root.
775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ASSERT_EQ(1, ax_tree.GetRoot()->GetID());
785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Grab the content view directly from cache to avoid walking down the tree.
805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  AXAuraObjWrapper* content =
815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      AXAuraObjCache::GetInstance()->GetOrCreate(content_);
825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  std::vector<AXAuraObjWrapper*> content_children;
835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ax_tree.GetChildren(content, &content_children);
845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ASSERT_EQ(1U, content_children.size());
855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Walk down to the text field and assert it is what we expect.
875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  AXAuraObjWrapper* textfield = content_children[0];
885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  AXAuraObjWrapper* cached_textfield =
895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      AXAuraObjCache::GetInstance()->GetOrCreate(textfield_);
905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ASSERT_EQ(cached_textfield, textfield);
915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  std::vector<AXAuraObjWrapper*> textfield_children;
925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ax_tree.GetChildren(textfield, &textfield_children);
935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ASSERT_EQ(0U, textfield_children.size());
945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ASSERT_EQ(content, textfield->GetParent());
965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Try walking up the tree to the root.
985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  AXAuraObjWrapper* test_root = NULL;
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (AXAuraObjWrapper* root_finder = ax_tree.GetParent(content); root_finder;
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       root_finder = ax_tree.GetParent(root_finder))
1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    test_root = root_finder;
1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ASSERT_EQ(ax_tree.GetRoot(), test_root);
1035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST_F(AXTreeSourceAshTest, Serialization) {
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AXTreeSourceAsh ax_tree;
1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ui::AXTreeSerializer<AXAuraObjWrapper*> ax_serializer(&ax_tree);
1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ui::AXTreeUpdate out_update;
1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // This is the initial serialization.
1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ax_serializer.SerializeChanges(ax_tree.GetRoot(), &out_update);
1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // We should get an update per node.
1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ASSERT_EQ(GetSize(ax_tree.GetRoot()), out_update.nodes.size());
1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Try removing some child views and re-adding.
1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  content_->RemoveAllChildViews(false /* delete_children */);
1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  content_->AddChildView(textfield_);
1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Grab the textfield since serialization only walks up the tree (not down
1215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // from root).
1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  AXAuraObjWrapper* textfield_wrapper =
1235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      AXAuraObjCache::GetInstance()->GetOrCreate(textfield_);
1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Now, re-serialize.
1265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ui::AXTreeUpdate out_update2;
1275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ax_serializer.SerializeChanges(textfield_wrapper, &out_update2);
1285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // We should have far fewer updates this time around.
1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ASSERT_EQ(2U, out_update2.nodes.size());
1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ASSERT_EQ(ui::AX_ROLE_CLIENT,
1325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu            out_update2.nodes[0].role);
1335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ASSERT_EQ(textfield_wrapper->GetID(), out_update2.nodes[1].id);
1355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ASSERT_EQ(ui::AX_ROLE_TEXT_FIELD,
1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu            out_update2.nodes[1].role);
1375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST_F(AXTreeSourceAshTest, DoDefault) {
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AXTreeSourceAsh ax_tree;
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Grab a wrapper to |DoDefault| (click).
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AXAuraObjWrapper* textfield_wrapper =
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      AXAuraObjCache::GetInstance()->GetOrCreate(textfield_);
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Click and verify focus.
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ASSERT_FALSE(textfield_->HasFocus());
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  textfield_wrapper->DoDefault();
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ASSERT_TRUE(textfield_->HasFocus());
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST_F(AXTreeSourceAshTest, Focus) {
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AXTreeSourceAsh ax_tree;
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Grab a wrapper to focus.
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AXAuraObjWrapper* textfield_wrapper =
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      AXAuraObjCache::GetInstance()->GetOrCreate(textfield_);
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Focus and verify.
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ASSERT_FALSE(textfield_->HasFocus());
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  textfield_wrapper->Focus();
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ASSERT_TRUE(textfield_->HasFocus());
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
164