1 // Copyright 2014 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 #ifndef COMPONENTS_LEVELDB_PROTO_TESTING_FAKE_DB_H_
6 #define COMPONENTS_LEVELDB_PROTO_TESTING_FAKE_DB_H_
7 
8 #include <map>
9 #include <memory>
10 #include <string>
11 #include <utility>
12 #include <vector>
13 
14 #include "base/bind.h"
15 #include "base/callback.h"
16 #include "base/files/file_path.h"
17 #include "base/task/post_task.h"
18 #include "base/test/test_simple_task_runner.h"
19 #include "components/leveldb_proto/internal/proto_database_impl.h"
20 #include "components/leveldb_proto/public/proto_database.h"
21 #include "components/leveldb_proto/public/shared_proto_database_client_list.h"
22 
23 namespace leveldb_proto {
24 namespace test {
25 
26 template <typename P, typename T = P>
27 class FakeDB : public ProtoDatabaseImpl<P, T> {
28   using Callback = base::OnceCallback<void(bool)>;
29 
30  public:
31   using EntryMap = std::map<std::string, P>;
32 
33   explicit FakeDB(EntryMap* db);
34 
35   // ProtoDatabase implementation.
36   void Init(Callbacks::InitStatusCallback callback) override;
37   void Init(const leveldb_env::Options& unique_db_options,
38             Callbacks::InitStatusCallback callback) override;
39   void UpdateEntries(std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector>
40                          entries_to_save,
41                      std::unique_ptr<std::vector<std::string>> keys_to_remove,
42                      Callbacks::UpdateCallback callback) override;
43   void UpdateEntriesWithRemoveFilter(
44       std::unique_ptr<typename Util::Internal<T>::KeyEntryVector>
45           entries_to_save,
46       const KeyFilter& filter,
47       Callbacks::UpdateCallback callback) override;
48   void LoadEntries(
49       typename Callbacks::Internal<T>::LoadCallback callback) override;
50   void LoadEntriesWithFilter(
51       const KeyFilter& key_filter,
52       typename Callbacks::Internal<T>::LoadCallback callback) override;
53   void LoadEntriesWithFilter(
54       const KeyFilter& filter,
55       const leveldb::ReadOptions& options,
56       const std::string& target_prefix,
57       typename Callbacks::Internal<T>::LoadCallback callback) override;
58   void LoadKeysAndEntries(
59       typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
60       override;
61   void LoadKeysAndEntriesWithFilter(
62       const KeyFilter& filter,
63       typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
64       override;
65   void LoadKeysAndEntriesWithFilter(
66       const KeyFilter& filter,
67       const leveldb::ReadOptions& options,
68       const std::string& target_prefix,
69       typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
70       override;
71   void LoadKeysAndEntriesInRange(
72       const std::string& start,
73       const std::string& end,
74       typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
75       override;
76   void LoadKeys(Callbacks::LoadKeysCallback callback) override;
77   void GetEntry(const std::string& key,
78                 typename Callbacks::Internal<T>::GetCallback callback) override;
79   void Destroy(Callbacks::DestroyCallback callback) override;
80 
81   base::FilePath& GetDirectory();
82 
83   void InitCallback(bool success);
84 
85   void InitStatusCallback(Enums::InitStatus status);
86 
87   void LoadCallback(bool success);
88 
89   void LoadKeysCallback(bool success);
90 
91   void GetCallback(bool success);
92 
93   void UpdateCallback(bool success);
94 
95   void DestroyCallback(bool success);
96 
97   static base::FilePath DirectoryForTestDB();
98 
99  private:
100   static void RunLoadCallback(
101       typename Callbacks::Internal<T>::LoadCallback callback,
102       std::unique_ptr<typename std::vector<T>> entries,
103       bool success);
104   static void RunLoadKeysAndEntriesCallback(
105       typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback,
106       std::unique_ptr<typename std::map<std::string, T>> entries,
107       bool success);
108 
109   static void RunLoadKeysCallback(
110       typename Callbacks::LoadKeysCallback callback,
111       std::unique_ptr<std::vector<std::string>> keys,
112       bool success);
113 
114   static void RunGetCallback(
115       typename Callbacks::Internal<T>::GetCallback callback,
116       std::unique_ptr<T> entry,
117       bool success);
118 
119   base::FilePath dir_;
120   EntryMap* db_;
121 
122   Callback init_callback_;
123   Callbacks::InitStatusCallback init_status_callback_;
124   Callback load_callback_;
125   Callback load_keys_callback_;
126   Callback get_callback_;
127   Callback update_callback_;
128   Callback destroy_callback_;
129 };
130 
131 namespace {
132 
133 template <typename P,
134           typename T,
135           std::enable_if_t<std::is_base_of<google::protobuf::MessageLite,
136                                            T>::value>* = nullptr>
DataToProtoWrap(T * data,P * proto)137 void DataToProtoWrap(T* data, P* proto) {
138   proto->Swap(data);
139 }
140 
141 template <typename P,
142           typename T,
143           std::enable_if_t<!std::is_base_of<google::protobuf::MessageLite,
144                                             T>::value>* = nullptr>
DataToProtoWrap(T * data,P * proto)145 void DataToProtoWrap(T* data, P* proto) {
146   DataToProto(data, proto);
147 }
148 
149 template <typename P,
150           typename T,
151           std::enable_if_t<std::is_base_of<google::protobuf::MessageLite,
152                                            T>::value>* = nullptr>
ProtoToDataWrap(const P & proto,T * data)153 void ProtoToDataWrap(const P& proto, T* data) {
154   *data = proto;
155 }
156 
157 template <typename P,
158           typename T,
159           std::enable_if_t<!std::is_base_of<google::protobuf::MessageLite,
160                                             T>::value>* = nullptr>
ProtoToDataWrap(const P & proto,T * data)161 void ProtoToDataWrap(const P& proto, T* data) {
162   P copy = proto;
163   ProtoToData(&copy, data);
164 }
165 
166 }  // namespace
167 
168 template <typename P, typename T>
FakeDB(EntryMap * db)169 FakeDB<P, T>::FakeDB(EntryMap* db)
170     : ProtoDatabaseImpl<P, T>(
171           ProtoDbType::TEST_DATABASE0,
172           base::FilePath(FILE_PATH_LITERAL("db_dir")),
173           base::MakeRefCounted<base::TestSimpleTaskRunner>()) {
174   db_ = db;
175 }
176 
177 template <typename P, typename T>
Init(Callbacks::InitStatusCallback callback)178 void FakeDB<P, T>::Init(Callbacks::InitStatusCallback callback) {
179   dir_ = base::FilePath(FILE_PATH_LITERAL("db_dir"));
180   init_status_callback_ = std::move(callback);
181 }
182 
183 template <typename P, typename T>
Init(const leveldb_env::Options & unique_db_options,Callbacks::InitStatusCallback callback)184 void FakeDB<P, T>::Init(const leveldb_env::Options& unique_db_options,
185                         Callbacks::InitStatusCallback callback) {
186   Init(std::move(callback));
187 }
188 
189 template <typename P, typename T>
UpdateEntries(std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,std::unique_ptr<std::vector<std::string>> keys_to_remove,Callbacks::UpdateCallback callback)190 void FakeDB<P, T>::UpdateEntries(
191     std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
192     std::unique_ptr<std::vector<std::string>> keys_to_remove,
193     Callbacks::UpdateCallback callback) {
194   for (auto& pair : *entries_to_save)
195     DataToProtoWrap(&pair.second, &(*db_)[pair.first]);
196 
197   for (const auto& key : *keys_to_remove)
198     db_->erase(key);
199 
200   update_callback_ = std::move(callback);
201 }
202 
203 template <typename P, typename T>
UpdateEntriesWithRemoveFilter(std::unique_ptr<typename Util::Internal<T>::KeyEntryVector> entries_to_save,const KeyFilter & delete_key_filter,Callbacks::UpdateCallback callback)204 void FakeDB<P, T>::UpdateEntriesWithRemoveFilter(
205     std::unique_ptr<typename Util::Internal<T>::KeyEntryVector> entries_to_save,
206     const KeyFilter& delete_key_filter,
207     Callbacks::UpdateCallback callback) {
208   for (auto& pair : *entries_to_save)
209     DataToProtoWrap(&pair.second, &(*db_)[pair.first]);
210 
211   auto it = db_->begin();
212   while (it != db_->end()) {
213     if (!delete_key_filter.is_null() && delete_key_filter.Run(it->first))
214       db_->erase(it++);
215     else
216       ++it;
217   }
218 
219   update_callback_ = std::move(callback);
220 }
221 
222 template <typename P, typename T>
LoadEntries(typename Callbacks::Internal<T>::LoadCallback callback)223 void FakeDB<P, T>::LoadEntries(
224     typename Callbacks::Internal<T>::LoadCallback callback) {
225   LoadEntriesWithFilter(KeyFilter(), std::move(callback));
226 }
227 
228 template <typename P, typename T>
LoadEntriesWithFilter(const KeyFilter & key_filter,typename Callbacks::Internal<T>::LoadCallback callback)229 void FakeDB<P, T>::LoadEntriesWithFilter(
230     const KeyFilter& key_filter,
231     typename Callbacks::Internal<T>::LoadCallback callback) {
232   LoadEntriesWithFilter(key_filter, leveldb::ReadOptions(), std::string(),
233                         std::move(callback));
234 }
235 
236 template <typename P, typename T>
LoadEntriesWithFilter(const KeyFilter & key_filter,const leveldb::ReadOptions & options,const std::string & target_prefix,typename Callbacks::Internal<T>::LoadCallback callback)237 void FakeDB<P, T>::LoadEntriesWithFilter(
238     const KeyFilter& key_filter,
239     const leveldb::ReadOptions& options,
240     const std::string& target_prefix,
241     typename Callbacks::Internal<T>::LoadCallback callback) {
242   std::unique_ptr<std::vector<T>> entries(new std::vector<T>());
243   for (const auto& pair : *db_) {
244     if (key_filter.is_null() || key_filter.Run(pair.first)) {
245       if (pair.first.compare(0, target_prefix.length(), target_prefix) == 0) {
246         entries->emplace_back(T());
247         ProtoToDataWrap<P, T>(pair.second, &entries->back());
248       }
249     }
250   }
251 
252   load_callback_ =
253       base::BindOnce(RunLoadCallback, std::move(callback), std::move(entries));
254 }
255 
256 template <typename P, typename T>
LoadKeysAndEntries(typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)257 void FakeDB<P, T>::LoadKeysAndEntries(
258     typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
259   LoadKeysAndEntriesWithFilter(KeyFilter(), std::move(callback));
260 }
261 
262 template <typename P, typename T>
LoadKeysAndEntriesWithFilter(const KeyFilter & key_filter,typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)263 void FakeDB<P, T>::LoadKeysAndEntriesWithFilter(
264     const KeyFilter& key_filter,
265     typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
266   LoadKeysAndEntriesWithFilter(key_filter, leveldb::ReadOptions(),
267                                std::string(), std::move(callback));
268 }
269 
270 template <typename P, typename T>
LoadKeysAndEntriesWithFilter(const KeyFilter & key_filter,const leveldb::ReadOptions & options,const std::string & target_prefix,typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)271 void FakeDB<P, T>::LoadKeysAndEntriesWithFilter(
272     const KeyFilter& key_filter,
273     const leveldb::ReadOptions& options,
274     const std::string& target_prefix,
275     typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
276   auto keys_entries = std::make_unique<std::map<std::string, T>>();
277   for (const auto& pair : *db_) {
278     if (key_filter.is_null() || key_filter.Run(pair.first)) {
279       if (pair.first.compare(0, target_prefix.length(), target_prefix) == 0)
280         ProtoToDataWrap<P, T>(pair.second, &(*keys_entries)[pair.first]);
281     }
282   }
283 
284   load_callback_ = base::BindOnce(RunLoadKeysAndEntriesCallback,
285                                   std::move(callback), std::move(keys_entries));
286 }
287 
288 template <typename P, typename T>
LoadKeysAndEntriesInRange(const std::string & start,const std::string & end,typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)289 void FakeDB<P, T>::LoadKeysAndEntriesInRange(
290     const std::string& start,
291     const std::string& end,
292     typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
293   auto keys_entries = std::make_unique<std::map<std::string, T>>();
294   for (const auto& pair : *db_) {
295     if (pair.first >= start && pair.first <= end)
296       ProtoToDataWrap<P, T>(pair.second, &(*keys_entries)[pair.first]);
297   }
298 
299   load_callback_ = base::BindOnce(RunLoadKeysAndEntriesCallback,
300                                   std::move(callback), std::move(keys_entries));
301 }
302 
303 template <typename P, typename T>
LoadKeys(Callbacks::LoadKeysCallback callback)304 void FakeDB<P, T>::LoadKeys(Callbacks::LoadKeysCallback callback) {
305   std::unique_ptr<std::vector<std::string>> keys(
306       new std::vector<std::string>());
307   for (const auto& pair : *db_)
308     keys->push_back(pair.first);
309 
310   load_keys_callback_ =
311       base::BindOnce(RunLoadKeysCallback, std::move(callback), std::move(keys));
312 }
313 
314 template <typename P, typename T>
GetEntry(const std::string & key,typename Callbacks::Internal<T>::GetCallback callback)315 void FakeDB<P, T>::GetEntry(
316     const std::string& key,
317     typename Callbacks::Internal<T>::GetCallback callback) {
318   std::unique_ptr<T> entry;
319   auto it = db_->find(key);
320   if (it != db_->end()) {
321     entry.reset(new T());
322     ProtoToDataWrap<P, T>(it->second, entry.get());
323   }
324 
325   get_callback_ =
326       base::BindOnce(RunGetCallback, std::move(callback), std::move(entry));
327 }
328 
329 template <typename P, typename T>
Destroy(Callbacks::DestroyCallback callback)330 void FakeDB<P, T>::Destroy(Callbacks::DestroyCallback callback) {
331   db_->clear();
332   destroy_callback_ = std::move(callback);
333 }
334 
335 template <typename P, typename T>
GetDirectory()336 base::FilePath& FakeDB<P, T>::GetDirectory() {
337   return dir_;
338 }
339 
340 template <typename P, typename T>
InitCallback(bool success)341 void FakeDB<P, T>::InitCallback(bool success) {
342   std::move(init_callback_).Run(success);
343 }
344 
345 template <typename P, typename T>
InitStatusCallback(Enums::InitStatus status)346 void FakeDB<P, T>::InitStatusCallback(Enums::InitStatus status) {
347   std::move(init_status_callback_).Run(status);
348 }
349 
350 template <typename P, typename T>
LoadCallback(bool success)351 void FakeDB<P, T>::LoadCallback(bool success) {
352   std::move(load_callback_).Run(success);
353 }
354 
355 template <typename P, typename T>
LoadKeysCallback(bool success)356 void FakeDB<P, T>::LoadKeysCallback(bool success) {
357   std::move(load_keys_callback_).Run(success);
358 }
359 
360 template <typename P, typename T>
GetCallback(bool success)361 void FakeDB<P, T>::GetCallback(bool success) {
362   std::move(get_callback_).Run(success);
363 }
364 
365 template <typename P, typename T>
UpdateCallback(bool success)366 void FakeDB<P, T>::UpdateCallback(bool success) {
367   std::move(update_callback_).Run(success);
368 }
369 
370 template <typename P, typename T>
DestroyCallback(bool success)371 void FakeDB<P, T>::DestroyCallback(bool success) {
372   std::move(destroy_callback_).Run(success);
373 }
374 
375 // static
376 template <typename P, typename T>
RunLoadCallback(typename Callbacks::Internal<T>::LoadCallback callback,std::unique_ptr<typename std::vector<T>> entries,bool success)377 void FakeDB<P, T>::RunLoadCallback(
378     typename Callbacks::Internal<T>::LoadCallback callback,
379     std::unique_ptr<typename std::vector<T>> entries,
380     bool success) {
381   std::move(callback).Run(success, std::move(entries));
382 }
383 
384 // static
385 template <typename P, typename T>
RunLoadKeysAndEntriesCallback(typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback,std::unique_ptr<typename std::map<std::string,T>> keys_entries,bool success)386 void FakeDB<P, T>::RunLoadKeysAndEntriesCallback(
387     typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback,
388     std::unique_ptr<typename std::map<std::string, T>> keys_entries,
389     bool success) {
390   std::move(callback).Run(success, std::move(keys_entries));
391 }
392 
393 // static
394 template <typename P, typename T>
RunLoadKeysCallback(Callbacks::LoadKeysCallback callback,std::unique_ptr<std::vector<std::string>> keys,bool success)395 void FakeDB<P, T>::RunLoadKeysCallback(
396     Callbacks::LoadKeysCallback callback,
397     std::unique_ptr<std::vector<std::string>> keys,
398     bool success) {
399   std::move(callback).Run(success, std::move(keys));
400 }
401 
402 // static
403 template <typename P, typename T>
RunGetCallback(typename Callbacks::Internal<T>::GetCallback callback,std::unique_ptr<T> entry,bool success)404 void FakeDB<P, T>::RunGetCallback(
405     typename Callbacks::Internal<T>::GetCallback callback,
406     std::unique_ptr<T> entry,
407     bool success) {
408   std::move(callback).Run(success, std::move(entry));
409 }
410 
411 // static
412 template <typename P, typename T>
DirectoryForTestDB()413 base::FilePath FakeDB<P, T>::DirectoryForTestDB() {
414   return base::FilePath(FILE_PATH_LITERAL("/fake/path"));
415 }
416 
417 }  // namespace test
418 }  // namespace leveldb_proto
419 
420 #endif  // COMPONENTS_LEVELDB_PROTO_TESTING_FAKE_DB_H_
421