// Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "components/prefs/testing_pref_store.h" #include #include #include #include #include "base/json/json_writer.h" #include "base/run_loop.h" #include "base/values.h" #include "testing/gtest/include/gtest/gtest.h" namespace { class ChangedValueWaiter : public PrefStore::Observer { public: ChangedValueWaiter(scoped_refptr store, std::string key) : store_(std::move(store)), key_(std::move(key)) { store_->AddObserver(this); const base::Value* old_value = nullptr; if (store_->GetValue(key_, &old_value)) { old_value_ = old_value->Clone(); } } ~ChangedValueWaiter() override { store_->RemoveObserver(this); } void Wait() { run_loop_.Run(); } private: void QuitRunLoopIfNewValueIsPresent() { std::optional new_value; { const base::Value* value = nullptr; if (store_->GetValue(key_, &value)) { new_value = value->Clone(); } } if (new_value != old_value_) { run_loop_.Quit(); } } void OnInitializationCompleted(bool succeeded) override { QuitRunLoopIfNewValueIsPresent(); } void OnPrefValueChanged(std::string_view key) override { if (key == key_) { QuitRunLoopIfNewValueIsPresent(); } } scoped_refptr store_; std::string key_; std::optional old_value_; base::RunLoop run_loop_; }; } // namespace TestingPrefStore::TestingPrefStore() : read_only_(false), read_success_(true), read_error_(PersistentPrefStore::PREF_READ_ERROR_NONE), block_async_read_(false), pending_async_read_(false), init_complete_(false), committed_(true) {} bool TestingPrefStore::GetValue(std::string_view key, const base::Value** value) const { return prefs_.GetValue(key, value); } base::Value::Dict TestingPrefStore::GetValues() const { return prefs_.AsDict(); } bool TestingPrefStore::GetMutableValue(std::string_view key, base::Value** value) { return prefs_.GetValue(key, value); } void TestingPrefStore::AddObserver(PrefStore::Observer* observer) { observers_.AddObserver(observer); } void TestingPrefStore::RemoveObserver(PrefStore::Observer* observer) { observers_.RemoveObserver(observer); } bool TestingPrefStore::HasObservers() const { return !observers_.empty(); } bool TestingPrefStore::IsInitializationComplete() const { return init_complete_; } void TestingPrefStore::SetValue(std::string_view key, base::Value value, uint32_t flags) { if (prefs_.SetValue(key, std::move(value))) { committed_ = false; NotifyPrefValueChanged(key); } } void TestingPrefStore::SetValueSilently(std::string_view key, base::Value value, uint32_t flags) { CheckPrefIsSerializable(key, value); if (prefs_.SetValue(key, std::move(value))) committed_ = false; } void TestingPrefStore::RemoveValue(std::string_view key, uint32_t flags) { if (prefs_.RemoveValue(key)) { committed_ = false; NotifyPrefValueChanged(key); } } void TestingPrefStore::RemoveValuesByPrefixSilently(std::string_view prefix) { prefs_.ClearWithPrefix(prefix); } bool TestingPrefStore::ReadOnly() const { return read_only_; } PersistentPrefStore::PrefReadError TestingPrefStore::GetReadError() const { return read_error_; } PersistentPrefStore::PrefReadError TestingPrefStore::ReadPrefs() { NotifyInitializationCompleted(); return read_error_; } void TestingPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) { DCHECK(!pending_async_read_); error_delegate_.emplace(error_delegate); if (block_async_read_) pending_async_read_ = true; else NotifyInitializationCompleted(); } void TestingPrefStore::CommitPendingWrite( base::OnceClosure reply_callback, base::OnceClosure synchronous_done_callback) { committed_ = true; PersistentPrefStore::CommitPendingWrite(std::move(reply_callback), std::move(synchronous_done_callback)); } void TestingPrefStore::SchedulePendingLossyWrites() {} void TestingPrefStore::SetInitializationCompleted() { NotifyInitializationCompleted(); } void TestingPrefStore::NotifyPrefValueChanged(std::string_view key) { for (Observer& observer : observers_) observer.OnPrefValueChanged(key); } void TestingPrefStore::NotifyInitializationCompleted() { DCHECK(!init_complete_); init_complete_ = true; if (read_success_ && read_error_ != PREF_READ_ERROR_NONE && error_delegate_.has_value() && error_delegate_.value()) { error_delegate_.value()->OnError(read_error_); } for (Observer& observer : observers_) observer.OnInitializationCompleted(read_success_); } void TestingPrefStore::ReportValueChanged(std::string_view key, uint32_t flags) { const base::Value* value = nullptr; if (prefs_.GetValue(key, &value)) CheckPrefIsSerializable(key, *value); for (Observer& observer : observers_) observer.OnPrefValueChanged(key); } void TestingPrefStore::SetString(const std::string& key, const std::string& value) { SetValue(key, base::Value(value), DEFAULT_PREF_WRITE_FLAGS); } void TestingPrefStore::SetInteger(const std::string& key, int value) { SetValue(key, base::Value(value), DEFAULT_PREF_WRITE_FLAGS); } void TestingPrefStore::SetBoolean(const std::string& key, bool value) { SetValue(key, base::Value(value), DEFAULT_PREF_WRITE_FLAGS); } bool TestingPrefStore::GetString(const std::string& key, std::string* value) const { const base::Value* stored_value; if (!prefs_.GetValue(key, &stored_value) || !stored_value) return false; if (value && stored_value->is_string()) { *value = stored_value->GetString(); return true; } return stored_value->is_string(); } bool TestingPrefStore::GetInteger(const std::string& key, int* value) const { const base::Value* stored_value; if (!prefs_.GetValue(key, &stored_value) || !stored_value) return false; if (value && stored_value->is_int()) { *value = stored_value->GetInt(); return true; } return stored_value->is_int(); } bool TestingPrefStore::GetBoolean(const std::string& key, bool* value) const { const base::Value* stored_value; if (!prefs_.GetValue(key, &stored_value) || !stored_value) return false; if (value && stored_value->is_bool()) { *value = stored_value->GetBool(); return true; } return stored_value->is_bool(); } void TestingPrefStore::SetBlockAsyncRead(bool block_async_read) { DCHECK(!init_complete_); block_async_read_ = block_async_read; if (pending_async_read_ && !block_async_read_) NotifyInitializationCompleted(); } void TestingPrefStore::WaitUntilValueChanges(std::string key) { ChangedValueWaiter waiter(this, std::move(key)); waiter.Wait(); } void TestingPrefStore::WaitForValue(std::string key, base::Value expected_value) { while (true) { const base::Value* curr_value = nullptr; if (GetValue(key, &curr_value) && *curr_value == expected_value) { break; } WaitUntilValueChanges(key); } } void TestingPrefStore::OnStoreDeletionFromDisk() {} void TestingPrefStore::set_read_only(bool read_only) { read_only_ = read_only; } void TestingPrefStore::set_read_success(bool read_success) { DCHECK(!init_complete_); read_success_ = read_success; } void TestingPrefStore::set_read_error( PersistentPrefStore::PrefReadError read_error) { DCHECK(!init_complete_); read_error_ = read_error; } TestingPrefStore::~TestingPrefStore() { for (auto& pref : prefs_) CheckPrefIsSerializable(pref.first, pref.second); } void TestingPrefStore::CheckPrefIsSerializable(std::string_view key, const base::Value& value) { std::string json; EXPECT_TRUE(base::JSONWriter::Write(value, &json)) << "Pref \"" << key << "\" is not serializable as JSON."; } bool TestingPrefStore::HasReadErrorDelegate() const { return error_delegate_.has_value(); }