// Copyright (c) 2012 The Chromium 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 "chromeos/dbus/shill_client_unittest_base.h"
#include "base/bind.h"
#include "base/json/json_writer.h"
#include "base/values.h"
#include "chromeos/network/shill_property_util.h"
#include "dbus/message.h"
#include "dbus/object_path.h"
#include "dbus/values_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
using ::testing::_;
using ::testing::Invoke;
using ::testing::Return;
namespace chromeos {
namespace {
// Pops a string-to-string dictionary from the reader.
base::DictionaryValue* PopStringToStringDictionary(
dbus::MessageReader* reader) {
dbus::MessageReader array_reader(NULL);
if (!reader->PopArray(&array_reader))
return NULL;
scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
while (array_reader.HasMoreData()) {
dbus::MessageReader entry_reader(NULL);
std::string key;
std::string value;
if (!array_reader.PopDictEntry(&entry_reader) ||
!entry_reader.PopString(&key) ||
!entry_reader.PopString(&value))
return NULL;
result->SetWithoutPathExpansion(key, new base::StringValue(value));
}
return result.release();
}
} // namespace
ValueMatcher::ValueMatcher(const base::Value& value)
: expected_value_(value.DeepCopy()) {}
bool ValueMatcher::MatchAndExplain(const base::Value& value,
MatchResultListener* listener) const {
return expected_value_->Equals(&value);
}
void ValueMatcher::DescribeTo(::std::ostream* os) const {
std::string expected_value_str;
base::JSONWriter::WriteWithOptions(expected_value_.get(),
base::JSONWriter::OPTIONS_PRETTY_PRINT,
&expected_value_str);
*os << "value equals " << expected_value_str;
}
void ValueMatcher::DescribeNegationTo(::std::ostream* os) const {
std::string expected_value_str;
base::JSONWriter::WriteWithOptions(expected_value_.get(),
base::JSONWriter::OPTIONS_PRETTY_PRINT,
&expected_value_str);
*os << "value does not equal " << expected_value_str;
}
ShillClientUnittestBase::MockClosure::MockClosure() {}
ShillClientUnittestBase::MockClosure::~MockClosure() {}
base::Closure ShillClientUnittestBase::MockClosure::GetCallback() {
return base::Bind(&MockClosure::Run, base::Unretained(this));
}
ShillClientUnittestBase::MockListValueCallback::MockListValueCallback() {}
ShillClientUnittestBase::MockListValueCallback::~MockListValueCallback() {}
ShillClientHelper::ListValueCallback
ShillClientUnittestBase::MockListValueCallback::GetCallback() {
return base::Bind(&MockListValueCallback::Run, base::Unretained(this));
}
ShillClientUnittestBase::MockErrorCallback::MockErrorCallback() {}
ShillClientUnittestBase::MockErrorCallback::~MockErrorCallback() {}
ShillClientUnittestBase::MockPropertyChangeObserver::
MockPropertyChangeObserver() {}
ShillClientUnittestBase::MockPropertyChangeObserver::
~MockPropertyChangeObserver() {}
ShillClientHelper::ErrorCallback
ShillClientUnittestBase::MockErrorCallback::GetCallback() {
return base::Bind(&MockErrorCallback::Run, base::Unretained(this));
}
ShillClientUnittestBase::ShillClientUnittestBase(
const std::string& interface_name,
const dbus::ObjectPath& object_path)
: interface_name_(interface_name),
object_path_(object_path),
response_(NULL) {
}
ShillClientUnittestBase::~ShillClientUnittestBase() {
}
void ShillClientUnittestBase::SetUp() {
// Create a mock bus.
dbus::Bus::Options options;
options.bus_type = dbus::Bus::SYSTEM;
mock_bus_ = new dbus::MockBus(options);
// Create a mock proxy.
mock_proxy_ = new dbus::MockObjectProxy(
mock_bus_.get(),
shill::kFlimflamServiceName,
object_path_);
// Set an expectation so mock_proxy's CallMethod() will use OnCallMethod()
// to return responses.
EXPECT_CALL(*mock_proxy_.get(), CallMethod(_, _, _))
.WillRepeatedly(Invoke(this, &ShillClientUnittestBase::OnCallMethod));
// Set an expectation so mock_proxy's CallMethodWithErrorCallback() will use
// OnCallMethodWithErrorCallback() to return responses.
EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _))
.WillRepeatedly(Invoke(
this, &ShillClientUnittestBase::OnCallMethodWithErrorCallback));
// Set an expectation so mock_proxy's ConnectToSignal() will use
// OnConnectToSignal() to run the callback.
EXPECT_CALL(
*mock_proxy_.get(),
ConnectToSignal(interface_name_, shill::kMonitorPropertyChanged, _, _))
.WillRepeatedly(
Invoke(this, &ShillClientUnittestBase::OnConnectToSignal));
// Set an expectation so mock_bus's GetObjectProxy() for the given
// service name and the object path will return mock_proxy_.
EXPECT_CALL(*mock_bus_.get(),
GetObjectProxy(shill::kFlimflamServiceName, object_path_))
.WillOnce(Return(mock_proxy_.get()));
// Set an expectation so mock_bus's GetDBusTaskRunner will return the current
// task runner.
EXPECT_CALL(*mock_bus_.get(), GetDBusTaskRunner())
.WillRepeatedly(Return(message_loop_.message_loop_proxy().get()));
// ShutdownAndBlock() will be called in TearDown().
EXPECT_CALL(*mock_bus_.get(), ShutdownAndBlock()).WillOnce(Return());
}
void ShillClientUnittestBase::TearDown() {
mock_bus_->ShutdownAndBlock();
}
void ShillClientUnittestBase::PrepareForMethodCall(
const std::string& method_name,
const ArgumentCheckCallback& argument_checker,
dbus::Response* response) {
expected_method_name_ = method_name;
argument_checker_ = argument_checker;
response_ = response;
}
void ShillClientUnittestBase::SendPropertyChangedSignal(
dbus::Signal* signal) {
ASSERT_FALSE(property_changed_handler_.is_null());
property_changed_handler_.Run(signal);
}
// static
void ShillClientUnittestBase::ExpectPropertyChanged(
const std::string& expected_name,
const base::Value* expected_value,
const std::string& name,
const base::Value& value) {
EXPECT_EQ(expected_name, name);
EXPECT_TRUE(expected_value->Equals(&value));
}
// static
void ShillClientUnittestBase::ExpectNoArgument(dbus::MessageReader* reader) {
EXPECT_FALSE(reader->HasMoreData());
}
// static
void ShillClientUnittestBase::ExpectStringArgument(
const std::string& expected_string,
dbus::MessageReader* reader) {
std::string str;
ASSERT_TRUE(reader->PopString(&str));
EXPECT_EQ(expected_string, str);
EXPECT_FALSE(reader->HasMoreData());
}
// static
void ShillClientUnittestBase::ExpectArrayOfStringsArgument(
const std::vector<std::string>& expected_strings,
dbus::MessageReader* reader) {
std::vector<std::string> strs;
ASSERT_TRUE(reader->PopArrayOfStrings(&strs));
EXPECT_EQ(expected_strings, strs);
EXPECT_FALSE(reader->HasMoreData());
}
// static
void ShillClientUnittestBase::ExpectValueArgument(
const base::Value* expected_value,
dbus::MessageReader* reader) {
scoped_ptr<base::Value> value(dbus::PopDataAsValue(reader));
ASSERT_TRUE(value.get());
EXPECT_TRUE(value->Equals(expected_value));
EXPECT_FALSE(reader->HasMoreData());
}
// static
void ShillClientUnittestBase::ExpectStringAndValueArguments(
const std::string& expected_string,
const base::Value* expected_value,
dbus::MessageReader* reader) {
std::string str;
ASSERT_TRUE(reader->PopString(&str));
EXPECT_EQ(expected_string, str);
scoped_ptr<base::Value> value(dbus::PopDataAsValue(reader));
ASSERT_TRUE(value.get());
EXPECT_TRUE(value->Equals(expected_value));
EXPECT_FALSE(reader->HasMoreData());
}
// static
void ShillClientUnittestBase::ExpectDictionaryValueArgument(
const base::DictionaryValue* expected_dictionary,
dbus::MessageReader* reader) {
dbus::MessageReader array_reader(NULL);
ASSERT_TRUE(reader->PopArray(&array_reader));
while (array_reader.HasMoreData()) {
dbus::MessageReader entry_reader(NULL);
ASSERT_TRUE(array_reader.PopDictEntry(&entry_reader));
std::string key;
ASSERT_TRUE(entry_reader.PopString(&key));
dbus::MessageReader variant_reader(NULL);
ASSERT_TRUE(entry_reader.PopVariant(&variant_reader));
scoped_ptr<base::Value> value;
// Variants in the dictionary can be basic types or string-to-string
// dictinoary.
switch (variant_reader.GetDataType()) {
case dbus::Message::ARRAY:
value.reset(PopStringToStringDictionary(&variant_reader));
break;
case dbus::Message::BOOL:
case dbus::Message::INT32:
case dbus::Message::STRING:
value.reset(dbus::PopDataAsValue(&variant_reader));
break;
default:
NOTREACHED();
}
ASSERT_TRUE(value.get());
const base::Value* expected_value = NULL;
EXPECT_TRUE(expected_dictionary->GetWithoutPathExpansion(key,
&expected_value));
EXPECT_TRUE(value->Equals(expected_value));
}
}
// static
base::DictionaryValue*
ShillClientUnittestBase::CreateExampleServiceProperties() {
base::DictionaryValue* properties = new base::DictionaryValue;
properties->SetWithoutPathExpansion(
shill::kGuidProperty,
new base::StringValue("00000000-0000-0000-0000-000000000000"));
properties->SetWithoutPathExpansion(
shill::kModeProperty, new base::StringValue(shill::kModeManaged));
properties->SetWithoutPathExpansion(shill::kTypeProperty,
new base::StringValue(shill::kTypeWifi));
shill_property_util::SetSSID("testssid", properties);
properties->SetWithoutPathExpansion(
shill::kSecurityProperty, new base::StringValue(shill::kSecurityPsk));
return properties;
}
// static
void ShillClientUnittestBase::ExpectNoResultValue(
DBusMethodCallStatus call_status) {
EXPECT_EQ(DBUS_METHOD_CALL_SUCCESS, call_status);
}
// static
void ShillClientUnittestBase::ExpectObjectPathResult(
const dbus::ObjectPath& expected_result,
DBusMethodCallStatus call_status,
const dbus::ObjectPath& result) {
EXPECT_EQ(DBUS_METHOD_CALL_SUCCESS, call_status);
EXPECT_EQ(expected_result, result);
}
// static
void ShillClientUnittestBase::ExpectObjectPathResultWithoutStatus(
const dbus::ObjectPath& expected_result,
const dbus::ObjectPath& result) {
EXPECT_EQ(expected_result, result);
}
// static
void ShillClientUnittestBase::ExpectBoolResultWithoutStatus(
bool expected_result,
bool result) {
EXPECT_EQ(expected_result, result);
}
// static
void ShillClientUnittestBase::ExpectStringResultWithoutStatus(
const std::string& expected_result,
const std::string& result) {
EXPECT_EQ(expected_result, result);
}
// static
void ShillClientUnittestBase::ExpectDictionaryValueResultWithoutStatus(
const base::DictionaryValue* expected_result,
const base::DictionaryValue& result) {
std::string expected_result_string;
base::JSONWriter::Write(expected_result, &expected_result_string);
std::string result_string;
base::JSONWriter::Write(&result, &result_string);
EXPECT_EQ(expected_result_string, result_string);
}
// static
void ShillClientUnittestBase::ExpectDictionaryValueResult(
const base::DictionaryValue* expected_result,
DBusMethodCallStatus call_status,
const base::DictionaryValue& result) {
EXPECT_EQ(DBUS_METHOD_CALL_SUCCESS, call_status);
ExpectDictionaryValueResultWithoutStatus(expected_result, result);
}
void ShillClientUnittestBase::OnConnectToSignal(
const std::string& interface_name,
const std::string& signal_name,
const dbus::ObjectProxy::SignalCallback& signal_callback,
const dbus::ObjectProxy::OnConnectedCallback& on_connected_callback) {
property_changed_handler_ = signal_callback;
const bool success = true;
message_loop_.PostTask(FROM_HERE,
base::Bind(on_connected_callback,
interface_name,
signal_name,
success));
}
void ShillClientUnittestBase::OnCallMethod(
dbus::MethodCall* method_call,
int timeout_ms,
const dbus::ObjectProxy::ResponseCallback& response_callback) {
EXPECT_EQ(interface_name_, method_call->GetInterface());
EXPECT_EQ(expected_method_name_, method_call->GetMember());
dbus::MessageReader reader(method_call);
argument_checker_.Run(&reader);
message_loop_.PostTask(FROM_HERE,
base::Bind(response_callback, response_));
}
void ShillClientUnittestBase::OnCallMethodWithErrorCallback(
dbus::MethodCall* method_call,
int timeout_ms,
const dbus::ObjectProxy::ResponseCallback& response_callback,
const dbus::ObjectProxy::ErrorCallback& error_callback) {
OnCallMethod(method_call, timeout_ms, response_callback);
}
} // namespace chromeos