Index: components/download/internal/model_impl_unittest.cc |
diff --git a/components/download/internal/model_impl_unittest.cc b/components/download/internal/model_impl_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1665a8968aabe175cfd4e303f8784c6d8043d3ff |
--- /dev/null |
+++ b/components/download/internal/model_impl_unittest.cc |
@@ -0,0 +1,318 @@ |
+// 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 "components/download/internal/model_impl.h" |
+ |
+#include "base/bind.h" |
+#include "base/guid.h" |
+#include "base/test/test_mock_time_task_runner.h" |
+#include "base/threading/thread_task_runner_handle.h" |
+#include "components/download/internal/entry.h" |
+#include "components/download/internal/noop_store.h" |
+#include "components/download/internal/test_support/mock_model_client.h" |
+#include "components/download/internal/test_support/mock_store.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+using testing::Return; |
+using testing::_; |
+ |
+namespace download { |
+namespace { |
+ |
+class BadStore : public Store { |
+ public: |
+ BadStore() = default; |
+ ~BadStore() override = default; |
+ |
+ // Store implementation. |
+ MOCK_METHOD0(IsInitialized, bool()); |
+ void Initialize(const InitCallback& callback) override { |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::Bind(callback, false, nullptr)); |
+ } |
+ |
+ void Destroy(const StoreCallback& callback) override { |
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, |
+ base::Bind(callback, false)); |
+ } |
+ |
+ void Update(const Entry& entry, const StoreCallback& callback) override { |
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, |
+ base::Bind(callback, false)); |
+ } |
+ |
+ void Remove(const std::string& guid, const StoreCallback& callback) override { |
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, |
+ base::Bind(callback, false)); |
+ } |
+}; |
+ |
+struct CompareByGuid { |
+ bool operator()(const Entry* a, const Entry* b) const { |
+ return a->guid < b->guid; |
+ } |
+}; |
+ |
+template <typename T> |
+bool VectorContentsEq(const std::vector<T>& list1, |
+ const std::vector<T>& list2) { |
+ if (list1.size() != list2.size()) |
+ return false; |
+ |
+ std::map<T, int, CompareByGuid> occurance_counts; |
+ for (auto it = list1.begin(); it != list1.end(); it++) |
+ occurance_counts[*it]++; |
+ |
+ for (auto it = list2.begin(); it != list2.end(); it++) |
+ occurance_counts[*it]--; |
+ |
+ for (auto it = occurance_counts.begin(); it != occurance_counts.end(); it++) { |
+ if (it->second != 0) |
+ return false; |
+ } |
+ |
+ return true; |
Peter Beverloo
2017/05/10 12:44:45
I think you could *significantly* simplify this (a
David Trainor- moved to gerrit
2017/05/15 15:59:51
O_o! Yeah way better :).
|
+} |
+ |
+Entry BuildEntry(DownloadClient client, const std::string& guid) { |
+ Entry entry; |
+ entry.client = client; |
+ entry.guid = guid; |
+ |
+ return entry; |
+} |
+ |
+bool CompareEntryBasics(const Entry& expected, const Entry* const actual) { |
+ return actual != nullptr && expected.client == actual->client && |
+ expected.guid == actual->guid && expected.state == actual->state; |
+} |
+ |
+class ModelImplStoreTestBase : public testing::Test { |
+ public: |
+ ModelImplStoreTestBase(Store* store) |
+ : task_runner_(new base::TestMockTimeTaskRunner), |
Peter Beverloo
2017/05/10 12:44:45
qq: would TestSimpleTaskRunner suffice? why is tim
David Trainor- moved to gerrit
2017/05/15 15:59:51
Good call. Done.
|
+ handle_(task_runner_), |
+ store_(store), |
+ model_(base::MakeUnique<ModelImpl>(&client_, |
+ base::WrapUnique<Store>(store))) {} |
+ |
+ ~ModelImplStoreTestBase() override = default; |
+ |
+ protected: |
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; |
+ base::ThreadTaskRunnerHandle handle_; |
+ MockModelClient client_; |
+ Store* store_; |
+ std::unique_ptr<ModelImpl> model_; |
+}; |
+ |
+class ModelImplNoopStoreTest : public ModelImplStoreTestBase { |
+ public: |
+ ModelImplNoopStoreTest() : ModelImplStoreTestBase(new NoopStore) {} |
+}; |
+ |
+class ModelImplMockStoreTest : public ModelImplStoreTestBase { |
+ public: |
+ ModelImplMockStoreTest() |
+ : ModelImplStoreTestBase(new MockStore), |
+ mocked_store_(static_cast<MockStore*>(store_)) {} |
+ |
+ protected: |
+ MockStore* mocked_store_; |
+}; |
+ |
+class ModelImplBadStoreTest : public ModelImplStoreTestBase { |
+ public: |
+ ModelImplBadStoreTest() |
+ : ModelImplStoreTestBase(new BadStore), |
+ mocked_store_(static_cast<BadStore*>(store_)) {} |
+ |
+ protected: |
+ BadStore* mocked_store_; |
+}; |
+ |
+TEST_F(ModelImplNoopStoreTest, Lifecycle) { |
+ EXPECT_CALL(client_, OnInitialized(true)).Times(1); |
+ model_->Initialize(); |
+ task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_CALL(client_, OnDestroyed(true)).Times(1); |
+ model_->Destroy(); |
+ task_runner_->RunUntilIdle(); |
+} |
+ |
+TEST_F(ModelImplNoopStoreTest, Add) { |
+ EXPECT_CALL(client_, OnInitialized(true)).Times(1); |
+ model_->Initialize(); |
+ task_runner_->RunUntilIdle(); |
+ |
+ std::string guid1 = base::GenerateGUID(); |
+ std::string guid2 = base::GenerateGUID(); |
+ |
+ DownloadClient client1 = DownloadClient::TEST_1; |
+ DownloadClient client2 = DownloadClient::TEST_2; |
+ |
+ Entry entry1 = BuildEntry(client1, guid1); |
+ Entry entry2 = BuildEntry(client2, guid2); |
+ |
+ EXPECT_CALL(client_, OnItemAdded(true, client1, guid1)).Times(1); |
+ EXPECT_CALL(client_, OnItemAdded(true, client2, guid2)).Times(1); |
+ |
+ EXPECT_EQ(nullptr, model_->Get(guid1)); |
+ EXPECT_EQ(nullptr, model_->Get(guid2)); |
+ |
+ model_->Add(entry1); |
+ model_->Add(entry2); |
+ |
+ // Validate that the new item is available immediately after adding. |
+ EXPECT_TRUE(CompareEntryBasics(entry1, model_->Get(guid1))); |
+ EXPECT_TRUE(CompareEntryBasics(entry2, model_->Get(guid2))); |
+ |
+ task_runner_->RunUntilIdle(); |
+} |
+ |
+TEST_F(ModelImplNoopStoreTest, Update) { |
+ EXPECT_CALL(client_, OnInitialized(true)).Times(1); |
+ model_->Initialize(); |
+ task_runner_->RunUntilIdle(); |
+ |
+ std::string guid = base::GenerateGUID(); |
+ DownloadClient client = DownloadClient::TEST_1; |
+ |
+ Entry entry1 = BuildEntry(client, guid); |
+ Entry entry2(entry1); |
+ |
+ entry1.state = Entry::State::NEW; |
+ entry2.state = Entry::State::ACTIVE; |
+ |
+ EXPECT_CALL(client_, OnItemAdded(true, client, guid)).Times(1); |
+ |
+ EXPECT_EQ(nullptr, model_->Get(guid)); |
+ |
+ model_->Add(entry1); |
+ task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_TRUE(CompareEntryBasics(entry1, model_->Get(guid))); |
+ |
+ model_->Update(entry2); |
+ |
+ // Validate that the updated item is available immediately after updating. |
+ EXPECT_TRUE(CompareEntryBasics(entry2, model_->Get(guid))); |
+ |
+ task_runner_->RunUntilIdle(); |
+} |
+ |
+TEST_F(ModelImplNoopStoreTest, Remove) { |
+ EXPECT_CALL(client_, OnInitialized(true)).Times(1); |
+ model_->Initialize(); |
+ task_runner_->RunUntilIdle(); |
+ |
+ std::string guid = base::GenerateGUID(); |
+ |
+ DownloadClient client = DownloadClient::TEST_1; |
+ |
+ Entry entry = BuildEntry(client, guid); |
+ |
+ EXPECT_CALL(client_, OnItemAdded(true, client, guid)).Times(1); |
+ |
+ EXPECT_EQ(nullptr, model_->Get(guid)); |
+ |
+ model_->Add(entry); |
+ task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_TRUE(CompareEntryBasics(entry, model_->Get(guid))); |
+ |
+ model_->Remove(guid); |
+ |
+ // Validate that the removed item is unavailable immediately after updating. |
+ EXPECT_EQ(nullptr, model_->Get(guid)); |
+ |
+ task_runner_->RunUntilIdle(); |
+} |
+ |
+TEST_F(ModelImplNoopStoreTest, Get) { |
+ model_->Initialize(); |
+ task_runner_->RunUntilIdle(); |
+ |
+ std::string guid = base::GenerateGUID(); |
+ Entry entry = BuildEntry(DownloadClient::TEST_1, guid); |
+ |
+ model_->Add(entry); |
+ task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_TRUE(CompareEntryBasics(entry, model_->Get(guid))); |
+} |
+ |
+TEST_F(ModelImplNoopStoreTest, PeekEntries) { |
+ model_->Initialize(); |
+ task_runner_->RunUntilIdle(); |
+ |
+ std::string guid1 = base::GenerateGUID(); |
+ std::string guid2 = base::GenerateGUID(); |
+ std::string guid3 = base::GenerateGUID(); |
+ |
+ Entry entry1 = BuildEntry(DownloadClient::TEST_1, guid1); |
+ Entry entry2 = BuildEntry(DownloadClient::TEST_2, guid2); |
+ Entry entry3 = BuildEntry(DownloadClient::TEST_3, guid3); |
+ |
+ Model::EntryList entries = {&entry1, &entry2, &entry3}; |
+ |
+ model_->Add(entry1); |
+ model_->Add(entry2); |
+ model_->Add(entry3); |
+ task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_TRUE(VectorContentsEq(entries, model_->PeekEntries())); |
+} |
+ |
+TEST_F(ModelImplMockStoreTest, TestStoreCalls) { |
+ { |
+ EXPECT_CALL(*mocked_store_, IsInitialized()).WillRepeatedly(Return(false)); |
+ EXPECT_CALL(*mocked_store_, Initialize(_)).Times(1); |
+ model_->Initialize(); |
+ } |
+ |
+ EXPECT_CALL(*mocked_store_, IsInitialized()).WillRepeatedly(Return(true)); |
+ |
+ std::string guid = base::GenerateGUID(); |
+ Entry entry = BuildEntry(DownloadClient::TEST_1, guid); |
+ |
+ EXPECT_CALL(*mocked_store_, Update(_, _)).Times(2); |
+ EXPECT_CALL(*mocked_store_, Remove(guid, _)).Times(1); |
+ EXPECT_CALL(*mocked_store_, Destroy(_)).Times(1); |
+ |
+ model_->Add(entry); |
+ model_->Update(entry); |
+ model_->Remove(guid); |
+ model_->Destroy(); |
+} |
+ |
+TEST_F(ModelImplBadStoreTest, ModelUpdatesFailed) { |
+ { |
+ EXPECT_CALL(*mocked_store_, IsInitialized()).WillRepeatedly(Return(false)); |
+ EXPECT_CALL(client_, OnInitialized(false)).Times(1); |
+ model_->Initialize(); |
+ } |
+ |
+ EXPECT_CALL(*mocked_store_, IsInitialized()).WillRepeatedly(Return(true)); |
+ |
+ std::string guid = base::GenerateGUID(); |
+ DownloadClient client = DownloadClient::TEST_1; |
+ Entry entry = BuildEntry(client, guid); |
+ |
+ EXPECT_CALL(client_, OnItemAdded(false, client, guid)).Times(1); |
+ EXPECT_CALL(client_, OnStoreUpdateFailed(client, guid)).Times(2); |
+ EXPECT_CALL(client_, OnDestroyed(false)); |
+ |
+ model_->Add(entry); |
+ model_->Update(entry); |
+ model_->Remove(guid); |
+ model_->Destroy(); |
+ |
+ task_runner_->RunUntilIdle(); |
+} |
+ |
+} // namespace |
+} // namespace download |