shill: Create a Mapped custom property accessor
Create an accessor that passes a property key to the get/set/clear.
BUG=chromium-os:28303
TEST=New unit tests
Change-Id: If9cb94cf60427c49c5e87c828b787fc6d17d1a0c
Reviewed-on: https://gerrit.chromium.org/gerrit/18988
Commit-Ready: Paul Stewart <pstew@chromium.org>
Reviewed-by: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/property_accessor.h b/property_accessor.h
index 39cd611..9005192 100644
--- a/property_accessor.h
+++ b/property_accessor.h
@@ -212,6 +212,58 @@
DISALLOW_COPY_AND_ASSIGN(CustomWriteOnlyAccessor);
};
+// CustomMappedAccessor<> passes an argument to the getter and setter
+// so that a generic method can be used, for example one that accesses the
+// property in a map.
+template<class C, class T, class A>
+class CustomMappedAccessor : public AccessorInterface<T> {
+ public:
+ // |target| is the object on which to call the methods |getter| and |setter|.
+ // |setter| is allowed to be NULL, in which case we will simply reject
+ // attempts to set via the accessor.
+ // |argument| is passed to the getter and setter methods to disambiguate
+ // between different properties in |target|.
+ // It is an error to pass NULL for any of |target|, |clearer| or |getter|.
+ CustomMappedAccessor(C *target,
+ void(C::*clearer)(const A &argument, Error *error),
+ T(C::*getter)(const A &argument, Error *error),
+ void(C::*setter)(const T &value, const A &argument,
+ Error *error),
+ const A &argument)
+ : target_(target),
+ clearer_(clearer),
+ getter_(getter),
+ setter_(setter),
+ argument_(argument) {
+ DCHECK(clearer);
+ DCHECK(target);
+ DCHECK(getter);
+ }
+ virtual ~CustomMappedAccessor() {}
+
+ void Clear(Error *error) {
+ (target_->*clearer_)(argument_, error);
+ }
+ T Get(Error *error) {
+ return (target_->*getter_)(argument_, error);
+ }
+ void Set(const T &value, Error *error) {
+ if (setter_) {
+ (target_->*setter_)(value, argument_, error);
+ } else {
+ error->Populate(Error::kInvalidArguments, "Property is read-only");
+ }
+ }
+
+ private:
+ C *const target_;
+ void(C::*const clearer_)(const A &argument, Error *error);
+ T(C::*const getter_)(const A &argument, Error *error);
+ void(C::*const setter_)(const T &value, const A &argument, Error *error);
+ A argument_;
+ DISALLOW_COPY_AND_ASSIGN(CustomMappedAccessor);
+};
+
} // namespace shill
#endif // SHILL_PROPERTY_ACCESSOR_
diff --git a/property_accessor_unittest.cc b/property_accessor_unittest.cc
index f95abdf..b52fe19 100644
--- a/property_accessor_unittest.cc
+++ b/property_accessor_unittest.cc
@@ -10,6 +10,7 @@
#include <vector>
#include <base/basictypes.h>
+#include <base/stl_util.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
@@ -378,4 +379,59 @@
}
}
+class StringMapWrapper {
+ public:
+ void Clear(const string &key, Error */*error*/) {
+ value_.erase(key);
+ }
+ string Get(const string &key, Error */*error*/) {
+ EXPECT_TRUE(ContainsKey(value_, key));
+ return value_[key];
+ }
+ void Set(const string &value, const string &key, Error */*error*/) {
+ value_[key] = value;
+ }
+
+ map<string,string> value_;
+};
+
+TEST(PropertyAccessorTest, CustomMappedAccessor) {
+ const string kKey = "entry_key";
+ const string kValue = "entry_value";
+ {
+ // Test reading.
+ StringMapWrapper wrapper;
+ CustomMappedAccessor<StringMapWrapper, string, string> accessor(
+ &wrapper, &StringMapWrapper::Clear, &StringMapWrapper::Get,
+ &StringMapWrapper::Set, kKey);
+ wrapper.value_[kKey] = kValue;
+ Error error;
+ EXPECT_EQ(kValue, accessor.Get(&error));
+ EXPECT_TRUE(error.IsSuccess());
+ }
+ {
+ // Test writing.
+ StringMapWrapper wrapper;
+ CustomMappedAccessor<StringMapWrapper, string, string> accessor(
+ &wrapper, &StringMapWrapper::Clear, &StringMapWrapper::Get,
+ &StringMapWrapper::Set, kKey);
+ Error error;
+ accessor.Set(kValue, &error);
+ EXPECT_TRUE(error.IsSuccess());
+ EXPECT_EQ(kValue, wrapper.value_[kKey]);
+ }
+ {
+ // Test clearing.
+ StringMapWrapper wrapper;
+ CustomMappedAccessor<StringMapWrapper, string, string> accessor(
+ &wrapper, &StringMapWrapper::Clear, &StringMapWrapper::Get,
+ &StringMapWrapper::Set, kKey);
+ wrapper.value_[kKey] = kValue;
+ Error error;
+ accessor.Clear(&error);
+ EXPECT_TRUE(error.IsSuccess());
+ EXPECT_FALSE(ContainsKey(wrapper.value_, kKey));
+ }
+}
+
} // namespace shill