Commit 51e1e97e authored by James Cook's avatar James Cook Committed by Commit Bot

Reland: Move AXTreeSourceAura tests into AXTreeSourceViews tests

Additional CLs have landed that resolve the memory leak in
views_mus_unittests detected by LSAN.

Original description:
>AXTreeSourceAura doesn't exist any more. The tests exercise the
>integration of AXRootObjWrapper with AXTreeSourceViews, so rename the
>tests ot AXTreeSourceViewsRootTest.
>
>Note that the tests lived in //chrome/browser/ui/ash. If we need an
>ash-specific tree source we could introduce an AXTreeSourceAsh either
>in //ash (for mash) or //chrome/browser/ui/ash (for SingleProcessMash).
>
>Bug: 910672
>Test: views_unittests
>Reviewed-on: https://chromium-review.googlesource.com/c/1358972
>Reviewed-by: David Tseng <dtseng@chromium.org>
>Commit-Queue: James Cook <jamescook@chromium.org>
>Cr-Commit-Position: refs/heads/master@{#613308}

TBR=dtseng@chromium.org

Change-Id: Id4dc9b6dd7bedffb6cc1184ac0c1f1e36f51ffc1
Reviewed-on: https://chromium-review.googlesource.com/c/1362193Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Commit-Queue: James Cook <jamescook@chromium.org>
Cr-Commit-Position: refs/heads/master@{#616111}
parent 06c91da2
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <vector>
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/test/views/chrome_views_test_base.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_serializable_tree.h"
#include "ui/accessibility/ax_tree_serializer.h"
#include "ui/accessibility/ax_tree_update.h"
#include "ui/aura/window.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
#include "ui/views/accessibility/ax_root_obj_wrapper.h"
#include "ui/views/accessibility/ax_tree_source_views.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
using views::AXAuraObjCache;
using views::AXAuraObjWrapper;
using views::AXTreeSourceViews;
using views::Textfield;
using views::View;
using views::Widget;
using AuraAXTreeSerializer = ui::
AXTreeSerializer<views::AXAuraObjWrapper*, ui::AXNodeData, ui::AXTreeData>;
// Helper to count the number of nodes in a tree.
size_t GetSize(AXAuraObjWrapper* tree) {
size_t count = 1;
std::vector<AXAuraObjWrapper*> out_children;
tree->GetChildren(&out_children);
for (size_t i = 0; i < out_children.size(); ++i)
count += GetSize(out_children[i]);
return count;
}
// Tests integration of AXTreeSourceViews with AXRootObjWrapper.
// TODO(jamescook): Move into //ui/views/accessibility and combine with
// AXTreeSourceViewsTest.
class AXTreeSourceAuraTest : public ChromeViewsTestBase {
public:
AXTreeSourceAuraTest() {}
~AXTreeSourceAuraTest() override {}
void SetUp() override {
ChromeViewsTestBase::SetUp();
widget_ = new Widget();
Widget::InitParams init_params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
init_params.context = GetContext();
widget_->Init(init_params);
content_ = new View();
widget_->SetContentsView(content_);
textfield_ = new Textfield();
textfield_->SetText(base::ASCIIToUTF16("Value"));
content_->AddChildView(textfield_);
widget_->Show();
}
void TearDown() override {
// ViewsTestBase requires all Widgets to be closed before shutdown.
widget_->CloseNow();
ChromeViewsTestBase::TearDown();
}
protected:
Widget* widget_;
View* content_;
Textfield* textfield_;
// A simulated desktop root with no delegate.
AXRootObjWrapper root_wrapper_{nullptr};
private:
DISALLOW_COPY_AND_ASSIGN(AXTreeSourceAuraTest);
};
TEST_F(AXTreeSourceAuraTest, Accessors) {
// Focus the textfield so the cursor does not disappear.
textfield_->RequestFocus();
AXTreeSourceViews ax_tree(&root_wrapper_, ui::AXTreeID::CreateNewAXTreeID());
ASSERT_TRUE(ax_tree.GetRoot());
// ID's should be > 0.
ASSERT_GE(ax_tree.GetRoot()->GetUniqueId(), 1);
// Grab the content view directly from cache to avoid walking down the tree.
AXAuraObjWrapper* content =
AXAuraObjCache::GetInstance()->GetOrCreate(content_);
std::vector<AXAuraObjWrapper*> content_children;
ax_tree.GetChildren(content, &content_children);
ASSERT_EQ(1U, content_children.size());
// Walk down to the text field and assert it is what we expect.
AXAuraObjWrapper* textfield = content_children[0];
AXAuraObjWrapper* cached_textfield =
AXAuraObjCache::GetInstance()->GetOrCreate(textfield_);
ASSERT_EQ(cached_textfield, textfield);
std::vector<AXAuraObjWrapper*> textfield_children;
ax_tree.GetChildren(textfield, &textfield_children);
// The textfield has an extra child in Harmony, the focus ring.
const size_t expected_children = 2;
ASSERT_EQ(expected_children, textfield_children.size());
ASSERT_EQ(content, textfield->GetParent());
ASSERT_NE(textfield->GetUniqueId(), ax_tree.GetRoot()->GetUniqueId());
// Try walking up the tree to the root.
AXAuraObjWrapper* test_root = NULL;
for (AXAuraObjWrapper* root_finder = ax_tree.GetParent(content); root_finder;
root_finder = ax_tree.GetParent(root_finder))
test_root = root_finder;
ASSERT_EQ(ax_tree.GetRoot(), test_root);
}
TEST_F(AXTreeSourceAuraTest, DoDefault) {
AXTreeSourceViews ax_tree(&root_wrapper_, ui::AXTreeID::CreateNewAXTreeID());
// Grab a wrapper to |DoDefault| (click).
AXAuraObjWrapper* textfield_wrapper =
AXAuraObjCache::GetInstance()->GetOrCreate(textfield_);
// Click and verify focus.
ASSERT_FALSE(textfield_->HasFocus());
ui::AXActionData action_data;
action_data.action = ax::mojom::Action::kDoDefault;
action_data.target_node_id = textfield_wrapper->GetUniqueId();
textfield_wrapper->HandleAccessibleAction(action_data);
ASSERT_TRUE(textfield_->HasFocus());
}
TEST_F(AXTreeSourceAuraTest, Focus) {
AXTreeSourceViews ax_tree(&root_wrapper_, ui::AXTreeID::CreateNewAXTreeID());
// Grab a wrapper to focus.
AXAuraObjWrapper* textfield_wrapper =
AXAuraObjCache::GetInstance()->GetOrCreate(textfield_);
// Focus and verify.
ASSERT_FALSE(textfield_->HasFocus());
ui::AXActionData action_data;
action_data.action = ax::mojom::Action::kFocus;
action_data.target_node_id = textfield_wrapper->GetUniqueId();
textfield_wrapper->HandleAccessibleAction(action_data);
ASSERT_TRUE(textfield_->HasFocus());
}
TEST_F(AXTreeSourceAuraTest, Serialize) {
AXTreeSourceViews ax_tree(&root_wrapper_, ui::AXTreeID::CreateNewAXTreeID());
AuraAXTreeSerializer ax_serializer(&ax_tree);
ui::AXTreeUpdate out_update;
// This is the initial serialization.
ax_serializer.SerializeChanges(ax_tree.GetRoot(), &out_update);
// The update should just be the desktop node.
ASSERT_EQ(1U, out_update.nodes.size());
// Try removing some child views and re-adding which should fire some events.
content_->RemoveAllChildViews(false /* delete_children */);
content_->AddChildView(textfield_);
// Grab the textfield since serialization only walks up the tree (not down
// from root).
AXAuraObjWrapper* textfield_wrapper =
AXAuraObjCache::GetInstance()->GetOrCreate(textfield_);
// Now, re-serialize.
ui::AXTreeUpdate out_update2;
ax_serializer.SerializeChanges(textfield_wrapper, &out_update2);
size_t node_count = out_update2.nodes.size();
// We should have far more updates this time around.
ASSERT_GE(node_count, 8U);
int text_field_update_index = -1;
for (size_t i = 0; i < node_count; ++i) {
if (textfield_wrapper->GetUniqueId() == out_update2.nodes[i].id)
text_field_update_index = i;
}
ASSERT_NE(-1, text_field_update_index);
ASSERT_EQ(ax::mojom::Role::kTextField,
out_update2.nodes[text_field_update_index].role);
}
TEST_F(AXTreeSourceAuraTest, SerializeWindowSetsClipsChildren) {
AXTreeSourceViews ax_tree(&root_wrapper_, ui::AXTreeID::CreateNewAXTreeID());
AuraAXTreeSerializer ax_serializer(&ax_tree);
AXAuraObjWrapper* widget_wrapper =
AXAuraObjCache::GetInstance()->GetOrCreate(widget_);
ui::AXNodeData node_data;
ax_tree.SerializeNode(widget_wrapper, &node_data);
EXPECT_EQ(ax::mojom::Role::kWindow, node_data.role);
bool clips_children = false;
EXPECT_TRUE(node_data.GetBoolAttribute(
ax::mojom::BoolAttribute::kClipsChildren, &clips_children));
EXPECT_TRUE(clips_children);
}
...@@ -3486,7 +3486,6 @@ test("unit_tests") { ...@@ -3486,7 +3486,6 @@ test("unit_tests") {
"../browser/speech/tts_chromeos_unittest.cc", "../browser/speech/tts_chromeos_unittest.cc",
"../browser/sync/sync_error_notifier_ash_unittest.cc", "../browser/sync/sync_error_notifier_ash_unittest.cc",
"../browser/ui/ash/accessibility/accessibility_controller_client_unittest.cc", "../browser/ui/ash/accessibility/accessibility_controller_client_unittest.cc",
"../browser/ui/ash/accessibility/ax_tree_source_aura_unittest.cc",
"../browser/ui/ash/ime_controller_client_unittest.cc", "../browser/ui/ash/ime_controller_client_unittest.cc",
"../browser/ui/ash/keyboard/chrome_keyboard_ui_unittest.cc", "../browser/ui/ash/keyboard/chrome_keyboard_ui_unittest.cc",
"../browser/ui/ash/keyboard/chrome_keyboard_web_contents_unittest.cc", "../browser/ui/ash/keyboard/chrome_keyboard_web_contents_unittest.cc",
......
...@@ -4,25 +4,50 @@ ...@@ -4,25 +4,50 @@
#include "ui/views/accessibility/ax_tree_source_views.h" #include "ui/views/accessibility/ax_tree_source_views.h"
#include <stddef.h>
#include <vector> #include <vector>
#include "base/macros.h" #include "base/macros.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_tree_data.h" #include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/ax_tree_id.h"
#include "ui/accessibility/ax_tree_serializer.h"
#include "ui/accessibility/ax_tree_update.h"
#include "ui/accessibility/platform/ax_unique_id.h" #include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/rect_f.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h" #include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h" #include "ui/views/accessibility/ax_aura_obj_wrapper.h"
#include "ui/views/accessibility/ax_root_obj_wrapper.h"
#include "ui/views/accessibility/view_accessibility.h" #include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/label.h" #include "ui/views/controls/label.h"
#include "ui/views/controls/textfield/textfield.h" #include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/views_test_base.h" #include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
namespace views { namespace views {
namespace { namespace {
using AuraAXTreeSerializer = ui::
AXTreeSerializer<views::AXAuraObjWrapper*, ui::AXNodeData, ui::AXTreeData>;
// Helper to count the number of nodes in a tree.
size_t GetSize(AXAuraObjWrapper* tree) {
size_t count = 1;
std::vector<AXAuraObjWrapper*> out_children;
tree->GetChildren(&out_children);
for (size_t i = 0; i < out_children.size(); ++i)
count += GetSize(out_children[i]);
return count;
}
// TestAXTreeSourceViews provides a root with a default tree ID. // TestAXTreeSourceViews provides a root with a default tree ID.
class TestAXTreeSourceViews : public AXTreeSourceViews { class TestAXTreeSourceViews : public AXTreeSourceViews {
public: public:
...@@ -154,5 +179,177 @@ TEST_F(AXTreeSourceViewsTest, IgnoredView) { ...@@ -154,5 +179,177 @@ TEST_F(AXTreeSourceViewsTest, IgnoredView) {
EXPECT_FALSE(tree.IsValid(cache->GetOrCreate(ignored_view))); EXPECT_FALSE(tree.IsValid(cache->GetOrCreate(ignored_view)));
} }
// Tests integration of AXTreeSourceViews with AXRootObjWrapper, similar to how
// AX trees are serialized by Chrome.
class AXTreeSourceViewsRootTest : public ViewsTestBase {
public:
AXTreeSourceViewsRootTest() = default;
~AXTreeSourceViewsRootTest() override = default;
void SetUp() override {
ViewsTestBase::SetUp();
// Must happen after SetUp() under mus/mash because it needs the aura::Env
// to be configured.
root_wrapper_ = std::make_unique<AXRootObjWrapper>(nullptr);
widget_ = new Widget();
Widget::InitParams init_params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
init_params.context = GetContext();
widget_->Init(init_params);
content_ = new View();
widget_->SetContentsView(content_);
textfield_ = new Textfield();
textfield_->SetText(base::ASCIIToUTF16("Value"));
content_->AddChildView(textfield_);
widget_->Show();
}
void TearDown() override {
// ViewsTestBase requires all Widgets to be closed before shutdown.
widget_->CloseNow();
root_wrapper_.reset();
ViewsTestBase::TearDown();
}
protected:
Widget* widget_;
View* content_;
Textfield* textfield_;
// A simulated desktop root with no delegate.
std::unique_ptr<AXRootObjWrapper> root_wrapper_;
private:
DISALLOW_COPY_AND_ASSIGN(AXTreeSourceViewsRootTest);
};
TEST_F(AXTreeSourceViewsRootTest, Accessors) {
// Focus the textfield so the cursor does not disappear.
textfield_->RequestFocus();
TestAXTreeSourceViews ax_tree(root_wrapper_.get());
ASSERT_TRUE(ax_tree.GetRoot());
// ID's should be > 0.
ASSERT_GE(ax_tree.GetRoot()->GetUniqueId(), 1);
// Grab the content view directly from cache to avoid walking down the tree.
AXAuraObjWrapper* content =
AXAuraObjCache::GetInstance()->GetOrCreate(content_);
std::vector<AXAuraObjWrapper*> content_children;
ax_tree.GetChildren(content, &content_children);
ASSERT_EQ(1U, content_children.size());
// Walk down to the text field and assert it is what we expect.
AXAuraObjWrapper* textfield = content_children[0];
AXAuraObjWrapper* cached_textfield =
AXAuraObjCache::GetInstance()->GetOrCreate(textfield_);
ASSERT_EQ(cached_textfield, textfield);
std::vector<AXAuraObjWrapper*> textfield_children;
ax_tree.GetChildren(textfield, &textfield_children);
// The textfield has an extra child in Harmony, the focus ring.
const size_t expected_children = 2;
ASSERT_EQ(expected_children, textfield_children.size());
ASSERT_EQ(content, textfield->GetParent());
ASSERT_NE(textfield->GetUniqueId(), ax_tree.GetRoot()->GetUniqueId());
// Try walking up the tree to the root.
AXAuraObjWrapper* test_root = NULL;
for (AXAuraObjWrapper* root_finder = ax_tree.GetParent(content); root_finder;
root_finder = ax_tree.GetParent(root_finder))
test_root = root_finder;
ASSERT_EQ(ax_tree.GetRoot(), test_root);
}
TEST_F(AXTreeSourceViewsRootTest, DoDefault) {
TestAXTreeSourceViews ax_tree(root_wrapper_.get());
// Grab a wrapper to |DoDefault| (click).
AXAuraObjWrapper* textfield_wrapper =
AXAuraObjCache::GetInstance()->GetOrCreate(textfield_);
// Click and verify focus.
ASSERT_FALSE(textfield_->HasFocus());
ui::AXActionData action_data;
action_data.action = ax::mojom::Action::kDoDefault;
action_data.target_node_id = textfield_wrapper->GetUniqueId();
textfield_wrapper->HandleAccessibleAction(action_data);
ASSERT_TRUE(textfield_->HasFocus());
}
TEST_F(AXTreeSourceViewsRootTest, Focus) {
TestAXTreeSourceViews ax_tree(root_wrapper_.get());
// Grab a wrapper to focus.
AXAuraObjWrapper* textfield_wrapper =
AXAuraObjCache::GetInstance()->GetOrCreate(textfield_);
// Focus and verify.
ASSERT_FALSE(textfield_->HasFocus());
ui::AXActionData action_data;
action_data.action = ax::mojom::Action::kFocus;
action_data.target_node_id = textfield_wrapper->GetUniqueId();
textfield_wrapper->HandleAccessibleAction(action_data);
ASSERT_TRUE(textfield_->HasFocus());
}
TEST_F(AXTreeSourceViewsRootTest, Serialize) {
TestAXTreeSourceViews ax_tree(root_wrapper_.get());
AuraAXTreeSerializer ax_serializer(&ax_tree);
ui::AXTreeUpdate out_update;
// This is the initial serialization.
ax_serializer.SerializeChanges(ax_tree.GetRoot(), &out_update);
// The update should just be the desktop node.
ASSERT_EQ(1U, out_update.nodes.size());
// Try removing some child views and re-adding which should fire some events.
content_->RemoveAllChildViews(false /* delete_children */);
content_->AddChildView(textfield_);
// Grab the textfield since serialization only walks up the tree (not down
// from root).
AXAuraObjWrapper* textfield_wrapper =
AXAuraObjCache::GetInstance()->GetOrCreate(textfield_);
// Now, re-serialize.
ui::AXTreeUpdate out_update2;
ax_serializer.SerializeChanges(textfield_wrapper, &out_update2);
size_t node_count = out_update2.nodes.size();
// We should have far more updates this time around.
ASSERT_GE(node_count, 8U);
int text_field_update_index = -1;
for (size_t i = 0; i < node_count; ++i) {
if (textfield_wrapper->GetUniqueId() == out_update2.nodes[i].id)
text_field_update_index = i;
}
ASSERT_NE(-1, text_field_update_index);
ASSERT_EQ(ax::mojom::Role::kTextField,
out_update2.nodes[text_field_update_index].role);
}
TEST_F(AXTreeSourceViewsRootTest, SerializeWindowSetsClipsChildren) {
TestAXTreeSourceViews ax_tree(root_wrapper_.get());
AuraAXTreeSerializer ax_serializer(&ax_tree);
AXAuraObjWrapper* widget_wrapper =
AXAuraObjCache::GetInstance()->GetOrCreate(widget_);
ui::AXNodeData node_data;
ax_tree.SerializeNode(widget_wrapper, &node_data);
EXPECT_EQ(ax::mojom::Role::kWindow, node_data.role);
bool clips_children = false;
EXPECT_TRUE(node_data.GetBoolAttribute(
ax::mojom::BoolAttribute::kClipsChildren, &clips_children));
EXPECT_TRUE(clips_children);
}
} // namespace } // namespace
} // namespace views } // namespace views
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment