chromium/ash/auth/views/auth_textfield_unittest.cc

// 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/auth_textfield.h"

#include <memory>
#include <string>

#include "ash/auth/views/test_support/mock_auth_textfield_observer.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "base/check.h"
#include "base/memory/raw_ptr.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/window.h"
#include "ui/events/event.h"
#include "ui/events/test/event_generator.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/widget/widget.h"

namespace ash {

namespace {

constexpr std::u16string kPassword = u"password";
constexpr std::u16string kPIN = u"123456";

}  // namespace

class PasswordTextfieldUnitTest : public AshTestBase {
 public:
  PasswordTextfieldUnitTest() = default;
  PasswordTextfieldUnitTest(const PasswordTextfieldUnitTest&) = delete;
  PasswordTextfieldUnitTest& operator=(const PasswordTextfieldUnitTest&) =
      delete;
  ~PasswordTextfieldUnitTest() override = default;

  void SetTextfieldToFocus() {
    auth_textfield_->GetFocusManager()->SetFocusedView(auth_textfield_);
  }

 protected:
  // AshTestBase:
  void SetUp() override {
    AshTestBase::SetUp();

    widget_ = CreateFramelessTestWidget();
    widget_->SetFullscreen(true);
    widget_->Show();

    auth_textfield_ = widget_->SetContentsView(
        std::make_unique<AuthTextfield>(AuthTextfield::AuthType::kPassword));
    mock_observer_ = std::make_unique<MockAuthTextfieldObserver>();
    auth_textfield_->AddObserver(mock_observer_.get());
  }

  void TearDown() override {
    AshTestBase::TearDown();
    auth_textfield_->RemoveObserver(mock_observer_.get());
    mock_observer_.reset();
    auth_textfield_ = nullptr;
    widget_.reset();
  }

  std::unique_ptr<views::Widget> widget_;
  std::unique_ptr<MockAuthTextfieldObserver> mock_observer_;
  raw_ptr<AuthTextfield> auth_textfield_;
};

// Testing textfield OnBlur Observer.
TEST_F(PasswordTextfieldUnitTest, OnBlurObserverTest) {
  EXPECT_CALL(*mock_observer_, OnTextfieldBlur()).Times(1);
  auth_textfield_->OnBlur();
}

// Testing textfield OnFocus Observer.
TEST_F(PasswordTextfieldUnitTest, OnFocusObserverTest) {
  EXPECT_CALL(*mock_observer_, OnTextfieldFocus()).Times(1);
  SetTextfieldToFocus();
}

// Testing textfield OnContentsChanged Observer.
TEST_F(PasswordTextfieldUnitTest, OnContentsChangedTest) {
  auth_textfield_->SetText(kPassword);
  SetTextfieldToFocus();
  const std::u16string modifiedString = kPassword + u"s";
  EXPECT_CALL(*mock_observer_, OnContentsChanged(modifiedString)).Times(1);
  ui::test::EventGenerator* generator = GetEventGenerator();
  generator->PressAndReleaseKey(ui::VKEY_S);
}

// Testing textfield OnTextVisibleChanged Observer.
TEST_F(PasswordTextfieldUnitTest, OnTextVisibleChangedTest) {
  auth_textfield_->SetText(kPassword);
  SetTextfieldToFocus();
  // by default the password should be hidden.
  CHECK(!auth_textfield_->IsTextVisible());
  EXPECT_CALL(*mock_observer_, OnTextVisibleChanged(true)).Times(1);
  auth_textfield_->SetTextVisible(true);
  CHECK(auth_textfield_->IsTextVisible());
}

// Testing password textfield OnSubmit Observer.
TEST_F(PasswordTextfieldUnitTest, OnSubmitTest) {
  auth_textfield_->SetText(kPassword);
  SetTextfieldToFocus();
  EXPECT_CALL(*mock_observer_, OnSubmit()).Times(1);
  ui::test::EventGenerator* generator = GetEventGenerator();
  generator->PressAndReleaseKey(ui::VKEY_RETURN);
}

// Testing password textfield OnEscape Observer.
TEST_F(PasswordTextfieldUnitTest, OnEscapeTest) {
  SetTextfieldToFocus();
  EXPECT_CALL(*mock_observer_, OnEscape()).Times(1);
  ui::test::EventGenerator* generator = GetEventGenerator();
  generator->PressAndReleaseKey(ui::VKEY_ESCAPE);
}

class PinTextfieldUnitTest : public AshTestBase {
 public:
  PinTextfieldUnitTest() = default;
  PinTextfieldUnitTest(const PinTextfieldUnitTest&) = delete;
  PinTextfieldUnitTest& operator=(const PinTextfieldUnitTest&) = delete;
  ~PinTextfieldUnitTest() override = default;

  void SetTextfieldToFocus() {
    auth_textfield_->GetFocusManager()->SetFocusedView(auth_textfield_);
  }

 protected:
  // AshTestBase:
  void SetUp() override {
    AshTestBase::SetUp();

    widget_ = CreateFramelessTestWidget();
    widget_->SetFullscreen(true);

    mock_observer_ = std::make_unique<MockAuthTextfieldObserver>();
    auth_textfield_ = widget_->SetContentsView(
        std::make_unique<AuthTextfield>(AuthTextfield::AuthType::kPin));
    auth_textfield_->SetText(kPIN);
    auth_textfield_->AddObserver(mock_observer_.get());
  }

  void TearDown() override {
    AshTestBase::TearDown();
    auth_textfield_->RemoveObserver(mock_observer_.get());
    mock_observer_.reset();
    auth_textfield_ = nullptr;
    widget_.reset();
  }

  std::unique_ptr<views::Widget> widget_;
  raw_ptr<AuthTextfield> auth_textfield_;
  std::unique_ptr<MockAuthTextfieldObserver> mock_observer_;
};

// Testing PIN textfield OnContentsChanged Observer.
TEST_F(PinTextfieldUnitTest, OnContentsChangedTest) {
  SetTextfieldToFocus();
  const std::u16string modifiedPIN = kPIN + u"5";
  EXPECT_CALL(*mock_observer_, OnContentsChanged(modifiedPIN)).Times(1);
  ui::test::EventGenerator* generator = GetEventGenerator();
  generator->PressAndReleaseKey(ui::VKEY_5);
}

// Testing PIN textfield OnContentsChanged Observer with letter.
TEST_F(PinTextfieldUnitTest, OnContentsChangedWithLetterTest) {
  SetTextfieldToFocus();
  EXPECT_CALL(*mock_observer_, OnContentsChanged(kPIN)).Times(0);
  ui::test::EventGenerator* generator = GetEventGenerator();
  generator->PressAndReleaseKey(ui::VKEY_E);
  CHECK_EQ(auth_textfield_->GetText(), kPIN);
}

// Testing PIN textfield InsertDigit function.
TEST_F(PinTextfieldUnitTest, InsertDigitTest) {
  const std::u16string modifiedPIN = kPIN + u"5";
  EXPECT_CALL(*mock_observer_, OnContentsChanged(modifiedPIN)).Times(1);
  auth_textfield_->InsertDigit(5);
}

// Testing PIN textfield backspace press.
TEST_F(PinTextfieldUnitTest, BackspacePressTest) {
  std::u16string modifiedPIN = kPIN;
  modifiedPIN.pop_back();
  SetTextfieldToFocus();
  EXPECT_CALL(*mock_observer_, OnContentsChanged(modifiedPIN)).Times(1);
  ui::test::EventGenerator* generator = GetEventGenerator();
  generator->PressAndReleaseKey(ui::VKEY_BACK);
}

// Testing PIN textfield Backspace function.
TEST_F(PinTextfieldUnitTest, BackspaceTest) {
  std::u16string modifiedPIN = kPIN;
  modifiedPIN.pop_back();
  EXPECT_CALL(*mock_observer_, OnContentsChanged(modifiedPIN)).Times(1);
  auth_textfield_->Backspace();
}

// Testing PIN textfield OnSubmit Observer.
TEST_F(PinTextfieldUnitTest, OnSubmitTest) {
  SetTextfieldToFocus();
  EXPECT_CALL(*mock_observer_, OnSubmit()).Times(1);
  ui::test::EventGenerator* generator = GetEventGenerator();
  generator->PressAndReleaseKey(ui::VKEY_RETURN);
}

// Testing PIN textfield OnEscape Observer.
TEST_F(PinTextfieldUnitTest, OnEscapeTest) {
  EXPECT_CALL(*mock_observer_, OnEscape()).Times(1);
  SetTextfieldToFocus();
  ui::test::EventGenerator* generator = GetEventGenerator();
  generator->PressAndReleaseKey(ui::VKEY_ESCAPE);
}

}  // namespace ash