1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 "base/prefs/json_pref_store.h" 6 7#include "base/bind.h" 8#include "base/file_util.h" 9#include "base/files/scoped_temp_dir.h" 10#include "base/memory/ref_counted.h" 11#include "base/memory/scoped_ptr.h" 12#include "base/message_loop/message_loop.h" 13#include "base/path_service.h" 14#include "base/prefs/pref_filter.h" 15#include "base/run_loop.h" 16#include "base/strings/string_number_conversions.h" 17#include "base/strings/string_util.h" 18#include "base/strings/utf_string_conversions.h" 19#include "base/threading/sequenced_worker_pool.h" 20#include "base/threading/thread.h" 21#include "base/values.h" 22#include "testing/gmock/include/gmock/gmock.h" 23#include "testing/gtest/include/gtest/gtest.h" 24 25namespace base { 26namespace { 27 28const char kHomePage[] = "homepage"; 29 30// A PrefFilter that will intercept all calls to FilterOnLoad() and hold on 31// to the |prefs| until explicitly asked to release them. 32class InterceptingPrefFilter : public PrefFilter { 33 public: 34 InterceptingPrefFilter(); 35 virtual ~InterceptingPrefFilter(); 36 37 // PrefFilter implementation: 38 virtual void FilterOnLoad( 39 const PostFilterOnLoadCallback& post_filter_on_load_callback, 40 scoped_ptr<base::DictionaryValue> pref_store_contents) OVERRIDE; 41 virtual void FilterUpdate(const std::string& path) OVERRIDE {} 42 virtual void FilterSerializeData( 43 base::DictionaryValue* pref_store_contents) OVERRIDE {} 44 45 bool has_intercepted_prefs() const { return intercepted_prefs_ != NULL; } 46 47 // Finalize an intercepted read, handing |intercepted_prefs_| back to its 48 // JsonPrefStore. 49 void ReleasePrefs(); 50 51 private: 52 PostFilterOnLoadCallback post_filter_on_load_callback_; 53 scoped_ptr<base::DictionaryValue> intercepted_prefs_; 54 55 DISALLOW_COPY_AND_ASSIGN(InterceptingPrefFilter); 56}; 57 58InterceptingPrefFilter::InterceptingPrefFilter() {} 59InterceptingPrefFilter::~InterceptingPrefFilter() {} 60 61void InterceptingPrefFilter::FilterOnLoad( 62 const PostFilterOnLoadCallback& post_filter_on_load_callback, 63 scoped_ptr<base::DictionaryValue> pref_store_contents) { 64 post_filter_on_load_callback_ = post_filter_on_load_callback; 65 intercepted_prefs_ = pref_store_contents.Pass(); 66} 67 68void InterceptingPrefFilter::ReleasePrefs() { 69 EXPECT_FALSE(post_filter_on_load_callback_.is_null()); 70 post_filter_on_load_callback_.Run(intercepted_prefs_.Pass(), false); 71 post_filter_on_load_callback_.Reset(); 72} 73 74class MockPrefStoreObserver : public PrefStore::Observer { 75 public: 76 MOCK_METHOD1(OnPrefValueChanged, void (const std::string&)); 77 MOCK_METHOD1(OnInitializationCompleted, void (bool)); 78}; 79 80class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate { 81 public: 82 MOCK_METHOD1(OnError, void(PersistentPrefStore::PrefReadError)); 83}; 84 85} // namespace 86 87class JsonPrefStoreTest : public testing::Test { 88 protected: 89 virtual void SetUp() OVERRIDE { 90 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 91 92 ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &data_dir_)); 93 data_dir_ = data_dir_.AppendASCII("prefs"); 94 ASSERT_TRUE(PathExists(data_dir_)); 95 } 96 97 virtual void TearDown() OVERRIDE { 98 // Make sure all pending tasks have been processed (e.g., deleting the 99 // JsonPrefStore may post write tasks). 100 message_loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure()); 101 message_loop_.Run(); 102 } 103 104 // The path to temporary directory used to contain the test operations. 105 base::ScopedTempDir temp_dir_; 106 // The path to the directory where the test data is stored. 107 base::FilePath data_dir_; 108 // A message loop that we can use as the file thread message loop. 109 MessageLoop message_loop_; 110}; 111 112// Test fallback behavior for a nonexistent file. 113TEST_F(JsonPrefStoreTest, NonExistentFile) { 114 base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt"); 115 ASSERT_FALSE(PathExists(bogus_input_file)); 116 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore( 117 bogus_input_file, 118 message_loop_.message_loop_proxy().get(), 119 scoped_ptr<PrefFilter>()); 120 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE, 121 pref_store->ReadPrefs()); 122 EXPECT_FALSE(pref_store->ReadOnly()); 123} 124 125// Test fallback behavior for a nonexistent file and alternate file. 126TEST_F(JsonPrefStoreTest, NonExistentFileAndAlternateFile) { 127 base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt"); 128 base::FilePath bogus_alternate_input_file = 129 data_dir_.AppendASCII("read_alternate.txt"); 130 ASSERT_FALSE(PathExists(bogus_input_file)); 131 ASSERT_FALSE(PathExists(bogus_alternate_input_file)); 132 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore( 133 bogus_input_file, 134 bogus_alternate_input_file, 135 message_loop_.message_loop_proxy().get(), 136 scoped_ptr<PrefFilter>()); 137 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE, 138 pref_store->ReadPrefs()); 139 EXPECT_FALSE(pref_store->ReadOnly()); 140} 141 142// Test fallback behavior for an invalid file. 143TEST_F(JsonPrefStoreTest, InvalidFile) { 144 base::FilePath invalid_file_original = data_dir_.AppendASCII("invalid.json"); 145 base::FilePath invalid_file = temp_dir_.path().AppendASCII("invalid.json"); 146 ASSERT_TRUE(base::CopyFile(invalid_file_original, invalid_file)); 147 scoped_refptr<JsonPrefStore> pref_store = 148 new JsonPrefStore(invalid_file, 149 message_loop_.message_loop_proxy().get(), 150 scoped_ptr<PrefFilter>()); 151 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE, 152 pref_store->ReadPrefs()); 153 EXPECT_FALSE(pref_store->ReadOnly()); 154 155 // The file should have been moved aside. 156 EXPECT_FALSE(PathExists(invalid_file)); 157 base::FilePath moved_aside = temp_dir_.path().AppendASCII("invalid.bad"); 158 EXPECT_TRUE(PathExists(moved_aside)); 159 EXPECT_TRUE(TextContentsEqual(invalid_file_original, moved_aside)); 160} 161 162// This function is used to avoid code duplication while testing synchronous and 163// asynchronous version of the JsonPrefStore loading. 164void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store, 165 const base::FilePath& output_file, 166 const base::FilePath& golden_output_file) { 167 const char kNewWindowsInTabs[] = "tabs.new_windows_in_tabs"; 168 const char kMaxTabs[] = "tabs.max_tabs"; 169 const char kLongIntPref[] = "long_int.pref"; 170 171 std::string cnn("http://www.cnn.com"); 172 173 const Value* actual; 174 EXPECT_TRUE(pref_store->GetValue(kHomePage, &actual)); 175 std::string string_value; 176 EXPECT_TRUE(actual->GetAsString(&string_value)); 177 EXPECT_EQ(cnn, string_value); 178 179 const char kSomeDirectory[] = "some_directory"; 180 181 EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual)); 182 base::FilePath::StringType path; 183 EXPECT_TRUE(actual->GetAsString(&path)); 184 EXPECT_EQ(base::FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")), path); 185 base::FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/")); 186 187 pref_store->SetValue(kSomeDirectory, new StringValue(some_path.value())); 188 EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual)); 189 EXPECT_TRUE(actual->GetAsString(&path)); 190 EXPECT_EQ(some_path.value(), path); 191 192 // Test reading some other data types from sub-dictionaries. 193 EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual)); 194 bool boolean = false; 195 EXPECT_TRUE(actual->GetAsBoolean(&boolean)); 196 EXPECT_TRUE(boolean); 197 198 pref_store->SetValue(kNewWindowsInTabs, new FundamentalValue(false)); 199 EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual)); 200 EXPECT_TRUE(actual->GetAsBoolean(&boolean)); 201 EXPECT_FALSE(boolean); 202 203 EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual)); 204 int integer = 0; 205 EXPECT_TRUE(actual->GetAsInteger(&integer)); 206 EXPECT_EQ(20, integer); 207 pref_store->SetValue(kMaxTabs, new FundamentalValue(10)); 208 EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual)); 209 EXPECT_TRUE(actual->GetAsInteger(&integer)); 210 EXPECT_EQ(10, integer); 211 212 pref_store->SetValue(kLongIntPref, 213 new StringValue(base::Int64ToString(214748364842LL))); 214 EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual)); 215 EXPECT_TRUE(actual->GetAsString(&string_value)); 216 int64 value; 217 base::StringToInt64(string_value, &value); 218 EXPECT_EQ(214748364842LL, value); 219 220 // Serialize and compare to expected output. 221 ASSERT_TRUE(PathExists(golden_output_file)); 222 pref_store->CommitPendingWrite(); 223 RunLoop().RunUntilIdle(); 224 EXPECT_TRUE(TextContentsEqual(golden_output_file, output_file)); 225 ASSERT_TRUE(base::DeleteFile(output_file, false)); 226} 227 228TEST_F(JsonPrefStoreTest, Basic) { 229 ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"), 230 temp_dir_.path().AppendASCII("write.json"))); 231 232 // Test that the persistent value can be loaded. 233 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json"); 234 ASSERT_TRUE(PathExists(input_file)); 235 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore( 236 input_file, 237 message_loop_.message_loop_proxy().get(), 238 scoped_ptr<PrefFilter>()); 239 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs()); 240 EXPECT_FALSE(pref_store->ReadOnly()); 241 EXPECT_TRUE(pref_store->IsInitializationComplete()); 242 243 // The JSON file looks like this: 244 // { 245 // "homepage": "http://www.cnn.com", 246 // "some_directory": "/usr/local/", 247 // "tabs": { 248 // "new_windows_in_tabs": true, 249 // "max_tabs": 20 250 // } 251 // } 252 253 RunBasicJsonPrefStoreTest( 254 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json")); 255} 256 257TEST_F(JsonPrefStoreTest, BasicAsync) { 258 ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"), 259 temp_dir_.path().AppendASCII("write.json"))); 260 261 // Test that the persistent value can be loaded. 262 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json"); 263 ASSERT_TRUE(PathExists(input_file)); 264 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore( 265 input_file, 266 message_loop_.message_loop_proxy().get(), 267 scoped_ptr<PrefFilter>()); 268 269 { 270 MockPrefStoreObserver mock_observer; 271 pref_store->AddObserver(&mock_observer); 272 273 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate; 274 pref_store->ReadPrefsAsync(mock_error_delegate); 275 276 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1); 277 EXPECT_CALL(*mock_error_delegate, 278 OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0); 279 RunLoop().RunUntilIdle(); 280 pref_store->RemoveObserver(&mock_observer); 281 282 EXPECT_FALSE(pref_store->ReadOnly()); 283 EXPECT_TRUE(pref_store->IsInitializationComplete()); 284 } 285 286 // The JSON file looks like this: 287 // { 288 // "homepage": "http://www.cnn.com", 289 // "some_directory": "/usr/local/", 290 // "tabs": { 291 // "new_windows_in_tabs": true, 292 // "max_tabs": 20 293 // } 294 // } 295 296 RunBasicJsonPrefStoreTest( 297 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json")); 298} 299 300TEST_F(JsonPrefStoreTest, PreserveEmptyValues) { 301 FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json"); 302 303 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore( 304 pref_file, 305 message_loop_.message_loop_proxy(), 306 scoped_ptr<PrefFilter>()); 307 308 // Set some keys with empty values. 309 pref_store->SetValue("list", new base::ListValue); 310 pref_store->SetValue("dict", new base::DictionaryValue); 311 312 // Write to file. 313 pref_store->CommitPendingWrite(); 314 MessageLoop::current()->RunUntilIdle(); 315 316 // Reload. 317 pref_store = new JsonPrefStore( 318 pref_file, 319 message_loop_.message_loop_proxy(), 320 scoped_ptr<PrefFilter>()); 321 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs()); 322 ASSERT_FALSE(pref_store->ReadOnly()); 323 324 // Check values. 325 const Value* result = NULL; 326 EXPECT_TRUE(pref_store->GetValue("list", &result)); 327 EXPECT_TRUE(ListValue().Equals(result)); 328 EXPECT_TRUE(pref_store->GetValue("dict", &result)); 329 EXPECT_TRUE(DictionaryValue().Equals(result)); 330} 331 332// This test is just documenting some potentially non-obvious behavior. It 333// shouldn't be taken as normative. 334TEST_F(JsonPrefStoreTest, RemoveClearsEmptyParent) { 335 FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json"); 336 337 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore( 338 pref_file, 339 message_loop_.message_loop_proxy(), 340 scoped_ptr<PrefFilter>()); 341 342 base::DictionaryValue* dict = new base::DictionaryValue; 343 dict->SetString("key", "value"); 344 pref_store->SetValue("dict", dict); 345 346 pref_store->RemoveValue("dict.key"); 347 348 const base::Value* retrieved_dict = NULL; 349 bool has_dict = pref_store->GetValue("dict", &retrieved_dict); 350 EXPECT_FALSE(has_dict); 351} 352 353// Tests asynchronous reading of the file when there is no file. 354TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) { 355 base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt"); 356 ASSERT_FALSE(PathExists(bogus_input_file)); 357 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore( 358 bogus_input_file, 359 message_loop_.message_loop_proxy().get(), 360 scoped_ptr<PrefFilter>()); 361 MockPrefStoreObserver mock_observer; 362 pref_store->AddObserver(&mock_observer); 363 364 MockReadErrorDelegate *mock_error_delegate = new MockReadErrorDelegate; 365 pref_store->ReadPrefsAsync(mock_error_delegate); 366 367 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1); 368 EXPECT_CALL(*mock_error_delegate, 369 OnError(PersistentPrefStore::PREF_READ_ERROR_NO_FILE)).Times(1); 370 RunLoop().RunUntilIdle(); 371 pref_store->RemoveObserver(&mock_observer); 372 373 EXPECT_FALSE(pref_store->ReadOnly()); 374} 375 376TEST_F(JsonPrefStoreTest, ReadWithInterceptor) { 377 ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"), 378 temp_dir_.path().AppendASCII("write.json"))); 379 380 // Test that the persistent value can be loaded. 381 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json"); 382 ASSERT_TRUE(PathExists(input_file)); 383 384 scoped_ptr<InterceptingPrefFilter> intercepting_pref_filter( 385 new InterceptingPrefFilter()); 386 InterceptingPrefFilter* raw_intercepting_pref_filter_ = 387 intercepting_pref_filter.get(); 388 scoped_refptr<JsonPrefStore> pref_store = 389 new JsonPrefStore(input_file, 390 message_loop_.message_loop_proxy().get(), 391 intercepting_pref_filter.PassAs<PrefFilter>()); 392 393 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE, 394 pref_store->ReadPrefs()); 395 EXPECT_FALSE(pref_store->ReadOnly()); 396 397 // The store shouldn't be considered initialized until the interceptor 398 // returns. 399 EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs()); 400 EXPECT_FALSE(pref_store->IsInitializationComplete()); 401 EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL)); 402 403 raw_intercepting_pref_filter_->ReleasePrefs(); 404 405 EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs()); 406 EXPECT_TRUE(pref_store->IsInitializationComplete()); 407 EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL)); 408 409 // The JSON file looks like this: 410 // { 411 // "homepage": "http://www.cnn.com", 412 // "some_directory": "/usr/local/", 413 // "tabs": { 414 // "new_windows_in_tabs": true, 415 // "max_tabs": 20 416 // } 417 // } 418 419 RunBasicJsonPrefStoreTest( 420 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json")); 421} 422 423TEST_F(JsonPrefStoreTest, ReadAsyncWithInterceptor) { 424 ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"), 425 temp_dir_.path().AppendASCII("write.json"))); 426 427 // Test that the persistent value can be loaded. 428 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json"); 429 ASSERT_TRUE(PathExists(input_file)); 430 431 scoped_ptr<InterceptingPrefFilter> intercepting_pref_filter( 432 new InterceptingPrefFilter()); 433 InterceptingPrefFilter* raw_intercepting_pref_filter_ = 434 intercepting_pref_filter.get(); 435 scoped_refptr<JsonPrefStore> pref_store = 436 new JsonPrefStore(input_file, 437 message_loop_.message_loop_proxy().get(), 438 intercepting_pref_filter.PassAs<PrefFilter>()); 439 440 MockPrefStoreObserver mock_observer; 441 pref_store->AddObserver(&mock_observer); 442 443 // Ownership of the |mock_error_delegate| is handed to the |pref_store| below. 444 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate; 445 446 { 447 pref_store->ReadPrefsAsync(mock_error_delegate); 448 449 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(0); 450 // EXPECT_CALL(*mock_error_delegate, 451 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0); 452 RunLoop().RunUntilIdle(); 453 454 EXPECT_FALSE(pref_store->ReadOnly()); 455 EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs()); 456 EXPECT_FALSE(pref_store->IsInitializationComplete()); 457 EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL)); 458 } 459 460 { 461 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1); 462 // EXPECT_CALL(*mock_error_delegate, 463 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0); 464 465 raw_intercepting_pref_filter_->ReleasePrefs(); 466 467 EXPECT_FALSE(pref_store->ReadOnly()); 468 EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs()); 469 EXPECT_TRUE(pref_store->IsInitializationComplete()); 470 EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL)); 471 } 472 473 pref_store->RemoveObserver(&mock_observer); 474 475 // The JSON file looks like this: 476 // { 477 // "homepage": "http://www.cnn.com", 478 // "some_directory": "/usr/local/", 479 // "tabs": { 480 // "new_windows_in_tabs": true, 481 // "max_tabs": 20 482 // } 483 // } 484 485 RunBasicJsonPrefStoreTest( 486 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json")); 487} 488 489TEST_F(JsonPrefStoreTest, AlternateFile) { 490 ASSERT_TRUE( 491 base::CopyFile(data_dir_.AppendASCII("read.json"), 492 temp_dir_.path().AppendASCII("alternate.json"))); 493 494 // Test that the alternate file is moved to the main file and read as-is from 495 // there. 496 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json"); 497 base::FilePath alternate_input_file = 498 temp_dir_.path().AppendASCII("alternate.json"); 499 ASSERT_FALSE(PathExists(input_file)); 500 ASSERT_TRUE(PathExists(alternate_input_file)); 501 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore( 502 input_file, 503 alternate_input_file, 504 message_loop_.message_loop_proxy().get(), 505 scoped_ptr<PrefFilter>()); 506 507 ASSERT_FALSE(PathExists(input_file)); 508 ASSERT_TRUE(PathExists(alternate_input_file)); 509 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs()); 510 511 ASSERT_TRUE(PathExists(input_file)); 512 ASSERT_FALSE(PathExists(alternate_input_file)); 513 514 EXPECT_FALSE(pref_store->ReadOnly()); 515 EXPECT_TRUE(pref_store->IsInitializationComplete()); 516 517 // The JSON file looks like this: 518 // { 519 // "homepage": "http://www.cnn.com", 520 // "some_directory": "/usr/local/", 521 // "tabs": { 522 // "new_windows_in_tabs": true, 523 // "max_tabs": 20 524 // } 525 // } 526 527 RunBasicJsonPrefStoreTest( 528 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json")); 529} 530 531TEST_F(JsonPrefStoreTest, AlternateFileIgnoredWhenMainFileExists) { 532 ASSERT_TRUE( 533 base::CopyFile(data_dir_.AppendASCII("read.json"), 534 temp_dir_.path().AppendASCII("write.json"))); 535 ASSERT_TRUE( 536 base::CopyFile(data_dir_.AppendASCII("invalid.json"), 537 temp_dir_.path().AppendASCII("alternate.json"))); 538 539 // Test that the alternate file is ignored and that the read occurs from the 540 // existing main file. There is no attempt at even deleting the alternate 541 // file as this scenario should never happen in normal user-data-dirs. 542 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json"); 543 base::FilePath alternate_input_file = 544 temp_dir_.path().AppendASCII("alternate.json"); 545 ASSERT_TRUE(PathExists(input_file)); 546 ASSERT_TRUE(PathExists(alternate_input_file)); 547 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore( 548 input_file, 549 alternate_input_file, 550 message_loop_.message_loop_proxy().get(), 551 scoped_ptr<PrefFilter>()); 552 553 ASSERT_TRUE(PathExists(input_file)); 554 ASSERT_TRUE(PathExists(alternate_input_file)); 555 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs()); 556 557 ASSERT_TRUE(PathExists(input_file)); 558 ASSERT_TRUE(PathExists(alternate_input_file)); 559 560 EXPECT_FALSE(pref_store->ReadOnly()); 561 EXPECT_TRUE(pref_store->IsInitializationComplete()); 562 563 // The JSON file looks like this: 564 // { 565 // "homepage": "http://www.cnn.com", 566 // "some_directory": "/usr/local/", 567 // "tabs": { 568 // "new_windows_in_tabs": true, 569 // "max_tabs": 20 570 // } 571 // } 572 573 RunBasicJsonPrefStoreTest( 574 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json")); 575} 576 577TEST_F(JsonPrefStoreTest, AlternateFileDNE) { 578 ASSERT_TRUE( 579 base::CopyFile(data_dir_.AppendASCII("read.json"), 580 temp_dir_.path().AppendASCII("write.json"))); 581 582 // Test that the basic read works fine when an alternate file is specified but 583 // does not exist. 584 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json"); 585 base::FilePath alternate_input_file = 586 temp_dir_.path().AppendASCII("alternate.json"); 587 ASSERT_TRUE(PathExists(input_file)); 588 ASSERT_FALSE(PathExists(alternate_input_file)); 589 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore( 590 input_file, 591 alternate_input_file, 592 message_loop_.message_loop_proxy().get(), 593 scoped_ptr<PrefFilter>()); 594 595 ASSERT_TRUE(PathExists(input_file)); 596 ASSERT_FALSE(PathExists(alternate_input_file)); 597 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs()); 598 599 ASSERT_TRUE(PathExists(input_file)); 600 ASSERT_FALSE(PathExists(alternate_input_file)); 601 602 EXPECT_FALSE(pref_store->ReadOnly()); 603 EXPECT_TRUE(pref_store->IsInitializationComplete()); 604 605 // The JSON file looks like this: 606 // { 607 // "homepage": "http://www.cnn.com", 608 // "some_directory": "/usr/local/", 609 // "tabs": { 610 // "new_windows_in_tabs": true, 611 // "max_tabs": 20 612 // } 613 // } 614 615 RunBasicJsonPrefStoreTest( 616 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json")); 617} 618 619TEST_F(JsonPrefStoreTest, BasicAsyncWithAlternateFile) { 620 ASSERT_TRUE( 621 base::CopyFile(data_dir_.AppendASCII("read.json"), 622 temp_dir_.path().AppendASCII("alternate.json"))); 623 624 // Test that the alternate file is moved to the main file and read as-is from 625 // there even when the read is made asynchronously. 626 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json"); 627 base::FilePath alternate_input_file = 628 temp_dir_.path().AppendASCII("alternate.json"); 629 ASSERT_FALSE(PathExists(input_file)); 630 ASSERT_TRUE(PathExists(alternate_input_file)); 631 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore( 632 input_file, 633 alternate_input_file, 634 message_loop_.message_loop_proxy().get(), 635 scoped_ptr<PrefFilter>()); 636 637 ASSERT_FALSE(PathExists(input_file)); 638 ASSERT_TRUE(PathExists(alternate_input_file)); 639 640 { 641 MockPrefStoreObserver mock_observer; 642 pref_store->AddObserver(&mock_observer); 643 644 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate; 645 pref_store->ReadPrefsAsync(mock_error_delegate); 646 647 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1); 648 EXPECT_CALL(*mock_error_delegate, 649 OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0); 650 RunLoop().RunUntilIdle(); 651 pref_store->RemoveObserver(&mock_observer); 652 653 EXPECT_FALSE(pref_store->ReadOnly()); 654 EXPECT_TRUE(pref_store->IsInitializationComplete()); 655 } 656 657 ASSERT_TRUE(PathExists(input_file)); 658 ASSERT_FALSE(PathExists(alternate_input_file)); 659 660 // The JSON file looks like this: 661 // { 662 // "homepage": "http://www.cnn.com", 663 // "some_directory": "/usr/local/", 664 // "tabs": { 665 // "new_windows_in_tabs": true, 666 // "max_tabs": 20 667 // } 668 // } 669 670 RunBasicJsonPrefStoreTest( 671 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json")); 672} 673 674} // namespace base 675