// 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/autocorrect_manager.h"
#include "ash/constants/ash_features.h"
#include "ash/system/federated/federated_client_manager.h"
#include "base/functional/callback_helpers.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/ash/input_method/autocorrect_enums.h"
#include "chrome/browser/ash/input_method/autocorrect_prefs.h"
#include "chrome/browser/ash/input_method/suggestion_enums.h"
#include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
#include "chrome/browser/ui/ash/input_method/suggestion_details.h"
#include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/ash/components/dbus/federated/federated_client.h"
#include "chromeos/ash/services/federated/public/cpp/fake_service_connection.h"
#include "chromeos/ash/services/federated/public/cpp/service_connection.h"
#include "chromeos/ash/services/ime/public/cpp/autocorrect.h"
#include "components/strings/grit/components_strings.h"
#include "components/ukm/test_ukm_recorder.h"
#include "content/public/test/browser_task_environment.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/ime/ash/ime_bridge.h"
#include "ui/base/ime/ash/input_method_ash.h"
#include "ui/base/ime/ash/mock_ime_input_context_handler.h"
#include "ui/base/ime/fake_text_input_client.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/keycodes/dom/dom_code.h"
namespace ash {
namespace input_method {
namespace {
using ::testing::_;
using ::testing::DoAll;
using ::testing::ExpectationSet;
using ::testing::Return;
using ::testing::SetArgPointee;
using ime::AutocorrectSuggestionProvider;
using UkmEntry = ukm::builders::InputMethod_Assistive_AutocorrectV2;
constexpr char kCoverageHistogramName[] = "InputMethod.Assistive.Coverage";
constexpr char kSuccessHistogramName[] = "InputMethod.Assistive.Success";
constexpr char kDelayHistogramName[] =
"InputMethod.Assistive.Autocorrect.Delay";
constexpr char kAutocorrectActionHistogramName[] =
"InputMethod.Assistive.Autocorrect.Actions";
constexpr char kVKAutocorrectActionHistogramName[] =
"InputMethod.Assistive.Autocorrect.Actions.VK";
constexpr char kVKAutocorrectV2ActionHistogramName[] =
"InputMethod.Assistive.AutocorrectV2.Actions.VK";
constexpr char kPKAutocorrectV2ActionHistogramName[] =
"InputMethod.Assistive.AutocorrectV2.Actions.PK";
constexpr char kPKAutocorrectV2ActionEnabledByDefaultHistogramName[] =
"InputMethod.Assistive.AutocorrectV2.Actions.PK.EnabledByDefault";
constexpr char kAutocorrectV2AcceptLatency[] =
"InputMethod.Assistive.AutocorrectV2.Latency.Accept";
constexpr char kAutocorrectV2AcceptLatencyEnabledByDefault[] =
"InputMethod.Assistive.AutocorrectV2.Latency.Accept.EnabledByDefault";
constexpr char kAutocorrectV2RejectLatency[] =
"InputMethod.Assistive.AutocorrectV2.Latency.Reject";
constexpr char kAutocorrectV2RejectLatencyEnabledByDefault[] =
"InputMethod.Assistive.AutocorrectV2.Latency.Reject.EnabledByDefault";
constexpr char kAutocorrectV2ExitFieldLatency[] =
"InputMethod.Assistive.AutocorrectV2.Latency.ExitField";
constexpr char kAutocorrectV2ExitFieldLatencyEnabledByDefault[] =
"InputMethod.Assistive.AutocorrectV2.Latency.ExitField.EnabledByDefault";
constexpr char kAutocorrectV2VkPendingLatency[] =
"InputMethod.Assistive.AutocorrectV2.Latency.VkPending";
constexpr char kAutocorrectV2PkPendingLatency[] =
"InputMethod.Assistive.AutocorrectV2.Latency.PkPending";
constexpr char kAutocorrectV2QualityVkAcceptedHistName[] =
"InputMethod.Assistive.AutocorrectV2.Quality.VkAccepted";
constexpr char kAutocorrectV2QualityVkRejectedHistName[] =
"InputMethod.Assistive.AutocorrectV2.Quality.VkRejected";
constexpr char kAutocorrectV2QualityPkAcceptedHistName[] =
"InputMethod.Assistive.AutocorrectV2.Quality.PkAccepted";
constexpr char kAutocorrectV2QualityDefaultPkAcceptedHistName[] =
"InputMethod.Assistive.AutocorrectV2.Quality.PkAccepted.EnabledByDefault";
constexpr char kAutocorrectV2QualityPkRejectedHistName[] =
"InputMethod.Assistive.AutocorrectV2.Quality.PkRejected";
constexpr char kAutocorrectV2QualityDefaultPkRejectedHistName[] =
"InputMethod.Assistive.AutocorrectV2.Quality.PkRejected.EnabledByDefault";
constexpr char kAutocorrectV2Distance2dVkAcceptedHistName[] =
"InputMethod.Assistive.AutocorrectV2.Distance."
"OriginalLengthVsLevenshteinDistance.VkAccepted";
constexpr char kAutocorrectV2Distance2dVkRejectedHistName[] =
"InputMethod.Assistive.AutocorrectV2.Distance."
"OriginalLengthVsLevenshteinDistance.VkRejected";
constexpr char kAutocorrectV2Distance2dPkAcceptedHistName[] =
"InputMethod.Assistive.AutocorrectV2.Distance."
"OriginalLengthVsLevenshteinDistance.PkAccepted";
constexpr char kAutocorrectV2Distance2dPkRejectedHistName[] =
"InputMethod.Assistive.AutocorrectV2.Distance."
"OriginalLengthVsLevenshteinDistance.PkRejected";
constexpr char kAutocorrectV2DistanceSuggestedVkAcceptedHistName[] =
"InputMethod.Assistive.AutocorrectV2.Distance.SuggestedLength.VkAccepted";
constexpr char kAutocorrectV2DistanceSuggestedVkRejectedHistName[] =
"InputMethod.Assistive.AutocorrectV2.Distance.SuggestedLength.VkRejected";
constexpr char kAutocorrectV2DistanceSuggestedPkAcceptedHistName[] =
"InputMethod.Assistive.AutocorrectV2.Distance.SuggestedLength.PkAccepted";
constexpr char kAutocorrectV2DistanceSuggestedPkRejectedHistName[] =
"InputMethod.Assistive.AutocorrectV2.Distance.SuggestedLength.PkRejected";
constexpr char kAutocorrectV2PkUserPreferenceAll[] =
"InputMethod.Assistive.AutocorrectV2.PkUserPreference.All";
constexpr char kAutocorrectV2PkUserPreferenceEnglish[] =
"InputMethod.Assistive.AutocorrectV2.PkUserPreference.English";
constexpr char kAutocorrectV2PkRejectionHistName[] =
"InputMethod.Assistive.AutocorrectV2.Rejection.PK";
constexpr char kAutocorrectV2VkRejectionHistName[] =
"InputMethod.Assistive.AutocorrectV2.Rejection.VK";
constexpr char kAutocorrectV2PkSuggestionProviderHistName[] =
"InputMethod.Assistive.AutocorrectV2.SuggestionProvider.Pk";
constexpr char kUsEnglishEngineId[] = "xkb:us::eng";
constexpr char kUsInternationalEngineId[] = "xkb:us:intl:eng";
constexpr char kSpainSpanishEngineId[] = "xkb:es::spa";
constexpr char kLatinAmericaSpanishEngineId[] = "xkb:latam::spa";
constexpr char kBrazilPortugeseEngineId[] = "xkb:br::por";
constexpr char kFranceFrenchEngineId[] = "xkb:fr::fra";
constexpr int kContextId = 5;
// A helper for testing autocorrect histograms. There are redundant metrics
// for each autocorrect action and the helper ensures that all the relevant
// metrics for one action are updated properly.
void ExpectAutocorrectHistograms(const base::HistogramTester& histogram_tester,
bool visible_vk,
int window_shown,
int underlined,
int reverted,
int accepted,
int cleared_underline,
int exited_text_field_with_underline = 0,
int invalid_range = 0,
bool enabled_by_default = false) {
// Window shown metrics.
histogram_tester.ExpectBucketCount(kCoverageHistogramName,
AssistiveType::kAutocorrectWindowShown,
window_shown);
histogram_tester.ExpectBucketCount(kAutocorrectActionHistogramName,
AutocorrectActions::kWindowShown,
window_shown);
if (visible_vk) {
histogram_tester.ExpectBucketCount(kVKAutocorrectActionHistogramName,
AutocorrectActions::kWindowShown,
window_shown);
histogram_tester.ExpectBucketCount(kVKAutocorrectV2ActionHistogramName,
AutocorrectActions::kWindowShown,
window_shown);
} else {
histogram_tester.ExpectBucketCount(kPKAutocorrectV2ActionHistogramName,
AutocorrectActions::kWindowShown,
window_shown);
histogram_tester.ExpectBucketCount(
kPKAutocorrectV2ActionEnabledByDefaultHistogramName,
AutocorrectActions::kWindowShown,
enabled_by_default ? window_shown : 0);
}
// Underlined metrics.
histogram_tester.ExpectBucketCount(kCoverageHistogramName,
AssistiveType::kAutocorrectUnderlined,
underlined);
histogram_tester.ExpectBucketCount(kAutocorrectActionHistogramName,
AutocorrectActions::kUnderlined,
underlined);
if (visible_vk) {
histogram_tester.ExpectBucketCount(kVKAutocorrectActionHistogramName,
AutocorrectActions::kUnderlined,
underlined);
histogram_tester.ExpectBucketCount(kVKAutocorrectV2ActionHistogramName,
AutocorrectActions::kUnderlined,
underlined);
} else {
histogram_tester.ExpectBucketCount(kPKAutocorrectV2ActionHistogramName,
AutocorrectActions::kUnderlined,
underlined);
histogram_tester.ExpectBucketCount(
kPKAutocorrectV2ActionEnabledByDefaultHistogramName,
AutocorrectActions::kUnderlined, enabled_by_default ? underlined : 0);
}
// Revert metrics.
histogram_tester.ExpectBucketCount(
kCoverageHistogramName, AssistiveType::kAutocorrectReverted, reverted);
histogram_tester.ExpectBucketCount(
kSuccessHistogramName, AssistiveType::kAutocorrectReverted, reverted);
histogram_tester.ExpectBucketCount(kAutocorrectActionHistogramName,
AutocorrectActions::kReverted, reverted);
if (visible_vk) {
histogram_tester.ExpectBucketCount(kVKAutocorrectActionHistogramName,
AutocorrectActions::kReverted, reverted);
histogram_tester.ExpectBucketCount(kVKAutocorrectV2ActionHistogramName,
AutocorrectActions::kReverted, reverted);
} else {
histogram_tester.ExpectBucketCount(kPKAutocorrectV2ActionHistogramName,
AutocorrectActions::kReverted, reverted);
histogram_tester.ExpectBucketCount(
kPKAutocorrectV2ActionEnabledByDefaultHistogramName,
AutocorrectActions::kReverted, enabled_by_default ? reverted : 0);
}
// Accept metrics.
histogram_tester.ExpectBucketCount(
kAutocorrectActionHistogramName,
AutocorrectActions::kUserAcceptedAutocorrect, accepted);
if (visible_vk) {
histogram_tester.ExpectBucketCount(
kVKAutocorrectActionHistogramName,
AutocorrectActions::kUserAcceptedAutocorrect, accepted);
histogram_tester.ExpectBucketCount(
kVKAutocorrectV2ActionHistogramName,
AutocorrectActions::kUserAcceptedAutocorrect, accepted);
} else {
histogram_tester.ExpectBucketCount(
kPKAutocorrectV2ActionHistogramName,
AutocorrectActions::kUserAcceptedAutocorrect, accepted);
histogram_tester.ExpectBucketCount(
kPKAutocorrectV2ActionEnabledByDefaultHistogramName,
AutocorrectActions::kUserAcceptedAutocorrect,
enabled_by_default ? accepted : 0);
}
// Clear underline metrics.
histogram_tester.ExpectBucketCount(
kAutocorrectActionHistogramName,
AutocorrectActions::kUserActionClearedUnderline, cleared_underline);
if (visible_vk) {
histogram_tester.ExpectBucketCount(
kVKAutocorrectActionHistogramName,
AutocorrectActions::kUserActionClearedUnderline, cleared_underline);
histogram_tester.ExpectBucketCount(
kVKAutocorrectV2ActionHistogramName,
AutocorrectActions::kUserActionClearedUnderline, cleared_underline);
} else {
histogram_tester.ExpectBucketCount(
kPKAutocorrectV2ActionHistogramName,
AutocorrectActions::kUserActionClearedUnderline, cleared_underline);
histogram_tester.ExpectBucketCount(
kPKAutocorrectV2ActionEnabledByDefaultHistogramName,
AutocorrectActions::kUserActionClearedUnderline,
enabled_by_default ? cleared_underline : 0);
}
// Invalid Range metrics.
histogram_tester.ExpectBucketCount(kAutocorrectActionHistogramName,
AutocorrectActions::kInvalidRange,
invalid_range);
if (visible_vk) {
histogram_tester.ExpectBucketCount(kVKAutocorrectActionHistogramName,
AutocorrectActions::kInvalidRange,
invalid_range);
histogram_tester.ExpectBucketCount(kVKAutocorrectV2ActionHistogramName,
AutocorrectActions::kInvalidRange,
invalid_range);
} else {
histogram_tester.ExpectBucketCount(kPKAutocorrectV2ActionHistogramName,
AutocorrectActions::kInvalidRange,
invalid_range);
histogram_tester.ExpectBucketCount(
kPKAutocorrectV2ActionEnabledByDefaultHistogramName,
AutocorrectActions::kInvalidRange,
enabled_by_default ? invalid_range : 0);
}
// Exited text field with underline.
histogram_tester.ExpectBucketCount(
kAutocorrectActionHistogramName,
AutocorrectActions::kUserExitedTextFieldWithUnderline,
exited_text_field_with_underline);
if (visible_vk) {
histogram_tester.ExpectBucketCount(
kVKAutocorrectActionHistogramName,
AutocorrectActions::kUserExitedTextFieldWithUnderline,
exited_text_field_with_underline);
histogram_tester.ExpectBucketCount(
kVKAutocorrectV2ActionHistogramName,
AutocorrectActions::kUserExitedTextFieldWithUnderline,
exited_text_field_with_underline);
} else {
histogram_tester.ExpectBucketCount(
kPKAutocorrectV2ActionHistogramName,
AutocorrectActions::kUserExitedTextFieldWithUnderline,
exited_text_field_with_underline);
histogram_tester.ExpectBucketCount(
kPKAutocorrectV2ActionEnabledByDefaultHistogramName,
AutocorrectActions::kUserExitedTextFieldWithUnderline,
enabled_by_default ? exited_text_field_with_underline : 0);
}
const int total_actions = window_shown + underlined + reverted + accepted +
cleared_underline +
exited_text_field_with_underline + invalid_range;
const int total_coverage = window_shown + underlined + reverted;
// Count total bucket to test side-effects and make the helper robust against
// future changes of the metric buckets.
histogram_tester.ExpectTotalCount(kCoverageHistogramName, total_coverage);
histogram_tester.ExpectTotalCount(kSuccessHistogramName, reverted);
histogram_tester.ExpectTotalCount(kAutocorrectActionHistogramName,
total_actions);
histogram_tester.ExpectTotalCount(kVKAutocorrectActionHistogramName,
visible_vk ? total_actions : 0);
histogram_tester.ExpectTotalCount(kVKAutocorrectV2ActionHistogramName,
visible_vk ? total_actions : 0);
histogram_tester.ExpectTotalCount(kPKAutocorrectV2ActionHistogramName,
visible_vk ? 0 : total_actions);
histogram_tester.ExpectTotalCount(
kPKAutocorrectV2ActionEnabledByDefaultHistogramName,
(visible_vk || !enabled_by_default) ? 0 : total_actions);
// Latency metrics.
histogram_tester.ExpectTotalCount(kDelayHistogramName, reverted);
histogram_tester.ExpectTotalCount(kAutocorrectV2AcceptLatency, accepted);
histogram_tester.ExpectTotalCount(kAutocorrectV2AcceptLatencyEnabledByDefault,
enabled_by_default ? accepted : 0);
histogram_tester.ExpectTotalCount(kAutocorrectV2ExitFieldLatency,
exited_text_field_with_underline);
histogram_tester.ExpectTotalCount(
kAutocorrectV2ExitFieldLatencyEnabledByDefault,
enabled_by_default ? exited_text_field_with_underline : 0);
histogram_tester.ExpectTotalCount(
kAutocorrectV2RejectLatency,
reverted + cleared_underline + invalid_range);
histogram_tester.ExpectTotalCount(
kAutocorrectV2RejectLatencyEnabledByDefault,
enabled_by_default ? reverted + cleared_underline + invalid_range : 0);
histogram_tester.ExpectTotalCount(
kAutocorrectV2VkPendingLatency,
visible_vk ? cleared_underline + reverted + accepted + invalid_range +
exited_text_field_with_underline
: 0);
histogram_tester.ExpectTotalCount(
kAutocorrectV2PkPendingLatency,
visible_vk ? 0
: cleared_underline + reverted + accepted + invalid_range +
exited_text_field_with_underline);
}
// A helper to create properties for hidden undo window.
AssistiveWindowProperties CreateHiddenUndoWindowProperties() {
AssistiveWindowProperties window_properties;
window_properties.type = ash::ime::AssistiveWindowType::kUndoWindow;
window_properties.visible = false;
return window_properties;
}
// A helper to create properties for shown undo window.
AssistiveWindowProperties CreateVisibleUndoWindowProperties(
const std::u16string& original_text,
const std::u16string& autocorrected_text) {
AssistiveWindowProperties window_properties;
window_properties.type = ash::ime::AssistiveWindowType::kUndoWindow;
window_properties.visible = true;
window_properties.announce_string =
l10n_util::GetStringFUTF16(IDS_SUGGESTION_AUTOCORRECT_UNDO_WINDOW_SHOWN,
original_text, autocorrected_text);
return window_properties;
}
// A helper to create properties for shown undo window with additional learn
// more button.
AssistiveWindowProperties CreateVisibleUndoWindowWithLearnMoreButtonProperties(
const std::u16string& original_text,
const std::u16string& autocorrected_text) {
AssistiveWindowProperties window_properties;
window_properties.type = ash::ime::AssistiveWindowType::kUndoWindow;
window_properties.visible = true;
window_properties.show_setting_link = true;
window_properties.announce_string =
l10n_util::GetStringFUTF16(IDS_SUGGESTION_AUTOCORRECT_UNDO_WINDOW_SHOWN,
original_text, autocorrected_text);
return window_properties;
}
// A helper to create highlighted undo button in assistive window.
ui::ime::AssistiveWindowButton CreateHighlightedUndoButton(
const std::u16string& original_text) {
ui::ime::AssistiveWindowButton button = ui::ime::AssistiveWindowButton();
button.id = ui::ime::ButtonId::kUndo;
button.window_type = ash::ime::AssistiveWindowType::kUndoWindow;
button.announce_string = l10n_util::GetStringFUTF16(
IDS_SUGGESTION_AUTOCORRECT_UNDO_BUTTON, original_text);
return button;
}
// A helper to create highlighted learn more button in assistive window.
ui::ime::AssistiveWindowButton CreateHighlightedLearnMoreButton() {
ui::ime::AssistiveWindowButton button = ui::ime::AssistiveWindowButton();
button.id = ui::ime::ButtonId::kLearnMore;
button.announce_string =
l10n_util::GetStringUTF16(IDS_SUGGESTION_AUTOCORRECT_LEARN_MORE);
button.window_type = ash::ime::AssistiveWindowType::kLearnMore;
return button;
}
// A helper for creating key event.
ui::KeyEvent CreateKeyEvent(ui::DomKey key, ui::DomCode code) {
return ui::KeyEvent(ui::EventType::kKeyPressed, ui::VKEY_UNKNOWN, code,
ui::EF_NONE, key, ui::EventTimeForNow());
}
ui::KeyEvent PressKeyWithCtrl(const ui::DomCode& code) {
return ui::KeyEvent(ui::EventType::kKeyPressed, ui::VKEY_UNKNOWN, code,
ui::EF_CONTROL_DOWN, ui::DomKey::NONE,
ui::EventTimeForNow());
}
ui::KeyEvent KeyA() {
return CreateKeyEvent(ui::DomKey::FromCharacter('a'), ui::DomCode::US_A);
}
void SetAutocorrectPreferenceTo(Profile& profile,
const std::string& engine_id,
int autocorrect_level) {
base::Value::Dict input_method_setting;
input_method_setting.SetByDottedPath(
engine_id + ".physicalKeyboardAutoCorrectionLevel", autocorrect_level);
profile.GetPrefs()->Set(::prefs::kLanguageInputMethodSpecificSettings,
base::Value(std::move(input_method_setting)));
}
void EnableAutocorrect(Profile& profile, const std::string& engine_id) {
SetAutocorrectPreferenceTo(/*profile=*/profile,
/*engine_id=*/engine_id,
/*autocorrect_level=*/1);
}
void DisableAutocorrect(Profile& profile, const std::string& engine_id) {
SetAutocorrectPreferenceTo(/*profile=*/profile,
/*engine_id=*/engine_id,
/*autocorrect_level=*/0);
}
std::string ToString(const AutocorrectSuggestionProvider& provider) {
switch (provider) {
case AutocorrectSuggestionProvider::kUsEnglish840:
return "UsEnglish840";
case AutocorrectSuggestionProvider::kUsEnglish840V2:
return "UsEnglish840V2";
case AutocorrectSuggestionProvider::kUsEnglishDownloaded:
return "UsEnglishDownloaded";
case AutocorrectSuggestionProvider::kUsEnglishPrebundled:
return "UsEnglishPrebundled";
case AutocorrectSuggestionProvider::kUnknown:
default:
return "Unknown";
}
}
class MockSuggestionHandler : public SuggestionHandlerInterface {
public:
MOCK_METHOD(bool,
DismissSuggestion,
(int context_id, std::string* error),
(override));
MOCK_METHOD(bool,
SetSuggestion,
(int context_id,
const ui::ime::SuggestionDetails& details,
std::string* error),
(override));
MOCK_METHOD(bool,
AcceptSuggestion,
(int context_id, std::string* error),
(override));
MOCK_METHOD(void,
OnSuggestionsChanged,
(const std::vector<std::string>& suggestions),
(override));
MOCK_METHOD(bool,
SetButtonHighlighted,
(int context_id,
const ui::ime::AssistiveWindowButton& button,
bool highlighted,
std::string* error),
(override));
MOCK_METHOD(void,
ClickButton,
(const ui::ime::AssistiveWindowButton& button),
(override));
MOCK_METHOD(bool,
AcceptSuggestionCandidate,
(int context_id,
const std::u16string& candidate,
size_t delete_previous_utf16_len,
bool use_replace_surrounding_text,
std::string* error),
(override));
MOCK_METHOD(bool,
SetAssistiveWindowProperties,
(int context_id,
const AssistiveWindowProperties& assistive_window,
std::string* error),
(override));
MOCK_METHOD(void, Announce, (const std::u16string& text), (override));
};
std::vector<base::test::FeatureRef> DisabledFeatures() {
return {ash::features::kImeRuleConfig};
}
std::vector<base::test::FeatureRef>
DisabledFeaturesIncludingAutocorrectByDefault() {
return {ash::features::kImeRuleConfig, ash::features::kAutocorrectByDefault};
}
std::vector<base::test::FeatureRef> RequiredForAutocorrectByDefault() {
return {ash::features::kAutocorrectByDefault,
ash::features::kImeFstDecoderParamsUpdate,
ash::features::kImeUsEnglishModelUpdate};
}
class AutocorrectManagerTest : public testing::Test {
protected:
AutocorrectManagerTest()
: profile_(std::make_unique<TestingProfile>()),
manager_(&mock_suggestion_handler_, profile_.get()),
scoped_federated_fake_for_test_(&fake_federated_service_connection_) {
// Disable ImeRulesConfigs by default.
feature_list_.InitWithFeatures({}, DisabledFeatures());
// TODO(b/b/289140140): Refactor FederatedClientManager such that the
// testing framework for clients can be simpler.
ash::FederatedClient::InitializeFake();
federated::FederatedClientManager::UseFakeAshInteractionForTest();
IMEBridge::Get()->SetInputContextHandler(&mock_ime_input_context_handler_);
keyboard_client_ = ChromeKeyboardControllerClient::CreateForTest();
keyboard_client_->set_keyboard_enabled_for_test(false);
}
void TearDown() override { ash::FederatedClient::Shutdown(); }
content::BrowserTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
::base::test::ScopedFeatureList feature_list_;
MockIMEInputContextHandler mock_ime_input_context_handler_;
::testing::StrictMock<MockSuggestionHandler> mock_suggestion_handler_;
std::unique_ptr<Profile> profile_;
std::unique_ptr<ChromeKeyboardControllerClient> keyboard_client_;
AutocorrectManager manager_;
base::HistogramTester histogram_tester_;
ash::federated::FakeServiceConnectionImpl fake_federated_service_connection_;
ash::federated::ScopedFakeServiceConnectionForTest
scoped_federated_fake_for_test_;
};
TEST_F(AutocorrectManagerTest,
HandleAutocorrectSetsRangeWhenNoPendingAutocorrectExists) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(0, 3));
}
TEST_F(AutocorrectManagerTest,
HandleAutocorrectSetsRangeWhenPendingAutocorrectExists) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.HandleAutocorrect(gfx::Range(4, 7), u"cn", u"can");
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(4, 7));
}
TEST_F(AutocorrectManagerTest,
HandleAutocorrectDoesNotSetRangeWhenInputContextIsNull) {
IMEBridge::Get()->SetInputContextHandler(nullptr);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"cn", u"can");
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range());
}
TEST_F(AutocorrectManagerTest,
HandleAutocorrectClearsRangeWithEmptyInputRange) {
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(3, 7),
base::DoNothing());
manager_.HandleAutocorrect(gfx::Range(), u"", u"");
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range());
}
TEST_F(AutocorrectManagerTest, OnKeyEventDoesNotClearAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
const ui::KeyEvent key_event =
CreateKeyEvent(ui::DomKey::FromCharacter('a'), ui::DomCode::US_A);
EXPECT_FALSE(manager_.OnKeyEvent(key_event));
EXPECT_FALSE(manager_.OnKeyEvent(key_event));
EXPECT_FALSE(manager_.OnKeyEvent(key_event));
EXPECT_FALSE(manager_.OnKeyEvent(key_event));
EXPECT_FALSE(manager_.OnKeyEvent(key_event));
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(0, 3));
}
TEST_F(AutocorrectManagerTest,
TypingFewCharsAfterRangeDoesNotClearAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the a", gfx::Range(5));
manager_.OnSurroundingTextChanged(u"the ab", gfx::Range(6));
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(0, 3));
}
TEST_F(AutocorrectManagerTest,
TypingEnoughCharsAfterRangeClearsAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the a", gfx::Range(5));
manager_.OnSurroundingTextChanged(u"the ab", gfx::Range(6));
manager_.OnSurroundingTextChanged(u"the abc", gfx::Range(7));
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range());
}
TEST_F(AutocorrectManagerTest,
TypingFewCharsBeforeRangeDoesNotClearAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(1, 4), u"teh", u"the");
manager_.OnSurroundingTextChanged(u" the ", gfx::Range(5));
// Move cursor to position 0.
manager_.OnSurroundingTextChanged(u" the ", gfx::Range(0));
// Add two chars and move the ranges accordingly.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(2, 5),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"a the ", gfx::Range(1));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(3, 6),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"ab the ", gfx::Range(2));
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(3, 6));
}
TEST_F(AutocorrectManagerTest,
TypingEnoughCharsBeforeRangeClearsAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(1, 4), u"teh", u"the");
manager_.OnSurroundingTextChanged(u" the ", gfx::Range(5));
// Move cursor to position 0.
manager_.OnSurroundingTextChanged(u" the ", gfx::Range(0));
// Add three chars and move the range accordingly.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(2, 5),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"a the ", gfx::Range(1));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(3, 6),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"ab the ", gfx::Range(2));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(4, 7),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"abc the ", gfx::Range(3));
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range());
}
TEST_F(AutocorrectManagerTest,
TypingFewCharsBeforeAndAfterRangeDoesNotClearAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(1, 4), u"teh", u"the");
manager_.OnSurroundingTextChanged(u" the ", gfx::Range(5));
manager_.OnSurroundingTextChanged(u" the a", gfx::Range(6));
manager_.OnSurroundingTextChanged(u" the a", gfx::Range(0));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(2, 5),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"b the a", gfx::Range(1));
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(2, 5));
}
TEST_F(AutocorrectManagerTest,
TypingEnoughCharsAfterAndBeforeRangeClearsAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(1, 4), u"teh", u"the");
manager_.OnSurroundingTextChanged(u" the ", gfx::Range(5));
manager_.OnSurroundingTextChanged(u" the a", gfx::Range(6));
manager_.OnSurroundingTextChanged(u" the a", gfx::Range(0));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(2, 5),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"b the a", gfx::Range(1));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(3, 6),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"bc the a", gfx::Range(2));
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range());
}
TEST_F(AutocorrectManagerTest,
RemovingCharsCloseToRangeDoesNotClearAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Add characters.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the ab", gfx::Range(6));
// Now remove them.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(0, 3));
}
TEST_F(AutocorrectManagerTest,
PastingEnoughCharsAndRemovingFewStillClearsAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Add characters.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the ab", gfx::Range(6));
// Now removing them should not be counted.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
// Now addition of a new character must trigger the clearance process,
// to ensure backspaced does not impact the output.
manager_.OnSurroundingTextChanged(u"the a", gfx::Range(5));
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range());
}
TEST_F(AutocorrectManagerTest,
PastingFewCharsBeforeRangeDoesNotClearAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(1, 4), u"teh", u"the");
manager_.OnSurroundingTextChanged(u" the ", gfx::Range(5));
manager_.OnSurroundingTextChanged(u" the ", gfx::Range(0));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(3, 6),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"ab the ", gfx::Range(2));
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(3, 6));
}
TEST_F(AutocorrectManagerTest,
PastingEnoughCharsBeforeRangeClearsAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(1, 4), u"teh", u"the");
manager_.OnSurroundingTextChanged(u" the ", gfx::Range(5));
manager_.OnSurroundingTextChanged(u" the ", gfx::Range(0));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(4, 7),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"abc the ", gfx::Range(3));
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range());
}
TEST_F(AutocorrectManagerTest, OnBlurClearsAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(1, 4), u"teh", u"the");
manager_.OnBlur();
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range());
}
TEST_F(AutocorrectManagerTest, OnFocusClearsAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(1, 4), u"teh", u"the");
manager_.OnFocus(1);
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range());
}
TEST_F(AutocorrectManagerTest, MovingCursorInsideRangeShowsAssistiveWindow) {
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
AssistiveWindowProperties properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, properties, _));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
}
TEST_F(AutocorrectManagerTest,
MovingCursorInsideRangeDoesNotShowUndoWindowWhenRangeNotValidated) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Range is not validate validated yet. So, no expectation on show undo
// window call. If it happens, test will fail by StrictMock.
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(1));
}
TEST_F(AutocorrectManagerTest, MovingCursorOutsideRangeHidesAssistiveWindow) {
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
{
::testing::InSequence seq;
AssistiveWindowProperties shown_properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
AssistiveWindowProperties hidden_properties =
CreateHiddenUndoWindowProperties();
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, hidden_properties, _));
}
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
}
TEST_F(AutocorrectManagerTest,
MovingCursorInsideRangeAndRemovingCharactersHidesAssistiveWindow) {
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
AssistiveWindowProperties properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
{
::testing::InSequence seq;
AssistiveWindowProperties shown_properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
AssistiveWindowProperties hidden_properties =
CreateHiddenUndoWindowProperties();
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, hidden_properties, _));
}
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(2));
manager_.OnSurroundingTextChanged(u"te ", gfx::Range(1));
}
TEST_F(AutocorrectManagerTest, MovingCursorRetriesPrevFailedUndoWindowHide) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
// Show undo window.
AssistiveWindowProperties shown_properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
// Accept autocorrect implicitly and make the request to hide the window
// fail.
AssistiveWindowProperties hidden_properties =
CreateHiddenUndoWindowProperties();
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, hidden_properties, _))
.WillOnce(DoAll(SetArgPointee<2>("Error"), Return(false)))
.RetiresOnSaturation();
manager_.OnSurroundingTextChanged(u"the abcd", gfx::Range(8));
// Now moving cursor should retry hiding autocorrect range.
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, hidden_properties, _));
manager_.OnSurroundingTextChanged(u"the abcd", gfx::Range(7));
}
TEST_F(AutocorrectManagerTest,
MovingCursorInsideRangeRetriesPrevFailedUndoWindowHide) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
// Show undo window.
AssistiveWindowProperties shown_properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
// Make first try to hide the window fail.
AssistiveWindowProperties hidden_properties =
CreateHiddenUndoWindowProperties();
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, hidden_properties, _))
.WillOnce(DoAll(SetArgPointee<2>("Error"), Return(false)));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
{
::testing::InSequence seq;
// Retries previously failed undo window hiding which now
// succeed.
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, hidden_properties, _));
// Showing new undo window.
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
}
// Try hiding undo window before showing it again.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
}
TEST_F(AutocorrectManagerTest,
ShowingNewUndoWindowStopsRetryingPrevFailedUndoWindowHide) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
// Show the undo window first time.
AssistiveWindowProperties shown_properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
// Make first two call to hide undo window to fail.
AssistiveWindowProperties hidden_properties =
CreateHiddenUndoWindowProperties();
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, hidden_properties, _))
.Times(2)
.WillRepeatedly(DoAll(SetArgPointee<2>("Error"), Return(false)))
.RetiresOnSaturation();
// Handle a new range to allow triggering an undo window override.
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Show a new undo window.
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
// No retry should be applied to hide undo window as it is overridden.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(2));
}
TEST_F(AutocorrectManagerTest, FocusChangeHidesUndoWindow) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
// Show a window.
AssistiveWindowProperties shown_properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
// OnFocus should try hiding the window.
AssistiveWindowProperties hidden_properties =
CreateHiddenUndoWindowProperties();
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, hidden_properties, _));
manager_.OnFocus(1);
}
TEST_F(AutocorrectManagerTest, EscapeHidesUndoWindow) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
// Show a window.
AssistiveWindowProperties shown_properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
// OnFocus should try hiding the window.
AssistiveWindowProperties hidden_properties =
CreateHiddenUndoWindowProperties();
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, hidden_properties, _));
manager_.OnKeyEvent(CreateKeyEvent(ui::DomKey::NONE, ui::DomCode::ESCAPE));
}
TEST_F(AutocorrectManagerTest, OnFocusRetriesHidingUndoWindow) {
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Show undo window.
AssistiveWindowProperties shown_properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
// Make it fail to hide window for OnBlur.
AssistiveWindowProperties hidden_properties =
CreateHiddenUndoWindowProperties();
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, hidden_properties, _))
.WillOnce(DoAll(SetArgPointee<2>("Error"), Return(false)));
manager_.OnBlur();
// OnFocus must try to hide undo window.
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, hidden_properties, _));
manager_.OnFocus(1);
}
TEST_F(AutocorrectManagerTest,
PressingUpArrowKeyHighlightsUndoButtonWhenUndoWindowIsVisible) {
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
{
::testing::InSequence seq;
AssistiveWindowProperties shown_properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
ui::ime::AssistiveWindowButton undo_button =
CreateHighlightedUndoButton(u"teh");
EXPECT_CALL(mock_suggestion_handler_,
SetButtonHighlighted(_, undo_button, true, _));
ui::ime::AssistiveWindowButton learn_more_button =
CreateHighlightedLearnMoreButton();
EXPECT_CALL(mock_suggestion_handler_,
SetButtonHighlighted(_, learn_more_button, false, _));
}
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
manager_.OnKeyEvent(CreateKeyEvent(ui::DomKey::NONE, ui::DomCode::ARROW_UP));
}
TEST_F(AutocorrectManagerTest,
PressingTabKeyHighlightsUndoButtonWhenUndoWindowIsVisible) {
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
{
::testing::InSequence seq;
AssistiveWindowProperties shown_properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
ui::ime::AssistiveWindowButton undo_button =
CreateHighlightedUndoButton(u"teh");
ui::ime::AssistiveWindowButton learn_more_button =
CreateHighlightedLearnMoreButton();
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
EXPECT_CALL(mock_suggestion_handler_,
SetButtonHighlighted(_, undo_button, true, _));
EXPECT_CALL(mock_suggestion_handler_,
SetButtonHighlighted(_, learn_more_button, false, _));
}
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
manager_.OnKeyEvent(CreateKeyEvent(ui::DomKey::NONE, ui::DomCode::TAB));
}
TEST_F(
AutocorrectManagerTest,
PressingRightArrowKeyHighlightsLearnMoreButtonWhenUndoButtonIsHighlighted) {
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
{
::testing::InSequence seq;
AssistiveWindowProperties shown_properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
ui::ime::AssistiveWindowButton undo_button =
CreateHighlightedUndoButton(u"teh");
ui::ime::AssistiveWindowButton learn_more_button =
CreateHighlightedLearnMoreButton();
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
EXPECT_CALL(mock_suggestion_handler_,
SetButtonHighlighted(_, undo_button, true, _));
EXPECT_CALL(mock_suggestion_handler_,
SetButtonHighlighted(_, learn_more_button, false, _));
EXPECT_CALL(mock_suggestion_handler_,
SetButtonHighlighted(_, undo_button, false, _));
EXPECT_CALL(mock_suggestion_handler_,
SetButtonHighlighted(_, learn_more_button, true, _));
}
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
manager_.OnKeyEvent(CreateKeyEvent(ui::DomKey::NONE, ui::DomCode::TAB));
manager_.OnKeyEvent(
CreateKeyEvent(ui::DomKey::NONE, ui::DomCode::ARROW_RIGHT));
}
TEST_F(AutocorrectManagerTest,
PressingEnterKeyHidesUndoWindowWhenButtonIsHighlighted) {
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
{
::testing::InSequence seq;
AssistiveWindowProperties shown_properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
ui::ime::AssistiveWindowButton undo_button =
CreateHighlightedUndoButton(u"teh");
EXPECT_CALL(mock_suggestion_handler_,
SetButtonHighlighted(_, undo_button, true, _));
ui::ime::AssistiveWindowButton learn_more_button =
CreateHighlightedLearnMoreButton();
EXPECT_CALL(mock_suggestion_handler_,
SetButtonHighlighted(_, learn_more_button, false, _));
AssistiveWindowProperties hidden_properties =
CreateHiddenUndoWindowProperties();
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, hidden_properties, _));
}
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
manager_.OnKeyEvent(CreateKeyEvent(ui::DomKey::NONE, ui::DomCode::ARROW_UP));
manager_.OnKeyEvent(CreateKeyEvent(ui::DomKey::NONE, ui::DomCode::ENTER));
}
TEST_F(AutocorrectManagerTest,
PressingEnterKeyHidesUndoWindowWhenLearnMoreButtonIsHighlighted) {
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
{
::testing::InSequence seq;
AssistiveWindowProperties shown_properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
AssistiveWindowProperties hidden_properties =
CreateHiddenUndoWindowProperties();
ui::ime::AssistiveWindowButton undo_button =
CreateHighlightedUndoButton(u"teh");
ui::ime::AssistiveWindowButton learn_more_button =
CreateHighlightedLearnMoreButton();
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
EXPECT_CALL(mock_suggestion_handler_,
SetButtonHighlighted(_, undo_button, true, _));
EXPECT_CALL(mock_suggestion_handler_,
SetButtonHighlighted(_, learn_more_button, false, _));
EXPECT_CALL(mock_suggestion_handler_,
SetButtonHighlighted(_, undo_button, false, _));
EXPECT_CALL(mock_suggestion_handler_,
SetButtonHighlighted(_, learn_more_button, true, _));
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, hidden_properties, _));
EXPECT_CALL(mock_suggestion_handler_, ClickButton(learn_more_button));
}
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
manager_.OnKeyEvent(CreateKeyEvent(ui::DomKey::NONE, ui::DomCode::ARROW_UP));
manager_.OnKeyEvent(
CreateKeyEvent(ui::DomKey::NONE, ui::DomCode::ARROW_RIGHT));
manager_.OnKeyEvent(CreateKeyEvent(ui::DomKey::NONE, ui::DomCode::ENTER));
}
TEST_F(AutocorrectManagerTest, LearnMoreButtonOnlyShown50Times) {
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
{
::testing::InSequence seq;
AssistiveWindowProperties shown_properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
AssistiveWindowProperties hidden_properties =
CreateHiddenUndoWindowProperties();
ExpectationSet learn_more_call_series;
// Expects the learn more button to show and hide for 50 times.
for (int i = 0; i < 50; ++i) {
learn_more_call_series +=
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
learn_more_call_series +=
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, hidden_properties, _));
}
shown_properties = CreateVisibleUndoWindowProperties(u"teh", u"the");
// After learn more button is shown 50 times, it expires and never shows
// again.
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _))
.After(learn_more_call_series);
}
std::u16string surrounding_text = u"the ";
manager_.OnSurroundingTextChanged(surrounding_text, gfx::Range(1));
for (int i = 0; i < 50; ++i) {
// For each iteration:
// First inserts "the " into the text input field, and place the cursor at
// the end of the text.
surrounding_text += u"the ";
int cursor_pos = surrounding_text.length();
manager_.OnSurroundingTextChanged(surrounding_text, gfx::Range(cursor_pos));
// Then handles an autocorrection that occurs on the text that is just
// inserted.
manager_.HandleAutocorrect(gfx::Range(cursor_pos - 4, cursor_pos - 1),
u"teh", u"the");
// Finally, moves the cursor in the middle of the new word to trigger the
// learn more button to show.
manager_.OnSurroundingTextChanged(surrounding_text,
gfx::Range(cursor_pos - 3));
}
}
TEST_F(AutocorrectManagerTest, UndoAutocorrectSingleWordInComposition) {
ui::FakeTextInputClient fake_text_input_client(ui::TEXT_INPUT_TYPE_TEXT);
InputMethodAsh ime(nullptr);
IMEBridge::Get()->SetInputContextHandler(&ime);
ime.SetFocusedTextInputClient(&fake_text_input_client);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
// Move cursor to the middle of 'the' and bring the text into composition.
fake_text_input_client.SetTextAndSelection(u"the ", gfx::Range(2));
ime.SetComposingRange(0, 3, {});
manager_.UndoAutocorrect();
EXPECT_EQ(fake_text_input_client.text(), u"teh ");
}
TEST_F(AutocorrectManagerTest, UndoAutocorrectDoesNotApplyOnRangeNotValidated) {
ui::FakeTextInputClient fake_text_input_client(ui::TEXT_INPUT_TYPE_TEXT);
InputMethodAsh ime(nullptr);
IMEBridge::Get()->SetInputContextHandler(&ime);
ime.SetFocusedTextInputClient(&fake_text_input_client);
// No OnSurroundingTextChanged is called to validate the suggestion.
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Move cursor to the middle of 'the' and bring the text into composition.
fake_text_input_client.SetTextAndSelection(u"the ", gfx::Range(2));
ime.SetComposingRange(0, 3, {});
manager_.UndoAutocorrect();
// Undo is not applied.
EXPECT_EQ(fake_text_input_client.text(), u"the ");
}
TEST_F(AutocorrectManagerTest, UndoAutocorrectMultipleWordInComposition) {
ui::FakeTextInputClient fake_text_input_client(ui::TEXT_INPUT_TYPE_TEXT);
InputMethodAsh ime(nullptr);
IMEBridge::Get()->SetInputContextHandler(&ime);
ime.SetFocusedTextInputClient(&fake_text_input_client);
manager_.HandleAutocorrect(gfx::Range(0, 11), u"helloworld", u"hello world");
manager_.OnSurroundingTextChanged(u"hello world ", gfx::Range(12));
// Move cursor to the middle of 'hello' and bring the word into composition.
fake_text_input_client.SetTextAndSelection(u"hello world ", gfx::Range(2));
ime.SetComposingRange(0, 5, {});
manager_.UndoAutocorrect();
EXPECT_EQ(fake_text_input_client.text(), u"helloworld ");
}
TEST_F(AutocorrectManagerTest, MovingCursorDoesNotAcceptAutocorrect) {
manager_.HandleAutocorrect(gfx::Range(5, 8), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"abcd the efghij", gfx::Range(4));
// Move cursor to different positions in one session does not
// accept or clear the the autocorrect range implicitly.
manager_.OnSurroundingTextChanged(u"abcd the efghij", gfx::Range(15));
manager_.OnSurroundingTextChanged(u"abcd the efghij", gfx::Range(0));
manager_.OnSurroundingTextChanged(u"abcd the efghij", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"abcd the efghij", gfx::Range(9));
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(5, 8));
}
TEST_F(AutocorrectManagerTest,
InsertingFewCharsDoesNotRecordMetricsForPendingAutocorrect) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
// Add characters.
manager_.OnSurroundingTextChanged(u" the b", gfx::Range(6));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
InsertingEnoughCharsRecordsMetricWhenAcceptingAutocorrect) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Add characters.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"c the b", gfx::Range(7));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/1,
/*cleared_underline=*/0);
}
TEST_F(
AutocorrectManagerTest,
InsertingEnoughCharsRecordsMetricWhenAcceptingAutocorrectEnabledByDefault) {
feature_list_.Reset();
feature_list_.InitWithFeatures({features::kAutocorrectByDefault},
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Add characters.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"c the b", gfx::Range(7));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/1,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/0,
/*invalid_range=*/0,
/*enabled_by_default=*/true);
}
TEST_F(AutocorrectManagerTest,
RemovingCharsDoesNotRecordMetricsForPendingAutocorrect) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Add characters.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the ab", gfx::Range(6));
// Now remove them.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
InsertingCharsRecordsMetricsWhenClearingAutocorrect) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the a", gfx::Range(5));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u" the b", gfx::Range(6));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/1);
}
TEST_F(
AutocorrectManagerTest,
InsertingCharsRecordsMetricsWhenClearingAutocorrectWhenEnabledByDefault) {
feature_list_.Reset();
feature_list_.InitWithFeatures({features::kAutocorrectByDefault},
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the a", gfx::Range(5));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u" the b", gfx::Range(6));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/1,
/*exited_text_field_with_underline=*/0,
/*invalid_range=*/0,
/*enabled_by_default=*/true);
}
TEST_F(AutocorrectManagerTest,
InsertingCharsDoesNotRecordsMetricsWhenSetRangeFails) {
// Disable autocorrect.
mock_ime_input_context_handler_.set_autocorrect_enabled(false);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the a", gfx::Range(5));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u" the b", gfx::Range(6));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/0,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
OnSurroundingCallDoesNotRecordMetricsWhenClearingInvalidRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Range not validated yet.
manager_.OnSurroundingTextChanged(u"t ", gfx::Range(2));
// Clear range.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
// Empty range is received and ignored because the new suggestion is still
// not validated.
manager_.OnSurroundingTextChanged(u"th ", gfx::Range(3));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
OnSurroundingCallRecordsMetricsWhenClearingValidatedRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Validate the range.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
// Clear the range.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
// Process the cleared range ('the' is mutated to implicitly reject it).
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/1);
}
TEST_F(AutocorrectManagerTest,
OnSurroundingRecordsMetricsCorrectlyForNullInputContext) {
// Create a pending autocorrect range.
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Make Input context null.
IMEBridge::Get()->SetInputContextHandler(nullptr);
// Null input context invalidates the previous range even if rules are
// triggered to accept the range.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the abc", gfx::Range(7));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline*/ 0,
/*invalid_range*/ 1);
}
TEST_F(
AutocorrectManagerTest,
OnSurroundingRecordsMetricsCorrectlyForNullInputContextWhenEnabledByDefault) {
feature_list_.Reset();
feature_list_.InitWithFeatures({features::kAutocorrectByDefault},
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
// Create a pending autocorrect range.
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Make Input context null.
IMEBridge::Get()->SetInputContextHandler(nullptr);
// Null input context invalidates the previous range even if rules are
// triggered to accept the range.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the abc", gfx::Range(7));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline*/ 0,
/*invalid_range*/ 1,
/*enabled_by_default=*/true);
}
TEST_F(AutocorrectManagerTest,
MovingCursorDoesNotRecordMetricsForPendingAutocorrect) {
manager_.HandleAutocorrect(gfx::Range(4, 7), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"abc the def", gfx::Range(8));
manager_.OnSurroundingTextChanged(u"abc the def", gfx::Range(1));
manager_.OnSurroundingTextChanged(u"abc the def", gfx::Range(10));
manager_.OnSurroundingTextChanged(u"abc the def", gfx::Range(3));
manager_.OnSurroundingTextChanged(u"abc the def", gfx::Range(8));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
MovingCursorToRangeStartRecordsMetricsForShownUndoWindow) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// This suppresses strict mock.
EXPECT_CALL(mock_suggestion_handler_, SetAssistiveWindowProperties(_, _, _));
manager_.OnSurroundingTextChanged(u"the", gfx::Range(0));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/1, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
MovingCursorToRangeEndRecordsMetricsForShownUndoWindow) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// This suppresses strict mock.
EXPECT_CALL(mock_suggestion_handler_, SetAssistiveWindowProperties(_, _, _));
// Moving cursor inside the range does not increase window_shown.
manager_.OnSurroundingTextChanged(u"the", gfx::Range(3));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/1, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
MovingCursorToRangeEndRecordsMetricsForShownUndoWindowEnableByDefault) {
feature_list_.Reset();
feature_list_.InitWithFeatures({features::kAutocorrectByDefault},
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// This suppresses strict mock.
EXPECT_CALL(mock_suggestion_handler_, SetAssistiveWindowProperties(_, _, _));
// Moving cursor inside the range does not increase window_shown.
manager_.OnSurroundingTextChanged(u"the", gfx::Range(3));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/1, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/0,
/*invalid_range=*/0,
/*enabled_by_default=*/true);
}
TEST_F(AutocorrectManagerTest,
KeepingCursorInsideRangeRecordsMetricsForShownUndoWindowOnce) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// This suppresses strict mock.
EXPECT_CALL(mock_suggestion_handler_, SetAssistiveWindowProperties(_, _, _));
manager_.OnSurroundingTextChanged(u"the", gfx::Range(0));
manager_.OnSurroundingTextChanged(u"the", gfx::Range(3));
manager_.OnSurroundingTextChanged(u"the", gfx::Range(2));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/1, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
MovingCursorOutThenInsideRangeDoesNotRecordsMetricsTwice) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// The function is called two times for show and one time for hide.
// This suppresses strict mock.
EXPECT_CALL(mock_suggestion_handler_, SetAssistiveWindowProperties(_, _, _))
.Times(3);
// Moving cursor first inside range, then outside the range and then again
// back to the range increments the metric for shown window twice.
manager_.OnSurroundingTextChanged(u"the", gfx::Range(1));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the", gfx::Range(3));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/1, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
OnKeyEventDoesNotRecordMetricsForAcceptingOrClearingAutocorrect) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
const ui::KeyEvent key_event =
CreateKeyEvent(ui::DomKey::FromCharacter('a'), ui::DomCode::US_A);
manager_.OnKeyEvent(key_event);
manager_.OnKeyEvent(key_event);
manager_.OnKeyEvent(key_event);
manager_.OnKeyEvent(key_event);
manager_.OnKeyEvent(key_event);
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
OnKeyEventDoesNotRecordMetricsAfterClearingRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
const ui::KeyEvent key_event =
CreateKeyEvent(ui::DomKey::FromCharacter('a'), ui::DomCode::US_A);
manager_.OnKeyEvent(key_event);
manager_.OnKeyEvent(key_event);
manager_.OnKeyEvent(key_event);
manager_.OnKeyEvent(key_event);
manager_.OnKeyEvent(key_event);
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest, OnBlurRecordsMetricsWhenClearingRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnBlur();
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/1);
}
TEST_F(AutocorrectManagerTest,
OnBlurRecordsMetricsWhenClearingRangeEnabledByDefault) {
feature_list_.Reset();
feature_list_.InitWithFeatures({features::kAutocorrectByDefault},
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnBlur();
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/1,
/*invalid_range=*/0,
/*enabled_by_default=*/true);
}
TEST_F(AutocorrectManagerTest,
OnBlurDoesNoRecordMetricsWhenNoPendingAutocorrectExists) {
manager_.OnBlur();
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/0,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
OnBlurDoesNoRecordMetricsWhenInputContextIsNull) {
// Make Input context null.
IMEBridge::Get()->SetInputContextHandler(nullptr);
manager_.OnBlur();
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/0,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/0);
}
TEST_F(AutocorrectManagerTest, OnFocusRecordsMetricsWhenClearingRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnFocus(1);
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/1);
}
TEST_F(AutocorrectManagerTest,
OnFocusDoesNoRecordMetricsWhenNoPendingAutocorrectExists) {
manager_.OnFocus(1);
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/0,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
HandleAutocorrectRecordsMetricsWhenNoPendingAutocorrectExists) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
HandleAutocorrectDoesNotRecordMetricsWhenSetRangeFails) {
// Disable autocorrect.
mock_ime_input_context_handler_.set_autocorrect_enabled(false);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/0,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
HandleAutocorrectRecordsMetricsWhenAcceptingPendingAutocorrect) {
// Create a pending autocorrect range.
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
// Create a new autocorrect range.
manager_.HandleAutocorrect(gfx::Range(4, 7), u"cn", u"can");
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/2,
/*reverted=*/0, /*accepted=*/1,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
HandleAutocorrectRecordsMetricsWithPendingRangeAndFailedSetRange) {
// Enable Autocorrect.
mock_ime_input_context_handler_.set_autocorrect_enabled(true);
// Create a pending autocorrect range.
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
// Disable autocorrect.
mock_ime_input_context_handler_.set_autocorrect_enabled(false);
// Create a new autocorrect range.
manager_.HandleAutocorrect(gfx::Range(4, 7), u"cn", u"can");
// This case should not happen in practice, but the expected result
// is counting the first autocorrect as rejected given there is no way
// to know if it was accepted.
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/1);
}
TEST_F(AutocorrectManagerTest,
HandleAutocorrectRecordsMetricsWhenClearingPendingAutocorrect) {
// Create a pending autocorrect range.
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
// Clear the previous autocorrect range.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
// Handle a new range.
manager_.HandleAutocorrect(gfx::Range(4, 7), u"cn", u"can");
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/2,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/1);
}
TEST_F(AutocorrectManagerTest,
HandleAutocorrectRecordsMetricsCorrectlyForNullInputContext) {
// Create a pending autocorrect range.
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
// Make Input context null.
IMEBridge::Get()->SetInputContextHandler(nullptr);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// The pending range must be counted as invalid, but `underlined` metric must
// not be incremented with the empty input context.
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline*/ 0,
/*invalid_range*/ 1);
// When there is no pending autocorrect range, nothing is incremented.
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline*/ 0,
/*invalid_range*/ 1);
}
TEST_F(AutocorrectManagerTest,
HandleAutocorrectRecordsMetricsForEmptyInputAndNoPendingRange) {
// Empty input range does not change autocorrect range.
manager_.HandleAutocorrect(gfx::Range(), u"", u"");
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/0,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
HandleAutocorrectRecordsMetricsForEmptyInputAndPendingRange) {
// When there is a pending autocorrect, empty input range makes the pending
// to be counted as accepted.
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.HandleAutocorrect(gfx::Range(), u"", u"");
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/1,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
HandleAutocorrectRecordsMetricsForEmptyInputAndClearedPending) {
// When there is a pending autocorrect, but cleared beforehand,
// empty input range makes the pending to be counted as cleared.
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.HandleAutocorrect(gfx::Range(), u"", u"");
manager_.OnSurroundingTextChanged(u"", gfx::Range(0));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/1);
}
TEST_F(AutocorrectManagerTest,
InsertingCharsDoesNotRecordMetricsForStaleAndAcceptedRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the abc", gfx::Range(7));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/1,
/*cleared_underline=*/0);
// Set stale autocorrect range.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(0, 3),
base::DoNothing());
// Adding extra character should not double count.
manager_.OnSurroundingTextChanged(u"the abcd", gfx::Range(8));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/1,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
InsertingCharsDoesNotRecordMetricsForStaleAndClearedRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/1);
// Set stale cleared range.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(0, 3),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"the abc", gfx::Range(7));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/1);
}
TEST_F(AutocorrectManagerTest,
AutocorrectHandlerDoesNotRecordMetricsForStaleAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the abc", gfx::Range(7));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/1,
/*cleared_underline=*/0);
// Set stale autocorrect range.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(0, 3),
base::DoNothing());
// Handle a new autocorrect and ensure the metric is not increased twice.
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/2,
/*reverted=*/0, /*accepted=*/1,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
OnBlurDoesNotRecordMetricsForStaleAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the abc", gfx::Range(7));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/1,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/0);
// Set stale autocorrect range.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(0, 3),
base::DoNothing());
// Handle a new autocorrect and ensure the metric is not increase twice.
manager_.OnBlur();
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/1,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
OnFocusDoesNotRecordMetricsForStaleAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
// Accept autocorrect implicitly.
manager_.OnBlur();
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/1);
// Set stale autocorrect range.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(0, 3),
base::DoNothing());
// Handle a new autocorrect and ensure the metric is not increase twice.
manager_.OnFocus(1);
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/1);
}
TEST_F(AutocorrectManagerTest, ImplicitAcceptanceClearsAutocorrectRange) {
manager_.HandleAutocorrect(gfx::Range(0, 7), u"smeone", u"someone");
manager_.OnSurroundingTextChanged(u"someone ", gfx::Range(8));
// Ensure range is as expected.
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(0, 7));
// Implicitly accept autocorrect by three character insertion.
manager_.OnSurroundingTextChanged(u"someone abc", gfx::Range(11));
EXPECT_TRUE(mock_ime_input_context_handler_.GetAutocorrectRange().is_empty());
}
TEST_F(AutocorrectManagerTest, AsyncDelayDoesNotMakeAutocorrectAccepted) {
// To commit autocorrect, a delete operation is first applied then an insert.
// In the case of async delay, the surrounding text related to each of these
// operations might be received after handling the range but needs to be
// ignored by validation process.
manager_.HandleAutocorrect(gfx::Range(0, 7), u"smeone", u"someone");
// Late surrounding text related to IME delete.
manager_.OnSurroundingTextChanged(u"s ", gfx::Range(1));
// Late surrounding text related to IME insert.
manager_.OnSurroundingTextChanged(u"someone ", gfx::Range(8));
// Autocorrect range is not cleared by the stale surrounding text.
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(0, 7));
}
TEST_F(AutocorrectManagerTest,
ImplicitAcceptanceRecordsMetricsAndIgnoresAsyncStaleData) {
manager_.HandleAutocorrect(gfx::Range(0, 7), u"smeone", u"someone");
// Late surrounding text related to IME delete.
manager_.OnSurroundingTextChanged(u"s ", gfx::Range(1));
// Late surrounding text related to IME insert.
manager_.OnSurroundingTextChanged(u"someone ", gfx::Range(8));
// User adds two characters.
manager_.OnSurroundingTextChanged(u"someone ab", gfx::Range(10));
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(0, 7));
// Third character, implicitly accepts autocorrect.
manager_.OnSurroundingTextChanged(u"someone abc", gfx::Range(11));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/1,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
RecordMetricsForVkWhenVkWasVisibleAtUnderlineTime) {
// VK is visible at the time of suggesting an autocorrect.
keyboard_client_->set_keyboard_enabled_for_test(true);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// To suppress strict mock.
EXPECT_CALL(mock_suggestion_handler_, SetAssistiveWindowProperties(_, _, _));
// VK is made hidden, but still the metrics need to be recorded for VK
// given VK was visible at underline time.
keyboard_client_->set_keyboard_enabled_for_test(false);
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/true,
/*window_shown=*/1, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
DoesNotRecordMetricsForVkWhenVkWasNotVisibleAtUnderlineTime) {
// VK is not visible at the time of suggesting an autocorrect.
keyboard_client_->set_keyboard_enabled_for_test(false);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// To suppress strict mock.
EXPECT_CALL(mock_suggestion_handler_, SetAssistiveWindowProperties(_, _, _));
// VK is made visible, but still metrics must not be recorded for VK
// as it was not visible at the time of underline.
keyboard_client_->set_keyboard_enabled_for_test(true);
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/1, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest, UndoRecordsMetricsAfterRevert) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.UndoAutocorrect();
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/1, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/0);
}
TEST_F(AutocorrectManagerTest, UndoRecordsMetricsAfterRevertEnableByDefault) {
feature_list_.Reset();
feature_list_.InitWithFeatures({features::kAutocorrectByDefault},
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.UndoAutocorrect();
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/1, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/0,
/*invalid_range=*/0,
/*enabled_by_default=*/true);
}
TEST_F(AutocorrectManagerTest, HandleAutocorrectRecordsMetricsWhenVkIsVisible) {
keyboard_client_->set_keyboard_enabled_for_test(true);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/true,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest, ExitingTextFieldRecordsMetricsWhenVkIsVisible) {
keyboard_client_->set_keyboard_enabled_for_test(true);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnBlur();
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/true,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/1);
}
TEST_F(AutocorrectManagerTest,
AcceptingAutocorrectRecordsMetricsWhenVkIsVisible) {
keyboard_client_->set_keyboard_enabled_for_test(true);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
// Implicitly accept autocorrect
manager_.OnSurroundingTextChanged(u"the abc", gfx::Range(7));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/true,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/1,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/0);
}
TEST_F(AutocorrectManagerTest, ThreeValidationFailuresDoesNotClearRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Three validation failures.
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
// Range is not cleared.
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(0, 3));
}
TEST_F(AutocorrectManagerTest, FourValidationFailuresClearsRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Four validation failure.
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
EXPECT_TRUE(mock_ime_input_context_handler_.GetAutocorrectRange().is_empty());
}
TEST_F(AutocorrectManagerTest, InvalidRangeFailsValidationAndClearsRange) {
manager_.HandleAutocorrect(gfx::Range(2, 5), u"teh", u"the");
// Four validation failure because the range is invalid.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
EXPECT_TRUE(mock_ime_input_context_handler_.GetAutocorrectRange().is_empty());
}
TEST_F(AutocorrectManagerTest,
FourValidationFailuresRecordsMetricsForInvalidRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Four validation failure.
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/0,
/*invalid_range*/ 1);
}
TEST_F(AutocorrectManagerTest, UndoRecordsMetricsWhenVkIsVisible) {
keyboard_client_->set_keyboard_enabled_for_test(true);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.UndoAutocorrect();
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/true,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/1, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/0);
}
TEST_F(AutocorrectManagerTest,
ClearingAutocorrectRecordsMetricsWhenVkIsVisible) {
keyboard_client_->set_keyboard_enabled_for_test(true);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/true,
/*window_shown=*/0, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/1,
/*exited_text_field_with_underline=*/0);
}
TEST_F(AutocorrectManagerTest, ConsistentAsyncDelayClearsRangeIncorrectly) {
// This is a case that if happens in practice will cause the Autocorrect
// logic to fail. Here, imagine that with any user input, autocorrect range
// is updated in the text input client with a delay. So, validation never
// succeeds because the range is always one step old.
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Each OnSurroundingTextChanged is received with stale autocorrect range
// belonging to the previous state.
manager_.OnSurroundingTextChanged(u"athe ", gfx::Range(1));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(1, 4),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"abthe ", gfx::Range(2));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(2, 5),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"abcthe ", gfx::Range(3));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(3, 6),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"abcdthe ", gfx::Range(4));
// Expect that the validation fails.
EXPECT_TRUE(mock_ime_input_context_handler_.GetAutocorrectRange().is_empty());
}
TEST_F(AutocorrectManagerTest,
AutocorrectIsIncorrectlyAcceptedWhenStaleRangeAndNewSuggestionMatch) {
// This is a case that has no solution to prevent and can result in
// an incorrect autocorrect behaviour when happening.
manager_.HandleAutocorrect(gfx::Range(0, 4), u"ths", u"this");
manager_.HandleAutocorrect(gfx::Range(5, 9), u"ths", u"this");
// Set stale autocorrect range.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(0, 4),
base::DoNothing());
// Surrounding text changed is stale (updated one is 'this this').
// The range is now validated because stale range matches the new suggestion.
manager_.OnSurroundingTextChanged(u"this t", gfx::Range(6));
// Updated surrounding text counts three insertions.
manager_.OnSurroundingTextChanged(u"this this ", gfx::Range(10));
// The range is accepted incorrectly.
EXPECT_TRUE(mock_ime_input_context_handler_.GetAutocorrectRange().is_empty());
}
TEST_F(AutocorrectManagerTest, InvalidOriginalTextArgClearsRange) {
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(0, 3),
base::DoNothing());
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(0, 3));
// Original text is empty and invalid.
manager_.HandleAutocorrect(gfx::Range(0, 3), u"", u"the");
EXPECT_TRUE(mock_ime_input_context_handler_.GetAutocorrectRange().is_empty());
}
TEST_F(AutocorrectManagerTest, InvalidOriginalTextArgDoesNotRecordMetrics) {
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(0, 3),
base::DoNothing());
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(0, 3));
manager_.HandleAutocorrect(gfx::Range(0, 3), u"", u"the");
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/0,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/0);
}
TEST_F(AutocorrectManagerTest, EmptySuggestedTextArgClearsRange) {
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(0, 3),
base::DoNothing());
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(0, 3));
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"");
EXPECT_TRUE(mock_ime_input_context_handler_.GetAutocorrectRange().is_empty());
}
TEST_F(AutocorrectManagerTest, EmptySuggestedTextArgDoesNotRecordMetrics) {
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(0, 3),
base::DoNothing());
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(0, 3));
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"");
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/0,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/0);
}
TEST_F(AutocorrectManagerTest, RangeAndSuggestionMismatchDoesNotRecordMetrics) {
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(0, 3),
base::DoNothing());
EXPECT_EQ(mock_ime_input_context_handler_.GetAutocorrectRange(),
gfx::Range(0, 3));
manager_.HandleAutocorrect(gfx::Range(0, 4), u"teh", u"");
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
/*window_shown=*/0, /*underlined=*/0,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0,
/*exited_text_field_with_underline=*/0);
}
TEST_F(AutocorrectManagerTest, ShowingUndoWindowRecordsMetricsWhenVkIsVisible) {
keyboard_client_->set_keyboard_enabled_for_test(true);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// This suppresses strict mock.
EXPECT_CALL(mock_suggestion_handler_, SetAssistiveWindowProperties(_, _, _));
manager_.OnSurroundingTextChanged(u"the", gfx::Range(0));
ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/true,
/*window_shown=*/1, /*underlined=*/1,
/*reverted=*/0, /*accepted=*/0,
/*cleared_underline=*/0);
}
TEST_F(AutocorrectManagerTest, RecordQualityBreakdownForAccentChange) {
manager_.HandleAutocorrect(gfx::Range(0, 8), u"francais", u"français");
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"français ", gfx::Range(9));
manager_.OnSurroundingTextChanged(u"français abc", gfx::Range(12));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionChangedAccent, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionMutatedLetters, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kOriginalTextIsAscii, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionResolved, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2QualityPkAcceptedHistName,
4);
}
TEST_F(AutocorrectManagerTest, RecordQualityBreakdownForWordSplit) {
manager_.HandleAutocorrect(gfx::Range(0, 11), u"helloworld", u"hello world");
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"hello world ", gfx::Range(12));
manager_.OnSurroundingTextChanged(u"hello world abc", gfx::Range(15));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionSplittedWord, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionInsertedLetters, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kOriginalTextIsAscii, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestedTextIsAscii, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionResolved, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2QualityPkAcceptedHistName,
5);
}
TEST_F(AutocorrectManagerTest, RecordQualityBreakdownForRemovingLetters) {
manager_.HandleAutocorrect(gfx::Range(0, 8), u"françaisss", u"français");
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"français ", gfx::Range(9));
manager_.OnSurroundingTextChanged(u"français abc", gfx::Range(12));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionRemovedLetters, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionResolved, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2QualityPkAcceptedHistName,
2);
}
TEST_F(AutocorrectManagerTest, RecordQualityBreakdownForCapitalizedWorld) {
manager_.HandleAutocorrect(gfx::Range(0, 1), u"i", u"I");
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"I ", gfx::Range(2));
manager_.OnSurroundingTextChanged(u"I have", gfx::Range(6));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionCapitalizedWord, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kOriginalTextIsAscii, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestedTextIsAscii, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionMutatedLetters, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionChangeLetterCases, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionResolved, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2QualityPkAcceptedHistName,
6);
}
TEST_F(AutocorrectManagerTest, RecordQualityBreakdownForLowerCasedLetter) {
manager_.HandleAutocorrect(gfx::Range(0, 8), u"Français", u"français");
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"français ", gfx::Range(9));
manager_.OnSurroundingTextChanged(u"français abc", gfx::Range(12));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionLowerCasedWord, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionResolved, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionMutatedLetters, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionChangeLetterCases, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2QualityPkAcceptedHistName,
4);
}
TEST_F(AutocorrectManagerTest, RecordQualityBreakdownForDefaultPkAccepted) {
feature_list_.Reset();
feature_list_.InitWithFeatures({features::kAutocorrectByDefault},
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.HandleAutocorrect(gfx::Range(0, 8), u"françaisss", u"français");
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"français ", gfx::Range(9));
manager_.OnSurroundingTextChanged(u"français abc", gfx::Range(12));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityDefaultPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionRemovedLetters, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityDefaultPkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionResolved, 1);
histogram_tester_.ExpectTotalCount(
kAutocorrectV2QualityDefaultPkAcceptedHistName, 2);
histogram_tester_.ExpectTotalCount(kAutocorrectV2QualityPkAcceptedHistName,
2);
}
TEST_F(AutocorrectManagerTest, RecordQualityBreakdownForVkAccepted) {
keyboard_client_->set_keyboard_enabled_for_test(true);
manager_.HandleAutocorrect(gfx::Range(0, 8), u"françaisss", u"français");
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"français ", gfx::Range(9));
manager_.OnSurroundingTextChanged(u"français abc", gfx::Range(12));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityVkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionRemovedLetters, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityVkAcceptedHistName,
AutocorrectQualityBreakdown::kSuggestionResolved, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2QualityVkAcceptedHistName,
2);
}
TEST_F(AutocorrectManagerTest, RecordQualityBreakdownForVkRejected) {
keyboard_client_->set_keyboard_enabled_for_test(true);
manager_.HandleAutocorrect(gfx::Range(0, 8), u"françaisss", u"français");
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"français ", gfx::Range(9));
// Clear range.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"franças ", gfx::Range(8));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityVkRejectedHistName,
AutocorrectQualityBreakdown::kSuggestionRemovedLetters, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityVkRejectedHistName,
AutocorrectQualityBreakdown::kSuggestionResolved, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2QualityVkRejectedHistName,
2);
}
TEST_F(AutocorrectManagerTest, RecordQualityBreakdownForPkRejected) {
manager_.HandleAutocorrect(gfx::Range(0, 8), u"françaisss", u"français");
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"français ", gfx::Range(9));
// Clear range.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"franças ", gfx::Range(8));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkRejectedHistName,
AutocorrectQualityBreakdown::kSuggestionRemovedLetters, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityPkRejectedHistName,
AutocorrectQualityBreakdown::kSuggestionResolved, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2QualityPkRejectedHistName,
2);
histogram_tester_.ExpectTotalCount(
kAutocorrectV2QualityDefaultPkRejectedHistName, 0);
}
TEST_F(AutocorrectManagerTest, RecordQualityBreakdownDefaultForPkRejected) {
feature_list_.Reset();
feature_list_.InitWithFeatures({features::kAutocorrectByDefault},
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.HandleAutocorrect(gfx::Range(0, 8), u"françaisss", u"français");
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"français ", gfx::Range(9));
// Clear range.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"franças ", gfx::Range(8));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityDefaultPkRejectedHistName,
AutocorrectQualityBreakdown::kSuggestionRemovedLetters, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2QualityDefaultPkRejectedHistName,
AutocorrectQualityBreakdown::kSuggestionResolved, 1);
histogram_tester_.ExpectTotalCount(
kAutocorrectV2QualityDefaultPkRejectedHistName, 2);
histogram_tester_.ExpectTotalCount(kAutocorrectV2QualityPkRejectedHistName,
2);
}
TEST_F(AutocorrectManagerTest, RecordDistanceMetricForVkAccepted) {
keyboard_client_->set_keyboard_enabled_for_test(true);
manager_.HandleAutocorrect(gfx::Range(0, 4), u"cafe", u"cafè");
// (|cafe|-1) * MAX_LENGTH + (|{'e'->'è'}| - 1)
int expected_value = (4 - 1) * 30 + (1 - 1);
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"cafè ", gfx::Range(5));
manager_.OnSurroundingTextChanged(u"cafè abc", gfx::Range(8));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2Distance2dVkAcceptedHistName, expected_value, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2DistanceSuggestedVkAcceptedHistName, 4, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2Distance2dVkAcceptedHistName,
1);
histogram_tester_.ExpectTotalCount(
kAutocorrectV2DistanceSuggestedVkAcceptedHistName, 1);
}
TEST_F(AutocorrectManagerTest, RecordDistanceMetricForPkAccepted) {
manager_.HandleAutocorrect(gfx::Range(0, 1), u"i", u"I");
// (|i|-1) * MAX_LENGTH + (|{'i'->'I'}| - 1)
int expected_value = (1 - 1) * 30 + (1 - 1);
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"I ", gfx::Range(2));
manager_.OnSurroundingTextChanged(u"I abc", gfx::Range(5));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2Distance2dPkAcceptedHistName, expected_value, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2DistanceSuggestedPkAcceptedHistName, 1, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2Distance2dPkAcceptedHistName,
1);
histogram_tester_.ExpectTotalCount(
kAutocorrectV2DistanceSuggestedPkAcceptedHistName, 1);
}
TEST_F(AutocorrectManagerTest, RecordDistanceMetricForVkRejected) {
keyboard_client_->set_keyboard_enabled_for_test(true);
manager_.HandleAutocorrect(gfx::Range(0, 12), u"ecauserthy", u"because they");
// (|ecauserthy|-1) * MAX_LENGTH + (|{''->'b'}, {'r'->' '}, {''->'e'}| - 1)
int expected_value = (10 - 1) * 30 + (3 - 1);
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"because they ", gfx::Range(13));
// Clear range.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"because ", gfx::Range(8));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2Distance2dVkRejectedHistName, expected_value, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2DistanceSuggestedVkRejectedHistName, 12, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2Distance2dVkRejectedHistName,
1);
histogram_tester_.ExpectTotalCount(
kAutocorrectV2DistanceSuggestedVkRejectedHistName, 1);
}
TEST_F(AutocorrectManagerTest, RecordDistanceMetricForPkRejected) {
manager_.HandleAutocorrect(
gfx::Range(0, 42),
u"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
u"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
// (min(|<word1>|, MAX_LENGTH) - 1) * MAX_LENGTH +
// (min(<number of changes>, MAX_LENGTH) - 1)
int expected_value = (30 - 1) * 30 + (30 - 1);
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(
u"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb ", gfx::Range(43));
// Clear range.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(
u"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ",
gfx::Range(55));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2Distance2dPkRejectedHistName, expected_value, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2DistanceSuggestedPkRejectedHistName, 30, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2Distance2dPkRejectedHistName,
1);
histogram_tester_.ExpectTotalCount(
kAutocorrectV2DistanceSuggestedPkRejectedHistName, 1);
}
TEST_F(AutocorrectManagerTest, DistanceMetricNoChange) {
manager_.HandleAutocorrect(gfx::Range(0, 9), u"no change", u"no change");
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"no change ", gfx::Range(10));
manager_.OnSurroundingTextChanged(u"no change abc", gfx::Range(13));
manager_.HandleAutocorrect(gfx::Range(0, 9), u"", u"not empty");
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"not empty ", gfx::Range(10));
manager_.OnSurroundingTextChanged(u"not empty abc", gfx::Range(13));
histogram_tester_.ExpectTotalCount(
kAutocorrectV2DistanceSuggestedPkAcceptedHistName, 0);
histogram_tester_.ExpectTotalCount(
kAutocorrectV2DistanceSuggestedPkAcceptedHistName, 0);
}
TEST_F(AutocorrectManagerTest, RecordDistanceMetricNoOverlap) {
manager_.HandleAutocorrect(gfx::Range(0, 32), u"aaaa",
u"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
// (|aaaa|-1) * MAX_LENGTH + (min(<number of changes>, MAX_LENGTH) - 1)
int expected_value1 = (4 - 1) * 30 + (30 - 1);
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb ",
gfx::Range(33));
manager_.OnSurroundingTextChanged(u"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb abc",
gfx::Range(35));
manager_.HandleAutocorrect(gfx::Range(0, 4), u"aaaaa", u"aaaa");
// (|aaaaa|-1) * MAX_LENGTH + (|{'a'->''}| - 1)
int expected_value2 = (5 - 1) * 30 + (1 - 1);
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"aaaa ", gfx::Range(5));
manager_.OnSurroundingTextChanged(u"aaaa abc", gfx::Range(8));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2Distance2dPkAcceptedHistName, expected_value1, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2Distance2dPkAcceptedHistName, expected_value2, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2DistanceSuggestedPkAcceptedHistName, 30, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2DistanceSuggestedPkAcceptedHistName, 4, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2Distance2dPkAcceptedHistName,
2);
histogram_tester_.ExpectTotalCount(
kAutocorrectV2DistanceSuggestedPkAcceptedHistName, 2);
}
TEST_F(AutocorrectManagerTest, RecordDistanceMetricAlmostMaxLength) {
manager_.HandleAutocorrect(gfx::Range(0, 1), u"iiiiiiiiiiiiiiiiiiiiiiiiiiiii",
u"I");
// (|<word1>| - 1) * MAX_LENGTH + (<number of changes> - 1)
int expected_value = (29 - 1) * 30 + (29 - 1);
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"I ", gfx::Range(2));
manager_.OnSurroundingTextChanged(u"I abc", gfx::Range(5));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2Distance2dPkAcceptedHistName, expected_value, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2Distance2dPkAcceptedHistName,
1);
}
TEST_F(AutocorrectManagerTest, RecordRejectionForPkUndoWithKeyboard) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
{
::testing::InSequence seq;
AssistiveWindowProperties shown_properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
ui::ime::AssistiveWindowButton undo_button =
CreateHighlightedUndoButton(u"teh");
EXPECT_CALL(mock_suggestion_handler_,
SetButtonHighlighted(_, undo_button, true, _));
ui::ime::AssistiveWindowButton learn_more_button =
CreateHighlightedLearnMoreButton();
EXPECT_CALL(mock_suggestion_handler_,
SetButtonHighlighted(_, learn_more_button, false, _));
AssistiveWindowProperties hidden_properties =
CreateHiddenUndoWindowProperties();
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, hidden_properties, _));
}
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(1));
manager_.OnKeyEvent(CreateKeyEvent(ui::DomKey::NONE, ui::DomCode::ARROW_UP));
manager_.OnKeyEvent(CreateKeyEvent(ui::DomKey::NONE, ui::DomCode::ENTER));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2PkRejectionHistName,
AutocorrectRejectionBreakdown::kUndoWithKeyboard, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2PkRejectionHistName,
AutocorrectRejectionBreakdown::kSuggestionRejected, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2PkRejectionHistName, 2);
}
TEST_F(AutocorrectManagerTest, RecordRejectionForPkUndoControlZ) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnKeyEvent(PressKeyWithCtrl(ui::DomCode::US_Z));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
histogram_tester_.ExpectBucketCount(kAutocorrectV2PkRejectionHistName,
AutocorrectRejectionBreakdown::kUndoCtrlZ,
1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2PkRejectionHistName,
AutocorrectRejectionBreakdown::kSuggestionRejected, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2PkRejectionHistName, 2);
}
TEST_F(AutocorrectManagerTest, RecordRejectionForPkControlBackspace) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnKeyEvent(PressKeyWithCtrl(ui::DomCode::BACKSPACE));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"", gfx::Range(0));
histogram_tester_.ExpectBucketCount(
kAutocorrectV2PkRejectionHistName,
AutocorrectRejectionBreakdown::kRejectedCtrlBackspace, 1);
histogram_tester_.ExpectBucketCount(
kAutocorrectV2PkRejectionHistName,
AutocorrectRejectionBreakdown::kSuggestionRejected, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2PkRejectionHistName, 2);
}
TEST_F(
AutocorrectManagerTest,
IsNotDisabledWhenNoSuggestionProviderAndAutocorrectByDefaultFlagIsDisabled) {
feature_list_.Reset();
feature_list_.InitWithFeatures(
/*enabled_features=*/{},
/*disabled_features=*/DisabledFeaturesIncludingAutocorrectByDefault());
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
EXPECT_FALSE(manager_.DisabledByInvalidExperimentContext());
}
TEST_F(AutocorrectManagerTest,
IsNotDisabledWhenNoSuggestionProviderAndUserExplicitlyEnablesPref) {
EnableAutocorrect(/*profile=*/*profile_, /*engine_id=*/kUsEnglishEngineId);
feature_list_.Reset();
feature_list_.InitWithFeatures(RequiredForAutocorrectByDefault(),
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
EXPECT_FALSE(manager_.DisabledByInvalidExperimentContext());
}
TEST_F(AutocorrectManagerTest,
IsNotDisabledWhenNoSuggestionProviderAndUserExplicitlyDisablesPref) {
DisableAutocorrect(/*profile=*/*profile_, /*engine_id=*/kUsEnglishEngineId);
feature_list_.Reset();
feature_list_.InitWithFeatures(RequiredForAutocorrectByDefault(),
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
EXPECT_FALSE(manager_.DisabledByInvalidExperimentContext());
}
TEST_F(AutocorrectManagerTest,
IsNotDisabledWhenNoSuggestionProviderAndVkIsVisible) {
keyboard_client_->set_keyboard_enabled_for_test(true);
feature_list_.Reset();
feature_list_.InitWithFeatures(RequiredForAutocorrectByDefault(),
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
EXPECT_FALSE(manager_.DisabledByInvalidExperimentContext());
}
class NotDisabledByInvalidSuggestionProvider
: public AutocorrectManagerTest,
public testing::WithParamInterface<AutocorrectSuggestionProvider> {};
INSTANTIATE_TEST_SUITE_P(
AutocorrectManagerTest,
NotDisabledByInvalidSuggestionProvider,
testing::ValuesIn<AutocorrectSuggestionProvider>({
AutocorrectSuggestionProvider::kUnknown,
AutocorrectSuggestionProvider::kUsEnglishPrebundled,
AutocorrectSuggestionProvider::kUsEnglishDownloaded,
AutocorrectSuggestionProvider::kUsEnglish840,
AutocorrectSuggestionProvider::kUsEnglish840V2,
}),
[](const testing::TestParamInfo<AutocorrectSuggestionProvider> info) {
return ToString(info.param);
});
TEST_P(NotDisabledByInvalidSuggestionProvider,
WhenAutocorrectByDefaultFlagDisabled) {
feature_list_.Reset();
feature_list_.InitWithFeatures(
/*enabled_features=*/{},
/*disabled_features=*/DisabledFeaturesIncludingAutocorrectByDefault());
const AutocorrectSuggestionProvider& provider = GetParam();
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
manager_.OnConnectedToSuggestionProvider(provider);
EXPECT_FALSE(manager_.DisabledByInvalidExperimentContext());
}
TEST_P(NotDisabledByInvalidSuggestionProvider, WhenUserExplicitlyEnablesPref) {
const AutocorrectSuggestionProvider& provider = GetParam();
EnableAutocorrect(/*profile=*/*profile_, /*engine_id=*/kUsEnglishEngineId);
feature_list_.Reset();
feature_list_.InitWithFeatures(RequiredForAutocorrectByDefault(),
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
manager_.OnConnectedToSuggestionProvider(provider);
EXPECT_FALSE(manager_.DisabledByInvalidExperimentContext());
}
TEST_P(NotDisabledByInvalidSuggestionProvider, WhenUserExplicitlyDisablesPref) {
const AutocorrectSuggestionProvider& provider = GetParam();
DisableAutocorrect(/*profile=*/*profile_, /*engine_id=*/kUsEnglishEngineId);
feature_list_.Reset();
feature_list_.InitWithFeatures(RequiredForAutocorrectByDefault(),
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
manager_.OnConnectedToSuggestionProvider(provider);
EXPECT_FALSE(manager_.DisabledByInvalidExperimentContext());
}
TEST_P(NotDisabledByInvalidSuggestionProvider, WhenVkIsVisible) {
const AutocorrectSuggestionProvider& provider = GetParam();
keyboard_client_->set_keyboard_enabled_for_test(true);
feature_list_.Reset();
feature_list_.InitWithFeatures(RequiredForAutocorrectByDefault(),
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
manager_.OnConnectedToSuggestionProvider(provider);
EXPECT_FALSE(manager_.DisabledByInvalidExperimentContext());
}
TEST_F(AutocorrectManagerTest,
IsDisabledWhenNoSuggestionProviderAndUserInDefaultBucket) {
feature_list_.Reset();
feature_list_.InitWithFeatures(RequiredForAutocorrectByDefault(),
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
EXPECT_TRUE(manager_.DisabledByInvalidExperimentContext());
}
TEST_F(AutocorrectManagerTest,
IsDisabledWhenMissingNewModelParametersButEn840Enabled) {
feature_list_.Reset();
feature_list_.InitWithFeatures({ash::features::kAutocorrectByDefault},
{ash::features::kImeFstDecoderParamsUpdate,
ash::features::kImeRuleConfig});
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
manager_.OnConnectedToSuggestionProvider(
AutocorrectSuggestionProvider::kUsEnglish840);
EXPECT_TRUE(manager_.DisabledByInvalidExperimentContext());
}
class EnabledByValidSuggestionProvider
: public AutocorrectManagerTest,
public testing::WithParamInterface<AutocorrectSuggestionProvider> {};
INSTANTIATE_TEST_SUITE_P(
AutocorrectManagerTest,
EnabledByValidSuggestionProvider,
testing::ValuesIn<>({
AutocorrectSuggestionProvider::kUsEnglish840,
AutocorrectSuggestionProvider::kUsEnglish840V2,
}),
[](const testing::TestParamInfo<AutocorrectSuggestionProvider> info) {
return ToString(info.param);
});
TEST_P(EnabledByValidSuggestionProvider,
IsNotDisabledWhenUserInDefaultBucketAndValidSuggestionProviderUsed) {
const AutocorrectSuggestionProvider& provider = GetParam();
feature_list_.Reset();
feature_list_.InitWithFeatures(RequiredForAutocorrectByDefault(),
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
manager_.OnConnectedToSuggestionProvider(provider);
EXPECT_FALSE(manager_.DisabledByInvalidExperimentContext());
}
class DisabledByInvalidSuggestionProvider
: public AutocorrectManagerTest,
public testing::WithParamInterface<AutocorrectSuggestionProvider> {};
INSTANTIATE_TEST_SUITE_P(
AutocorrectManagerTest,
DisabledByInvalidSuggestionProvider,
testing::ValuesIn<>({
AutocorrectSuggestionProvider::kUnknown,
AutocorrectSuggestionProvider::kUsEnglishPrebundled,
AutocorrectSuggestionProvider::kUsEnglishDownloaded,
}),
[](const testing::TestParamInfo<AutocorrectSuggestionProvider> info) {
return ToString(info.param);
});
TEST_P(DisabledByInvalidSuggestionProvider, WhenUserInDefaultExperiment) {
const AutocorrectSuggestionProvider& provider = GetParam();
feature_list_.Reset();
feature_list_.InitWithFeatures(RequiredForAutocorrectByDefault(),
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
manager_.OnConnectedToSuggestionProvider(provider);
EXPECT_TRUE(manager_.DisabledByInvalidExperimentContext());
}
struct RejectCase {
std::string test_name;
bool vk_enabled;
std::string histogram_name;
};
class RejectMetric : public AutocorrectManagerTest,
public testing::WithParamInterface<RejectCase> {};
TEST_P(RejectMetric, RecordRejectionForMetricOther) {
const RejectCase& test_case = GetParam();
keyboard_client_->set_keyboard_enabled_for_test(test_case.vk_enabled);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// Accept autocorrect implicitly.
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
// Clear range.
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
histogram_tester_.ExpectBucketCount(
test_case.histogram_name, AutocorrectRejectionBreakdown::kRejectionOther,
1);
histogram_tester_.ExpectBucketCount(
test_case.histogram_name,
AutocorrectRejectionBreakdown::kSuggestionRejected, 1);
histogram_tester_.ExpectTotalCount(test_case.histogram_name, 2);
}
TEST_P(RejectMetric, RecordRejectionForVkUndo) {
const RejectCase& test_case = GetParam();
keyboard_client_->set_keyboard_enabled_for_test(test_case.vk_enabled);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.UndoAutocorrect();
histogram_tester_.ExpectBucketCount(
test_case.histogram_name,
AutocorrectRejectionBreakdown::kUndoWithoutKeyboard, 1);
histogram_tester_.ExpectBucketCount(
test_case.histogram_name,
AutocorrectRejectionBreakdown::kSuggestionRejected, 1);
histogram_tester_.ExpectTotalCount(test_case.histogram_name, 2);
}
TEST_P(RejectMetric, RecordRejectionForBackspace) {
const RejectCase& test_case = GetParam();
keyboard_client_->set_keyboard_enabled_for_test(test_case.vk_enabled);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
if (!test_case.vk_enabled) {
manager_.OnKeyEvent(
CreateKeyEvent(ui::DomKey::NONE, ui::DomCode::BACKSPACE));
}
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"th", gfx::Range(2));
histogram_tester_.ExpectBucketCount(
test_case.histogram_name,
AutocorrectRejectionBreakdown::kRejectedBackspace,
test_case.vk_enabled ? 0 : 1);
histogram_tester_.ExpectBucketCount(
test_case.histogram_name, AutocorrectRejectionBreakdown::kRemovedLetters,
1);
histogram_tester_.ExpectBucketCount(
test_case.histogram_name,
AutocorrectRejectionBreakdown::kSuggestionRejected, 1);
histogram_tester_.ExpectTotalCount(test_case.histogram_name,
test_case.vk_enabled ? 2 : 3);
}
TEST_P(RejectMetric, RecordRejectionForFullSelectionTyping) {
const RejectCase& test_case = GetParam();
keyboard_client_->set_keyboard_enabled_for_test(test_case.vk_enabled);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(0, 3));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"new ", gfx::Range(4));
histogram_tester_.ExpectBucketCount(
test_case.histogram_name,
AutocorrectRejectionBreakdown::kRejectedTypingFull, 1);
histogram_tester_.ExpectBucketCount(
test_case.histogram_name,
AutocorrectRejectionBreakdown::kSuggestionRejected, 1);
histogram_tester_.ExpectTotalCount(test_case.histogram_name, 2);
}
TEST_P(RejectMetric, RecordRejectionForPartialSelectionTyping) {
const RejectCase& test_case = GetParam();
keyboard_client_->set_keyboard_enabled_for_test(test_case.vk_enabled);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(0, 2));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"newe ", gfx::Range(3));
histogram_tester_.ExpectBucketCount(
test_case.histogram_name,
AutocorrectRejectionBreakdown::kRejectedTypingPartial, 1);
histogram_tester_.ExpectBucketCount(
test_case.histogram_name,
AutocorrectRejectionBreakdown::kSuggestionRejected, 1);
histogram_tester_.ExpectTotalCount(test_case.histogram_name, 2);
}
TEST_P(RejectMetric, RecordRejectionForFullWithExternalSelectionTyping) {
const RejectCase& test_case = GetParam();
keyboard_client_->set_keyboard_enabled_for_test(test_case.vk_enabled);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(0, 4));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"new ", gfx::Range(4));
histogram_tester_.ExpectBucketCount(
test_case.histogram_name,
AutocorrectRejectionBreakdown::kRejectedTypingFullWithExternal, 1);
histogram_tester_.ExpectBucketCount(
test_case.histogram_name,
AutocorrectRejectionBreakdown::kSuggestionRejected, 1);
histogram_tester_.ExpectTotalCount(test_case.histogram_name, 2);
}
TEST_P(RejectMetric, RecordRejectionForPartialWithExternalSelectionTyping) {
const RejectCase& test_case = GetParam();
keyboard_client_->set_keyboard_enabled_for_test(test_case.vk_enabled);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(2, 4));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"thnew", gfx::Range(5));
histogram_tester_.ExpectBucketCount(
test_case.histogram_name,
AutocorrectRejectionBreakdown::kRejectedTypingPartialWithExternal, 1);
histogram_tester_.ExpectBucketCount(
test_case.histogram_name,
AutocorrectRejectionBreakdown::kSuggestionRejected, 1);
histogram_tester_.ExpectTotalCount(test_case.histogram_name, 2);
}
TEST_P(RejectMetric, RecordRejectionForTypingNoSelection) {
const RejectCase& test_case = GetParam();
keyboard_client_->set_keyboard_enabled_for_test(test_case.vk_enabled);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
{
::testing::InSequence seq;
AssistiveWindowProperties shown_properties =
CreateVisibleUndoWindowWithLearnMoreButtonProperties(u"teh", u"the");
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, shown_properties, _));
AssistiveWindowProperties hidden_properties =
CreateHiddenUndoWindowProperties();
EXPECT_CALL(mock_suggestion_handler_,
SetAssistiveWindowProperties(_, hidden_properties, _));
}
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(2));
mock_ime_input_context_handler_.SetAutocorrectRange(gfx::Range(),
base::DoNothing());
manager_.OnSurroundingTextChanged(u"thee ", gfx::Range(3));
histogram_tester_.ExpectBucketCount(
test_case.histogram_name,
AutocorrectRejectionBreakdown::kRejectedTypingNoSelection, 1);
histogram_tester_.ExpectBucketCount(
test_case.histogram_name,
AutocorrectRejectionBreakdown::kSuggestionRejected, 1);
histogram_tester_.ExpectTotalCount(test_case.histogram_name, 2);
}
INSTANTIATE_TEST_SUITE_P(
AutocorrectManagerTest,
RejectMetric,
testing::ValuesIn<RejectCase>({
{"VkEnabled",
/*vk_enabled=*/true,
/*histogram_name=*/kAutocorrectV2VkRejectionHistName},
{"VkDisabled",
/*vk_enabled=*/false,
/*histogram_name=*/kAutocorrectV2PkRejectionHistName},
}),
[](const testing::TestParamInfo<RejectCase> info) {
return info.param.test_name;
});
struct PkUserPrefCase {
std::string test_name;
std::string engine_id;
std::optional<int> autocorrect_level;
AutocorrectPreference expected_pref;
};
class PkEnglishUserPreferenceMetric
: public AutocorrectManagerTest,
public testing::WithParamInterface<PkUserPrefCase> {};
INSTANTIATE_TEST_SUITE_P(
AutocorrectManagerTest,
PkEnglishUserPreferenceMetric,
testing::ValuesIn<PkUserPrefCase>({
{"UsEnglishEnabled",
/*engine_id=*/kUsEnglishEngineId,
/*autocorrect_level=*/1,
/*expected_pref=*/AutocorrectPreference::kEnabled},
{"UsEnglishDisabled",
/*engine_id=*/kUsEnglishEngineId,
/*autocorrect_level=*/0,
/*expected_pref=*/AutocorrectPreference::kDisabled},
{"UsEnglishDefault",
/*engine_id=*/kUsEnglishEngineId,
/*autocorrect_level=*/std::nullopt,
/*expected_pref=*/AutocorrectPreference::kEnabledByDefault},
}),
[](const testing::TestParamInfo<PkUserPrefCase> info) {
return info.param.test_name;
});
TEST_P(PkEnglishUserPreferenceMetric, IsNotRecordedWhenKeyEventNotEncountered) {
const PkUserPrefCase& test_case = GetParam();
if (test_case.autocorrect_level) {
SetAutocorrectPreferenceTo(
/*profile=*/*profile_,
/*engine_id=*/test_case.engine_id,
/*autocorrect_level=*/*test_case.autocorrect_level);
}
manager_.OnActivate(test_case.engine_id);
manager_.OnFocus(kContextId);
histogram_tester_.ExpectTotalCount(kAutocorrectV2PkUserPreferenceAll, 0);
histogram_tester_.ExpectTotalCount(kAutocorrectV2PkUserPreferenceEnglish, 0);
}
TEST_P(PkEnglishUserPreferenceMetric, IsNotRecordedWhenKeyEventCameFromTheVk) {
const PkUserPrefCase& test_case = GetParam();
keyboard_client_->set_keyboard_enabled_for_test(true);
if (test_case.autocorrect_level) {
SetAutocorrectPreferenceTo(
/*profile=*/*profile_,
/*engine_id=*/test_case.engine_id,
/*autocorrect_level=*/*test_case.autocorrect_level);
}
manager_.OnActivate(test_case.engine_id);
manager_.OnFocus(kContextId);
manager_.OnKeyEvent(KeyA());
histogram_tester_.ExpectTotalCount(kAutocorrectV2PkUserPreferenceAll, 0);
histogram_tester_.ExpectTotalCount(kAutocorrectV2PkUserPreferenceEnglish, 0);
}
TEST_P(PkEnglishUserPreferenceMetric,
IsRecordedCorrectlyAfterOnFocusThenOnKeyEvent) {
const PkUserPrefCase& test_case = GetParam();
if (test_case.autocorrect_level) {
SetAutocorrectPreferenceTo(
/*profile=*/*profile_,
/*engine_id=*/test_case.engine_id,
/*autocorrect_level=*/*test_case.autocorrect_level);
}
manager_.OnActivate(test_case.engine_id);
manager_.OnFocus(kContextId);
manager_.OnKeyEvent(KeyA());
histogram_tester_.ExpectTotalCount(kAutocorrectV2PkUserPreferenceAll, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2PkUserPreferenceEnglish, 1);
histogram_tester_.ExpectBucketCount(kAutocorrectV2PkUserPreferenceAll,
test_case.expected_pref, 1);
histogram_tester_.ExpectBucketCount(kAutocorrectV2PkUserPreferenceEnglish,
test_case.expected_pref, 1);
}
TEST_P(PkEnglishUserPreferenceMetric,
IsRecordedForEveryOnFocusAndOnKeyEventSequence) {
const PkUserPrefCase& test_case = GetParam();
if (test_case.autocorrect_level) {
SetAutocorrectPreferenceTo(
/*profile=*/*profile_,
/*engine_id=*/test_case.engine_id,
/*autocorrect_level=*/*test_case.autocorrect_level);
}
manager_.OnActivate(test_case.engine_id);
manager_.OnFocus(kContextId);
manager_.OnKeyEvent(KeyA());
manager_.OnFocus(kContextId);
manager_.OnKeyEvent(KeyA());
manager_.OnKeyEvent(KeyA());
histogram_tester_.ExpectTotalCount(kAutocorrectV2PkUserPreferenceAll, 2);
histogram_tester_.ExpectTotalCount(kAutocorrectV2PkUserPreferenceEnglish, 2);
histogram_tester_.ExpectBucketCount(kAutocorrectV2PkUserPreferenceAll,
test_case.expected_pref, 2);
histogram_tester_.ExpectBucketCount(kAutocorrectV2PkUserPreferenceEnglish,
test_case.expected_pref, 2);
}
class PkAllLangsUserPreferenceMetric
: public AutocorrectManagerTest,
public testing::WithParamInterface<PkUserPrefCase> {};
INSTANTIATE_TEST_SUITE_P(
AutocorrectManagerTest,
PkAllLangsUserPreferenceMetric,
testing::ValuesIn<PkUserPrefCase>({
{"UsInternationalEnabled",
/*engine_id=*/kUsInternationalEngineId,
/*autocorrect_level=*/1,
/*expected_pref=*/AutocorrectPreference::kEnabled},
{"UsInternationalDisabled",
/*engine_id=*/kUsInternationalEngineId,
/*autocorrect_level=*/0,
/*expected_pref=*/AutocorrectPreference::kDisabled},
{"UsInternationalDefault",
/*engine_id=*/kUsInternationalEngineId,
/*autocorrect_level=*/std::nullopt,
/*expected_pref=*/AutocorrectPreference::kDefault},
{"SpainSpanishEnabled",
/*engine_id=*/kSpainSpanishEngineId,
/*autocorrect_level=*/1,
/*expected_pref=*/AutocorrectPreference::kEnabled},
{"SpainSpanishDisabled",
/*engine_id=*/kSpainSpanishEngineId,
/*autocorrect_level=*/0,
/*expected_pref=*/AutocorrectPreference::kDisabled},
{"SpainSpanishDefault",
/*engine_id=*/kSpainSpanishEngineId,
/*autocorrect_level=*/std::nullopt,
/*expected_pref=*/AutocorrectPreference::kDefault},
{"LatinAmericaSpanishEnabled",
/*engine_id=*/kLatinAmericaSpanishEngineId,
/*autocorrect_level=*/1,
/*expected_pref=*/AutocorrectPreference::kEnabled},
{"LatinAmericaSpanishDisabled",
/*engine_id=*/kLatinAmericaSpanishEngineId,
/*autocorrect_level=*/0,
/*expected_pref=*/AutocorrectPreference::kDisabled},
{"LatinAmericaSpanishDefault",
/*engine_id=*/kLatinAmericaSpanishEngineId,
/*autocorrect_level=*/std::nullopt,
/*expected_pref=*/AutocorrectPreference::kDefault},
{"BrazilPortugeseEnabled",
/*engine_id=*/kBrazilPortugeseEngineId,
/*autocorrect_level=*/1,
/*expected_pref=*/AutocorrectPreference::kEnabled},
{"BrazilPortugeseDisabled",
/*engine_id=*/kBrazilPortugeseEngineId,
/*autocorrect_level=*/0,
/*expected_pref=*/AutocorrectPreference::kDisabled},
{"BrazilPortugeseDefault",
/*engine_id=*/kBrazilPortugeseEngineId,
/*autocorrect_level=*/std::nullopt,
/*expected_pref=*/AutocorrectPreference::kDefault},
{"FranceFrenchEnabled",
/*engine_id=*/kFranceFrenchEngineId,
/*autocorrect_level=*/1,
/*expected_pref=*/AutocorrectPreference::kEnabled},
{"FranceFrenchDisabled",
/*engine_id=*/kFranceFrenchEngineId,
/*autocorrect_level=*/0,
/*expected_pref=*/AutocorrectPreference::kDisabled},
{"FranceFrenchDefault",
/*engine_id=*/kFranceFrenchEngineId,
/*autocorrect_level=*/std::nullopt,
/*expected_pref=*/AutocorrectPreference::kDefault},
}),
[](const testing::TestParamInfo<PkUserPrefCase> info) {
return info.param.test_name;
});
TEST_P(PkAllLangsUserPreferenceMetric,
IsRecordedCorrectlyAfterOnFocusThenOnKeyEvent) {
const PkUserPrefCase& test_case = GetParam();
if (test_case.autocorrect_level) {
SetAutocorrectPreferenceTo(
/*profile=*/*profile_,
/*engine_id=*/test_case.engine_id,
/*autocorrect_level=*/*test_case.autocorrect_level);
}
manager_.OnActivate(test_case.engine_id);
manager_.OnFocus(kContextId);
manager_.OnKeyEvent(KeyA());
histogram_tester_.ExpectTotalCount(kAutocorrectV2PkUserPreferenceAll, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2PkUserPreferenceEnglish, 0);
histogram_tester_.ExpectBucketCount(kAutocorrectV2PkUserPreferenceAll,
test_case.expected_pref, 1);
}
TEST_F(AutocorrectManagerTest,
RecordsCorrectMetricForEnabledByDefaultWithEnglish) {
feature_list_.Reset();
feature_list_.InitWithFeatures({features::kAutocorrectByDefault},
DisabledFeatures());
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
manager_.OnKeyEvent(KeyA());
histogram_tester_.ExpectTotalCount(kAutocorrectV2PkUserPreferenceAll, 1);
histogram_tester_.ExpectTotalCount(kAutocorrectV2PkUserPreferenceEnglish, 1);
histogram_tester_.ExpectBucketCount(kAutocorrectV2PkUserPreferenceAll,
AutocorrectPreference::kEnabledByDefault,
1);
histogram_tester_.ExpectBucketCount(kAutocorrectV2PkUserPreferenceEnglish,
AutocorrectPreference::kEnabledByDefault,
1);
}
struct PkEnabledByDefaultCase {
std::string test_name;
std::string engine_id;
std::optional<int> autocorrect_level;
AutocorrectPreference preference_before;
AutocorrectPreference preference_after;
};
class PkEnabledByDefaultTest
: public AutocorrectManagerTest,
public testing::WithParamInterface<PkEnabledByDefaultCase> {};
TEST_P(PkEnabledByDefaultTest, ItIsEnabledByDefaultWhenFlagIsEnabled) {
const PkEnabledByDefaultCase& test_case = GetParam();
PrefService* prefs = profile_->GetPrefs();
feature_list_.Reset();
feature_list_.InitWithFeatures({features::kAutocorrectByDefault},
DisabledFeatures());
if (test_case.autocorrect_level) {
SetAutocorrectPreferenceTo(*profile_, test_case.engine_id,
*test_case.autocorrect_level);
}
auto before = GetPhysicalKeyboardAutocorrectPref(*prefs, test_case.engine_id);
manager_.OnActivate(test_case.engine_id);
auto after = GetPhysicalKeyboardAutocorrectPref(*prefs, test_case.engine_id);
EXPECT_EQ(before, test_case.preference_before);
EXPECT_EQ(after, test_case.preference_after);
}
TEST_P(PkEnabledByDefaultTest, ItIsNotEnabledByDefaultWhenFlagIsDisabled) {
const PkEnabledByDefaultCase& test_case = GetParam();
PrefService* prefs = profile_->GetPrefs();
feature_list_.Reset();
feature_list_.InitWithFeatures(
/*enabled_features=*/{},
/*disabled_features=*/DisabledFeaturesIncludingAutocorrectByDefault());
if (test_case.autocorrect_level) {
SetAutocorrectPreferenceTo(*profile_, kUsEnglishEngineId,
*test_case.autocorrect_level);
}
auto before = GetPhysicalKeyboardAutocorrectPref(*prefs, kUsEnglishEngineId);
manager_.OnActivate(test_case.engine_id);
auto after = GetPhysicalKeyboardAutocorrectPref(*prefs, kUsEnglishEngineId);
// Because the flag is disabled then the preference should not change.
EXPECT_EQ(before, test_case.preference_before);
EXPECT_EQ(after, test_case.preference_before);
}
INSTANTIATE_TEST_SUITE_P(
AutocorrectManagerTest,
PkEnabledByDefaultTest,
testing::ValuesIn<PkEnabledByDefaultCase>({
PkEnabledByDefaultCase{
"EnglishDefaultToEnabledByDefault",
/*engine_id=*/kUsEnglishEngineId,
/*autocorrect_level=*/std::nullopt,
/*preference_before=*/AutocorrectPreference::kDefault,
/*preference_after=*/AutocorrectPreference::kEnabledByDefault},
PkEnabledByDefaultCase{
"EnglishDisabledRemainsDisabled",
/*engine_id=*/kUsEnglishEngineId,
/*autocorrect_level=*/0,
/*preference_before=*/AutocorrectPreference::kDisabled,
/*preference_after=*/AutocorrectPreference::kDisabled},
PkEnabledByDefaultCase{
"EnglishEnabledRemainsEnabled",
/*engine_id=*/kUsEnglishEngineId,
/*autocorrect_level=*/1,
/*preference_before=*/AutocorrectPreference::kEnabled,
/*preference_after=*/AutocorrectPreference::kEnabled},
PkEnabledByDefaultCase{
"EnglishAggressiveRemainsEnabled",
/*engine_id=*/kUsEnglishEngineId,
/*autocorrect_level=*/2,
/*preference_before=*/AutocorrectPreference::kEnabled,
/*preference_after=*/AutocorrectPreference::kEnabled},
PkEnabledByDefaultCase{
"PortugeseDefaultRemainsDefault",
/*engine_id=*/kBrazilPortugeseEngineId,
/*autocorrect_level=*/std::nullopt,
/*preference_before=*/AutocorrectPreference::kDefault,
/*preference_after=*/AutocorrectPreference::kDefault},
PkEnabledByDefaultCase{
"PortugeseDisabledRemainsDisabled",
/*engine_id=*/kBrazilPortugeseEngineId,
/*autocorrect_level=*/0,
/*preference_before=*/AutocorrectPreference::kDisabled,
/*preference_after=*/AutocorrectPreference::kDisabled},
PkEnabledByDefaultCase{
"PortugeseEnabledRemainsEnabled",
/*engine_id=*/kBrazilPortugeseEngineId,
/*autocorrect_level=*/1,
/*preference_before=*/AutocorrectPreference::kEnabled,
/*preference_after=*/AutocorrectPreference::kEnabled},
PkEnabledByDefaultCase{
"PortugeseAggressiveRemainsEnabled",
/*engine_id=*/kBrazilPortugeseEngineId,
/*autocorrect_level=*/2,
/*preference_before=*/AutocorrectPreference::kEnabled,
/*preference_after=*/AutocorrectPreference::kEnabled},
PkEnabledByDefaultCase{
"SpainSpanishDefaultRemainsDefault",
/*engine_id=*/kSpainSpanishEngineId,
/*autocorrect_level=*/std::nullopt,
/*preference_before=*/AutocorrectPreference::kDefault,
/*preference_after=*/AutocorrectPreference::kDefault},
PkEnabledByDefaultCase{
"SpainSpanishDisabledRemainsDisabled",
/*engine_id=*/kSpainSpanishEngineId,
/*autocorrect_level=*/0,
/*preference_before=*/AutocorrectPreference::kDisabled,
/*preference_after=*/AutocorrectPreference::kDisabled},
PkEnabledByDefaultCase{
"SpainSpanishEnabledRemainsEnabled",
/*engine_id=*/kSpainSpanishEngineId,
/*autocorrect_level=*/1,
/*preference_before=*/AutocorrectPreference::kEnabled,
/*preference_after=*/AutocorrectPreference::kEnabled},
PkEnabledByDefaultCase{
"SpainSpanishAggressiveRemainsEnabled",
/*engine_id=*/kSpainSpanishEngineId,
/*autocorrect_level=*/2,
/*preference_before=*/AutocorrectPreference::kEnabled,
/*preference_after=*/AutocorrectPreference::kEnabled},
}),
[](const testing::TestParamInfo<PkEnabledByDefaultCase> info) {
return info.param.test_name;
});
class AutocorrectSuggestionProviderMetric
: public AutocorrectManagerTest,
public testing::WithParamInterface<AutocorrectSuggestionProvider> {};
INSTANTIATE_TEST_SUITE_P(
AutocorrectManagerTest,
AutocorrectSuggestionProviderMetric,
testing::ValuesIn<AutocorrectSuggestionProvider>({
AutocorrectSuggestionProvider::kUnknown,
AutocorrectSuggestionProvider::kUsEnglishPrebundled,
AutocorrectSuggestionProvider::kUsEnglishDownloaded,
AutocorrectSuggestionProvider::kUsEnglish840,
AutocorrectSuggestionProvider::kUsEnglish840V2,
}),
[](const testing::TestParamInfo<AutocorrectSuggestionProvider> info) {
return ToString(info.param);
});
TEST_P(AutocorrectSuggestionProviderMetric, IsNotRecordedOnFocus) {
const AutocorrectSuggestionProvider& provider = GetParam();
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
manager_.OnConnectedToSuggestionProvider(provider);
histogram_tester_.ExpectTotalCount(
/*name=*/kAutocorrectV2PkSuggestionProviderHistName,
/*expected_count=*/0);
}
TEST_P(AutocorrectSuggestionProviderMetric, IsNotRecordedWhenVkIsVisible) {
const AutocorrectSuggestionProvider& provider = GetParam();
keyboard_client_->set_keyboard_enabled_for_test(true);
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
manager_.OnConnectedToSuggestionProvider(provider);
manager_.OnKeyEvent(KeyA());
histogram_tester_.ExpectTotalCount(
/*name=*/kAutocorrectV2PkSuggestionProviderHistName,
/*expected_count=*/0);
}
TEST_P(AutocorrectSuggestionProviderMetric,
IsNotRecordedWhenAnEngineOtherThenEnglishIsActive) {
const AutocorrectSuggestionProvider& provider = GetParam();
manager_.OnActivate(kSpainSpanishEngineId);
manager_.OnFocus(kContextId);
manager_.OnConnectedToSuggestionProvider(provider);
manager_.OnKeyEvent(KeyA());
histogram_tester_.ExpectTotalCount(
/*name=*/kAutocorrectV2PkSuggestionProviderHistName,
/*expected_count=*/0);
}
TEST_P(AutocorrectSuggestionProviderMetric, IsRecordedCorrectly) {
const AutocorrectSuggestionProvider& provider = GetParam();
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
manager_.OnConnectedToSuggestionProvider(provider);
manager_.OnKeyEvent(KeyA());
histogram_tester_.ExpectTotalCount(
/*name=*/kAutocorrectV2PkSuggestionProviderHistName,
/*expected_count=*/1);
histogram_tester_.ExpectBucketCount(
/*name=*/kAutocorrectV2PkSuggestionProviderHistName,
/*sample*/ provider, /*expected_count=*/1);
}
TEST_P(AutocorrectSuggestionProviderMetric, IsRecordedOnlyOncePerInput) {
const AutocorrectSuggestionProvider& provider = GetParam();
manager_.OnActivate(kUsEnglishEngineId);
manager_.OnFocus(kContextId);
manager_.OnConnectedToSuggestionProvider(provider);
manager_.OnKeyEvent(KeyA());
manager_.OnKeyEvent(KeyA());
manager_.OnKeyEvent(KeyA());
histogram_tester_.ExpectTotalCount(
/*name=*/kAutocorrectV2PkSuggestionProviderHistName,
/*expected_count=*/1);
histogram_tester_.ExpectBucketCount(
/*name=*/kAutocorrectV2PkSuggestionProviderHistName,
/*sample*/ provider, /*expected_count=*/1);
}
class AutocorrectManagerUkmMetricsTest : public AutocorrectManagerTest {
protected:
AutocorrectManagerUkmMetricsTest() {
ukm::SourceId source_id = test_recorder_.GetNewSourceID();
test_recorder_.UpdateSourceURL(source_id,
GURL("https://test.example.com/"));
fake_text_input_client_.set_source_id(source_id);
IMEBridge::Get()->SetInputContextHandler(&mock_input_method_ash_);
mock_input_method_ash_.SetFocusedTextInputClient(&fake_text_input_client_);
}
ui::FakeTextInputClient fake_text_input_client_{ui::TEXT_INPUT_TYPE_TEXT};
InputMethodAsh mock_input_method_ash_{nullptr};
ukm::TestAutoSetUkmRecorder test_recorder_;
};
TEST_F(AutocorrectManagerUkmMetricsTest,
RecordsAppCompatUkmForUnderlinedSuggestion) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
auto ukm_entries = test_recorder_.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(1u, ukm_entries.size());
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[0], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(AutocorrectCompatibilitySummary::kUnderlined));
}
TEST_F(AutocorrectManagerUkmMetricsTest,
DoesNotRecordsAppCompatUkmForInvalidSourceId) {
fake_text_input_client_.set_source_id(ukm::kInvalidSourceId);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
auto ukm_entries = test_recorder_.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(0u, ukm_entries.size());
}
TEST_F(AutocorrectManagerUkmMetricsTest,
RecordsAppCompatUkmForVKUnderlinedSuggestion) {
keyboard_client_->set_keyboard_enabled_for_test(true);
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
auto ukm_entries = test_recorder_.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(1u, ukm_entries.size());
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[0], UkmEntry::kCompatibilitySummary_VKName,
static_cast<int>(AutocorrectCompatibilitySummary::kUnderlined));
}
TEST_F(AutocorrectManagerUkmMetricsTest, RecordsAppCompatUkmForInvalidRange) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
task_environment_.FastForwardBy(base::Milliseconds(501));
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
auto ukm_entries = test_recorder_.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(2u, ukm_entries.size());
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[1], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(AutocorrectCompatibilitySummary::kInvalidRange));
}
TEST_F(AutocorrectManagerUkmMetricsTest,
RecordsAppCompatUkmForRevertedSuggestion) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
task_environment_.FastForwardBy(base::Milliseconds(501));
manager_.UndoAutocorrect();
auto ukm_entries = test_recorder_.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(2u, ukm_entries.size());
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[1], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(AutocorrectCompatibilitySummary::kReverted));
}
TEST_F(AutocorrectManagerUkmMetricsTest, RecordsAppCompatUkmForWindowShown) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// This suppresses strict mock.
EXPECT_CALL(mock_suggestion_handler_, SetAssistiveWindowProperties(_, _, _));
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(0));
auto ukm_entries = test_recorder_.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(2u, ukm_entries.size());
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[1], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(AutocorrectCompatibilitySummary::kWindowShown));
}
TEST_F(AutocorrectManagerUkmMetricsTest,
RecordsAppCompatUkmForVeryFastAcceptedSuggestion) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
task_environment_.FastForwardBy(base::Milliseconds(200));
// Implicitly accept autocorrect.
manager_.OnSurroundingTextChanged(u"the abc", gfx::Range(7));
auto ukm_entries = test_recorder_.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(3u, ukm_entries.size());
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[1], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(
AutocorrectCompatibilitySummary::kUserAcceptedAutocorrect));
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[2], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(
AutocorrectCompatibilitySummary::kVeryFastAcceptedAutocorrect));
}
TEST_F(AutocorrectManagerUkmMetricsTest,
RecordsAppCompatUkmForFastAcceptedSuggestion) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
task_environment_.FastForwardBy(base::Milliseconds(500));
// Implicitly accept autocorrect.
manager_.OnSurroundingTextChanged(u"the abc", gfx::Range(7));
auto ukm_entries = test_recorder_.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(3u, ukm_entries.size());
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[1], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(
AutocorrectCompatibilitySummary::kUserAcceptedAutocorrect));
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[2], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(
AutocorrectCompatibilitySummary::kFastAcceptedAutocorrect));
}
TEST_F(AutocorrectManagerUkmMetricsTest,
RecordsAppCompatUkmForAcceptedSuggestion) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
task_environment_.FastForwardBy(base::Milliseconds(501));
// Implicitly accept autocorrect.
manager_.OnSurroundingTextChanged(u"the abc", gfx::Range(7));
auto ukm_entries = test_recorder_.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(2u, ukm_entries.size());
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[1], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(
AutocorrectCompatibilitySummary::kUserAcceptedAutocorrect));
}
TEST_F(AutocorrectManagerUkmMetricsTest,
RecordsAppCompatUkmForVeryFastRejectedSuggestion) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
task_environment_.FastForwardBy(base::Milliseconds(200));
// Clear the range.
mock_input_method_ash_.SetAutocorrectRange(gfx::Range(), base::DoNothing());
// Process the cleared range ('the' is mutated to implicitly reject it).
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
auto ukm_entries = test_recorder_.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(3u, ukm_entries.size());
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[1], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(
AutocorrectCompatibilitySummary::kUserActionClearedUnderline));
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[2], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(
AutocorrectCompatibilitySummary::kVeryFastRejectedAutocorrect));
}
TEST_F(AutocorrectManagerUkmMetricsTest,
RecordsAppCompatUkmForFastRejectedSuggestion) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
task_environment_.FastForwardBy(base::Milliseconds(500));
// Clear the range.
mock_input_method_ash_.SetAutocorrectRange(gfx::Range(), base::DoNothing());
// Process the cleared range ('the' is mutated to implicitly reject it).
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
auto ukm_entries = test_recorder_.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(3u, ukm_entries.size());
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[1], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(
AutocorrectCompatibilitySummary::kUserActionClearedUnderline));
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[2], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(
AutocorrectCompatibilitySummary::kFastRejectedAutocorrect));
}
TEST_F(AutocorrectManagerUkmMetricsTest,
RecordsAppCompatUkmForRejectedSuggestion) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
task_environment_.FastForwardBy(base::Milliseconds(501));
// Clear the range.
mock_input_method_ash_.SetAutocorrectRange(gfx::Range(), base::DoNothing());
// Process the cleared range ('the' is mutated to implicitly reject it).
manager_.OnSurroundingTextChanged(u"teh ", gfx::Range(4));
auto ukm_entries = test_recorder_.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(2u, ukm_entries.size());
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[1], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(
AutocorrectCompatibilitySummary::kUserActionClearedUnderline));
}
TEST_F(AutocorrectManagerUkmMetricsTest,
RecordsAppCompatUkmForVeryFastExitField) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
task_environment_.FastForwardBy(base::Milliseconds(200));
manager_.OnBlur();
auto ukm_entries = test_recorder_.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(3u, ukm_entries.size());
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[1], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(
AutocorrectCompatibilitySummary::kUserExitedTextFieldWithUnderline));
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[2], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(AutocorrectCompatibilitySummary::kVeryFastExitField));
}
TEST_F(AutocorrectManagerUkmMetricsTest, RecordsAppCompatUkmForFastExitField) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
task_environment_.FastForwardBy(base::Milliseconds(500));
manager_.OnBlur();
auto ukm_entries = test_recorder_.GetEntriesByName(UkmEntry::kEntryName);
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[1], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(
AutocorrectCompatibilitySummary::kUserExitedTextFieldWithUnderline));
EXPECT_EQ(3u, ukm_entries.size());
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[2], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(AutocorrectCompatibilitySummary::kFastExitField));
}
TEST_F(AutocorrectManagerUkmMetricsTest, RecordsAppCompatUkmForExitField) {
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
manager_.OnSurroundingTextChanged(u"the ", gfx::Range(4));
task_environment_.FastForwardBy(base::Milliseconds(501));
manager_.OnBlur();
auto ukm_entries = test_recorder_.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(2u, ukm_entries.size());
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
ukm_entries[1], UkmEntry::kCompatibilitySummary_PKName,
static_cast<int>(
AutocorrectCompatibilitySummary::kUserExitedTextFieldWithUnderline));
}
// TODO(b/319190264): Consider parameterizing these federated tests on UMA
// consent status, pending outcome of FederatedClientManager unit testing
// refactor.
TEST_F(AutocorrectManagerTest, FederatedLoggingWhenUmaEnabled) {
feature_list_.Reset();
feature_list_.InitWithFeatures({features::kAutocorrectFederatedPhh},
DisabledFeatures());
bool chrome_metrics_enabled = true;
ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(
&chrome_metrics_enabled);
EXPECT_EQ(0, manager_.GetFederatedClientManagerForTest()
.get_num_successful_reports_for_test());
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// The handling of an autocorrection triggers a federated logging event.
EXPECT_EQ(1, manager_.GetFederatedClientManagerForTest()
.get_num_successful_reports_for_test());
ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(nullptr);
}
TEST_F(AutocorrectManagerTest, NoFederatedLoggingWhenUmaDisabled) {
feature_list_.Reset();
feature_list_.InitWithFeatures({features::kAutocorrectFederatedPhh},
DisabledFeatures());
bool chrome_metrics_enabled = false;
ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(
&chrome_metrics_enabled);
EXPECT_EQ(0, manager_.GetFederatedClientManagerForTest()
.get_num_successful_reports_for_test());
manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
// No federated logging despite enabled feature flag, because Chrome metrics
// collection is disabled.
EXPECT_EQ(0, manager_.GetFederatedClientManagerForTest()
.get_num_successful_reports_for_test());
ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(nullptr);
}
} // namespace
} // namespace input_method
} // namespace ash