chromium/chrome/browser/extensions/api/enterprise_kiosk_input/enterprise_kiosk_input_unittest.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/extensions/api/enterprise_kiosk_input.h"

#include <string>
#include <vector>

#include "base/memory/scoped_refptr.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/ash/crosapi/test_crosapi_dependency_registry.h"
#include "chrome/browser/ash/crosapi/test_crosapi_environment.h"
#include "chrome/browser/extensions/api/enterprise_kiosk_input/enterprise_kiosk_input_api.h"
#include "components/crx_file/id_util.h"
#include "extensions/browser/api_test_utils.h"
#include "extensions/browser/api_unittest.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/ime/ash/extension_ime_util.h"
#include "ui/base/ime/ash/fake_input_method_delegate.h"
#include "ui/base/ime/ash/input_method_descriptor.h"
#include "ui/base/ime/ash/input_method_manager.h"
#include "ui/base/ime/ash/input_method_util.h"
#include "ui/base/ime/ash/mock_input_method_manager.h"

namespace extensions {

namespace {

constexpr char kUsLayout[] = "xkb:us::eng";
constexpr char kLatamLayout[] = "xkb:latam::spa";
constexpr char kFrLayout[] = "xkb:fr::fra";
constexpr char kDeLayout[] = "xkb:de::ger";
constexpr char kInvalidLayout[] = "asdf_invalid_pinyin";
constexpr char kNoError[] = "";
constexpr char kErrorMessageTemplate[] =
    "Could not change current input method. Invalid input method id: %s.";

namespace im = ::ash::input_method;
namespace ime_util = ::ash::extension_ime_util;

std::string GetComponentExtensionImeId(const std::string& layout) {
  return ime_util::GetComponentInputMethodID(ime_util::kXkbExtensionId, layout);
}

class TestInputMethodManager : public im::MockInputMethodManager {
 public:
  class TestState : public im::MockInputMethodManager::State {
   public:
    TestState() {
      enabled_input_method_ids_.reserve(3);

      enabled_input_method_ids_.emplace_back(
          GetComponentExtensionImeId(kUsLayout));
      enabled_input_method_ids_.emplace_back(
          GetComponentExtensionImeId(kLatamLayout));
      enabled_input_method_ids_.emplace_back(
          GetComponentExtensionImeId(kFrLayout));

      current_ime_id_ = enabled_input_method_ids_[0];
    }

    TestState(const TestState&) = delete;
    TestState& operator=(const TestState&) = delete;

    void ChangeInputMethod(const std::string& input_method_id,
                           bool show_message) override {
      for (const auto& enabled_id : enabled_input_method_ids_) {
        if (input_method_id == enabled_id) {
          current_ime_id_ = input_method_id;
        }
      }
    }

    im::InputMethodDescriptor GetCurrentInputMethod() const override {
      return im::InputMethodDescriptor(
          /*id=*/current_ime_id_,
          /*name=*/"",
          /*indicator=*/"",
          /*keyboard_layout=*/"",
          /*language_codes=*/std::vector<std::string>(),
          /*is_login_keyboard=*/false,
          /*options_page_url=*/GURL(),
          /*input_view_url=*/GURL(),
          /*handwriting_language=*/std::nullopt);
    }

    const std::vector<std::string>& GetEnabledInputMethodIds() const override {
      return enabled_input_method_ids_;
    }

   protected:
    friend base::RefCounted<im::InputMethodManager::State>;
    ~TestState() override = default;

   private:
    std::vector<std::string> enabled_input_method_ids_;
    std::string current_ime_id_;
  };

  TestInputMethodManager() : state_(new TestState) {}

  TestInputMethodManager(const TestInputMethodManager&) = delete;
  TestInputMethodManager& operator=(const TestInputMethodManager&) = delete;

  scoped_refptr<im::InputMethodManager::State> GetActiveIMEState() override {
    return state_;
  }

  std::string GetMigratedInputMethodID(
      const std::string& input_method_id) override {
    if (input_method_id == kUsLayout || input_method_id == kLatamLayout ||
        input_method_id == kFrLayout) {
      return GetComponentExtensionImeId(input_method_id);
    }
    return "";
  }

 private:
  scoped_refptr<TestState> state_;
};

}  // namespace

class EnterpriseKioskInputTest : public extensions::ApiUnitTest {
 public:
  void SetUp() override {
    ApiUnitTest::SetUp();
    crosapi_environment_.SetUp();
  }

  void TearDown() override {
    crosapi_environment_.TearDown();
    ApiUnitTest::TearDown();
  }

 protected:
  base::Value::List CreateArgs(const std::string& input_method_id) {
    api::enterprise_kiosk_input::SetCurrentInputMethodOptions options;
    options.input_method_id = input_method_id;
    base::Value::List args;
    args.Append(options.ToValue());
    return args;
  }
  crosapi::TestCrosapiEnvironment crosapi_environment_;
};

// Test for API enterprise.kioskInput.setCurrentInputMethod
TEST_F(EnterpriseKioskInputTest, SetCurrentInputMethodFunctionTest) {
  TestInputMethodManager::Initialize(new TestInputMethodManager);

  scoped_refptr<im::InputMethodManager::State> ime_state =
      im::InputMethodManager::Get()->GetActiveIMEState();
  ASSERT_TRUE(ime_state);

  EXPECT_EQ(GetComponentExtensionImeId(kUsLayout),
            ime_state->GetCurrentInputMethod().id());

  {
    auto function = base::MakeRefCounted<
        EnterpriseKioskInputSetCurrentInputMethodFunction>();
    api_test_utils::RunFunction(function.get(), CreateArgs(kLatamLayout),
                                browser_context(),
                                api_test_utils::FunctionMode::kNone);
    EXPECT_EQ(function->GetError(), kNoError);
    EXPECT_EQ(GetComponentExtensionImeId(kLatamLayout),
              ime_state->GetCurrentInputMethod().id());
  }

  {
    auto function = base::MakeRefCounted<
        EnterpriseKioskInputSetCurrentInputMethodFunction>();
    api_test_utils::RunFunction(function.get(), CreateArgs(kDeLayout),
                                browser_context(),
                                api_test_utils::FunctionMode::kNone);
    EXPECT_EQ(function->GetError(),
              base::StringPrintf(kErrorMessageTemplate, kDeLayout));
    EXPECT_EQ(GetComponentExtensionImeId(kLatamLayout),
              ime_state->GetCurrentInputMethod().id());
  }

  {
    auto function = base::MakeRefCounted<
        EnterpriseKioskInputSetCurrentInputMethodFunction>();
    api_test_utils::RunFunction(function.get(), CreateArgs(kInvalidLayout),
                                browser_context(),
                                api_test_utils::FunctionMode::kNone);
    EXPECT_EQ(function->GetError(),
              base::StringPrintf(kErrorMessageTemplate, kInvalidLayout));
    EXPECT_EQ(GetComponentExtensionImeId(kLatamLayout),
              ime_state->GetCurrentInputMethod().id());
  }
}

}  // namespace extensions