//
// 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