Home | History | Annotate | Download | only in prefs
      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 
     25 namespace base {
     26 namespace {
     27 
     28 const 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.
     32 class 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 
     58 InterceptingPrefFilter::InterceptingPrefFilter() {}
     59 InterceptingPrefFilter::~InterceptingPrefFilter() {}
     60 
     61 void 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 
     68 void 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 
     74 class MockPrefStoreObserver : public PrefStore::Observer {
     75  public:
     76   MOCK_METHOD1(OnPrefValueChanged, void (const std::string&));
     77   MOCK_METHOD1(OnInitializationCompleted, void (bool));
     78 };
     79 
     80 class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
     81  public:
     82   MOCK_METHOD1(OnError, void(PersistentPrefStore::PrefReadError));
     83 };
     84 
     85 }  // namespace
     86 
     87 class 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.
    113 TEST_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.
    126 TEST_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.
    143 TEST_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.
    164 void 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 
    228 TEST_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 
    257 TEST_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 
    300 TEST_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.
    334 TEST_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.
    354 TEST_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 
    376 TEST_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 
    423 TEST_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 
    489 TEST_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 
    531 TEST_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 
    577 TEST_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 
    619 TEST_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