blob: 9ed12969cf34d999d220a710a4757b9583c87814 [file] [log] [blame]
// Copyright 2018 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 "ash/components/shortcut_viewer/views/keyboard_shortcut_view.h"
#include <set>
#include "ash/components/shortcut_viewer/keyboard_shortcut_viewer_metadata.h"
#include "ash/components/shortcut_viewer/views/keyboard_shortcut_item_view.h"
#include "ash/components/shortcut_viewer/views/ksv_search_box_view.h"
#include "ash/test/ash_test_base.h"
#include "base/test/metrics/histogram_tester.h"
#include "services/ui/public/cpp/input_devices/input_device_client_test_api.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/window.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/events/test/event_generator.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/widget/widget.h"
namespace keyboard_shortcut_viewer {
class KeyboardShortcutViewTest : public ash::AshTestBase {
public:
KeyboardShortcutViewTest() = default;
~KeyboardShortcutViewTest() override = default;
views::Widget* Toggle() {
return KeyboardShortcutView::Toggle(base::TimeTicks(), CurrentContext());
}
// ash::AshTestBase:
void SetUp() override {
ash::AshTestBase::SetUp();
// Simulate the complete listing of input devices, required by the viewer.
ui::InputDeviceClientTestApi().OnDeviceListsComplete();
}
protected:
int GetTabCount() const {
DCHECK(GetView());
return GetView()->GetTabCountForTesting();
}
const std::vector<std::unique_ptr<KeyboardShortcutItemView>>&
GetShortcutViews() {
DCHECK(GetView());
return GetView()->GetShortcutViewsForTesting();
}
KSVSearchBoxView* GetSearchBoxView() {
DCHECK(GetView());
return GetView()->GetSearchBoxViewForTesting();
}
void KeyPress(ui::KeyboardCode key_code, bool should_insert) {
ui::KeyEvent event(ui::ET_KEY_PRESSED, key_code, ui::EF_NONE);
GetSearchBoxView()->OnKeyEvent(&event);
if (!should_insert)
return;
// Emulates the input method.
if (::isalnum(static_cast<int>(key_code))) {
base::char16 character = ::tolower(static_cast<int>(key_code));
GetSearchBoxView()->search_box()->InsertText(
base::string16(1, character));
}
}
base::HistogramTester histograms_;
private:
KeyboardShortcutView* GetView() const {
return KeyboardShortcutView::GetInstanceForTesting();
}
DISALLOW_COPY_AND_ASSIGN(KeyboardShortcutViewTest);
};
// Shows and closes the widget for KeyboardShortcutViewer.
TEST_F(KeyboardShortcutViewTest, ShowAndClose) {
// Show the widget.
views::Widget* widget = Toggle();
EXPECT_TRUE(widget);
// Cleaning up.
widget->CloseNow();
}
TEST_F(KeyboardShortcutViewTest, StartupTimeHistogram) {
views::Widget* widget = Toggle();
base::RunLoop runloop;
widget->GetCompositor()->RequestPresentationTimeForNextFrame(base::BindOnce(
[](base::RepeatingClosure closure,
const gfx::PresentationFeedback& feedback) { closure.Run(); },
runloop.QuitClosure()));
runloop.Run();
histograms_.ExpectTotalCount("Keyboard.ShortcutViewer.StartupTime", 1);
widget->CloseNow();
}
// KeyboardShortcutViewer window should be centered in screen.
TEST_F(KeyboardShortcutViewTest, CenterWindowInScreen) {
// Show the widget.
views::Widget* widget = Toggle();
EXPECT_TRUE(widget);
gfx::Rect root_window_bounds =
display::Screen::GetScreen()
->GetDisplayNearestWindow(widget->GetNativeWindow()->GetRootWindow())
.work_area();
gfx::Rect shortcuts_window_bounds =
widget->GetNativeWindow()->GetBoundsInScreen();
EXPECT_EQ(root_window_bounds.CenterPoint().x(),
shortcuts_window_bounds.CenterPoint().x());
EXPECT_EQ(root_window_bounds.CenterPoint().y(),
shortcuts_window_bounds.CenterPoint().y());
// Cleaning up.
widget->CloseNow();
}
// Test that the number of side tabs equals to the number of categories.
TEST_F(KeyboardShortcutViewTest, SideTabsCount) {
// Show the widget.
views::Widget* widget = Toggle();
int category_number = 0;
ShortcutCategory current_category = ShortcutCategory::kUnknown;
for (const auto& item_view : GetShortcutViews()) {
const ShortcutCategory category = item_view->category();
if (current_category != category) {
DCHECK(current_category < category);
++category_number;
current_category = category;
}
}
EXPECT_EQ(GetTabCount(), category_number);
// Cleaning up.
widget->CloseNow();
}
// Test that the top line in two views should be center aligned.
TEST_F(KeyboardShortcutViewTest, TopLineCenterAlignedInItemView) {
// Show the widget.
views::Widget* widget = Toggle();
for (const auto& item_view : GetShortcutViews()) {
// We only initialize the first visible category and other non-visible panes
// are deferred initialized.
if (item_view->category() != ShortcutCategory::kPopular)
continue;
DCHECK(item_view->child_count() == 2);
// The top lines in both |description_label_view_| and
// |shortcut_label_view_| should be center aligned. Only need to check one
// view in the top line, because StyledLabel always center align all the
// views in a line.
const views::View* description_view = item_view->child_at(0);
const views::View* shortcut_view = item_view->child_at(1);
const views::View* description_top_line_view =
description_view->child_at(0);
const views::View* shortcut_top_line_view = shortcut_view->child_at(0);
EXPECT_EQ(description_top_line_view->GetBoundsInScreen().CenterPoint().y(),
shortcut_top_line_view->GetBoundsInScreen().CenterPoint().y());
}
// Cleaning up.
widget->CloseNow();
}
// Test that the focus is on search box when window inits and exits search mode.
TEST_F(KeyboardShortcutViewTest, FocusOnSearchBox) {
// Show the widget.
views::Widget* widget = Toggle();
// Case 1: when window creates. The focus should be on search box.
EXPECT_TRUE(GetSearchBoxView()->search_box()->HasFocus());
// Press a key should enter search mode.
KeyPress(ui::VKEY_A, /*should_insert=*/true);
EXPECT_TRUE(GetSearchBoxView()->back_button()->visible());
EXPECT_FALSE(GetSearchBoxView()->search_box()->text().empty());
// Case 2: Exit search mode by clicking |back_button|. The focus should be on
// search box.
GetSearchBoxView()->ButtonPressed(
GetSearchBoxView()->back_button(),
ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON));
EXPECT_TRUE(GetSearchBoxView()->search_box()->text().empty());
EXPECT_TRUE(GetSearchBoxView()->search_box()->HasFocus());
// Enter search mode again.
KeyPress(ui::VKEY_A, /*should_insert=*/true);
EXPECT_FALSE(GetSearchBoxView()->search_box()->text().empty());
// Case 3: Exit search mode by pressing |VKEY_ESCAPE|. The focus should be on
// search box.
KeyPress(ui::VKEY_ESCAPE, /*should_insert=*/false);
EXPECT_TRUE(GetSearchBoxView()->search_box()->text().empty());
EXPECT_TRUE(GetSearchBoxView()->search_box()->HasFocus());
// Cleaning up.
widget->CloseNow();
}
// Test that the window can be closed by accelerator.
TEST_F(KeyboardShortcutViewTest, CloseWindowByAccelerator) {
// Show the widget.
views::Widget* widget = Toggle();
EXPECT_FALSE(widget->IsClosed());
ui::test::EventGenerator* event_generator = GetEventGenerator();
event_generator->PressKey(ui::VKEY_W, ui::EF_CONTROL_DOWN);
EXPECT_TRUE(widget->IsClosed());
}
// Test that the window can be activated or closed by toggling.
TEST_F(KeyboardShortcutViewTest, ToggleWindow) {
// Show the widget.
views::Widget* widget = Toggle();
EXPECT_FALSE(widget->IsClosed());
// Call |Toggle()| to activate the inactive widget.
EXPECT_TRUE(widget->IsActive());
widget->Deactivate();
EXPECT_FALSE(widget->IsActive());
Toggle();
EXPECT_TRUE(widget->IsActive());
// Call |Toggle()| to close the active widget.
Toggle();
EXPECT_TRUE(widget->IsClosed());
}
} // namespace keyboard_shortcut_viewer