1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/prefs/testing_pref_store.h"
6
7 #include <memory>
8 #include <string>
9 #include <string_view>
10 #include <utility>
11
12 #include "base/json/json_writer.h"
13 #include "base/run_loop.h"
14 #include "base/values.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace {
18
19 class ChangedValueWaiter : public PrefStore::Observer {
20 public:
ChangedValueWaiter(scoped_refptr<PrefStore> store,std::string key)21 ChangedValueWaiter(scoped_refptr<PrefStore> store, std::string key)
22 : store_(std::move(store)), key_(std::move(key)) {
23 store_->AddObserver(this);
24
25 const base::Value* old_value = nullptr;
26 if (store_->GetValue(key_, &old_value)) {
27 old_value_ = old_value->Clone();
28 }
29 }
30
~ChangedValueWaiter()31 ~ChangedValueWaiter() override { store_->RemoveObserver(this); }
32
Wait()33 void Wait() { run_loop_.Run(); }
34
35 private:
QuitRunLoopIfNewValueIsPresent()36 void QuitRunLoopIfNewValueIsPresent() {
37 std::optional<base::Value> new_value;
38 {
39 const base::Value* value = nullptr;
40 if (store_->GetValue(key_, &value)) {
41 new_value = value->Clone();
42 }
43 }
44
45 if (new_value != old_value_) {
46 run_loop_.Quit();
47 }
48 }
49
OnInitializationCompleted(bool succeeded)50 void OnInitializationCompleted(bool succeeded) override {
51 QuitRunLoopIfNewValueIsPresent();
52 }
53
OnPrefValueChanged(std::string_view key)54 void OnPrefValueChanged(std::string_view key) override {
55 if (key == key_) {
56 QuitRunLoopIfNewValueIsPresent();
57 }
58 }
59
60 scoped_refptr<PrefStore> store_;
61 std::string key_;
62 std::optional<base::Value> old_value_;
63 base::RunLoop run_loop_;
64 };
65
66 } // namespace
67
TestingPrefStore()68 TestingPrefStore::TestingPrefStore()
69 : read_only_(false),
70 read_success_(true),
71 read_error_(PersistentPrefStore::PREF_READ_ERROR_NONE),
72 block_async_read_(false),
73 pending_async_read_(false),
74 init_complete_(false),
75 committed_(true) {}
76
GetValue(std::string_view key,const base::Value ** value) const77 bool TestingPrefStore::GetValue(std::string_view key,
78 const base::Value** value) const {
79 return prefs_.GetValue(key, value);
80 }
81
GetValues() const82 base::Value::Dict TestingPrefStore::GetValues() const {
83 return prefs_.AsDict();
84 }
85
GetMutableValue(std::string_view key,base::Value ** value)86 bool TestingPrefStore::GetMutableValue(std::string_view key,
87 base::Value** value) {
88 return prefs_.GetValue(key, value);
89 }
90
AddObserver(PrefStore::Observer * observer)91 void TestingPrefStore::AddObserver(PrefStore::Observer* observer) {
92 observers_.AddObserver(observer);
93 }
94
RemoveObserver(PrefStore::Observer * observer)95 void TestingPrefStore::RemoveObserver(PrefStore::Observer* observer) {
96 observers_.RemoveObserver(observer);
97 }
98
HasObservers() const99 bool TestingPrefStore::HasObservers() const {
100 return !observers_.empty();
101 }
102
IsInitializationComplete() const103 bool TestingPrefStore::IsInitializationComplete() const {
104 return init_complete_;
105 }
106
SetValue(std::string_view key,base::Value value,uint32_t flags)107 void TestingPrefStore::SetValue(std::string_view key,
108 base::Value value,
109 uint32_t flags) {
110 if (prefs_.SetValue(key, std::move(value))) {
111 committed_ = false;
112 NotifyPrefValueChanged(key);
113 }
114 }
115
SetValueSilently(std::string_view key,base::Value value,uint32_t flags)116 void TestingPrefStore::SetValueSilently(std::string_view key,
117 base::Value value,
118 uint32_t flags) {
119 CheckPrefIsSerializable(key, value);
120 if (prefs_.SetValue(key, std::move(value)))
121 committed_ = false;
122 }
123
RemoveValue(std::string_view key,uint32_t flags)124 void TestingPrefStore::RemoveValue(std::string_view key, uint32_t flags) {
125 if (prefs_.RemoveValue(key)) {
126 committed_ = false;
127 NotifyPrefValueChanged(key);
128 }
129 }
130
RemoveValuesByPrefixSilently(std::string_view prefix)131 void TestingPrefStore::RemoveValuesByPrefixSilently(std::string_view prefix) {
132 prefs_.ClearWithPrefix(prefix);
133 }
134
ReadOnly() const135 bool TestingPrefStore::ReadOnly() const {
136 return read_only_;
137 }
138
GetReadError() const139 PersistentPrefStore::PrefReadError TestingPrefStore::GetReadError() const {
140 return read_error_;
141 }
142
ReadPrefs()143 PersistentPrefStore::PrefReadError TestingPrefStore::ReadPrefs() {
144 NotifyInitializationCompleted();
145 return read_error_;
146 }
147
ReadPrefsAsync(ReadErrorDelegate * error_delegate)148 void TestingPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
149 DCHECK(!pending_async_read_);
150 error_delegate_.emplace(error_delegate);
151 if (block_async_read_)
152 pending_async_read_ = true;
153 else
154 NotifyInitializationCompleted();
155 }
156
CommitPendingWrite(base::OnceClosure reply_callback,base::OnceClosure synchronous_done_callback)157 void TestingPrefStore::CommitPendingWrite(
158 base::OnceClosure reply_callback,
159 base::OnceClosure synchronous_done_callback) {
160 committed_ = true;
161 PersistentPrefStore::CommitPendingWrite(std::move(reply_callback),
162 std::move(synchronous_done_callback));
163 }
164
SchedulePendingLossyWrites()165 void TestingPrefStore::SchedulePendingLossyWrites() {}
166
SetInitializationCompleted()167 void TestingPrefStore::SetInitializationCompleted() {
168 NotifyInitializationCompleted();
169 }
170
NotifyPrefValueChanged(std::string_view key)171 void TestingPrefStore::NotifyPrefValueChanged(std::string_view key) {
172 for (Observer& observer : observers_)
173 observer.OnPrefValueChanged(key);
174 }
175
NotifyInitializationCompleted()176 void TestingPrefStore::NotifyInitializationCompleted() {
177 DCHECK(!init_complete_);
178 init_complete_ = true;
179 if (read_success_ && read_error_ != PREF_READ_ERROR_NONE &&
180 error_delegate_.has_value() && error_delegate_.value()) {
181 error_delegate_.value()->OnError(read_error_);
182 }
183 for (Observer& observer : observers_)
184 observer.OnInitializationCompleted(read_success_);
185 }
186
ReportValueChanged(std::string_view key,uint32_t flags)187 void TestingPrefStore::ReportValueChanged(std::string_view key,
188 uint32_t flags) {
189 const base::Value* value = nullptr;
190 if (prefs_.GetValue(key, &value))
191 CheckPrefIsSerializable(key, *value);
192
193 for (Observer& observer : observers_)
194 observer.OnPrefValueChanged(key);
195 }
196
SetString(const std::string & key,const std::string & value)197 void TestingPrefStore::SetString(const std::string& key,
198 const std::string& value) {
199 SetValue(key, base::Value(value), DEFAULT_PREF_WRITE_FLAGS);
200 }
201
SetInteger(const std::string & key,int value)202 void TestingPrefStore::SetInteger(const std::string& key, int value) {
203 SetValue(key, base::Value(value), DEFAULT_PREF_WRITE_FLAGS);
204 }
205
SetBoolean(const std::string & key,bool value)206 void TestingPrefStore::SetBoolean(const std::string& key, bool value) {
207 SetValue(key, base::Value(value), DEFAULT_PREF_WRITE_FLAGS);
208 }
209
GetString(const std::string & key,std::string * value) const210 bool TestingPrefStore::GetString(const std::string& key,
211 std::string* value) const {
212 const base::Value* stored_value;
213 if (!prefs_.GetValue(key, &stored_value) || !stored_value)
214 return false;
215
216 if (value && stored_value->is_string()) {
217 *value = stored_value->GetString();
218 return true;
219 }
220 return stored_value->is_string();
221 }
222
GetInteger(const std::string & key,int * value) const223 bool TestingPrefStore::GetInteger(const std::string& key, int* value) const {
224 const base::Value* stored_value;
225 if (!prefs_.GetValue(key, &stored_value) || !stored_value)
226 return false;
227
228 if (value && stored_value->is_int()) {
229 *value = stored_value->GetInt();
230 return true;
231 }
232 return stored_value->is_int();
233 }
234
GetBoolean(const std::string & key,bool * value) const235 bool TestingPrefStore::GetBoolean(const std::string& key, bool* value) const {
236 const base::Value* stored_value;
237 if (!prefs_.GetValue(key, &stored_value) || !stored_value)
238 return false;
239
240 if (value && stored_value->is_bool()) {
241 *value = stored_value->GetBool();
242 return true;
243 }
244 return stored_value->is_bool();
245 }
246
SetBlockAsyncRead(bool block_async_read)247 void TestingPrefStore::SetBlockAsyncRead(bool block_async_read) {
248 DCHECK(!init_complete_);
249 block_async_read_ = block_async_read;
250 if (pending_async_read_ && !block_async_read_)
251 NotifyInitializationCompleted();
252 }
253
WaitUntilValueChanges(std::string key)254 void TestingPrefStore::WaitUntilValueChanges(std::string key) {
255 ChangedValueWaiter waiter(this, std::move(key));
256 waiter.Wait();
257 }
258
WaitForValue(std::string key,base::Value expected_value)259 void TestingPrefStore::WaitForValue(std::string key,
260 base::Value expected_value) {
261 while (true) {
262 const base::Value* curr_value = nullptr;
263 if (GetValue(key, &curr_value) && *curr_value == expected_value) {
264 break;
265 }
266
267 WaitUntilValueChanges(key);
268 }
269 }
270
OnStoreDeletionFromDisk()271 void TestingPrefStore::OnStoreDeletionFromDisk() {}
272
set_read_only(bool read_only)273 void TestingPrefStore::set_read_only(bool read_only) {
274 read_only_ = read_only;
275 }
276
set_read_success(bool read_success)277 void TestingPrefStore::set_read_success(bool read_success) {
278 DCHECK(!init_complete_);
279 read_success_ = read_success;
280 }
281
set_read_error(PersistentPrefStore::PrefReadError read_error)282 void TestingPrefStore::set_read_error(
283 PersistentPrefStore::PrefReadError read_error) {
284 DCHECK(!init_complete_);
285 read_error_ = read_error;
286 }
287
~TestingPrefStore()288 TestingPrefStore::~TestingPrefStore() {
289 for (auto& pref : prefs_)
290 CheckPrefIsSerializable(pref.first, pref.second);
291 }
292
CheckPrefIsSerializable(std::string_view key,const base::Value & value)293 void TestingPrefStore::CheckPrefIsSerializable(std::string_view key,
294 const base::Value& value) {
295 std::string json;
296 EXPECT_TRUE(base::JSONWriter::Write(value, &json))
297 << "Pref \"" << key << "\" is not serializable as JSON.";
298 }
299
HasReadErrorDelegate() const300 bool TestingPrefStore::HasReadErrorDelegate() const {
301 return error_delegate_.has_value();
302 }
303