Index: services/preferences/pref_service_factory_unittest.cc |
diff --git a/services/preferences/pref_service_factory_unittest.cc b/services/preferences/pref_service_factory_unittest.cc |
index 21094e823adff98799081d2455d458a8237ad647..7310d2e436d9c5e2e327abfee66308edcce05197 100644 |
--- a/services/preferences/pref_service_factory_unittest.cc |
+++ b/services/preferences/pref_service_factory_unittest.cc |
@@ -7,6 +7,7 @@ |
#include "base/files/scoped_temp_dir.h" |
#include "base/memory/ptr_util.h" |
#include "base/message_loop/message_loop.h" |
+#include "base/strings/utf_string_conversions.h" |
#include "base/test/sequenced_worker_pool_owner.h" |
#include "components/prefs/pref_change_registrar.h" |
#include "components/prefs/pref_registry_simple.h" |
@@ -16,6 +17,7 @@ |
#include "mojo/public/cpp/bindings/binding_set.h" |
#include "services/preferences/public/cpp/pref_service_main.h" |
#include "services/preferences/public/cpp/pref_store_impl.h" |
+#include "services/preferences/public/cpp/scoped_pref_update.h" |
#include "services/preferences/public/interfaces/preferences.mojom.h" |
#include "services/service_manager/public/cpp/binder_registry.h" |
#include "services/service_manager/public/cpp/interface_factory.h" |
@@ -76,6 +78,7 @@ constexpr int kInitialValue = 1; |
constexpr int kUpdatedValue = 2; |
constexpr char kKey[] = "some_key"; |
constexpr char kOtherKey[] = "some_other_key"; |
+constexpr char kDictionaryKey[] = "a.dictionary.pref"; |
class PrefServiceFactoryTest : public base::MessageLoop::DestructionObserver, |
public service_manager::test::ServiceTest { |
@@ -131,6 +134,7 @@ class PrefServiceFactoryTest : public base::MessageLoop::DestructionObserver, |
auto pref_registry = make_scoped_refptr(new PrefRegistrySimple()); |
pref_registry->RegisterIntegerPref(kKey, kInitialValue); |
pref_registry->RegisterIntegerPref(kOtherKey, kInitialValue); |
+ pref_registry->RegisterDictionaryPref(kDictionaryKey); |
ConnectToPrefService(connector(), pref_registry, |
std::vector<PrefValueStore::PrefStoreType>(), |
base::Bind(&PrefServiceFactoryTest::OnCreate, |
@@ -265,5 +269,211 @@ TEST_F(PrefServiceFactoryTest, ReadOnlyPrefStore_UserPrefStoreLayering) { |
EXPECT_EQ(2, pref_service->GetInteger(kKey)); |
} |
+void Fail(PrefService* pref_service) { |
+ FAIL() << "Unexpected change notification: " |
+ << *pref_service->GetDictionary(kDictionaryKey); |
+} |
+ |
+TEST_F(PrefServiceFactoryTest, MultipleClients_SubPrefUpdates_Basic) { |
+ auto pref_service = Create(); |
+ auto pref_service2 = Create(); |
+ |
+ void (*updates[])(ScopedDictionaryPrefUpdate*) = { |
+ [](ScopedDictionaryPrefUpdate* update) { |
+ (*update)->SetInteger("path.to.integer", 1); |
+ int out = 0; |
+ ASSERT_TRUE((*update)->GetInteger("path.to.integer", &out)); |
+ EXPECT_EQ(1, out); |
+ }, |
+ [](ScopedDictionaryPrefUpdate* update) { |
+ (*update)->SetIntegerWithoutPathExpansion("key.for.integer", 2); |
+ int out = 0; |
+ ASSERT_TRUE( |
+ (*update)->GetIntegerWithoutPathExpansion("key.for.integer", &out)); |
+ EXPECT_EQ(2, out); |
+ }, |
+ [](ScopedDictionaryPrefUpdate* update) { |
+ (*update)->SetDouble("path.to.double", 3); |
+ double out = 0; |
+ ASSERT_TRUE((*update)->GetDouble("path.to.double", &out)); |
+ EXPECT_EQ(3, out); |
+ }, |
+ [](ScopedDictionaryPrefUpdate* update) { |
+ (*update)->SetDoubleWithoutPathExpansion("key.for.double", 4); |
+ double out = 0; |
+ ASSERT_TRUE( |
+ (*update)->GetDoubleWithoutPathExpansion("key.for.double", &out)); |
+ EXPECT_EQ(4, out); |
+ }, |
+ [](ScopedDictionaryPrefUpdate* update) { |
+ (*update)->SetBoolean("path.to.boolean", true); |
+ bool out = 0; |
+ ASSERT_TRUE((*update)->GetBoolean("path.to.boolean", &out)); |
+ EXPECT_TRUE(out); |
+ }, |
+ [](ScopedDictionaryPrefUpdate* update) { |
+ (*update)->SetBooleanWithoutPathExpansion("key.for.boolean", false); |
+ bool out = 0; |
+ ASSERT_TRUE( |
+ (*update)->GetBooleanWithoutPathExpansion("key.for.boolean", &out)); |
+ EXPECT_FALSE(out); |
+ }, |
+ [](ScopedDictionaryPrefUpdate* update) { |
+ (*update)->SetString("path.to.string", "hello"); |
+ std::string out; |
+ ASSERT_TRUE((*update)->GetString("path.to.string", &out)); |
+ EXPECT_EQ("hello", out); |
+ }, |
+ [](ScopedDictionaryPrefUpdate* update) { |
+ (*update)->SetStringWithoutPathExpansion("key.for.string", "prefs!"); |
+ std::string out; |
+ ASSERT_TRUE( |
+ (*update)->GetStringWithoutPathExpansion("key.for.string", &out)); |
+ EXPECT_EQ("prefs!", out); |
+ }, |
+ [](ScopedDictionaryPrefUpdate* update) { |
+ (*update)->SetString("path.to.string", base::ASCIIToUTF16("hello")); |
+ base::string16 out; |
+ ASSERT_TRUE((*update)->GetString("path.to.string", &out)); |
+ EXPECT_EQ(base::ASCIIToUTF16("hello"), out); |
+ }, |
+ [](ScopedDictionaryPrefUpdate* update) { |
+ (*update)->SetStringWithoutPathExpansion("key.for.string16", |
+ base::ASCIIToUTF16("prefs!")); |
+ base::string16 out; |
+ ASSERT_TRUE( |
+ (*update)->GetStringWithoutPathExpansion("key.for.string16", &out)); |
+ EXPECT_EQ(base::ASCIIToUTF16("prefs!"), out); |
+ }, |
+ [](ScopedDictionaryPrefUpdate* update) { |
+ base::Value buffer(std::vector<char>{1, 2, 3, 4, 5}); |
+ (*update)->Set("path.to.binary", base::MakeUnique<base::Value>(buffer)); |
+ const base::Value* out; |
+ ASSERT_TRUE((*update)->GetBinary("path.to.binary", &out)); |
+ EXPECT_EQ(buffer, *out); |
+ }, |
+ [](ScopedDictionaryPrefUpdate* update) { |
+ base::ListValue list; |
+ list.AppendInteger(1); |
+ list.AppendDouble(2); |
+ list.AppendBoolean(true); |
+ list.AppendString("four"); |
+ (*update)->Set("path.to.list", list.CreateDeepCopy()); |
+ const base::ListValue* out = nullptr; |
+ ASSERT_TRUE((*update)->GetList("path.to.list", &out)); |
+ EXPECT_EQ(list, *out); |
+ }, |
+ [](ScopedDictionaryPrefUpdate* update) { |
+ base::ListValue list; |
+ list.AppendInteger(1); |
+ list.AppendDouble(2); |
+ list.AppendBoolean(true); |
+ list.AppendString("four"); |
+ (*update)->SetWithoutPathExpansion("key.for.list", |
+ list.CreateDeepCopy()); |
+ const base::ListValue* out = nullptr; |
+ ASSERT_TRUE( |
+ (*update)->GetListWithoutPathExpansion("key.for.list", &out)); |
+ EXPECT_EQ(list, *out); |
+ }, |
+ [](ScopedDictionaryPrefUpdate* update) { |
+ base::DictionaryValue dict; |
+ dict.SetInteger("int", 1); |
+ dict.SetDouble("double", 2); |
+ dict.SetBoolean("bool", true); |
+ dict.SetString("string", "four"); |
+ (*update)->Set("path.to.dict", dict.CreateDeepCopy()); |
+ const base::DictionaryValue* out = nullptr; |
+ ASSERT_TRUE((*update)->GetDictionary("path.to.dict", &out)); |
+ EXPECT_EQ(dict, *out); |
+ }, |
+ [](ScopedDictionaryPrefUpdate* update) { |
+ base::DictionaryValue dict; |
+ dict.SetInteger("int", 1); |
+ dict.SetDouble("double", 2); |
+ dict.SetBoolean("bool", true); |
+ dict.SetString("string", "four"); |
+ (*update)->SetWithoutPathExpansion("key.for.dict", |
+ dict.CreateDeepCopy()); |
+ const base::DictionaryValue* out = nullptr; |
+ ASSERT_TRUE( |
+ (*update)->GetDictionaryWithoutPathExpansion("key.for.dict", &out)); |
+ EXPECT_EQ(dict, *out); |
+ }, |
+ }; |
+ int current_value = kInitialValue + 1; |
+ for (auto& mutation : updates) { |
+ base::DictionaryValue expected_value; |
+ { |
+ ScopedDictionaryPrefUpdate update(pref_service.get(), kDictionaryKey); |
+ EXPECT_EQ(update->AsConstDictionary()->empty(), update->empty()); |
+ EXPECT_EQ(update->AsConstDictionary()->size(), update->size()); |
+ mutation(&update); |
+ EXPECT_EQ(update->AsConstDictionary()->empty(), update->empty()); |
+ EXPECT_EQ(update->AsConstDictionary()->size(), update->size()); |
+ expected_value = *update->AsConstDictionary(); |
+ } |
+ |
+ EXPECT_EQ(expected_value, *pref_service->GetDictionary(kDictionaryKey)); |
+ WaitForPrefChange(pref_service2.get(), kDictionaryKey); |
+ EXPECT_EQ(expected_value, *pref_service2->GetDictionary(kDictionaryKey)); |
+ |
+ { |
+ ScopedDictionaryPrefUpdate update(pref_service.get(), kDictionaryKey); |
+ mutation(&update); |
+ EXPECT_EQ(expected_value, *update->AsConstDictionary()); |
+ } |
+ { |
+ PrefChangeRegistrar registrar; |
+ registrar.Init(pref_service2.get()); |
+ registrar.Add(kDictionaryKey, base::Bind(&Fail, pref_service2.get())); |
+ pref_service->SetInteger(kKey, ++current_value); |
+ WaitForPrefChange(pref_service2.get(), kKey); |
+ } |
+ if (!pref_service->GetDictionary(kDictionaryKey)->empty()) { |
+ { |
+ ScopedDictionaryPrefUpdate update(pref_service.get(), kDictionaryKey); |
+ update->Clear(); |
+ } |
+ WaitForPrefChange(pref_service2.get(), kDictionaryKey); |
+ } |
+ } |
+} |
+ |
+TEST_F(PrefServiceFactoryTest, MultipleClients_SubPrefUpdates_Erase) { |
+ auto pref_service = Create(); |
+ auto pref_service2 = Create(); |
+ { |
+ ScopedDictionaryPrefUpdate update(pref_service.get(), kDictionaryKey); |
+ update->SetInteger("path.to.integer", 1); |
+ } |
+ WaitForPrefChange(pref_service2.get(), kDictionaryKey); |
+ |
+ { |
+ ScopedDictionaryPrefUpdate update(pref_service.get(), kDictionaryKey); |
+ ASSERT_TRUE(update->RemovePath("path.to.integer", nullptr)); |
+ } |
+ WaitForPrefChange(pref_service2.get(), kDictionaryKey); |
+ EXPECT_TRUE(pref_service2->GetDictionary(kDictionaryKey)->empty()); |
+} |
+ |
+TEST_F(PrefServiceFactoryTest, MultipleClients_SubPrefUpdates_ClearDictionary) { |
+ auto pref_service = Create(); |
+ auto pref_service2 = Create(); |
+ |
+ { ScopedDictionaryPrefUpdate update(pref_service.get(), kDictionaryKey); } |
+ WaitForPrefChange(pref_service2.get(), kDictionaryKey); |
+ |
+ { |
+ ScopedDictionaryPrefUpdate update(pref_service.get(), kDictionaryKey); |
+ update->Clear(); |
+ } |
+ PrefChangeRegistrar registrar; |
+ registrar.Init(pref_service2.get()); |
+ registrar.Add(kDictionaryKey, base::Bind(&Fail, pref_service2.get())); |
+ pref_service->SetInteger(kKey, kUpdatedValue); |
+ WaitForPrefChange(pref_service2.get(), kKey); |
+} |
+ |
} // namespace |
} // namespace prefs |