// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/auth/views/active_session_auth_view.h"
#include <memory>
#include <optional>
#include "ash/auth/views/auth_container_view.h"
#include "ash/auth/views/auth_header_view.h"
#include "ash/auth/views/auth_input_row_view.h"
#include "ash/auth/views/pin_keyboard_view.h"
#include "ash/auth/views/test_support/mock_active_session_auth_view_observer.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/ash_test_util.h"
#include "base/containers/enum_set.h"
#include "components/account_id/account_id.h"
#include "components/user_manager/fake_user_manager.h"
#include "components/user_manager/scoped_user_manager.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
#include "ui/views/test/views_test_utils.h"
#include "ui/views/view.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget.h"
namespace ash {
namespace {
const char kTestAccount[] = "[email protected]";
const std::u16string title = u"title";
const std::u16string description = u"description";
class ActiveSessionAuthViewUnitTest : public AshTestBase {
public:
ActiveSessionAuthViewUnitTest() = default;
ActiveSessionAuthViewUnitTest(const ActiveSessionAuthViewUnitTest&) = delete;
ActiveSessionAuthViewUnitTest& operator=(
const ActiveSessionAuthViewUnitTest&) = delete;
~ActiveSessionAuthViewUnitTest() override = default;
protected:
void SetUp() override {
AshTestBase::SetUp();
widget_ = CreateFramelessTestWidget();
widget_->SetFullscreen(true);
widget_->Show();
AccountId account_id = AccountId::FromUserEmail(kTestAccount);
auto fake_user_manager = std::make_unique<user_manager::FakeUserManager>();
fake_user_manager->AddUser(account_id);
scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
std::move(fake_user_manager));
container_view_ =
widget_->SetContentsView(std::make_unique<ActiveSessionAuthView>(
account_id, title, description,
AuthFactorSet{AuthInputType::kPassword, AuthInputType::kPin}));
test_api_ =
std::make_unique<ActiveSessionAuthView::TestApi>(container_view_);
// Going through the components of the container view and initialized their
// test api's variables.
test_api_header_ = std::make_unique<AuthHeaderView::TestApi>(
test_api_->GetAuthHeaderView());
test_api_auth_container_ = std::make_unique<AuthContainerView::TestApi>(
test_api_->GetAuthContainerView());
close_button_ = test_api_->GetCloseButton();
test_api_pin_container_ = std::make_unique<PinContainerView::TestApi>(
test_api_auth_container_->GetPinContainerView());
test_api_pin_keyboard_ = std::make_unique<PinKeyboardView::TestApi>(
test_api_pin_container_->GetPinKeyboardView());
test_api_pin_input_ = std::make_unique<AuthInputRowView::TestApi>(
test_api_pin_container_->GetAuthInputRowView());
test_api_password_ = std::make_unique<AuthInputRowView::TestApi>(
test_api_auth_container_->GetPasswordView());
test_pin_status_ = std::make_unique<PinStatusView::TestApi>(
test_api_auth_container_->GetPinStatusView());
mock_observer_ = std::make_unique<MockActiveSessionAuthViewObserver>();
container_view_->AddObserver(mock_observer_.get());
CHECK(close_button_->GetVisible());
CHECK(test_api_header_->GetView()->GetVisible());
CHECK(test_api_auth_container_->GetView()->GetVisible());
}
void TearDown() override {
test_api_pin_input_.reset();
test_api_pin_keyboard_.reset();
test_api_pin_container_.reset();
test_api_password_.reset();
test_api_auth_container_.reset();
test_api_header_.reset();
test_pin_status_.reset();
close_button_ = nullptr;
test_api_.reset();
container_view_->RemoveObserver(mock_observer_.get());
mock_observer_.reset();
container_view_ = nullptr;
widget_.reset();
scoped_user_manager_.reset();
AshTestBase::TearDown();
}
std::unique_ptr<views::Widget> widget_;
std::unique_ptr<MockActiveSessionAuthViewObserver> mock_observer_;
std::unique_ptr<AuthInputRowView::TestApi> test_api_pin_input_;
std::unique_ptr<PinKeyboardView::TestApi> test_api_pin_keyboard_;
std::unique_ptr<PinContainerView::TestApi> test_api_pin_container_;
std::unique_ptr<AuthInputRowView::TestApi> test_api_password_;
std::unique_ptr<AuthHeaderView::TestApi> test_api_header_;
std::unique_ptr<AuthContainerView::TestApi> test_api_auth_container_;
std::unique_ptr<PinStatusView::TestApi> test_pin_status_;
std::unique_ptr<ActiveSessionAuthView::TestApi> test_api_;
raw_ptr<views::Button> close_button_;
raw_ptr<ActiveSessionAuthView> container_view_ = nullptr;
std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
};
// Verify close observer.
TEST_F(ActiveSessionAuthViewUnitTest, CloseButtonTest) {
EXPECT_CALL(*mock_observer_, OnClose()).Times(1);
// Click on close button.
LeftClickOn(close_button_);
}
// Verify close observer with disabled input area.
TEST_F(ActiveSessionAuthViewUnitTest, CloseButtonWithDisabledInputTest) {
EXPECT_CALL(*mock_observer_, OnClose()).Times(1);
container_view_->SetInputEnabled(false);
// Click on close button.
LeftClickOn(close_button_);
}
// Verify password submit observer.
TEST_F(ActiveSessionAuthViewUnitTest, PasswordSubmitTest) {
const std::u16string kPassword(u"password");
EXPECT_CALL(*mock_observer_, OnPasswordSubmit(kPassword)).Times(1);
container_view_->GetFocusManager()->SetFocusedView(
test_api_password_->GetTextfield());
for (const char16_t c : kPassword) {
PressAndReleaseKey(ui::DomCodeToUsLayoutNonLocatedKeyboardCode(
ui::UsLayoutDomKeyToDomCode(ui::DomKey::FromCharacter(c))));
}
EXPECT_EQ(test_api_pin_input_->GetTextfield()->GetText(), std::u16string());
EXPECT_EQ(test_api_password_->GetTextfield()->GetText(), kPassword);
// Click on Submit.
LeftClickOn(test_api_password_->GetSubmitButton());
}
// Verify the password input is no op with disabled input area.
TEST_F(ActiveSessionAuthViewUnitTest, PasswordSubmitWithDisabledInputTest) {
const std::u16string kPassword(u"password");
EXPECT_CALL(*mock_observer_, OnPasswordSubmit(kPassword)).Times(0);
container_view_->GetFocusManager()->SetFocusedView(
test_api_password_->GetTextfield());
container_view_->SetInputEnabled(false);
for (const char16_t c : kPassword) {
PressAndReleaseKey(ui::DomCodeToUsLayoutNonLocatedKeyboardCode(
ui::UsLayoutDomKeyToDomCode(ui::DomKey::FromCharacter(c))));
}
EXPECT_EQ(test_api_pin_input_->GetTextfield()->GetText(), std::u16string());
EXPECT_EQ(test_api_password_->GetTextfield()->GetText(), std::u16string());
// Click on Submit.
LeftClickOn(test_api_password_->GetSubmitButton());
}
// Verify PIN submit observer.
TEST_F(ActiveSessionAuthViewUnitTest, PinSubmitTest) {
// Switch to pin.
LeftClickOn(test_api_auth_container_->GetSwitchButton());
views::test::RunScheduledLayout(widget_.get());
container_view_->GetFocusManager()->SetFocusedView(
test_api_pin_input_->GetTextfield());
const std::u16string kPin(u"6893112");
EXPECT_CALL(*mock_observer_, OnPinSubmit(kPin)).Times(1);
for (const char16_t c : kPin) {
PressAndReleaseKey(ui::DomCodeToUsLayoutNonLocatedKeyboardCode(
ui::UsLayoutDomKeyToDomCode(ui::DomKey::FromCharacter(c))));
}
EXPECT_EQ(test_api_pin_input_->GetTextfield()->GetText(), kPin);
EXPECT_EQ(test_api_password_->GetTextfield()->GetText(), std::u16string());
// Click on Submit.
LeftClickOn(test_api_pin_input_->GetSubmitButton());
}
// Verify restore on input text change.
TEST_F(ActiveSessionAuthViewUnitTest, RestoreTitleTest1) {
const std::u16string errorTitle = u"error";
test_api_header_->GetView()->SetErrorTitle(errorTitle);
EXPECT_EQ(test_api_header_->GetCurrentTitle(), errorTitle);
container_view_->GetFocusManager()->SetFocusedView(
test_api_password_->GetTextfield());
PressAndReleaseKey(ui::VKEY_I);
// Test the title is restore properly.
EXPECT_EQ(test_api_header_->GetCurrentTitle(), u"title");
}
// Verify restore on switch button click.
TEST_F(ActiveSessionAuthViewUnitTest, RestoreTitleTest2) {
const std::u16string errorTitle = u"error";
test_api_header_->GetView()->SetErrorTitle(errorTitle);
EXPECT_EQ(test_api_header_->GetCurrentTitle(), errorTitle);
container_view_->GetFocusManager()->SetFocusedView(
test_api_password_->GetTextfield());
// Switch to pin.
LeftClickOn(test_api_auth_container_->GetSwitchButton());
// Test the title is restore properly.
EXPECT_EQ(test_api_header_->GetCurrentTitle(), u"title");
}
// Verify the ResetInputfields functionality.
TEST_F(ActiveSessionAuthViewUnitTest, ResetInputfieldsTest) {
test_api_password_->GetTextfield()->SetText(u"password");
test_api_pin_input_->GetTextfield()->SetText(u"pin");
test_api_->GetView()->ResetInputfields();
EXPECT_EQ(test_api_password_->GetTextfield()->GetText(), std::u16string());
EXPECT_EQ(test_api_pin_input_->GetTextfield()->GetText(), std::u16string());
}
TEST_F(ActiveSessionAuthViewUnitTest, SetPinStatusTest) {
const std::u16string status_message = u"Too many failed attempts.";
test_api_->GetView()->SetPinStatus(status_message);
EXPECT_EQ(test_pin_status_->GetCurrentText(), status_message);
}
} // namespace
} // namespace ash