// // Copyright (C) 2012 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "shill/property_accessor.h" #include <limits> #include <map> #include <string> #include <vector> #include <base/stl_util.h> #include <gtest/gtest.h> #include <gmock/gmock.h> #include "shill/error.h" using std::map; using std::string; using std::vector; using ::testing::Return; 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) { string storage; { Error error; string orig_value = storage; StringAccessor accessor(new PropertyAccessor<string>(&storage)); EXPECT_EQ(storage, accessor->Get(&error)); 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<string>(&storage)); EXPECT_EQ(storage, accessor->Get(&error)); 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<string>(&storage)); accessor->Clear(&error); ASSERT_FALSE(error.IsSuccess()); } { Error error; StringAccessor accessor(new WriteOnlyPropertyAccessor<string>(&storage)); accessor->Get(&error); EXPECT_TRUE(error.IsFailure()); EXPECT_EQ(Error::kPermissionDenied, error.type()); } { Error error; string expected_string = "what"; WriteOnlyPropertyAccessor<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(string(), accessor.Get(&error)); ASSERT_FALSE(error.IsSuccess()); storage = "nooooo"; EXPECT_EQ("nooooo", *accessor.property_); } { Error error; string orig_value = storage = "original value"; WriteOnlyPropertyAccessor<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 byteArray; { Error error; ByteArray orig_byteArray = byteArray; ByteArrayAccessor accessor(new PropertyAccessor<ByteArray>(&byteArray)); EXPECT_EQ(byteArray, accessor->Get(&error)); ByteArray expected_byteArray({ 0x01, 0x7F, 0x80, 0xFF }); EXPECT_TRUE(accessor->Set(expected_byteArray, &error)); EXPECT_TRUE(error.IsSuccess()); EXPECT_EQ(expected_byteArray, accessor->Get(&error)); // Resetting to the same value should return false, but without // an error. EXPECT_FALSE(accessor->Set(expected_byteArray, &error)); EXPECT_TRUE(error.IsSuccess()); accessor->Clear(&error); EXPECT_TRUE(error.IsSuccess()); EXPECT_EQ(orig_byteArray, accessor->Get(&error)); byteArray = ByteArray({ 0xFF, 0x7F, 0x80, 0x00 }); EXPECT_EQ(byteArray, accessor->Get(&error)); } { Error error; ByteArrayAccessor accessor(new ConstPropertyAccessor<ByteArray>(&byteArray)); EXPECT_EQ(byteArray, accessor->Get(&error)); ByteArray expected_byteArray({ 0x01, 0x7F, 0x80, 0xFF }); EXPECT_FALSE(accessor->Set(expected_byteArray, &error)); ASSERT_FALSE(error.IsSuccess()); EXPECT_EQ(Error::kInvalidArguments, error.type()); EXPECT_EQ(byteArray, accessor->Get(&error)); byteArray = ByteArray({ 0xFF, 0x7F, 0x80, 0x00 }); EXPECT_EQ(byteArray, accessor->Get(&error)); } { Error error; ByteArrayAccessor accessor(new ConstPropertyAccessor<ByteArray>(&byteArray)); accessor->Clear(&error); ASSERT_FALSE(error.IsSuccess()); } { Error error; ByteArrayAccessor accessor(new WriteOnlyPropertyAccessor<ByteArray>(&byteArray)); accessor->Get(&error); EXPECT_TRUE(error.IsFailure()); EXPECT_EQ(Error::kPermissionDenied, error.type()); } { Error error; ByteArray expected_byteArray({ 0x01, 0x7F, 0x80, 0xFF }); WriteOnlyPropertyAccessor<ByteArray> accessor(&byteArray); EXPECT_TRUE(accessor.Set(expected_byteArray, &error)); EXPECT_TRUE(error.IsSuccess()); EXPECT_EQ(expected_byteArray, *accessor.property_); // Resetting to the same value should return false, but without // an error. EXPECT_FALSE(accessor.Set(expected_byteArray, &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()); byteArray = ByteArray({ 0xFF, 0x7F, 0x80, 0x00 }); EXPECT_EQ(ByteArray({ 0xFF, 0x7F, 0x80, 0x00 }), *accessor.property_); } { Error error; ByteArray orig_byteArray = byteArray = ByteArray({ 0x00, 0x7F, 0x80, 0xFF }); WriteOnlyPropertyAccessor<ByteArray> accessor(&byteArray); EXPECT_TRUE(accessor.Set(ByteArray({ 0xFF, 0x7F, 0x80, 0x00 }), &error)); accessor.Clear(&error); EXPECT_TRUE(error.IsSuccess()); EXPECT_EQ(orig_byteArray, *accessor.property_); } } class StringWrapper { public: string Get(Error* /*error*/) { return value_; } string ConstGet(Error* /*error*/) const { return value_; } bool Set(const string& value, Error* /*error*/) { if (value_ == value) { return false; } value_ = value; return true; } void Clear(Error* /*error*/) { value_.clear(); } 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 string orig_value = wrapper.value_ = "original value"; CustomAccessor<StringWrapper, string> accessor(&wrapper, &StringWrapper::Get, &StringWrapper::Set); EXPECT_EQ(orig_value, accessor.Get(&error)); EXPECT_TRUE(error.IsSuccess()); const 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, string> accessor(&wrapper, &StringWrapper::Get, nullptr); EXPECT_EQ(wrapper.value_, accessor.Get(&error)); const 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, 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, 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 string default_value = "default value"; CustomWriteOnlyAccessor<StringWrapper, string> accessor( &wrapper, &StringWrapper::Set, nullptr, &default_value); wrapper.value_ = "can't read this"; EXPECT_EQ(string(), accessor.Get(&error)); EXPECT_TRUE(error.IsFailure()); EXPECT_EQ(Error::kPermissionDenied, error.type()); } { // Test writing. Error error; const string default_value = "default value"; const string expected_string = "what"; CustomWriteOnlyAccessor<StringWrapper, 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 string default_value = "default value"; CustomWriteOnlyAccessor<StringWrapper, 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, string> accessor( &wrapper, &StringWrapper::Set, &StringWrapper::Clear, nullptr); wrapper.value_ = "can't read this"; EXPECT_EQ(string(), accessor.Get(&error)); EXPECT_TRUE(error.IsFailure()); EXPECT_EQ(Error::kPermissionDenied, error.type()); } { // Test writing. Error error; const string expected_string = "what"; CustomWriteOnlyAccessor<StringWrapper, 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, 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, string> accessor( &wrapper, &StringWrapper::ConstGet); const 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 string& key, Error* /*error*/) { value_.erase(key); } string Get(const string& key, Error* /*error*/) { EXPECT_TRUE(ContainsKey(value_, key)); return value_[key]; } bool Set(const string& key, const string& value, Error* /*error*/) { if (value_[key] == value) { return false; } value_[key] = value; return true; } 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; 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, 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