summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-12 03:41:37 +0000
committerxiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-12 03:41:37 +0000
commitea3e497b1949405ae04caa8b1dc8400672b1dfa1 (patch)
tree597971f904ab59e7e47fbe108c241e66640c5d4e
parent92a794994111f442e9c7ba1792a5418a77c2ca74 (diff)
downloadchromium_src-ea3e497b1949405ae04caa8b1dc8400672b1dfa1.zip
chromium_src-ea3e497b1949405ae04caa8b1dc8400672b1dfa1.tar.gz
chromium_src-ea3e497b1949405ae04caa8b1dc8400672b1dfa1.tar.bz2
Keep emtpy List/Dictionary pref value with non-empty default.
- Add a MarkNeedsEmptyValue method to JsonPrefStore; - In PrefService::RegisterPreference, mark ListValue and DictionaryValue pref with non-empty default as needing empty value in |user_pref_store_|; - Update ChromeLauncherDelegate to put back default pinned apps and add migration logic for M19 users; - Add unit tests; BUG=122679 TEST=Verify fix for issue 122679. Review URL: http://codereview.chromium.org/10055003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@131919 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/prefs/overlay_user_pref_store.cc5
-rw-r--r--chrome/browser/prefs/overlay_user_pref_store.h1
-rw-r--r--chrome/browser/prefs/pref_service.cc17
-rw-r--r--chrome/browser/prefs/pref_service_mock_builder.cc14
-rw-r--r--chrome/browser/prefs/pref_service_mock_builder.h7
-rw-r--r--chrome/browser/prefs/pref_service_unittest.cc81
-rw-r--r--chrome/browser/prefs/testing_pref_store.cc3
-rw-r--r--chrome/browser/prefs/testing_pref_store.h1
-rw-r--r--chrome/browser/ui/views/ash/launcher/chrome_launcher_delegate.cc39
-rw-r--r--chrome/common/json_pref_store.cc28
-rw-r--r--chrome/common/json_pref_store.h4
-rw-r--r--chrome/common/json_pref_store_unittest.cc49
-rw-r--r--chrome/common/persistent_pref_store.h4
-rw-r--r--chrome/test/data/pref_service/read.need_empty_value.json10
-rw-r--r--chrome/test/data/pref_service/write.golden.need_empty_value.json6
15 files changed, 251 insertions, 18 deletions
diff --git a/chrome/browser/prefs/overlay_user_pref_store.cc b/chrome/browser/prefs/overlay_user_pref_store.cc
index ca4f585..8d04ec3 100644
--- a/chrome/browser/prefs/overlay_user_pref_store.cc
+++ b/chrome/browser/prefs/overlay_user_pref_store.cc
@@ -101,6 +101,11 @@ void OverlayUserPrefStore::RemoveValue(const std::string& key) {
ReportValueChanged(key);
}
+void OverlayUserPrefStore::MarkNeedsEmptyValue(const std::string& key) {
+ if (!ShallBeStoredInOverlay(key))
+ underlay_->MarkNeedsEmptyValue(key);
+}
+
bool OverlayUserPrefStore::ReadOnly() const {
return false;
}
diff --git a/chrome/browser/prefs/overlay_user_pref_store.h b/chrome/browser/prefs/overlay_user_pref_store.h
index f0a1f4b..105dc67 100644
--- a/chrome/browser/prefs/overlay_user_pref_store.h
+++ b/chrome/browser/prefs/overlay_user_pref_store.h
@@ -45,6 +45,7 @@ class OverlayUserPrefStore : public PersistentPrefStore,
virtual void SetValueSilently(const std::string& key,
base::Value* value) OVERRIDE;
virtual void RemoveValue(const std::string& key) OVERRIDE;
+ virtual void MarkNeedsEmptyValue(const std::string& key) OVERRIDE;
virtual bool ReadOnly() const OVERRIDE;
virtual PrefReadError GetReadError() const OVERRIDE;
virtual PrefReadError ReadPrefs() OVERRIDE;
diff --git a/chrome/browser/prefs/pref_service.cc b/chrome/browser/prefs/pref_service.cc
index cf9f22e..de7f406 100644
--- a/chrome/browser/prefs/pref_service.cc
+++ b/chrome/browser/prefs/pref_service.cc
@@ -727,6 +727,23 @@ void PrefService::RegisterPreference(const char* path,
DCHECK(orig_type != Value::TYPE_NULL && orig_type != Value::TYPE_BINARY) <<
"invalid preference type: " << orig_type;
+ // For ListValue and DictionaryValue with non empty default, empty value
+ // for |path| needs to be persisted in |user_pref_store_|. So that
+ // non empty default is not used when user sets an empty ListValue or
+ // DictionaryValue.
+ bool needs_empty_value = false;
+ if (orig_type == base::Value::TYPE_LIST) {
+ const base::ListValue* list = NULL;
+ if (default_value->GetAsList(&list) && !list->empty())
+ needs_empty_value = true;
+ } else if (orig_type == base::Value::TYPE_DICTIONARY) {
+ const base::DictionaryValue* dict = NULL;
+ if (default_value->GetAsDictionary(&dict) && !dict->empty())
+ needs_empty_value = true;
+ }
+ if (needs_empty_value)
+ user_pref_store_->MarkNeedsEmptyValue(path);
+
// Hand off ownership.
default_store_->SetDefaultValue(path, scoped_value.release());
diff --git a/chrome/browser/prefs/pref_service_mock_builder.cc b/chrome/browser/prefs/pref_service_mock_builder.cc
index 5b4ba24..edfe696 100644
--- a/chrome/browser/prefs/pref_service_mock_builder.cc
+++ b/chrome/browser/prefs/pref_service_mock_builder.cc
@@ -77,10 +77,16 @@ PrefServiceMockBuilder::WithCommandLine(CommandLine* command_line) {
PrefServiceMockBuilder&
PrefServiceMockBuilder::WithUserFilePrefs(const FilePath& prefs_file) {
- user_prefs_ =
- new JsonPrefStore(prefs_file,
- BrowserThread::GetMessageLoopProxyForThread(
- BrowserThread::FILE));
+ return WithUserFilePrefs(prefs_file,
+ BrowserThread::GetMessageLoopProxyForThread(
+ BrowserThread::FILE));
+}
+
+PrefServiceMockBuilder&
+PrefServiceMockBuilder::WithUserFilePrefs(
+ const FilePath& prefs_file,
+ base::MessageLoopProxy* message_loop_proxy) {
+ user_prefs_ = new JsonPrefStore(prefs_file, message_loop_proxy);
return *this;
}
diff --git a/chrome/browser/prefs/pref_service_mock_builder.h b/chrome/browser/prefs/pref_service_mock_builder.h
index 5ea5ace..2dd764f 100644
--- a/chrome/browser/prefs/pref_service_mock_builder.h
+++ b/chrome/browser/prefs/pref_service_mock_builder.h
@@ -15,6 +15,10 @@ class CommandLine;
class FilePath;
class PrefService;
+namespace base {
+class MessageLoopProxy;
+}
+
namespace policy {
class PolicyService;
}
@@ -46,6 +50,9 @@ class PrefServiceMockBuilder {
// Specifies to use an actual file-backed user pref store.
PrefServiceMockBuilder& WithUserFilePrefs(const FilePath& prefs_file);
+ PrefServiceMockBuilder& WithUserFilePrefs(
+ const FilePath& prefs_file,
+ base::MessageLoopProxy* message_loop_proxy);
// Creates the PrefService, invalidating the entire builder configuration.
PrefService* Create();
diff --git a/chrome/browser/prefs/pref_service_unittest.cc b/chrome/browser/prefs/pref_service_unittest.cc
index 8a7069c..38d6ea96 100644
--- a/chrome/browser/prefs/pref_service_unittest.cc
+++ b/chrome/browser/prefs/pref_service_unittest.cc
@@ -5,7 +5,10 @@
#include <string>
#include "base/command_line.h"
+#include "base/file_util.h"
#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/scoped_temp_dir.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/policy/configuration_policy_pref_store.h"
@@ -16,9 +19,11 @@
#include "chrome/browser/prefs/pref_observer_mock.h"
#include "chrome/browser/prefs/pref_service_mock_builder.h"
#include "chrome/browser/prefs/pref_value_store.h"
+#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/prefs/testing_pref_store.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/json_pref_store.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_pref_service.h"
@@ -182,6 +187,82 @@ TEST(PrefServiceTest, UpdateCommandLinePrefStore) {
EXPECT_TRUE(actual_bool_value);
}
+class PrefServiceUserFilePrefsTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_dir_));
+ data_dir_ = data_dir_.AppendASCII("pref_service");
+ ASSERT_TRUE(file_util::PathExists(data_dir_));
+ }
+
+ void ClearListValue(PrefService* prefs, const char* key) {
+ ListPrefUpdate updater(prefs, key);
+ updater->Clear();
+ }
+
+ void ClearDictionaryValue(PrefService* prefs, const char* key) {
+ DictionaryPrefUpdate updater(prefs, key);
+ updater->Clear();
+ }
+
+ // The path to temporary directory used to contain the test operations.
+ ScopedTempDir temp_dir_;
+ // The path to the directory where the test data is stored.
+ FilePath data_dir_;
+ // A message loop that we can use as the file thread message loop.
+ MessageLoop message_loop_;
+};
+
+// Verifies that ListValue and DictionaryValue pref with non emtpy default
+// preserves its empty value.
+TEST_F(PrefServiceUserFilePrefsTest, PreserveEmptyValue) {
+ FilePath pref_file = temp_dir_.path().AppendASCII("write.json");
+
+ ASSERT_TRUE(file_util::CopyFile(
+ data_dir_.AppendASCII("read.need_empty_value.json"),
+ pref_file));
+
+ PrefServiceMockBuilder builder;
+ builder.WithUserFilePrefs(pref_file, base::MessageLoopProxy::current());
+ scoped_ptr<PrefService> prefs(builder.Create());
+
+ // Register testing prefs.
+ prefs->RegisterListPref("list",
+ PrefService::UNSYNCABLE_PREF);
+ prefs->RegisterDictionaryPref("dict",
+ PrefService::UNSYNCABLE_PREF);
+
+ base::ListValue* non_empty_list = new base::ListValue;
+ non_empty_list->Append(base::Value::CreateStringValue("test"));
+ prefs->RegisterListPref("list_needs_empty_value",
+ non_empty_list,
+ PrefService::UNSYNCABLE_PREF);
+
+ base::DictionaryValue* non_empty_dict = new base::DictionaryValue;
+ non_empty_dict->SetString("dummy", "whatever");
+ prefs->RegisterDictionaryPref("dict_needs_empty_value",
+ non_empty_dict,
+ PrefService::UNSYNCABLE_PREF);
+
+ // Set all testing prefs to empty.
+ ClearListValue(prefs.get(), "list");
+ ClearListValue(prefs.get(), "list_needs_empty_value");
+ ClearDictionaryValue(prefs.get(), "dict");
+ ClearDictionaryValue(prefs.get(), "dict_needs_empty_value");
+
+ // Write to file.
+ prefs->CommitPendingWrite();
+ MessageLoop::current()->RunAllPending();
+
+ // Compare to expected output.
+ FilePath golden_output_file =
+ data_dir_.AppendASCII("write.golden.need_empty_value.json");
+ ASSERT_TRUE(file_util::PathExists(golden_output_file));
+ EXPECT_TRUE(file_util::TextContentsEqual(golden_output_file, pref_file));
+}
+
class PrefServiceSetValueTest : public testing::Test {
protected:
static const char kName[];
diff --git a/chrome/browser/prefs/testing_pref_store.cc b/chrome/browser/prefs/testing_pref_store.cc
index 8948598..f7ce0f4 100644
--- a/chrome/browser/prefs/testing_pref_store.cc
+++ b/chrome/browser/prefs/testing_pref_store.cc
@@ -53,6 +53,9 @@ void TestingPrefStore::RemoveValue(const std::string& key) {
NotifyPrefValueChanged(key);
}
+void TestingPrefStore::MarkNeedsEmptyValue(const std::string& key) {
+}
+
bool TestingPrefStore::ReadOnly() const {
return read_only_;
}
diff --git a/chrome/browser/prefs/testing_pref_store.h b/chrome/browser/prefs/testing_pref_store.h
index 85965da..9cda821 100644
--- a/chrome/browser/prefs/testing_pref_store.h
+++ b/chrome/browser/prefs/testing_pref_store.h
@@ -38,6 +38,7 @@ class TestingPrefStore : public PersistentPrefStore {
virtual void SetValueSilently(const std::string& key,
base::Value* value) OVERRIDE;
virtual void RemoveValue(const std::string& key) OVERRIDE;
+ virtual void MarkNeedsEmptyValue(const std::string& key) OVERRIDE;
virtual bool ReadOnly() const OVERRIDE;
virtual PrefReadError GetReadError() const OVERRIDE;
virtual PersistentPrefStore::PrefReadError ReadPrefs() OVERRIDE;
diff --git a/chrome/browser/ui/views/ash/launcher/chrome_launcher_delegate.cc b/chrome/browser/ui/views/ash/launcher/chrome_launcher_delegate.cc
index 0eb6e30..d7179f6 100644
--- a/chrome/browser/ui/views/ash/launcher/chrome_launcher_delegate.cc
+++ b/chrome/browser/ui/views/ash/launcher/chrome_launcher_delegate.cc
@@ -140,19 +140,31 @@ ChromeLauncherDelegate::~ChromeLauncherDelegate() {
}
void ChromeLauncherDelegate::Init() {
- const base::ListValue* pinned_apps =
- profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
-
- // Use default pinned apps only when current pinned apps list is empty and
- // kUseDefaultPinnedApps is true.
- // TODO(xiyuan): Remove this after http://crbug.com/122679 is resolved.
- scoped_ptr<base::ListValue> default_pinned_apps;
- if (pinned_apps->empty() &&
- profile_->GetPrefs()->GetBoolean(prefs::kUseDefaultPinnedApps)) {
- default_pinned_apps.reset(CreateDefaultPinnedAppsList());
- pinned_apps = default_pinned_apps.get();
+ // TODO(xiyuan): Remove migration code and kUseDefaultPinnedApp after M20.
+ // Migration cases:
+ // - Users that unpin all apps:
+ // - have default pinned apps
+ // - kUseDefaultPinnedApps set to false
+ // Migrate them by setting an empty list for kPinnedLauncherApps.
+ //
+ // - Users that have customized pinned apps:
+ // - have non-default non-empty pinned apps list
+ // - kUseDefaultPinnedApps set to false
+ // Nothing needs to be done because customized pref overrides default.
+ //
+ // - Users that have default apps (i.e. new user or never pin/unpin):
+ // - have default pinned apps
+ // - kUseDefaultPinnedApps is still true
+ // Nothing needs to be done because they should get the default.
+ if (profile_->GetPrefs()->FindPreference(
+ prefs::kPinnedLauncherApps)->IsDefaultValue() &&
+ !profile_->GetPrefs()->GetBoolean(prefs::kUseDefaultPinnedApps)) {
+ ListPrefUpdate updater(profile_->GetPrefs(), prefs::kPinnedLauncherApps);
+ updater.Get()->Clear();
}
+ const base::ListValue* pinned_apps =
+ profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
for (size_t i = 0; i < pinned_apps->GetSize(); ++i) {
DictionaryValue* app = NULL;
if (pinned_apps->GetDictionary(i, &app)) {
@@ -201,6 +213,7 @@ void ChromeLauncherDelegate::RegisterUserPrefs(PrefService* user_prefs) {
true,
PrefService::SYNCABLE_PREF);
user_prefs->RegisterListPref(prefs::kPinnedLauncherApps,
+ CreateDefaultPinnedAppsList(),
PrefService::SYNCABLE_PREF);
user_prefs->RegisterStringPref(prefs::kShelfAutoHideBehavior,
kShelfAutoHideBehaviorDefault,
@@ -573,7 +586,7 @@ void ChromeLauncherDelegate::PersistPinnedState() {
profile_->GetPrefs()->SetBoolean(prefs::kUseDefaultPinnedApps, false);
ListPrefUpdate updater(profile_->GetPrefs(), prefs::kPinnedLauncherApps);
- updater.Get()->Clear();
+ updater->Clear();
for (size_t i = 0; i < model_->items().size(); ++i) {
if (model_->items()[i].type == ash::TYPE_APP_SHORTCUT) {
ash::LauncherID id = model_->items()[i].id;
@@ -583,7 +596,7 @@ void ChromeLauncherDelegate::PersistPinnedState() {
id_to_item_map_[id].app_id,
id_to_item_map_[id].app_type);
if (app_value)
- updater.Get()->Append(app_value);
+ updater->Append(app_value);
}
}
}
diff --git a/chrome/common/json_pref_store.cc b/chrome/common/json_pref_store.cc
index 006ed33..488d7c7 100644
--- a/chrome/common/json_pref_store.cc
+++ b/chrome/common/json_pref_store.cc
@@ -212,6 +212,10 @@ void JsonPrefStore::RemoveValue(const std::string& key) {
ReportValueChanged(key);
}
+void JsonPrefStore::MarkNeedsEmptyValue(const std::string& key) {
+ keys_need_empty_value_.insert(key);
+}
+
bool JsonPrefStore::ReadOnly() const {
return read_only_;
}
@@ -310,5 +314,29 @@ bool JsonPrefStore::SerializeData(std::string* output) {
JSONStringValueSerializer serializer(output);
serializer.set_pretty_print(true);
scoped_ptr<DictionaryValue> copy(prefs_->DeepCopyWithoutEmptyChildren());
+
+ // Iterates |keys_need_empty_value_| and if the key exists in |prefs_|,
+ // ensure its empty ListValue or DictonaryValue is preserved.
+ for (std::set<std::string>::const_iterator
+ it = keys_need_empty_value_.begin();
+ it != keys_need_empty_value_.end();
+ ++it) {
+ const std::string& key = *it;
+
+ base::Value* value = NULL;
+ if (!prefs_->Get(key, &value))
+ continue;
+
+ if (value->IsType(base::Value::TYPE_LIST)) {
+ const base::ListValue* list = NULL;
+ if (value->GetAsList(&list) && list->empty())
+ copy->Set(key, new base::ListValue);
+ } else if (value->IsType(base::Value::TYPE_DICTIONARY)) {
+ const base::DictionaryValue* dict = NULL;
+ if (value->GetAsDictionary(&dict) && dict->empty())
+ copy->Set(key, new base::DictionaryValue);
+ }
+ }
+
return serializer.Serialize(*(copy.get()));
}
diff --git a/chrome/common/json_pref_store.h b/chrome/common/json_pref_store.h
index e902751..21198cc 100644
--- a/chrome/common/json_pref_store.h
+++ b/chrome/common/json_pref_store.h
@@ -6,6 +6,7 @@
#define CHROME_COMMON_JSON_PREF_STORE_H_
#pragma once
+#include <set>
#include <string>
#include "base/basictypes.h"
@@ -49,6 +50,7 @@ class JsonPrefStore : public PersistentPrefStore,
virtual void SetValueSilently(const std::string& key,
base::Value* value) OVERRIDE;
virtual void RemoveValue(const std::string& key) OVERRIDE;
+ virtual void MarkNeedsEmptyValue(const std::string& key) OVERRIDE;
virtual bool ReadOnly() const OVERRIDE;
virtual PrefReadError GetReadError() const OVERRIDE;
virtual PrefReadError ReadPrefs() OVERRIDE;
@@ -83,6 +85,8 @@ class JsonPrefStore : public PersistentPrefStore,
bool initialized_;
PrefReadError read_error_;
+ std::set<std::string> keys_need_empty_value_;
+
DISALLOW_COPY_AND_ASSIGN(JsonPrefStore);
};
diff --git a/chrome/common/json_pref_store_unittest.cc b/chrome/common/json_pref_store_unittest.cc
index 05d2493..5b5a5f3 100644
--- a/chrome/common/json_pref_store_unittest.cc
+++ b/chrome/common/json_pref_store_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -244,3 +244,50 @@ TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) {
EXPECT_FALSE(pref_store->ReadOnly());
}
+
+TEST_F(JsonPrefStoreTest, NeedsEmptyValue) {
+ FilePath pref_file = temp_dir_.path().AppendASCII("write.json");
+
+ ASSERT_TRUE(file_util::CopyFile(
+ data_dir_.AppendASCII("read.need_empty_value.json"),
+ pref_file));
+
+ // Test that the persistent value can be loaded.
+ ASSERT_TRUE(file_util::PathExists(pref_file));
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(pref_file, message_loop_proxy_.get());
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
+ ASSERT_FALSE(pref_store->ReadOnly());
+
+ // The JSON file looks like this:
+ // {
+ // "list": [ 1 ],
+ // "list_needs_empty_value": [ 2 ],
+ // "dict": {
+ // "dummy": true,
+ // },
+ // "dict_needs_empty_value": {
+ // "dummy": true,
+ // },
+ // }
+
+ // Set flag to preserve empty values for the following keys.
+ pref_store->MarkNeedsEmptyValue("list_needs_empty_value");
+ pref_store->MarkNeedsEmptyValue("dict_needs_empty_value");
+
+ // Set all keys to empty values.
+ pref_store->SetValue("list", new base::ListValue);
+ pref_store->SetValue("list_needs_empty_value", new base::ListValue);
+ pref_store->SetValue("dict", new base::DictionaryValue);
+ pref_store->SetValue("dict_needs_empty_value", new base::DictionaryValue);
+
+ // Write to file.
+ pref_store->CommitPendingWrite();
+ MessageLoop::current()->RunAllPending();
+
+ // Compare to expected output.
+ FilePath golden_output_file =
+ data_dir_.AppendASCII("write.golden.need_empty_value.json");
+ ASSERT_TRUE(file_util::PathExists(golden_output_file));
+ EXPECT_TRUE(file_util::TextContentsEqual(golden_output_file, pref_file));
+}
diff --git a/chrome/common/persistent_pref_store.h b/chrome/common/persistent_pref_store.h
index df5a49a..8b8b87b 100644
--- a/chrome/common/persistent_pref_store.h
+++ b/chrome/common/persistent_pref_store.h
@@ -65,6 +65,10 @@ class PersistentPrefStore : public PrefStore {
// Removes the value for |key|.
virtual void RemoveValue(const std::string& key) = 0;
+ // Marks that the |key| with empty ListValue/DictionaryValue needs to be
+ // persisted.
+ virtual void MarkNeedsEmptyValue(const std::string& key) = 0;
+
// Whether the store is in a pseudo-read-only mode where changes are not
// actually persisted to disk. This happens in some cases when there are
// read errors during startup.
diff --git a/chrome/test/data/pref_service/read.need_empty_value.json b/chrome/test/data/pref_service/read.need_empty_value.json
new file mode 100644
index 0000000..48e1749
--- /dev/null
+++ b/chrome/test/data/pref_service/read.need_empty_value.json
@@ -0,0 +1,10 @@
+{
+ "list": [ 1 ],
+ "list_needs_empty_value": [ 2 ],
+ "dict": {
+ "dummy": true
+ },
+ "dict_needs_empty_value": {
+ "dummy": true
+ }
+}
diff --git a/chrome/test/data/pref_service/write.golden.need_empty_value.json b/chrome/test/data/pref_service/write.golden.need_empty_value.json
new file mode 100644
index 0000000..fa79590
--- /dev/null
+++ b/chrome/test/data/pref_service/write.golden.need_empty_value.json
@@ -0,0 +1,6 @@
+{
+ "dict_needs_empty_value": {
+
+ },
+ "list_needs_empty_value": [ ]
+}