1//
2// Copyright (C) 2014 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "update_engine/common/fake_prefs.h"
18
19#include <algorithm>
20
21#include <gtest/gtest.h>
22
23using std::string;
24
25using chromeos_update_engine::FakePrefs;
26
27namespace {
28
29void CheckNotNull(const string& key, void* ptr) {
30  EXPECT_NE(nullptr, ptr)
31      << "Called Get*() for key \"" << key << "\" with a null parameter.";
32}
33
34}  // namespace
35
36namespace chromeos_update_engine {
37
38FakePrefs::~FakePrefs() {
39  EXPECT_TRUE(observers_.empty());
40}
41
42// Compile-time type-dependent constants definitions.
43template<>
44FakePrefs::PrefType const FakePrefs::PrefConsts<string>::type =
45    FakePrefs::PrefType::kString;
46template<>
47string FakePrefs::PrefValue::* const  // NOLINT(runtime/string), not static str.
48    FakePrefs::PrefConsts<string>::member = &FakePrefs::PrefValue::as_str;
49
50template<>
51FakePrefs::PrefType const FakePrefs::PrefConsts<int64_t>::type =
52    FakePrefs::PrefType::kInt64;
53template<>
54int64_t FakePrefs::PrefValue::* const FakePrefs::PrefConsts<int64_t>::member =
55    &FakePrefs::PrefValue::as_int64;
56
57template<>
58FakePrefs::PrefType const FakePrefs::PrefConsts<bool>::type =
59    FakePrefs::PrefType::kBool;
60template<>
61bool FakePrefs::PrefValue::* const FakePrefs::PrefConsts<bool>::member =
62    &FakePrefs::PrefValue::as_bool;
63
64bool FakePrefs::GetString(const string& key, string* value) const {
65  return GetValue(key, value);
66}
67
68bool FakePrefs::SetString(const string& key, const string& value) {
69  SetValue(key, value);
70  return true;
71}
72
73bool FakePrefs::GetInt64(const string& key, int64_t* value) const {
74  return GetValue(key, value);
75}
76
77bool FakePrefs::SetInt64(const string& key, const int64_t value) {
78  SetValue(key, value);
79  return true;
80}
81
82bool FakePrefs::GetBoolean(const string& key, bool* value) const {
83  return GetValue(key, value);
84}
85
86bool FakePrefs::SetBoolean(const string& key, const bool value) {
87  SetValue(key, value);
88  return true;
89}
90
91bool FakePrefs::Exists(const string& key) const {
92  return values_.find(key) != values_.end();
93}
94
95bool FakePrefs::Delete(const string& key) {
96  if (values_.find(key) == values_.end())
97    return false;
98  values_.erase(key);
99  const auto observers_for_key = observers_.find(key);
100  if (observers_for_key != observers_.end()) {
101    std::vector<ObserverInterface*> copy_observers(observers_for_key->second);
102    for (ObserverInterface* observer : copy_observers)
103      observer->OnPrefDeleted(key);
104  }
105  return true;
106}
107
108string FakePrefs::GetTypeName(PrefType type) {
109  switch (type) {
110    case PrefType::kString:
111      return "string";
112    case PrefType::kInt64:
113      return "int64_t";
114    case PrefType::kBool:
115      return "bool";
116  }
117  return "Unknown";
118}
119
120void FakePrefs::CheckKeyType(const string& key, PrefType type) const {
121  auto it = values_.find(key);
122  EXPECT_TRUE(it == values_.end() || it->second.type == type)
123      << "Key \"" << key << "\" if defined as " << GetTypeName(it->second.type)
124      << " but is accessed as a " << GetTypeName(type);
125}
126
127template<typename T>
128void FakePrefs::SetValue(const string& key, const T& value) {
129  CheckKeyType(key, PrefConsts<T>::type);
130  values_[key].type = PrefConsts<T>::type;
131  values_[key].value.*(PrefConsts<T>::member) = value;
132  const auto observers_for_key = observers_.find(key);
133  if (observers_for_key != observers_.end()) {
134    std::vector<ObserverInterface*> copy_observers(observers_for_key->second);
135    for (ObserverInterface* observer : copy_observers)
136      observer->OnPrefSet(key);
137  }
138}
139
140template<typename T>
141bool FakePrefs::GetValue(const string& key, T* value) const {
142  CheckKeyType(key, PrefConsts<T>::type);
143  auto it = values_.find(key);
144  if (it == values_.end())
145    return false;
146  CheckNotNull(key, value);
147  *value = it->second.value.*(PrefConsts<T>::member);
148  return true;
149}
150
151void FakePrefs::AddObserver(const string& key, ObserverInterface* observer) {
152  observers_[key].push_back(observer);
153}
154
155void FakePrefs::RemoveObserver(const string& key, ObserverInterface* observer) {
156  std::vector<ObserverInterface*>& observers_for_key = observers_[key];
157  auto observer_it =
158      std::find(observers_for_key.begin(), observers_for_key.end(), observer);
159  EXPECT_NE(observer_it, observers_for_key.end())
160      << "Trying to remove an observer instance not watching the key "
161      << key;
162  if (observer_it != observers_for_key.end())
163    observers_for_key.erase(observer_it);
164  if (observers_for_key.empty())
165    observers_.erase(key);
166}
167
168}  // namespace chromeos_update_engine
169