chromium/chrome/browser/ash/preferences/preferences_browsertest.cc

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

#include <stddef.h>
#include <sys/types.h>

#include <memory>

#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
#include "base/check_deref.h"
#include "base/command_line.h"
#include "base/memory/raw_ptr.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "chrome/browser/ash/input_method/input_method_manager_impl.h"
#include "chrome/browser/ash/login/login_manager_test.h"
#include "chrome/browser/ash/login/test/login_manager_mixin.h"
#include "chrome/browser/ash/login/ui/user_adding_screen.h"
#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/ash/system/fake_input_device_settings.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/pref_names.h"
#include "chromeos/ash/components/settings/cros_settings.h"
#include "components/prefs/pref_service.h"
#include "components/user_manager/scoped_user_manager.h"
#include "components/user_manager/user_manager.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/ime/ash/fake_ime_keyboard.h"
#include "ui/events/event_utils.h"

namespace ash {

class PreferencesTest : public LoginManagerTest {
 public:
  PreferencesTest()
      : LoginManagerTest(), input_settings_(nullptr), keyboard_(nullptr) {
    login_mixin_.AppendRegularUsers(2);

    feature_list_.InitAndEnableFeature(features::kAllowScrollSettings);
  }

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

  void SetUp() override {
    LoginManagerTest::SetUp();

    auto user_manager = std::make_unique<ash::FakeChromeUserManager>();
    scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
        std::move(user_manager));
  }

  void SetUpOnMainThread() override {
    LoginManagerTest::SetUpOnMainThread();
    input_settings_ = system::InputDeviceSettings::Get()->GetFakeInterface();
    EXPECT_NE(nullptr, input_settings_);

    GetFakeUserManager().SetOwnerId(login_mixin_.users()[0].account_id);

    // In browser_test environment, FakeImeKeyboard is used by
    // InputMethodManager.
    keyboard_ = static_cast<input_method::FakeImeKeyboard*>(
        input_method::InputMethodManager::Get()->GetImeKeyboard());
  }

  // Sets set of preferences in given |prefs|. Value of preference depends on
  // |variant| value. For opposite |variant| values all preferences receive
  // different values.
  void SetPrefs(PrefService* prefs, bool variant) {
    prefs->SetBoolean(prefs::kMouseReverseScroll, variant);
    prefs->SetBoolean(prefs::kNaturalScroll, variant);
    prefs->SetBoolean(prefs::kTapToClickEnabled, variant);
    prefs->SetBoolean(prefs::kPrimaryMouseButtonRight, !variant);
    prefs->SetBoolean(prefs::kPrimaryPointingStickButtonRight, !variant);
    prefs->SetBoolean(prefs::kMouseAcceleration, variant);
    prefs->SetBoolean(prefs::kMouseScrollAcceleration, variant);
    prefs->SetBoolean(prefs::kPointingStickAcceleration, variant);
    prefs->SetBoolean(prefs::kTouchpadAcceleration, variant);
    prefs->SetBoolean(prefs::kTouchpadScrollAcceleration, variant);
    prefs->SetBoolean(prefs::kTouchpadHapticFeedback, variant);
    prefs->SetBoolean(prefs::kEnableTouchpadThreeFingerClick, !variant);
    prefs->SetInteger(prefs::kMouseSensitivity, !variant);
    prefs->SetInteger(prefs::kMouseScrollSensitivity, variant ? 1 : 4);
    prefs->SetInteger(prefs::kPointingStickSensitivity, !variant);
    prefs->SetInteger(prefs::kTouchpadSensitivity, variant);
    prefs->SetInteger(prefs::kTouchpadHapticClickSensitivity, variant ? 1 : 3);
    prefs->SetInteger(prefs::kTouchpadScrollSensitivity, variant ? 1 : 4);
    prefs->SetBoolean(prefs::kXkbAutoRepeatEnabled, variant);
    prefs->SetInteger(prefs::kXkbAutoRepeatDelay, variant ? 100 : 500);
    prefs->SetInteger(prefs::kXkbAutoRepeatInterval, variant ? 1 : 4);
    prefs->SetString(
        ::prefs::kLanguagePreloadEngines,
        variant ? "xkb:us::eng,xkb:us:dvorak:eng" : "xkb:us::eng,xkb:ru::rus");
  }

  ash::FakeChromeUserManager& GetFakeUserManager() {
    return CHECK_DEREF(static_cast<ash::FakeChromeUserManager*>(
        user_manager::UserManager::Get()));
  }

  void CheckSettingsCorrespondToPrefs(PrefService* prefs) {
    EXPECT_EQ(prefs->GetBoolean(prefs::kTapToClickEnabled),
              input_settings_->current_touchpad_settings().GetTapToClick());
    EXPECT_EQ(
        prefs->GetBoolean(prefs::kPrimaryMouseButtonRight),
        input_settings_->current_mouse_settings().GetPrimaryButtonRight());
    EXPECT_EQ(prefs->GetBoolean(prefs::kPrimaryPointingStickButtonRight),
              input_settings_->current_pointing_stick_settings()
                  .GetPrimaryButtonRight());
    EXPECT_EQ(prefs->GetBoolean(prefs::kMouseReverseScroll),
              input_settings_->current_mouse_settings().GetReverseScroll());
    EXPECT_EQ(prefs->GetBoolean(prefs::kMouseAcceleration),
              input_settings_->current_mouse_settings().GetAcceleration());
    EXPECT_EQ(
        prefs->GetBoolean(prefs::kMouseScrollAcceleration),
        input_settings_->current_mouse_settings().GetScrollAcceleration());
    EXPECT_EQ(
        prefs->GetBoolean(prefs::kPointingStickAcceleration),
        input_settings_->current_pointing_stick_settings().GetAcceleration());
    EXPECT_EQ(prefs->GetBoolean(prefs::kTouchpadAcceleration),
              input_settings_->current_touchpad_settings().GetAcceleration());
    EXPECT_EQ(
        prefs->GetBoolean(prefs::kTouchpadScrollAcceleration),
        input_settings_->current_touchpad_settings().GetScrollAcceleration());
    EXPECT_EQ(prefs->GetBoolean(prefs::kTouchpadHapticFeedback),
              input_settings_->current_touchpad_settings().GetHapticFeedback());
    EXPECT_EQ(
        prefs->GetBoolean(prefs::kEnableTouchpadThreeFingerClick),
        input_settings_->current_touchpad_settings().GetThreeFingerClick());
    EXPECT_EQ(prefs->GetInteger(prefs::kMouseSensitivity),
              input_settings_->current_mouse_settings().GetSensitivity());
    EXPECT_EQ(prefs->GetInteger(prefs::kMouseScrollSensitivity),
              input_settings_->current_mouse_settings().GetScrollSensitivity());
    EXPECT_EQ(
        prefs->GetInteger(prefs::kPointingStickSensitivity),
        input_settings_->current_pointing_stick_settings().GetSensitivity());
    EXPECT_EQ(prefs->GetInteger(prefs::kTouchpadSensitivity),
              input_settings_->current_touchpad_settings().GetSensitivity());
    EXPECT_EQ(prefs->GetInteger(prefs::kTouchpadHapticClickSensitivity),
              input_settings_->current_touchpad_settings()
                  .GetHapticClickSensitivity());
    EXPECT_EQ(
        prefs->GetInteger(prefs::kTouchpadScrollSensitivity),
        input_settings_->current_touchpad_settings().GetScrollSensitivity());
    EXPECT_EQ(prefs->GetBoolean(prefs::kXkbAutoRepeatEnabled),
              keyboard_->GetAutoRepeatEnabled());
    input_method::AutoRepeatRate rate = keyboard_->last_auto_repeat_rate_;
    EXPECT_EQ(prefs->GetInteger(prefs::kXkbAutoRepeatDelay),
              rate.initial_delay.InMilliseconds());
    EXPECT_EQ(prefs->GetInteger(prefs::kXkbAutoRepeatInterval),
              rate.repeat_interval.InMilliseconds());
    EXPECT_EQ(prefs->GetString(::prefs::kLanguageCurrentInputMethod),
              input_method::InputMethodManager::Get()
                  ->GetActiveIMEState()
                  ->GetCurrentInputMethod()
                  .id());
  }

  void CheckLocalStateCorrespondsToPrefs(PrefService* prefs) {
    PrefService* local_state = g_browser_process->local_state();
    EXPECT_EQ(local_state->GetBoolean(prefs::kOwnerTapToClickEnabled),
              prefs->GetBoolean(prefs::kTapToClickEnabled));
    EXPECT_EQ(local_state->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight),
              prefs->GetBoolean(prefs::kPrimaryMouseButtonRight));
    EXPECT_EQ(
        local_state->GetBoolean(prefs::kOwnerPrimaryPointingStickButtonRight),
        prefs->GetBoolean(prefs::kPrimaryPointingStickButtonRight));
  }

  LoginManagerMixin login_mixin_{&mixin_host_};

 private:
  base::test::ScopedFeatureList feature_list_;
  raw_ptr<system::InputDeviceSettings::FakeInterface> input_settings_;
  raw_ptr<input_method::FakeImeKeyboard, DanglingUntriaged> keyboard_;
  std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
};

IN_PROC_BROWSER_TEST_F(PreferencesTest, MultiProfiles) {
  user_manager::UserManager* user_manager = user_manager::UserManager::Get();

  const auto& users = login_mixin_.users();
  // Add first user and init its preferences. Check that corresponding
  // settings has been changed.
  LoginUser(users[0].account_id);
  const user_manager::User* user1 = user_manager->FindUser(users[0].account_id);
  PrefService* prefs1 =
      ProfileHelper::Get()->GetProfileByUser(user1)->GetPrefs();
  SetPrefs(prefs1, false);
  content::RunAllPendingInMessageLoop();
  CheckSettingsCorrespondToPrefs(prefs1);

  // Add second user and init its prefs with different values.
  UserAddingScreen::Get()->Start();
  content::RunAllPendingInMessageLoop();
  AddUser(users[1].account_id);
  content::RunAllPendingInMessageLoop();
  const user_manager::User* user2 = user_manager->FindUser(users[1].account_id);
  EXPECT_TRUE(user2->is_active());
  PrefService* prefs2 =
      ProfileHelper::Get()->GetProfileByUser(user2)->GetPrefs();
  SetPrefs(prefs2, true);

  // Check that settings were changed accordingly.
  EXPECT_TRUE(user2->is_active());
  CheckSettingsCorrespondToPrefs(prefs2);

  // Check that changing prefs of the active user doesn't affect prefs of the
  // inactive user.
  base::Value::Dict prefs_backup =
      prefs1->GetPreferenceValues(PrefService::INCLUDE_DEFAULTS);
  SetPrefs(prefs2, false);
  CheckSettingsCorrespondToPrefs(prefs2);
  EXPECT_EQ(prefs_backup,
            prefs1->GetPreferenceValues(PrefService::INCLUDE_DEFAULTS));
  SetPrefs(prefs2, true);
  CheckSettingsCorrespondToPrefs(prefs2);
  EXPECT_EQ(prefs_backup,
            prefs1->GetPreferenceValues(PrefService::INCLUDE_DEFAULTS));

  // Check that changing prefs of the inactive user doesn't affect prefs of the
  // active user.
  prefs_backup = prefs2->GetPreferenceValues(PrefService::INCLUDE_DEFAULTS);
  SetPrefs(prefs1, true);
  CheckSettingsCorrespondToPrefs(prefs2);
  EXPECT_EQ(prefs_backup,
            prefs2->GetPreferenceValues(PrefService::INCLUDE_DEFAULTS));
  SetPrefs(prefs1, false);
  CheckSettingsCorrespondToPrefs(prefs2);
  EXPECT_EQ(prefs_backup,
            prefs2->GetPreferenceValues(PrefService::INCLUDE_DEFAULTS));

  // Check that changing non-owner prefs doesn't change corresponding local
  // state prefs and vice versa.
  EXPECT_EQ(user_manager->GetOwnerAccountId(), users[0].account_id);
  CheckLocalStateCorrespondsToPrefs(prefs1);
  prefs2->SetBoolean(prefs::kTapToClickEnabled,
                     !prefs1->GetBoolean(prefs::kTapToClickEnabled));
  CheckLocalStateCorrespondsToPrefs(prefs1);
  prefs1->SetBoolean(prefs::kTapToClickEnabled,
                     !prefs1->GetBoolean(prefs::kTapToClickEnabled));
  CheckLocalStateCorrespondsToPrefs(prefs1);

  // Switch user back.
  user_manager->SwitchActiveUser(users[0].account_id);
  CheckSettingsCorrespondToPrefs(prefs1);
  CheckLocalStateCorrespondsToPrefs(prefs1);
}

}  // namespace ash