Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(316)

Unified Diff: services/preferences/public/cpp/tests/persistent_pref_store_client_unittest.cc

Issue 2812863002: Pref service: Add a ScopedDictionaryPrefUpdate to track value changes. (Closed)
Patch Set: rebase Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: services/preferences/public/cpp/tests/persistent_pref_store_client_unittest.cc
diff --git a/services/preferences/public/cpp/tests/persistent_pref_store_client_unittest.cc b/services/preferences/public/cpp/tests/persistent_pref_store_client_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..47c408112cc9fe49afc0b7d80b105c34b4a3b2d6
--- /dev/null
+++ b/services/preferences/public/cpp/tests/persistent_pref_store_client_unittest.cc
@@ -0,0 +1,500 @@
+// Copyright 2017 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.
+
+#include "services/preferences/public/cpp/persistent_pref_store_client.h"
+
+#include <utility>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/values.h"
+#include "components/prefs/pref_notifier_impl.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/preferences/public/cpp/scoped_pref_update.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace prefs {
+namespace {
+
+constexpr char kDictionaryKey[] = "path.to.key";
+constexpr char kUninitializedDictionaryKey[] = "path.to.an.uninitialized.dict";
+
+void DoNothingWithReadError(::PersistentPrefStore::PrefReadError read_error) {}
+
+class PersistentPrefStoreClientTest : public testing::Test,
+ public mojom::PersistentPrefStore {
+ public:
+ PersistentPrefStoreClientTest() : binding_(this) {}
+
+ // testing::Test:
+ void SetUp() override {
+ auto persistent_pref_store_client = make_scoped_refptr(
+ new PersistentPrefStoreClient(mojom::PersistentPrefStoreConnection::New(
+ mojom::PrefStoreConnection::New(
+ mojom::PrefStoreObserverRequest(),
+ base::MakeUnique<base::DictionaryValue>(), true),
+ binding_.CreateInterfacePtrAndBind(),
+ ::PersistentPrefStore::PREF_READ_ERROR_NONE, false)));
+ auto pref_registry = make_scoped_refptr(new PrefRegistrySimple());
+ pref_registry->RegisterDictionaryPref(kDictionaryKey);
+ pref_registry->RegisterDictionaryPref(kUninitializedDictionaryKey);
+ PrefNotifierImpl* pref_notifier = new PrefNotifierImpl;
+ pref_service_ = base::MakeUnique<PrefService>(
+ pref_notifier,
+ new PrefValueStore(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, pref_notifier),
+ persistent_pref_store_client.get(), pref_registry.get(),
+ base::Bind(&DoNothingWithReadError), false);
+ { ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey); }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_atomic_update());
+ EXPECT_EQ(base::DictionaryValue(), *update->get_atomic_update());
+ }
+
+ void TearDown() override {
+ pref_service_ = nullptr;
+ base::RunLoop().RunUntilIdle();
+ binding_.Close();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ PrefService* pref_service() { return pref_service_.get(); }
+
+ mojom::PrefUpdateValuePtr WaitForUpdate() {
+ base::RunLoop run_loop;
+ on_update_ = run_loop.QuitClosure();
+ run_loop.Run();
+ EXPECT_EQ(1u, last_updates_.size());
+ auto result = std::move(last_updates_[0]->value);
+ last_updates_.clear();
+ return result;
+ }
+
+ void ExpectNoUpdate() {
+ binding_.FlushForTesting();
+ EXPECT_TRUE(last_updates_.empty());
+ }
+
+ private:
+ void SetValues(std::vector<mojom::PrefUpdatePtr> updates) override {
+ last_updates_ = std::move(updates);
+ if (on_update_)
+ std::move(on_update_).Run();
+ }
+
+ void CommitPendingWrite() override {}
+ void SchedulePendingLossyWrites() override {}
+ void ClearMutableValues() override {}
+
+ base::MessageLoop message_loop_;
+
+ std::unique_ptr<PrefService> pref_service_;
+
+ mojo::Binding<mojom::PersistentPrefStore> binding_;
+
+ std::vector<mojom::PrefUpdatePtr> last_updates_;
+ base::OnceClosure on_update_;
+
+ DISALLOW_COPY_AND_ASSIGN(PersistentPrefStoreClientTest);
+};
+
+TEST_F(PersistentPrefStoreClientTest, SubPrefUpdates_Basic) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path.to.integer", 1);
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(1u, split_updates.size());
+ EXPECT_EQ(base::Value(1), *split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"path", "to", "integer"}),
+ split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest,
+ SubPrefUpdates_BasicWithoutPathExpansion) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetIntegerWithoutPathExpansion("key.for.integer", 1);
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ EXPECT_EQ(1u, split_updates.size());
+ EXPECT_EQ(base::Value(1), *split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"key.for.integer"}),
+ split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest, SubPrefUpdates_Remove) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path.to.another_integer", 1);
+ update->SetInteger("path.to.integer", 1);
+ }
+ WaitForUpdate();
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->Remove("path.to.integer", nullptr);
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(1u, split_updates.size());
+ EXPECT_FALSE(split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"path", "to", "integer"}),
+ split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest,
+ SubPrefUpdates_RemoveWithoutPathExpansion) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetIntegerWithoutPathExpansion("path.to.another_integer", 1);
+ update->SetIntegerWithoutPathExpansion("path.to.integer", 1);
+ }
+ WaitForUpdate();
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->RemoveWithoutPathExpansion("path.to.integer", nullptr);
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(1u, split_updates.size());
+ EXPECT_FALSE(split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"path.to.integer"}),
+ split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest, SubPrefUpdates_MultipleUpdates) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetDoubleWithoutPathExpansion("a.double", 1);
+ }
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path.to.integer", 2);
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(2u, split_updates.size());
+ EXPECT_EQ(base::Value(1.0), *split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"a.double"}), split_updates[0]->path);
+ EXPECT_EQ(base::Value(2), *split_updates[1]->value);
+ EXPECT_EQ((std::vector<std::string>{"path", "to", "integer"}),
+ split_updates[1]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest, SubPrefUpdates_NestedUpdateAfterSet) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path.to.integer", 1);
+ }
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ DictionaryValueUpdate* dict;
+ ASSERT_TRUE(update->GetDictionary("path.to", &dict));
+ dict->Clear();
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(1u, split_updates.size());
+ EXPECT_EQ(base::DictionaryValue(), *split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"path", "to"}), split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest, SubPrefUpdates_NestedUpdateBeforeSet) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->Set("path.to", base::MakeUnique<base::DictionaryValue>());
+ }
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path.to.integer", 1);
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(1u, split_updates.size());
+ base::DictionaryValue expected_value;
+ expected_value.SetInteger("integer", 1);
+ EXPECT_EQ(expected_value, *split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"path", "to"}), split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest, SubPrefUpdates_DoubleNestedUpdate) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path.to.integer", 1);
+ }
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ DictionaryValueUpdate* dict;
+ ASSERT_TRUE(update->GetDictionary("path", &dict));
+ dict->Clear();
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(1u, split_updates.size());
+ EXPECT_EQ(base::DictionaryValue(), *split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"path"}), split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest, SubPrefUpdates_ManualNesting) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path.to.integer", 1);
+ }
+ WaitForUpdate();
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ DictionaryValueUpdate* dict = nullptr;
+ ASSERT_TRUE(update->GetDictionary("path.to", &dict));
+ dict->SetString("string", "string value");
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(1u, split_updates.size());
+ EXPECT_EQ(base::Value("string value"), *split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"path", "to", "string"}),
+ split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest,
+ SubPrefUpdates_ManualDictCreationAndNesting) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ auto* dict = update->SetDictionary(
+ "path.to", base::MakeUnique<base::DictionaryValue>());
+ dict->SetString("string", "string value");
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(1u, split_updates.size());
+ base::DictionaryValue expected_value;
+ expected_value.SetString("string", "string value");
+ EXPECT_EQ(expected_value, *split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"path", "to"}), split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest,
+ SubPrefUpdates_ManualDictCreationWithoutPathExpansionAndNesting) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ auto* dict = update->SetDictionaryWithoutPathExpansion(
+ "a.dictionary", base::MakeUnique<base::DictionaryValue>());
+ dict->SetStringWithoutPathExpansion("a.string", "string value");
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(1u, split_updates.size());
+ base::DictionaryValue expected_value;
+ expected_value.SetStringWithoutPathExpansion("a.string", "string value");
+ EXPECT_EQ(expected_value, *split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"a.dictionary"}), split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest,
+ SubPrefUpdates_AsDictionaryTriggersFullWrite) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path.to.integer", 1);
+ update->AsDictionary();
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_atomic_update());
+ base::DictionaryValue expected_value;
+ expected_value.SetInteger("path.to.integer", 1);
+ EXPECT_EQ(expected_value, *update->get_atomic_update());
+}
+
+TEST_F(PersistentPrefStoreClientTest, SubPrefUpdates_AsConstDictionaryIsNoOp) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path.to.integer", 1);
+ update->AsConstDictionary();
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(1u, split_updates.size());
+ EXPECT_EQ(base::Value(1), *split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"path", "to", "integer"}),
+ split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest, SubPrefUpdates_RemovePath_Basic) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path.to.integer", 1);
+ update->SetInteger("path.to.something.else", 1);
+ }
+ WaitForUpdate();
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->RemovePath("path.to.integer", nullptr);
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(1u, split_updates.size());
+ EXPECT_FALSE(split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"path", "to", "integer"}),
+ split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest,
+ SubPrefUpdates_RemovePath_RemoveContainingDict) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path.to.integer", 1);
+ update->SetInteger("path.for.something.else", 1);
+ }
+ WaitForUpdate();
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->RemovePath("path.to.integer", nullptr);
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(1u, split_updates.size());
+ EXPECT_FALSE(split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"path", "to"}), split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest,
+ SubPrefUpdates_RemovePath_SinglePathComponent) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("integer", 1);
+ update->SetInteger("something_else", 1);
+ }
+ WaitForUpdate();
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->RemovePath("integer", nullptr);
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(1u, split_updates.size());
+ EXPECT_FALSE(split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"integer"}), split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest, SubPrefUpdates_RemovePath_FullPref) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path.to.integer", 1);
+ }
+ WaitForUpdate();
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->RemovePath("path.to.integer", nullptr);
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(1u, split_updates.size());
+ EXPECT_FALSE(split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"path"}), split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest,
+ SubPrefUpdates_RemovePathSinglePathComponent_FullPref) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("integer", 1);
+ }
+ WaitForUpdate();
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->RemovePath("integer", nullptr);
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(1u, split_updates.size());
+ EXPECT_FALSE(split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"integer"}), split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest, SubPrefUpdates_NoChange) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path.to.integer", 1);
+ }
+ WaitForUpdate();
+ { ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey); }
+ ExpectNoUpdate();
+}
+
+TEST_F(PersistentPrefStoreClientTest, SubPrefUpdates_SetToExistingValue) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path.to.integer", 1);
+ }
+ WaitForUpdate();
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path.to.integer", 1);
+ }
+ ExpectNoUpdate();
+}
+
+TEST_F(PersistentPrefStoreClientTest, SubPrefUpdates_ClearEmptyDictionary) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->Clear();
+ }
+ ExpectNoUpdate();
+}
+
+TEST_F(PersistentPrefStoreClientTest, SubPrefUpdates_ReplaceDictionary) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path.to.integer", 1);
+ }
+ WaitForUpdate();
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(), kDictionaryKey);
+ update->SetInteger("path", 2);
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_split_updates());
+ auto& split_updates = update->get_split_updates();
+ ASSERT_EQ(1u, split_updates.size());
+ EXPECT_EQ(base::Value(2), *split_updates[0]->value);
+ EXPECT_EQ((std::vector<std::string>{"path"}), split_updates[0]->path);
+}
+
+TEST_F(PersistentPrefStoreClientTest, SubPrefUpdates_Uninitialized) {
+ {
+ ScopedDictionaryPrefUpdate update(pref_service(),
+ kUninitializedDictionaryKey);
+ update->SetInteger("path.to.integer", 1);
+ }
+ auto update = WaitForUpdate();
+ ASSERT_TRUE(update->is_atomic_update());
+ base::DictionaryValue expected_value;
+ expected_value.SetInteger("path.to.integer", 1);
+ EXPECT_EQ(expected_value, *update->get_atomic_update());
+}
+
+} // namespace
+} // namespace prefs
« no previous file with comments | « services/preferences/public/cpp/tests/BUILD.gn ('k') | services/preferences/public/cpp/tests/pref_store_client_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698