chromium/chrome/browser/chromeos/reporting/local_state_reporting_settings_unittest.cc

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

#include "chrome/browser/chromeos/reporting/local_state_reporting_settings.h"

#include <memory>

#include "base/callback_list.h"
#include "base/functional/callback_helpers.h"
#include "base/test/bind.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using ::testing::Eq;
using ::testing::IsNull;
using ::testing::NotNull;

namespace reporting {
namespace {

constexpr char kSettingPath[] = "TestSetting";

class LocalStateReportingSettingsTest : public ::testing::Test {
 protected:
  TestingPrefServiceSimple* local_state() { return local_state_.Get(); }

 private:
  ::content::BrowserTaskEnvironment task_environment_;
  ScopedTestingLocalState local_state_{TestingBrowserProcess::GetGlobal()};

 protected:
  LocalStateReportingSettings local_state_reporting_settings_;
};

TEST_F(LocalStateReportingSettingsTest, InvalidIntegerPrefPath) {
  local_state()->registry()->RegisterIntegerPref(kSettingPath,
                                                 /*default_value=*/0);

  // Attempt to retrieve the integer reporting setting with incorrect data type
  // and confirm it fails.
  bool out_bool_value;
  ASSERT_FALSE(local_state_reporting_settings_.GetBoolean(kSettingPath,
                                                          &out_bool_value));
  ASSERT_FALSE(local_state_reporting_settings_.GetReportingEnabled(
      kSettingPath, &out_bool_value));
  const base::Value::List* out_list_value = nullptr;
  ASSERT_FALSE(
      local_state_reporting_settings_.GetList(kSettingPath, &out_list_value));
  EXPECT_THAT(out_list_value, IsNull());
}

TEST_F(LocalStateReportingSettingsTest, InvalidBooleanPrefPath) {
  local_state()->registry()->RegisterBooleanPref(kSettingPath,
                                                 /*default_value=*/true);

  // Attempt to retrieve the boolean reporting setting with incorrect data type
  // and confirm it fails.
  int out_int_value;
  ASSERT_FALSE(
      local_state_reporting_settings_.GetInteger(kSettingPath, &out_int_value));
  const base::Value::List* out_list_value = nullptr;
  ASSERT_FALSE(
      local_state_reporting_settings_.GetList(kSettingPath, &out_list_value));
  EXPECT_THAT(out_list_value, IsNull());
}

TEST_F(LocalStateReportingSettingsTest, InvalidListPrefPath) {
  local_state()->registry()->RegisterListPref(
      kSettingPath, /*default_value=*/base::Value::List());

  // Attempt to retrieve the list reporting setting with incorrect data type and
  // confirm it fails.
  bool out_bool_value;
  ASSERT_FALSE(local_state_reporting_settings_.GetBoolean(kSettingPath,
                                                          &out_bool_value));
  int out_int_value;
  EXPECT_FALSE(
      local_state_reporting_settings_.GetInteger(kSettingPath, &out_int_value));
}

TEST_F(LocalStateReportingSettingsTest, GetUnregisteredSetting) {
  bool out_bool_value;
  EXPECT_FALSE(local_state_reporting_settings_.GetBoolean(kSettingPath,
                                                          &out_bool_value));
  int out_int_value;
  EXPECT_FALSE(
      local_state_reporting_settings_.GetInteger(kSettingPath, &out_int_value));
  const base::Value::List* out_list_value = nullptr;
  EXPECT_FALSE(
      local_state_reporting_settings_.GetList(kSettingPath, &out_list_value));
}

TEST_F(LocalStateReportingSettingsTest, GetBoolean) {
  local_state()->registry()->RegisterBooleanPref(kSettingPath,
                                                 /*default_value=*/false);
  bool out_value = true;
  ASSERT_TRUE(
      local_state_reporting_settings_.GetBoolean(kSettingPath, &out_value));
  ASSERT_FALSE(out_value);

  // Update setting value and ensure the next fetch returns the updated value.
  local_state()->SetBoolean(kSettingPath, true);
  ASSERT_TRUE(
      local_state_reporting_settings_.GetBoolean(kSettingPath, &out_value));
  EXPECT_TRUE(out_value);
}

TEST_F(LocalStateReportingSettingsTest, GetReportingEnabled_Boolean) {
  local_state()->registry()->RegisterBooleanPref(kSettingPath,
                                                 /*default_value=*/false);
  bool out_value = true;
  ASSERT_TRUE(local_state_reporting_settings_.GetReportingEnabled(kSettingPath,
                                                                  &out_value));
  EXPECT_FALSE(out_value);

  // Update setting value and ensure the next fetch returns the updated value.
  local_state()->SetBoolean(kSettingPath, true);
  ASSERT_TRUE(
      local_state_reporting_settings_.GetBoolean(kSettingPath, &out_value));
  EXPECT_TRUE(out_value);
}

TEST_F(LocalStateReportingSettingsTest, GetInteger) {
  local_state()->registry()->RegisterIntegerPref(kSettingPath,
                                                 /*default_value=*/0);
  int out_value;
  ASSERT_TRUE(
      local_state_reporting_settings_.GetInteger(kSettingPath, &out_value));
  ASSERT_THAT(out_value, Eq(0));

  // Update setting value and ensure the next fetch returns the updated value.
  static constexpr int new_value = 1;
  local_state()->SetInteger(kSettingPath, new_value);
  ASSERT_TRUE(
      local_state_reporting_settings_.GetInteger(kSettingPath, &out_value));
  EXPECT_THAT(out_value, Eq(new_value));
}

TEST_F(LocalStateReportingSettingsTest, GetList) {
  local_state()->registry()->RegisterListPref(
      kSettingPath, /*default_value=*/base::Value::List());
  const base::Value::List* out_value;
  ASSERT_TRUE(
      local_state_reporting_settings_.GetList(kSettingPath, &out_value));
  ASSERT_THAT(out_value, NotNull());
  EXPECT_TRUE(out_value->empty());

  // Update setting value and ensure the next fetch returns the updated value.
  static constexpr char kListSettingItem[] = "item";
  local_state()->SetList(kSettingPath,
                         base::Value::List().Append(kListSettingItem));
  ASSERT_TRUE(
      local_state_reporting_settings_.GetList(kSettingPath, &out_value));
  ASSERT_THAT(out_value, NotNull());
  ASSERT_THAT(out_value->size(), Eq(1uL));
  EXPECT_THAT(out_value->front().GetString(), Eq(kListSettingItem));
}

TEST_F(LocalStateReportingSettingsTest, GetReportingEnabled_List) {
  local_state()->registry()->RegisterListPref(
      kSettingPath, /*default_value=*/base::Value::List());
  bool out_value = true;
  ASSERT_TRUE(local_state_reporting_settings_.GetReportingEnabled(kSettingPath,
                                                                  &out_value));
  EXPECT_FALSE(out_value);

  // Update setting value and ensure the next fetch returns the updated value.
  static constexpr char kListSettingItem[] = "item";
  local_state()->SetList(kSettingPath,
                         base::Value::List().Append(kListSettingItem));
  ASSERT_TRUE(local_state_reporting_settings_.GetReportingEnabled(kSettingPath,
                                                                  &out_value));
  EXPECT_TRUE(out_value);
}

TEST_F(LocalStateReportingSettingsTest, ObserveBooleanSetting) {
  local_state()->registry()->RegisterBooleanPref(kSettingPath,
                                                 /*default_value=*/false);
  bool callback_called = false;
  const auto callback_subscription =
      local_state_reporting_settings_.AddSettingsObserver(
          kSettingPath, base::BindLambdaForTesting(
                            [&callback_called]() { callback_called = true; }));

  // Update setting value and ensure callback was triggered.
  local_state()->SetBoolean(kSettingPath, true);
  ASSERT_TRUE(callback_called);
}

TEST_F(LocalStateReportingSettingsTest, ObserveIntegerSetting) {
  local_state()->registry()->RegisterIntegerPref(kSettingPath,
                                                 /*default_value=*/0);
  bool callback_called = false;
  const auto callback_subscription =
      local_state_reporting_settings_.AddSettingsObserver(
          kSettingPath, base::BindLambdaForTesting(
                            [&callback_called]() { callback_called = true; }));

  // Update setting value and ensure callback was triggered.
  local_state()->SetInteger(kSettingPath, 1);
  ASSERT_TRUE(callback_called);
}

TEST_F(LocalStateReportingSettingsTest, ObserveListSetting) {
  local_state()->registry()->RegisterListPref(
      kSettingPath, /*default_value=*/base::Value::List());
  bool callback_called = false;
  const auto callback_subscription =
      local_state_reporting_settings_.AddSettingsObserver(
          kSettingPath, base::BindLambdaForTesting(
                            [&callback_called]() { callback_called = true; }));

  // Update setting value and ensure callback was triggered.
  local_state()->SetList(kSettingPath, base::Value::List().Append("item"));
  ASSERT_TRUE(callback_called);
}

TEST_F(LocalStateReportingSettingsTest, MultipleSettingObservers) {
  local_state()->registry()->RegisterBooleanPref(kSettingPath,
                                                 /*default_value=*/false);
  int callback_trigger_count = 0;
  const auto callback_subscription_1 =
      local_state_reporting_settings_.AddSettingsObserver(
          kSettingPath, base::BindLambdaForTesting([&callback_trigger_count]() {
            callback_trigger_count++;
          }));
  const auto callback_subscription_2 =
      local_state_reporting_settings_.AddSettingsObserver(
          kSettingPath, base::BindLambdaForTesting([&callback_trigger_count]() {
            callback_trigger_count++;
          }));

  // Update setting value and ensure both callbacks were triggered.
  local_state()->SetBoolean(kSettingPath, true);
  ASSERT_THAT(callback_trigger_count, Eq(2));
}

}  // namespace
}  // namespace reporting