chromium/chrome/browser/ash/input_method/grammar_service_client_unittest.cc

// Copyright 2020 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/browser/ash/input_method/grammar_service_client.h"

#include <vector>

#include "base/functional/bind.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/services/machine_learning/public/cpp/fake_service_connection.h"
#include "chromeos/services/machine_learning/public/mojom/grammar_checker.mojom.h"
#include "components/prefs/pref_service.h"
#include "components/spellcheck/browser/pref_names.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/ime/grammar_fragment.h"
#include "ui/gfx/range/range.h"

namespace ash {
namespace input_method {
namespace {

namespace machine_learning = ::chromeos::machine_learning;

class GrammarServiceClientTest : public testing::Test {
 public:
  GrammarServiceClientTest() = default;

 private:
  content::BrowserTaskEnvironment task_environment_;
};

TEST_F(GrammarServiceClientTest, ReturnsEmptyResultWhenSpellCheckIsDiabled) {
  machine_learning::FakeServiceConnectionImpl fake_service_connection;
  machine_learning::ServiceConnection::UseFakeServiceConnectionForTesting(
      &fake_service_connection);
  machine_learning::ServiceConnection::GetInstance()->Initialize();

  auto profile = std::make_unique<TestingProfile>();
  profile->GetPrefs()->SetBoolean(spellcheck::prefs::kSpellCheckEnable, false);

  GrammarServiceClient client;
  base::RunLoop().RunUntilIdle();

  client.RequestTextCheck(
      profile.get(), u"cat",
      base::BindOnce(
          [](bool success, const std::vector<ui::GrammarFragment>& results) {
            EXPECT_FALSE(success);
            EXPECT_TRUE(results.empty());
          }));

  base::RunLoop().RunUntilIdle();
}

TEST_F(GrammarServiceClientTest, ParsesResults) {
  machine_learning::FakeServiceConnectionImpl fake_service_connection;
  machine_learning::ServiceConnection::UseFakeServiceConnectionForTesting(
      &fake_service_connection);
  machine_learning::ServiceConnection::GetInstance()->Initialize();

  auto profile = std::make_unique<TestingProfile>();
  profile->GetPrefs()->SetBoolean(spellcheck::prefs::kSpellCheckEnable, true);

  // Construct fake output
  machine_learning::mojom::GrammarCheckerResultPtr result =
      machine_learning::mojom::GrammarCheckerResult::New();
  result->status = machine_learning::mojom::GrammarCheckerResult::Status::OK;
  machine_learning::mojom::GrammarCheckerCandidatePtr candidate =
      machine_learning::mojom::GrammarCheckerCandidate::New();
  candidate->text = "fake output";
  candidate->score = 0.5f;
  machine_learning::mojom::GrammarCorrectionFragmentPtr fragment =
      machine_learning::mojom::GrammarCorrectionFragment::New();
  fragment->offset = 3;
  fragment->length = 5;
  fragment->replacement = "fake replacement";
  candidate->fragments.emplace_back(std::move(fragment));
  result->candidates.emplace_back(std::move(candidate));
  fake_service_connection.SetOutputGrammarCheckerResult(result);

  std::vector<machine_learning::mojom::TextLanguagePtr> languages;
  languages.push_back(
      machine_learning::mojom::TextLanguage::New("en", /*confidence=*/1));
  fake_service_connection.SetOutputLanguages(languages);

  GrammarServiceClient client;
  base::RunLoop().RunUntilIdle();

  client.RequestTextCheck(
      profile.get(), u"fake input",
      base::BindOnce(
          [](bool success, const std::vector<ui::GrammarFragment>& results) {
            EXPECT_TRUE(success);
            ASSERT_EQ(results.size(), 1U);
            EXPECT_EQ(results[0].range, gfx::Range(3, 8));
            EXPECT_EQ(results[0].suggestion, "fake replacement");
          }));

  base::RunLoop().RunUntilIdle();
}

TEST_F(GrammarServiceClientTest, RejectsNonEnglishQuery) {
  machine_learning::FakeServiceConnectionImpl fake_service_connection;
  machine_learning::ServiceConnection::UseFakeServiceConnectionForTesting(
      &fake_service_connection);
  machine_learning::ServiceConnection::GetInstance()->Initialize();

  auto profile = std::make_unique<TestingProfile>();
  profile->GetPrefs()->SetBoolean(spellcheck::prefs::kSpellCheckEnable, true);

  // Construct fake output
  std::vector<machine_learning::mojom::TextLanguagePtr> languages;
  languages.push_back(
      machine_learning::mojom::TextLanguage::New("jp", /* confidence */ 1));
  fake_service_connection.SetOutputLanguages(languages);

  GrammarServiceClient client;
  base::RunLoop().RunUntilIdle();

  client.RequestTextCheck(
      profile.get(), u"fake input",
      base::BindOnce(
          [](bool success, const std::vector<ui::GrammarFragment>& results) {
            EXPECT_FALSE(success);
          }));

  base::RunLoop().RunUntilIdle();
}

TEST_F(GrammarServiceClientTest, RejectsLongQueries) {
  machine_learning::FakeServiceConnectionImpl fake_service_connection;
  machine_learning::ServiceConnection::UseFakeServiceConnectionForTesting(
      &fake_service_connection);
  machine_learning::ServiceConnection::GetInstance()->Initialize();

  auto profile = std::make_unique<TestingProfile>();
  profile->GetPrefs()->SetBoolean(spellcheck::prefs::kSpellCheckEnable, true);

  GrammarServiceClient client;
  base::RunLoop().RunUntilIdle();

  const std::u16string long_text =
      u"This is a very very very very very very very very very very very very "
      "very very loooooooooooong sentence, indeed very very very very very "
      "very very very very very very very very very loooooooooooong. Followed "
      "by a fake input sentence.";

  client.RequestTextCheck(
      profile.get(), long_text,
      base::BindOnce(
          [](bool success, const std::vector<ui::GrammarFragment>& results) {
            EXPECT_FALSE(success);
          }));

  base::RunLoop().RunUntilIdle();
}

}  // namespace
}  // namespace input_method
}  // namespace ash