blob: 0bd716fc462886809a3ad572add1830e3e4cafca [file] [log] [blame]
// Copyright 2017 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 "chrome/browser/ui/views/omnibox/omnibox_result_view.h"
#include <memory>
#include "chrome/browser/ui/omnibox/omnibox_theme.h"
#include "chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h"
#include "chrome/test/views/chrome_views_test_base.h"
#include "components/omnibox/browser/omnibox_edit_model.h"
#include "components/omnibox/browser/test_omnibox_client.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
#include "ui/events/event_utils.h"
#include "ui/gfx/image/image.h"
#include "ui/views/widget/widget.h"
namespace {
// An arbitrary index for the result view under test. Used to test the selection
// state. There are 6 results total so the index should be in the range 0-5.
static constexpr int kTestResultViewIndex = 4;
class TestOmniboxPopupContentsView : public OmniboxPopupContentsView {
public:
explicit TestOmniboxPopupContentsView(OmniboxEditModel* edit_model)
: OmniboxPopupContentsView(
/*omnibox_view=*/nullptr,
edit_model,
/*location_bar_view=*/nullptr),
selected_index_(0) {}
void SetSelectedLine(size_t index) override { selected_index_ = index; }
bool IsSelectedIndex(size_t index) const override {
return selected_index_ == index;
}
private:
size_t selected_index_;
DISALLOW_COPY_AND_ASSIGN(TestOmniboxPopupContentsView);
};
} // namespace
class OmniboxResultViewTest : public ChromeViewsTestBase {
public:
void SetUp() override {
ChromeViewsTestBase::SetUp();
edit_model_ = std::make_unique<OmniboxEditModel>(
nullptr, nullptr, std::make_unique<TestOmniboxClient>());
popup_view_ =
std::make_unique<TestOmniboxPopupContentsView>(edit_model_.get());
result_view_ =
new OmniboxResultView(popup_view_.get(), kTestResultViewIndex);
// Create a widget and assign bounds to support calls to HitTestPoint.
widget_.reset(new views::Widget);
views::Widget::InitParams init_params =
CreateParams(views::Widget::InitParams::TYPE_POPUP);
init_params.ownership =
views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget_->Init(init_params);
views::View* root_view = widget_->GetRootView();
root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500));
result_view_->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
root_view->AddChildView(result_view_);
}
void TearDown() override {
widget_.reset();
ChromeViewsTestBase::TearDown();
}
ui::MouseEvent CreateEvent(ui::EventType type, int flags) {
return CreateEvent(type, flags, 0, 0);
}
ui::MouseEvent CreateEvent(ui::EventType type, int flags, float x, float y) {
return ui::MouseEvent(type, gfx::Point(x, y), gfx::Point(),
ui::EventTimeForNow(), flags, 0);
}
OmniboxPopupContentsView* popup_view() { return popup_view_.get(); }
OmniboxResultView* result_view() { return result_view_; }
private:
std::unique_ptr<OmniboxEditModel> edit_model_;
std::unique_ptr<TestOmniboxPopupContentsView> popup_view_;
OmniboxResultView* result_view_;
std::unique_ptr<views::Widget> widget_;
};
TEST_F(OmniboxResultViewTest, MousePressedWithLeftButtonSelectsThisResult) {
EXPECT_NE(OmniboxPartState::SELECTED, result_view()->GetThemeState());
EXPECT_FALSE(popup_view()->IsSelectedIndex(kTestResultViewIndex));
// Right button press should not select.
result_view()->OnMousePressed(
CreateEvent(ui::ET_MOUSE_PRESSED, ui::EF_RIGHT_MOUSE_BUTTON));
EXPECT_NE(OmniboxPartState::SELECTED, result_view()->GetThemeState());
EXPECT_FALSE(popup_view()->IsSelectedIndex(kTestResultViewIndex));
// Middle button press should not select.
result_view()->OnMousePressed(
CreateEvent(ui::ET_MOUSE_PRESSED, ui::EF_MIDDLE_MOUSE_BUTTON));
EXPECT_NE(OmniboxPartState::SELECTED, result_view()->GetThemeState());
EXPECT_FALSE(popup_view()->IsSelectedIndex(kTestResultViewIndex));
// Multi-button press should not select.
result_view()->OnMousePressed(
CreateEvent(ui::ET_MOUSE_PRESSED,
ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON));
EXPECT_NE(OmniboxPartState::SELECTED, result_view()->GetThemeState());
EXPECT_FALSE(popup_view()->IsSelectedIndex(kTestResultViewIndex));
// Left button press should select.
result_view()->OnMousePressed(
CreateEvent(ui::ET_MOUSE_PRESSED, ui::EF_LEFT_MOUSE_BUTTON));
EXPECT_EQ(OmniboxPartState::SELECTED, result_view()->GetThemeState());
EXPECT_TRUE(popup_view()->IsSelectedIndex(kTestResultViewIndex));
}
TEST_F(OmniboxResultViewTest, MouseDragWithLeftButtonSelectsThisResult) {
EXPECT_NE(OmniboxPartState::SELECTED, result_view()->GetThemeState());
EXPECT_FALSE(popup_view()->IsSelectedIndex(kTestResultViewIndex));
// Right button drag should not select.
result_view()->OnMouseDragged(
CreateEvent(ui::ET_MOUSE_DRAGGED, ui::EF_RIGHT_MOUSE_BUTTON));
EXPECT_NE(OmniboxPartState::SELECTED, result_view()->GetThemeState());
EXPECT_FALSE(popup_view()->IsSelectedIndex(kTestResultViewIndex));
// Middle button drag should not select.
result_view()->OnMouseDragged(
CreateEvent(ui::ET_MOUSE_DRAGGED, ui::EF_MIDDLE_MOUSE_BUTTON));
EXPECT_NE(OmniboxPartState::SELECTED, result_view()->GetThemeState());
EXPECT_FALSE(popup_view()->IsSelectedIndex(kTestResultViewIndex));
// Multi-button drag should not select.
result_view()->OnMouseDragged(
CreateEvent(ui::ET_MOUSE_DRAGGED,
ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON));
EXPECT_NE(OmniboxPartState::SELECTED, result_view()->GetThemeState());
EXPECT_FALSE(popup_view()->IsSelectedIndex(kTestResultViewIndex));
// Left button drag should select.
result_view()->OnMouseDragged(
CreateEvent(ui::ET_MOUSE_DRAGGED, ui::EF_LEFT_MOUSE_BUTTON));
EXPECT_EQ(OmniboxPartState::HOVERED_AND_SELECTED,
result_view()->GetThemeState());
EXPECT_TRUE(popup_view()->IsSelectedIndex(kTestResultViewIndex));
}
TEST_F(OmniboxResultViewTest, MouseDragWithNonLeftButtonSetsHoveredState) {
EXPECT_NE(OmniboxPartState::HOVERED, result_view()->GetThemeState());
// Right button drag should put the view in the HOVERED state.
result_view()->OnMouseDragged(
CreateEvent(ui::ET_MOUSE_DRAGGED, ui::EF_RIGHT_MOUSE_BUTTON));
EXPECT_EQ(OmniboxPartState::HOVERED, result_view()->GetThemeState());
// Left button drag should take the view out of the HOVERED state.
result_view()->OnMouseDragged(
CreateEvent(ui::ET_MOUSE_DRAGGED, ui::EF_LEFT_MOUSE_BUTTON));
EXPECT_NE(OmniboxPartState::HOVERED, result_view()->GetThemeState());
}
TEST_F(OmniboxResultViewTest, MouseDragOutOfViewCancelsHoverState) {
EXPECT_NE(OmniboxPartState::HOVERED, result_view()->GetThemeState());
// Right button drag in the view should put the view in the HOVERED state.
result_view()->OnMouseDragged(
CreateEvent(ui::ET_MOUSE_DRAGGED, ui::EF_RIGHT_MOUSE_BUTTON, 0, 0));
EXPECT_EQ(OmniboxPartState::HOVERED, result_view()->GetThemeState());
// Right button drag outside of the view should revert the HOVERED state.
result_view()->OnMouseDragged(
CreateEvent(ui::ET_MOUSE_DRAGGED, ui::EF_RIGHT_MOUSE_BUTTON, 200, 200));
EXPECT_NE(OmniboxPartState::HOVERED, result_view()->GetThemeState());
}
TEST_F(OmniboxResultViewTest, MouseMoveAndExitSetsHoveredState) {
EXPECT_NE(OmniboxPartState::HOVERED, result_view()->GetThemeState());
// Moving the mouse over the view should put the view in the HOVERED state.
result_view()->OnMouseMoved(CreateEvent(ui::ET_MOUSE_MOVED, 0));
EXPECT_EQ(OmniboxPartState::HOVERED, result_view()->GetThemeState());
// Continuing to move over the view should not change the state.
result_view()->OnMouseMoved(CreateEvent(ui::ET_MOUSE_MOVED, 0));
EXPECT_EQ(OmniboxPartState::HOVERED, result_view()->GetThemeState());
// But exiting should revert the HOVERED state.
result_view()->OnMouseExited(CreateEvent(ui::ET_MOUSE_MOVED, 0));
EXPECT_NE(OmniboxPartState::HOVERED, result_view()->GetThemeState());
}
TEST_F(OmniboxResultViewTest, AccessibleNodeData) {
// Check accessibility of result.
base::string16 match_url = base::ASCIIToUTF16("https://google.com");
AutocompleteMatch match(nullptr, 500, false,
AutocompleteMatchType::HISTORY_TITLE);
match.contents = match_url;
match.contents_class.push_back(
ACMatchClassification(0, ACMatchClassification::URL));
match.destination_url = GURL(match_url);
match.description = base::ASCIIToUTF16("Google");
match.allowed_to_be_default_match = true;
result_view()->SetMatch(match);
ui::AXNodeData result_node_data;
result_view()->GetAccessibleNodeData(&result_node_data);
EXPECT_TRUE(
result_node_data.HasBoolAttribute(ax::mojom::BoolAttribute::kSelected));
EXPECT_FALSE(
result_node_data.GetBoolAttribute(ax::mojom::BoolAttribute::kSelected));
EXPECT_EQ(result_node_data.role, ax::mojom::Role::kListBoxOption);
EXPECT_EQ(
result_node_data.GetString16Attribute(ax::mojom::StringAttribute::kName),
base::ASCIIToUTF16("Google https://google.com location from history"));
EXPECT_EQ(
result_node_data.GetIntAttribute(ax::mojom::IntAttribute::kPosInSet),
kTestResultViewIndex + 1);
EXPECT_EQ(result_node_data.GetIntAttribute(ax::mojom::IntAttribute::kSetSize),
6);
// Select it and check selected state.
ui::AXNodeData result_after_click;
result_view()->OnMousePressed(
CreateEvent(ui::ET_MOUSE_PRESSED, ui::EF_LEFT_MOUSE_BUTTON));
result_view()->GetAccessibleNodeData(&result_after_click);
EXPECT_TRUE(
result_after_click.GetBoolAttribute(ax::mojom::BoolAttribute::kSelected));
// Check accessibility of list box.
ui::AXNodeData popup_node_data;
popup_view()->GetAccessibleNodeData(&popup_node_data);
EXPECT_EQ(popup_node_data.role, ax::mojom::Role::kListBox);
EXPECT_FALSE(popup_node_data.HasState(ax::mojom::State::kExpanded));
EXPECT_TRUE(popup_node_data.HasState(ax::mojom::State::kCollapsed));
EXPECT_TRUE(popup_node_data.HasState(ax::mojom::State::kInvisible));
}