| // 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/property_accessor.h" |
| |
| #include <limits> |
| #include <map> |
| #include <string> |
| |
| #include <base/containers/contains.h> |
| #include <gtest/gtest.h> |
| #include <gmock/gmock.h> |
| |
| #include "shill/error.h" |
| |
| using ::testing::Test; |
| |
| namespace shill { |
| |
| TEST(PropertyAccessorTest, SignedIntCorrectness) { |
| int32_t int_store = 0; |
| { |
| Error error; |
| int32_t orig_value = int_store; |
| Int32Accessor accessor(new PropertyAccessor<int32_t>(&int_store)); |
| EXPECT_EQ(int_store, accessor->Get(&error)); |
| |
| int32_t expected_int32 = 127; |
| EXPECT_TRUE(accessor->Set(expected_int32, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(expected_int32, accessor->Get(&error)); |
| // Resetting to the same value should return false, but without |
| // an error. |
| EXPECT_FALSE(accessor->Set(expected_int32, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| |
| accessor->Clear(&error); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(orig_value, accessor->Get(&error)); |
| |
| int_store = std::numeric_limits<int32_t>::max(); |
| EXPECT_EQ(std::numeric_limits<int32_t>::max(), accessor->Get(&error)); |
| } |
| { |
| Error error; |
| Int32Accessor accessor(new ConstPropertyAccessor<int32_t>(&int_store)); |
| EXPECT_EQ(int_store, accessor->Get(&error)); |
| |
| int32_t expected_int32 = 127; |
| accessor->Set(expected_int32, &error); |
| ASSERT_FALSE(error.IsSuccess()); |
| EXPECT_EQ(Error::kInvalidArguments, error.type()); |
| EXPECT_EQ(int_store, accessor->Get(&error)); |
| |
| int_store = std::numeric_limits<int32_t>::max(); |
| EXPECT_EQ(std::numeric_limits<int32_t>::max(), accessor->Get(&error)); |
| } |
| { |
| Error error; |
| Int32Accessor accessor(new ConstPropertyAccessor<int32_t>(&int_store)); |
| accessor->Clear(&error); |
| ASSERT_FALSE(error.IsSuccess()); |
| } |
| { |
| Error error; |
| Int32Accessor accessor(new WriteOnlyPropertyAccessor<int32_t>(&int_store)); |
| accessor->Get(&error); |
| EXPECT_TRUE(error.IsFailure()); |
| EXPECT_EQ(Error::kPermissionDenied, error.type()); |
| } |
| { |
| Error error; |
| int32_t expected_int32 = 127; |
| WriteOnlyPropertyAccessor<int32_t> accessor(&int_store); |
| EXPECT_TRUE(accessor.Set(expected_int32, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(expected_int32, *accessor.property_); |
| // Resetting to the same value should return false, but without |
| // an error. |
| EXPECT_FALSE(accessor.Set(expected_int32, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| // As a write-only, the value can't be read. |
| EXPECT_EQ(int32_t(), accessor.Get(&error)); |
| ASSERT_FALSE(error.IsSuccess()); |
| |
| int_store = std::numeric_limits<int32_t>::max(); |
| EXPECT_EQ(std::numeric_limits<int32_t>::max(), *accessor.property_); |
| } |
| { |
| Error error; |
| int32_t orig_value = int_store = 0; |
| WriteOnlyPropertyAccessor<int32_t> accessor(&int_store); |
| |
| EXPECT_TRUE(accessor.Set(127, &error)); |
| accessor.Clear(&error); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(orig_value, *accessor.property_); |
| } |
| } |
| |
| TEST(PropertyAccessorTest, UnsignedIntCorrectness) { |
| uint32_t int_store = 0; |
| { |
| Error error; |
| uint32_t orig_value = int_store; |
| Uint32Accessor accessor(new PropertyAccessor<uint32_t>(&int_store)); |
| EXPECT_EQ(int_store, accessor->Get(&error)); |
| |
| uint32_t expected_uint32 = 127; |
| EXPECT_TRUE(accessor->Set(expected_uint32, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(expected_uint32, accessor->Get(&error)); |
| // Resetting to the same value should return false, but without |
| // an error. |
| EXPECT_FALSE(accessor->Set(expected_uint32, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| |
| accessor->Clear(&error); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(orig_value, accessor->Get(&error)); |
| |
| int_store = std::numeric_limits<uint32_t>::max(); |
| EXPECT_EQ(std::numeric_limits<uint32_t>::max(), accessor->Get(&error)); |
| } |
| { |
| Error error; |
| Uint32Accessor accessor(new ConstPropertyAccessor<uint32_t>(&int_store)); |
| EXPECT_EQ(int_store, accessor->Get(&error)); |
| |
| uint32_t expected_uint32 = 127; |
| EXPECT_FALSE(accessor->Set(expected_uint32, &error)); |
| ASSERT_FALSE(error.IsSuccess()); |
| EXPECT_EQ(Error::kInvalidArguments, error.type()); |
| EXPECT_EQ(int_store, accessor->Get(&error)); |
| |
| int_store = std::numeric_limits<uint32_t>::max(); |
| EXPECT_EQ(std::numeric_limits<uint32_t>::max(), accessor->Get(&error)); |
| } |
| { |
| Error error; |
| Uint32Accessor accessor(new ConstPropertyAccessor<uint32_t>(&int_store)); |
| accessor->Clear(&error); |
| ASSERT_FALSE(error.IsSuccess()); |
| } |
| { |
| Error error; |
| Uint32Accessor accessor( |
| new WriteOnlyPropertyAccessor<uint32_t>(&int_store)); |
| accessor->Get(&error); |
| EXPECT_TRUE(error.IsFailure()); |
| EXPECT_EQ(Error::kPermissionDenied, error.type()); |
| } |
| { |
| Error error; |
| uint32_t expected_uint32 = 127; |
| WriteOnlyPropertyAccessor<uint32_t> accessor(&int_store); |
| EXPECT_TRUE(accessor.Set(expected_uint32, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(expected_uint32, *accessor.property_); |
| // Resetting to the same value should return false, but without |
| // an error. |
| EXPECT_FALSE(accessor.Set(expected_uint32, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| // As a write-only, the value can't be read. |
| EXPECT_EQ(uint32_t(), accessor.Get(&error)); |
| ASSERT_FALSE(error.IsSuccess()); |
| |
| int_store = std::numeric_limits<uint32_t>::max(); |
| EXPECT_EQ(std::numeric_limits<uint32_t>::max(), *accessor.property_); |
| } |
| { |
| Error error; |
| uint32_t orig_value = int_store = 0; |
| WriteOnlyPropertyAccessor<uint32_t> accessor(&int_store); |
| |
| EXPECT_TRUE(accessor.Set(127, &error)); |
| accessor.Clear(&error); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(orig_value, *accessor.property_); |
| } |
| } |
| |
| TEST(PropertyAccessorTest, StringCorrectness) { |
| std::string storage; |
| { |
| Error error; |
| std::string orig_value = storage; |
| StringAccessor accessor(new PropertyAccessor<std::string>(&storage)); |
| EXPECT_EQ(storage, accessor->Get(&error)); |
| |
| std::string expected_string("what"); |
| EXPECT_TRUE(accessor->Set(expected_string, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(expected_string, accessor->Get(&error)); |
| // Resetting to the same value should return false, but without |
| // an error. |
| EXPECT_FALSE(accessor->Set(expected_string, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| |
| accessor->Clear(&error); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(orig_value, accessor->Get(&error)); |
| |
| storage = "nooooo"; |
| EXPECT_EQ(storage, accessor->Get(&error)); |
| } |
| { |
| Error error; |
| StringAccessor accessor(new ConstPropertyAccessor<std::string>(&storage)); |
| EXPECT_EQ(storage, accessor->Get(&error)); |
| |
| std::string expected_string("what"); |
| EXPECT_FALSE(accessor->Set(expected_string, &error)); |
| ASSERT_FALSE(error.IsSuccess()); |
| EXPECT_EQ(Error::kInvalidArguments, error.type()); |
| EXPECT_EQ(storage, accessor->Get(&error)); |
| |
| storage = "nooooo"; |
| EXPECT_EQ(storage, accessor->Get(&error)); |
| } |
| { |
| Error error; |
| StringAccessor accessor(new ConstPropertyAccessor<std::string>(&storage)); |
| accessor->Clear(&error); |
| ASSERT_FALSE(error.IsSuccess()); |
| } |
| { |
| Error error; |
| StringAccessor accessor( |
| new WriteOnlyPropertyAccessor<std::string>(&storage)); |
| accessor->Get(&error); |
| EXPECT_TRUE(error.IsFailure()); |
| EXPECT_EQ(Error::kPermissionDenied, error.type()); |
| } |
| { |
| Error error; |
| std::string expected_string = "what"; |
| WriteOnlyPropertyAccessor<std::string> accessor(&storage); |
| EXPECT_TRUE(accessor.Set(expected_string, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(expected_string, *accessor.property_); |
| // Resetting to the same value should return false, but without |
| // an error. |
| EXPECT_FALSE(accessor.Set(expected_string, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| // As a write-only, the value can't be read. |
| EXPECT_EQ(std::string(), accessor.Get(&error)); |
| ASSERT_FALSE(error.IsSuccess()); |
| |
| storage = "nooooo"; |
| EXPECT_EQ("nooooo", *accessor.property_); |
| } |
| { |
| Error error; |
| std::string orig_value = storage = "original value"; |
| WriteOnlyPropertyAccessor<std::string> accessor(&storage); |
| EXPECT_TRUE(accessor.Set("new value", &error)); |
| accessor.Clear(&error); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(orig_value, *accessor.property_); |
| } |
| } |
| |
| TEST(PropertyAccessorTest, ByteArrayCorrectness) { |
| ByteArray byte_array; |
| { |
| Error error; |
| ByteArray orig_byte_array = byte_array; |
| ByteArrayAccessor accessor(new PropertyAccessor<ByteArray>(&byte_array)); |
| EXPECT_EQ(byte_array, accessor->Get(&error)); |
| |
| ByteArray expected_byte_array({0x01, 0x7F, 0x80, 0xFF}); |
| EXPECT_TRUE(accessor->Set(expected_byte_array, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(expected_byte_array, accessor->Get(&error)); |
| |
| // Resetting to the same value should return false, but without |
| // an error. |
| EXPECT_FALSE(accessor->Set(expected_byte_array, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| |
| accessor->Clear(&error); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(orig_byte_array, accessor->Get(&error)); |
| |
| byte_array = ByteArray({0xFF, 0x7F, 0x80, 0x00}); |
| EXPECT_EQ(byte_array, accessor->Get(&error)); |
| } |
| { |
| Error error; |
| ByteArrayAccessor accessor( |
| new ConstPropertyAccessor<ByteArray>(&byte_array)); |
| EXPECT_EQ(byte_array, accessor->Get(&error)); |
| |
| ByteArray expected_byte_array({0x01, 0x7F, 0x80, 0xFF}); |
| EXPECT_FALSE(accessor->Set(expected_byte_array, &error)); |
| ASSERT_FALSE(error.IsSuccess()); |
| EXPECT_EQ(Error::kInvalidArguments, error.type()); |
| EXPECT_EQ(byte_array, accessor->Get(&error)); |
| |
| byte_array = ByteArray({0xFF, 0x7F, 0x80, 0x00}); |
| EXPECT_EQ(byte_array, accessor->Get(&error)); |
| } |
| { |
| Error error; |
| ByteArrayAccessor accessor( |
| new ConstPropertyAccessor<ByteArray>(&byte_array)); |
| accessor->Clear(&error); |
| ASSERT_FALSE(error.IsSuccess()); |
| } |
| { |
| Error error; |
| ByteArrayAccessor accessor( |
| new WriteOnlyPropertyAccessor<ByteArray>(&byte_array)); |
| accessor->Get(&error); |
| EXPECT_TRUE(error.IsFailure()); |
| EXPECT_EQ(Error::kPermissionDenied, error.type()); |
| } |
| { |
| Error error; |
| ByteArray expected_byte_array({0x01, 0x7F, 0x80, 0xFF}); |
| WriteOnlyPropertyAccessor<ByteArray> accessor(&byte_array); |
| |
| EXPECT_TRUE(accessor.Set(expected_byte_array, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(expected_byte_array, *accessor.property_); |
| |
| // Resetting to the same value should return false, but without |
| // an error. |
| EXPECT_FALSE(accessor.Set(expected_byte_array, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| |
| // As a write-only, the value can't be read. |
| EXPECT_EQ(ByteArray(), accessor.Get(&error)); |
| EXPECT_FALSE(error.IsSuccess()); |
| |
| byte_array = ByteArray({0xFF, 0x7F, 0x80, 0x00}); |
| EXPECT_EQ(ByteArray({0xFF, 0x7F, 0x80, 0x00}), *accessor.property_); |
| } |
| { |
| Error error; |
| ByteArray orig_byte_array = byte_array = |
| ByteArray({0x00, 0x7F, 0x80, 0xFF}); |
| WriteOnlyPropertyAccessor<ByteArray> accessor(&byte_array); |
| |
| EXPECT_TRUE(accessor.Set(ByteArray({0xFF, 0x7F, 0x80, 0x00}), &error)); |
| accessor.Clear(&error); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(orig_byte_array, *accessor.property_); |
| } |
| } |
| |
| class StringWrapper { |
| public: |
| std::string Get(Error* /*error*/) { return value_; } |
| std::string ConstGet(Error* /*error*/) const { return value_; } |
| bool Set(const std::string& value, Error* /*error*/) { |
| if (value_ == value) { |
| return false; |
| } |
| value_ = value; |
| return true; |
| } |
| void Clear(Error* /*error*/) { value_.clear(); } |
| |
| std::string value_; |
| }; |
| |
| TEST(PropertyAccessorTest, CustomAccessorCorrectness) { |
| StringWrapper wrapper; |
| { |
| // Custom accessor: read, write, write-same, clear, read-updated. |
| // Together, write and write-same verify that the CustomAccessor |
| // template passes through the value from the called function. |
| Error error; |
| const std::string orig_value = wrapper.value_ = "original value"; |
| CustomAccessor<StringWrapper, std::string> accessor( |
| &wrapper, &StringWrapper::Get, &StringWrapper::Set); |
| EXPECT_EQ(orig_value, accessor.Get(&error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| |
| const std::string expected_string = "new value"; |
| EXPECT_TRUE(accessor.Set(expected_string, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(expected_string, accessor.Get(&error)); |
| // Set to same value. |
| EXPECT_FALSE(accessor.Set(expected_string, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| |
| accessor.Clear(&error); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(orig_value, accessor.Get(&error)); |
| |
| wrapper.value_ = "nooooo"; |
| EXPECT_EQ(wrapper.value_, accessor.Get(&error)); |
| } |
| { |
| // Custom read-only accessor: read, write, read-updated. |
| Error error; |
| CustomAccessor<StringWrapper, std::string> accessor( |
| &wrapper, &StringWrapper::Get, nullptr); |
| EXPECT_EQ(wrapper.value_, accessor.Get(&error)); |
| |
| const std::string expected_string = "what"; |
| EXPECT_FALSE(accessor.Set(expected_string, &error)); |
| ASSERT_FALSE(error.IsSuccess()); |
| EXPECT_EQ(Error::kInvalidArguments, error.type()); |
| EXPECT_EQ(wrapper.value_, accessor.Get(&error)); |
| |
| wrapper.value_ = "nooooo"; |
| EXPECT_EQ(wrapper.value_, accessor.Get(&error)); |
| } |
| { |
| // Custom read-only accessor: clear. |
| Error error; |
| CustomAccessor<StringWrapper, std::string> accessor( |
| &wrapper, &StringWrapper::Get, nullptr); |
| accessor.Clear(&error); |
| ASSERT_FALSE(error.IsSuccess()); |
| } |
| { |
| // Custom read-only accessor with custom clear method. |
| Error error; |
| CustomAccessor<StringWrapper, std::string> accessor( |
| &wrapper, &StringWrapper::Get, nullptr, &StringWrapper::Clear); |
| wrapper.value_ = "empty this"; |
| accessor.Clear(&error); |
| ASSERT_TRUE(error.IsSuccess()); |
| EXPECT_TRUE(wrapper.value_.empty()); |
| } |
| } |
| |
| TEST(PropertyAccessorTest, CustomWriteOnlyAccessorWithDefault) { |
| StringWrapper wrapper; |
| { |
| // Test reading. |
| Error error; |
| const std::string default_value = "default value"; |
| CustomWriteOnlyAccessor<StringWrapper, std::string> accessor( |
| &wrapper, &StringWrapper::Set, nullptr, &default_value); |
| wrapper.value_ = "can't read this"; |
| EXPECT_EQ(std::string(), accessor.Get(&error)); |
| EXPECT_TRUE(error.IsFailure()); |
| EXPECT_EQ(Error::kPermissionDenied, error.type()); |
| } |
| { |
| // Test writing. |
| Error error; |
| const std::string default_value = "default value"; |
| const std::string expected_string = "what"; |
| CustomWriteOnlyAccessor<StringWrapper, std::string> accessor( |
| &wrapper, &StringWrapper::Set, nullptr, &default_value); |
| EXPECT_TRUE(accessor.Set(expected_string, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(expected_string, wrapper.value_); |
| // Set to same value. With the above, this verifies that the |
| // CustomWriteOnlyAccessor template passes through the return |
| // value. |
| EXPECT_FALSE(accessor.Set(expected_string, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| } |
| { |
| // Test clearing. |
| Error error; |
| const std::string default_value = "default value"; |
| CustomWriteOnlyAccessor<StringWrapper, std::string> accessor( |
| &wrapper, &StringWrapper::Set, nullptr, &default_value); |
| accessor.Set("new value", &error); |
| EXPECT_EQ("new value", wrapper.value_); |
| accessor.Clear(&error); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(default_value, wrapper.value_); |
| } |
| } |
| |
| TEST(PropertyAccessorTest, CustomWriteOnlyAccessorWithClear) { |
| StringWrapper wrapper; |
| { |
| // Test reading. |
| Error error; |
| CustomWriteOnlyAccessor<StringWrapper, std::string> accessor( |
| &wrapper, &StringWrapper::Set, &StringWrapper::Clear, nullptr); |
| wrapper.value_ = "can't read this"; |
| EXPECT_EQ(std::string(), accessor.Get(&error)); |
| EXPECT_TRUE(error.IsFailure()); |
| EXPECT_EQ(Error::kPermissionDenied, error.type()); |
| } |
| { |
| // Test writing. |
| Error error; |
| const std::string expected_string = "what"; |
| CustomWriteOnlyAccessor<StringWrapper, std::string> accessor( |
| &wrapper, &StringWrapper::Set, &StringWrapper::Clear, nullptr); |
| EXPECT_TRUE(accessor.Set(expected_string, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(expected_string, wrapper.value_); |
| // Set to same value. With the above, this verifies that the |
| // CustomWriteOnlyAccessor template passes through the return |
| // value. |
| EXPECT_FALSE(accessor.Set(expected_string, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| } |
| { |
| // Test clearing. |
| Error error; |
| CustomWriteOnlyAccessor<StringWrapper, std::string> accessor( |
| &wrapper, &StringWrapper::Set, &StringWrapper::Clear, nullptr); |
| EXPECT_TRUE(accessor.Set("new value", &error)); |
| EXPECT_EQ("new value", wrapper.value_); |
| accessor.Clear(&error); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ("", wrapper.value_); |
| } |
| } |
| |
| TEST(PropertyAccessorTest, CustomReadOnlyAccessor) { |
| StringWrapper wrapper; |
| CustomReadOnlyAccessor<StringWrapper, std::string> accessor( |
| &wrapper, &StringWrapper::ConstGet); |
| const std::string orig_value = wrapper.value_ = "original value"; |
| { |
| // Test reading. |
| Error error; |
| EXPECT_EQ(orig_value, accessor.Get(&error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| } |
| { |
| // Test writing. |
| Error error; |
| EXPECT_FALSE(accessor.Set("new value", &error)); |
| EXPECT_EQ(Error::kInvalidArguments, error.type()); |
| EXPECT_EQ(orig_value, accessor.Get(&error)); |
| } |
| { |
| // Test writing original value -- this also fails. |
| Error error; |
| EXPECT_FALSE(accessor.Set(orig_value, &error)); |
| EXPECT_EQ(Error::kInvalidArguments, error.type()); |
| EXPECT_EQ(orig_value, accessor.Get(&error)); |
| } |
| { |
| // Test clearing. |
| Error error; |
| accessor.Clear(&error); |
| EXPECT_EQ(Error::kInvalidArguments, error.type()); |
| EXPECT_EQ(orig_value, accessor.Get(&error)); |
| } |
| } |
| |
| class StringMapWrapper { |
| public: |
| void Clear(const std::string& key, Error* /*error*/) { value_.erase(key); } |
| std::string Get(const std::string& key, Error* /*error*/) { |
| EXPECT_TRUE(base::Contains(value_, key)); |
| return value_[key]; |
| } |
| bool Set(const std::string& key, const std::string& value, Error* /*error*/) { |
| if (value_[key] == value) { |
| return false; |
| } |
| value_[key] = value; |
| return true; |
| } |
| |
| std::map<std::string, std::string> value_; |
| }; |
| |
| TEST(PropertyAccessorTest, CustomMappedAccessor) { |
| const std::string kKey = "entry_key"; |
| const std::string kValue = "entry_value"; |
| { |
| // Test reading. |
| StringMapWrapper wrapper; |
| CustomMappedAccessor<StringMapWrapper, std::string, std::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, std::string, std::string> accessor( |
| &wrapper, &StringMapWrapper::Clear, &StringMapWrapper::Get, |
| &StringMapWrapper::Set, kKey); |
| Error error; |
| EXPECT_TRUE(accessor.Set(kValue, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(kValue, wrapper.value_[kKey]); |
| // Set to same value. With the above, this verifies that the |
| // CustomMappedAccessor template passes through the return |
| // value. |
| EXPECT_FALSE(accessor.Set(kValue, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| } |
| { |
| // Test clearing. |
| StringMapWrapper wrapper; |
| CustomMappedAccessor<StringMapWrapper, std::string, std::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(base::Contains(wrapper.value_, kKey)); |
| } |
| } |
| |
| } // namespace shill |