| // Copyright 2018 The Chromium OS 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 "shill/fake_store.h" |
| |
| #include <typeinfo> |
| #include <vector> |
| |
| #include "shill/logging.h" |
| |
| using std::set; |
| using std::string; |
| using std::vector; |
| |
| namespace shill { |
| |
| namespace Logging { |
| |
| static auto kModuleLogScope = ScopeLogger::kStorage; |
| static string ObjectID(const FakeStore* j) { |
| return "(unknown)"; |
| } |
| |
| } // namespace Logging |
| |
| namespace { |
| |
| bool DoesGroupContainProperties( |
| const brillo::VariantDictionary& group, |
| const brillo::VariantDictionary& required_properties) { |
| for (const auto& required_property_name_and_value : required_properties) { |
| const auto& required_key = required_property_name_and_value.first; |
| const auto& required_value = required_property_name_and_value.second; |
| const auto& group_it = group.find(required_key); |
| if (group_it == group.end() || group_it->second != required_value) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| } // namespace |
| |
| FakeStore::FakeStore() = default; |
| |
| bool FakeStore::IsEmpty() const { |
| // For now, the choice for return value is arbitrary. Revisit if we |
| // find tests depend on this behaving correctly. (i.e., if any tests |
| // require this to return true after a Close().) |
| return true; |
| } |
| |
| bool FakeStore::Open() { |
| return true; |
| } |
| |
| bool FakeStore::Close() { |
| return true; |
| } |
| |
| bool FakeStore::Flush() { |
| return true; |
| } |
| |
| bool FakeStore::MarkAsCorrupted() { |
| return true; |
| } |
| |
| set<string> FakeStore::GetGroups() const { |
| set<string> matching_groups; |
| for (const auto& group_name_and_settings : group_name_to_settings_) { |
| matching_groups.insert(group_name_and_settings.first); |
| } |
| return matching_groups; |
| } |
| |
| // Returns a set so that caller can easily test whether a particular group |
| // is contained within this collection. |
| set<string> FakeStore::GetGroupsWithKey(const string& key) const { |
| set<string> matching_groups; |
| // iterate over groups, find ones with matching key |
| for (const auto& group_name_and_settings : group_name_to_settings_) { |
| const auto& group_name = group_name_and_settings.first; |
| const auto& group_settings = group_name_and_settings.second; |
| if (group_settings.find(key) != group_settings.end()) { |
| matching_groups.insert(group_name); |
| } |
| } |
| return matching_groups; |
| } |
| |
| set<string> FakeStore::GetGroupsWithProperties( |
| const KeyValueStore& properties) const { |
| set<string> matching_groups; |
| const brillo::VariantDictionary& properties_dict(properties.properties()); |
| for (const auto& group_name_and_settings : group_name_to_settings_) { |
| const auto& group_name = group_name_and_settings.first; |
| const auto& group_settings = group_name_and_settings.second; |
| if (DoesGroupContainProperties(group_settings, properties_dict)) { |
| matching_groups.insert(group_name); |
| } |
| } |
| return matching_groups; |
| } |
| |
| bool FakeStore::ContainsGroup(const string& group) const { |
| const auto& it = group_name_to_settings_.find(group); |
| return it != group_name_to_settings_.end(); |
| } |
| |
| bool FakeStore::DeleteKey(const string& group, const string& key) { |
| const auto& group_name_and_settings = group_name_to_settings_.find(group); |
| if (group_name_and_settings == group_name_to_settings_.end()) { |
| LOG(ERROR) << "Could not find group |" << group << "|."; |
| return false; |
| } |
| |
| auto& group_settings = group_name_and_settings->second; |
| auto property_it = group_settings.find(key); |
| if (property_it != group_settings.end()) { |
| group_settings.erase(property_it); |
| } |
| |
| return true; |
| } |
| |
| bool FakeStore::DeleteGroup(const string& group) { |
| auto group_name_and_settings = group_name_to_settings_.find(group); |
| if (group_name_and_settings != group_name_to_settings_.end()) { |
| group_name_to_settings_.erase(group_name_and_settings); |
| } |
| return true; |
| } |
| |
| bool FakeStore::SetHeader(const string& header) { |
| return true; |
| } |
| |
| bool FakeStore::GetString(const string& group, |
| const string& key, |
| string* value) const { |
| return ReadSetting(group, key, value); |
| } |
| |
| bool FakeStore::SetString(const string& group, |
| const string& key, |
| const string& value) { |
| return WriteSetting(group, key, value); |
| } |
| |
| bool FakeStore::GetBool(const string& group, |
| const string& key, |
| bool* value) const { |
| return ReadSetting(group, key, value); |
| } |
| |
| bool FakeStore::SetBool(const string& group, const string& key, bool value) { |
| return WriteSetting(group, key, value); |
| } |
| |
| bool FakeStore::GetInt(const string& group, |
| const string& key, |
| int* value) const { |
| return ReadSetting(group, key, value); |
| } |
| |
| bool FakeStore::SetInt(const string& group, const string& key, int value) { |
| return WriteSetting(group, key, value); |
| } |
| |
| bool FakeStore::GetUint64(const string& group, |
| const string& key, |
| uint64_t* value) const { |
| return ReadSetting(group, key, value); |
| } |
| |
| bool FakeStore::SetUint64(const string& group, |
| const string& key, |
| uint64_t value) { |
| return WriteSetting(group, key, value); |
| } |
| |
| bool FakeStore::GetStringList(const string& group, |
| const string& key, |
| vector<string>* value) const { |
| return ReadSetting(group, key, value); |
| } |
| |
| bool FakeStore::SetStringList(const string& group, |
| const string& key, |
| const vector<string>& value) { |
| return WriteSetting(group, key, value); |
| } |
| |
| bool FakeStore::GetCryptedString(const string& group, |
| const string& key, |
| string* value) const { |
| return GetString(group, key, value); |
| } |
| |
| bool FakeStore::SetCryptedString(const string& group, |
| const string& key, |
| const string& value) { |
| return SetString(group, key, value); |
| } |
| |
| // Private methods. |
| template <typename T> |
| bool FakeStore::ReadSetting(const string& group, |
| const string& key, |
| T* out) const { |
| const auto& group_name_and_settings = group_name_to_settings_.find(group); |
| if (group_name_and_settings == group_name_to_settings_.end()) { |
| SLOG(this, 10) << "Could not find group |" << group << "|."; |
| return false; |
| } |
| |
| const auto& group_settings = group_name_and_settings->second; |
| const auto& property_name_and_value = group_settings.find(key); |
| if (property_name_and_value == group_settings.end()) { |
| SLOG(this, 10) << "Could not find property |" << key << "|."; |
| return false; |
| } |
| |
| if (!property_name_and_value->second.IsTypeCompatible<T>()) { |
| // We assume that the reader and the writer agree on the exact |
| // type. So we do not allow implicit conversion. |
| LOG(ERROR) << "Can not read |" << brillo::GetUndecoratedTypeName<T>() |
| << "| from |" |
| << property_name_and_value->second.GetUndecoratedTypeName() |
| << "|."; |
| return false; |
| } |
| |
| if (out) { |
| return property_name_and_value->second.GetValue(out); |
| } else { |
| return true; |
| } |
| } |
| |
| template <typename T> |
| bool FakeStore::WriteSetting(const string& group, |
| const string& key, |
| const T& new_value) { |
| auto group_name_and_settings = group_name_to_settings_.find(group); |
| if (group_name_and_settings == group_name_to_settings_.end()) { |
| group_name_to_settings_[group][key] = new_value; |
| return true; |
| } |
| |
| auto& group_settings = group_name_and_settings->second; |
| auto property_name_and_value = group_settings.find(key); |
| if (property_name_and_value == group_settings.end()) { |
| group_settings[key] = new_value; |
| return true; |
| } |
| |
| if (!property_name_and_value->second.IsTypeCompatible<T>()) { |
| SLOG(this, 10) << "New type |" << brillo::GetUndecoratedTypeName<T>() |
| << "| differs from current type |" |
| << property_name_and_value->second.GetUndecoratedTypeName() |
| << "|."; |
| return false; |
| } else { |
| property_name_and_value->second = new_value; |
| return true; |
| } |
| } |
| |
| } // namespace shill |