1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chromeos/dbus/shill_client_unittest_base.h"
6
7#include "base/bind.h"
8#include "base/json/json_writer.h"
9#include "base/values.h"
10#include "chromeos/network/shill_property_util.h"
11#include "dbus/message.h"
12#include "dbus/object_path.h"
13#include "dbus/values_util.h"
14#include "testing/gmock/include/gmock/gmock.h"
15#include "testing/gtest/include/gtest/gtest.h"
16#include "third_party/cros_system_api/dbus/service_constants.h"
17
18using ::testing::_;
19using ::testing::Invoke;
20using ::testing::Return;
21
22namespace chromeos {
23
24namespace {
25
26// Pops a string-to-string dictionary from the reader.
27base::DictionaryValue* PopStringToStringDictionary(
28    dbus::MessageReader* reader) {
29  dbus::MessageReader array_reader(NULL);
30  if (!reader->PopArray(&array_reader))
31    return NULL;
32  scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
33  while (array_reader.HasMoreData()) {
34    dbus::MessageReader entry_reader(NULL);
35    std::string key;
36    std::string value;
37    if (!array_reader.PopDictEntry(&entry_reader) ||
38        !entry_reader.PopString(&key) ||
39        !entry_reader.PopString(&value))
40      return NULL;
41    result->SetWithoutPathExpansion(key, base::Value::CreateStringValue(value));
42  }
43  return result.release();
44}
45
46}  // namespace
47
48ValueMatcher::ValueMatcher(const base::Value& value)
49  : expected_value_(value.DeepCopy()) {}
50
51bool ValueMatcher::MatchAndExplain(const base::Value& value,
52                             MatchResultListener* listener) const {
53  return expected_value_->Equals(&value);
54}
55
56void ValueMatcher::DescribeTo(::std::ostream* os) const {
57  std::string expected_value_str;
58  base::JSONWriter::WriteWithOptions(expected_value_.get(),
59                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
60                                     &expected_value_str);
61  *os << "value equals " << expected_value_str;
62}
63
64void ValueMatcher::DescribeNegationTo(::std::ostream* os) const {
65  std::string expected_value_str;
66  base::JSONWriter::WriteWithOptions(expected_value_.get(),
67                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
68                                     &expected_value_str);
69  *os << "value does not equal " << expected_value_str;
70}
71
72
73ShillClientUnittestBase::MockClosure::MockClosure() {}
74
75ShillClientUnittestBase::MockClosure::~MockClosure() {}
76
77base::Closure ShillClientUnittestBase::MockClosure::GetCallback() {
78  return base::Bind(&MockClosure::Run, base::Unretained(this));
79}
80
81
82ShillClientUnittestBase::MockListValueCallback::MockListValueCallback() {}
83
84ShillClientUnittestBase::MockListValueCallback::~MockListValueCallback() {}
85
86ShillClientHelper::ListValueCallback
87ShillClientUnittestBase::MockListValueCallback::GetCallback() {
88  return base::Bind(&MockListValueCallback::Run, base::Unretained(this));
89}
90
91
92ShillClientUnittestBase::MockErrorCallback::MockErrorCallback() {}
93
94ShillClientUnittestBase::MockErrorCallback::~MockErrorCallback() {}
95
96ShillClientUnittestBase::MockPropertyChangeObserver::
97  MockPropertyChangeObserver() {}
98
99ShillClientUnittestBase::MockPropertyChangeObserver::
100  ~MockPropertyChangeObserver() {}
101
102ShillClientHelper::ErrorCallback
103ShillClientUnittestBase::MockErrorCallback::GetCallback() {
104  return base::Bind(&MockErrorCallback::Run, base::Unretained(this));
105}
106
107
108ShillClientUnittestBase::ShillClientUnittestBase(
109    const std::string& interface_name,
110    const dbus::ObjectPath& object_path)
111    : interface_name_(interface_name),
112      object_path_(object_path),
113      response_(NULL) {
114}
115
116ShillClientUnittestBase::~ShillClientUnittestBase() {
117}
118
119void ShillClientUnittestBase::SetUp() {
120  // Create a mock bus.
121  dbus::Bus::Options options;
122  options.bus_type = dbus::Bus::SYSTEM;
123  mock_bus_ = new dbus::MockBus(options);
124
125  // Create a mock proxy.
126  mock_proxy_ = new dbus::MockObjectProxy(
127      mock_bus_.get(),
128      shill::kFlimflamServiceName,
129      object_path_);
130
131  // Set an expectation so mock_proxy's CallMethod() will use OnCallMethod()
132  // to return responses.
133  EXPECT_CALL(*mock_proxy_.get(), CallMethod(_, _, _))
134      .WillRepeatedly(Invoke(this, &ShillClientUnittestBase::OnCallMethod));
135
136  // Set an expectation so mock_proxy's CallMethodWithErrorCallback() will use
137  // OnCallMethodWithErrorCallback() to return responses.
138  EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _))
139      .WillRepeatedly(Invoke(
140           this, &ShillClientUnittestBase::OnCallMethodWithErrorCallback));
141
142  // Set an expectation so mock_proxy's ConnectToSignal() will use
143  // OnConnectToSignal() to run the callback.
144  EXPECT_CALL(
145      *mock_proxy_.get(),
146      ConnectToSignal(interface_name_, shill::kMonitorPropertyChanged, _, _))
147      .WillRepeatedly(
148           Invoke(this, &ShillClientUnittestBase::OnConnectToSignal));
149
150  // Set an expectation so mock_bus's GetObjectProxy() for the given
151  // service name and the object path will return mock_proxy_.
152  EXPECT_CALL(*mock_bus_.get(),
153              GetObjectProxy(shill::kFlimflamServiceName, object_path_))
154      .WillOnce(Return(mock_proxy_.get()));
155
156  // Set an expectation so mock_bus's GetDBusTaskRunner will return the current
157  // task runner.
158  EXPECT_CALL(*mock_bus_.get(), GetDBusTaskRunner())
159      .WillRepeatedly(Return(message_loop_.message_loop_proxy()));
160
161  // ShutdownAndBlock() will be called in TearDown().
162  EXPECT_CALL(*mock_bus_.get(), ShutdownAndBlock()).WillOnce(Return());
163}
164
165void ShillClientUnittestBase::TearDown() {
166  mock_bus_->ShutdownAndBlock();
167}
168
169void ShillClientUnittestBase::PrepareForMethodCall(
170    const std::string& method_name,
171    const ArgumentCheckCallback& argument_checker,
172    dbus::Response* response) {
173  expected_method_name_ = method_name;
174  argument_checker_ = argument_checker;
175  response_ = response;
176}
177
178void ShillClientUnittestBase::SendPropertyChangedSignal(
179    dbus::Signal* signal) {
180  ASSERT_FALSE(property_changed_handler_.is_null());
181  property_changed_handler_.Run(signal);
182}
183
184// static
185void ShillClientUnittestBase::ExpectPropertyChanged(
186    const std::string& expected_name,
187    const base::Value* expected_value,
188    const std::string& name,
189    const base::Value& value) {
190  EXPECT_EQ(expected_name, name);
191  EXPECT_TRUE(expected_value->Equals(&value));
192}
193
194// static
195void ShillClientUnittestBase::ExpectNoArgument(dbus::MessageReader* reader) {
196  EXPECT_FALSE(reader->HasMoreData());
197}
198
199// static
200void ShillClientUnittestBase::ExpectStringArgument(
201    const std::string& expected_string,
202    dbus::MessageReader* reader) {
203  std::string str;
204  ASSERT_TRUE(reader->PopString(&str));
205  EXPECT_EQ(expected_string, str);
206  EXPECT_FALSE(reader->HasMoreData());
207}
208
209// static
210void ShillClientUnittestBase::ExpectArrayOfStringsArgument(
211    const std::vector<std::string>& expected_strings,
212    dbus::MessageReader* reader) {
213  std::vector<std::string> strs;
214  ASSERT_TRUE(reader->PopArrayOfStrings(&strs));
215  EXPECT_EQ(expected_strings, strs);
216  EXPECT_FALSE(reader->HasMoreData());
217}
218
219// static
220void ShillClientUnittestBase::ExpectValueArgument(
221    const base::Value* expected_value,
222    dbus::MessageReader* reader) {
223  scoped_ptr<base::Value> value(dbus::PopDataAsValue(reader));
224  ASSERT_TRUE(value.get());
225  EXPECT_TRUE(value->Equals(expected_value));
226  EXPECT_FALSE(reader->HasMoreData());
227}
228
229// static
230void ShillClientUnittestBase::ExpectStringAndValueArguments(
231    const std::string& expected_string,
232    const base::Value* expected_value,
233    dbus::MessageReader* reader) {
234  std::string str;
235  ASSERT_TRUE(reader->PopString(&str));
236  EXPECT_EQ(expected_string, str);
237  scoped_ptr<base::Value> value(dbus::PopDataAsValue(reader));
238  ASSERT_TRUE(value.get());
239  EXPECT_TRUE(value->Equals(expected_value));
240  EXPECT_FALSE(reader->HasMoreData());
241}
242
243// static
244void ShillClientUnittestBase::ExpectDictionaryValueArgument(
245    const base::DictionaryValue* expected_dictionary,
246    dbus::MessageReader* reader) {
247  dbus::MessageReader array_reader(NULL);
248  ASSERT_TRUE(reader->PopArray(&array_reader));
249  while (array_reader.HasMoreData()) {
250    dbus::MessageReader entry_reader(NULL);
251    ASSERT_TRUE(array_reader.PopDictEntry(&entry_reader));
252    std::string key;
253    ASSERT_TRUE(entry_reader.PopString(&key));
254    dbus::MessageReader variant_reader(NULL);
255    ASSERT_TRUE(entry_reader.PopVariant(&variant_reader));
256    scoped_ptr<base::Value> value;
257    // Variants in the dictionary can be basic types or string-to-string
258    // dictinoary.
259    switch (variant_reader.GetDataType()) {
260      case dbus::Message::ARRAY:
261        value.reset(PopStringToStringDictionary(&variant_reader));
262        break;
263      case dbus::Message::BOOL:
264      case dbus::Message::INT32:
265      case dbus::Message::STRING:
266        value.reset(dbus::PopDataAsValue(&variant_reader));
267        break;
268      default:
269        NOTREACHED();
270    }
271    ASSERT_TRUE(value.get());
272    const base::Value* expected_value = NULL;
273    EXPECT_TRUE(expected_dictionary->GetWithoutPathExpansion(key,
274                                                             &expected_value));
275    EXPECT_TRUE(value->Equals(expected_value));
276  }
277}
278
279// static
280base::DictionaryValue*
281ShillClientUnittestBase::CreateExampleServiceProperties() {
282  base::DictionaryValue* properties = new base::DictionaryValue;
283  properties->SetWithoutPathExpansion(
284      shill::kGuidProperty,
285      base::Value::CreateStringValue("00000000-0000-0000-0000-000000000000"));
286  properties->SetWithoutPathExpansion(
287      shill::kModeProperty,
288      base::Value::CreateStringValue(shill::kModeManaged));
289  properties->SetWithoutPathExpansion(
290      shill::kTypeProperty,
291      base::Value::CreateStringValue(shill::kTypeWifi));
292  shill_property_util::SetSSID("testssid", properties);
293  properties->SetWithoutPathExpansion(
294      shill::kSecurityProperty,
295      base::Value::CreateStringValue(shill::kSecurityPsk));
296  return properties;
297}
298
299
300// static
301void ShillClientUnittestBase::ExpectNoResultValue(
302    DBusMethodCallStatus call_status) {
303  EXPECT_EQ(DBUS_METHOD_CALL_SUCCESS, call_status);
304}
305
306// static
307void ShillClientUnittestBase::ExpectObjectPathResult(
308    const dbus::ObjectPath& expected_result,
309    DBusMethodCallStatus call_status,
310    const dbus::ObjectPath& result) {
311  EXPECT_EQ(DBUS_METHOD_CALL_SUCCESS, call_status);
312  EXPECT_EQ(expected_result, result);
313}
314
315// static
316void ShillClientUnittestBase::ExpectObjectPathResultWithoutStatus(
317    const dbus::ObjectPath& expected_result,
318    const dbus::ObjectPath& result) {
319  EXPECT_EQ(expected_result, result);
320}
321
322// static
323void ShillClientUnittestBase::ExpectBoolResultWithoutStatus(
324    bool expected_result,
325    bool result) {
326  EXPECT_EQ(expected_result, result);
327}
328
329// static
330void ShillClientUnittestBase::ExpectStringResultWithoutStatus(
331    const std::string& expected_result,
332    const std::string& result) {
333  EXPECT_EQ(expected_result, result);
334}
335
336// static
337void ShillClientUnittestBase::ExpectDictionaryValueResultWithoutStatus(
338    const base::DictionaryValue* expected_result,
339    const base::DictionaryValue& result) {
340  std::string expected_result_string;
341  base::JSONWriter::Write(expected_result, &expected_result_string);
342  std::string result_string;
343  base::JSONWriter::Write(&result, &result_string);
344  EXPECT_EQ(expected_result_string, result_string);
345}
346
347// static
348void ShillClientUnittestBase::ExpectDictionaryValueResult(
349    const base::DictionaryValue* expected_result,
350    DBusMethodCallStatus call_status,
351    const base::DictionaryValue& result) {
352  EXPECT_EQ(DBUS_METHOD_CALL_SUCCESS, call_status);
353  ExpectDictionaryValueResultWithoutStatus(expected_result, result);
354}
355
356void ShillClientUnittestBase::OnConnectToSignal(
357    const std::string& interface_name,
358    const std::string& signal_name,
359    const dbus::ObjectProxy::SignalCallback& signal_callback,
360    const dbus::ObjectProxy::OnConnectedCallback& on_connected_callback) {
361  property_changed_handler_ = signal_callback;
362  const bool success = true;
363  message_loop_.PostTask(FROM_HERE,
364                         base::Bind(on_connected_callback,
365                                    interface_name,
366                                    signal_name,
367                                    success));
368}
369
370void ShillClientUnittestBase::OnCallMethod(
371    dbus::MethodCall* method_call,
372    int timeout_ms,
373    const dbus::ObjectProxy::ResponseCallback& response_callback) {
374  EXPECT_EQ(interface_name_, method_call->GetInterface());
375  EXPECT_EQ(expected_method_name_, method_call->GetMember());
376  dbus::MessageReader reader(method_call);
377  argument_checker_.Run(&reader);
378  message_loop_.PostTask(FROM_HERE,
379                         base::Bind(response_callback, response_));
380}
381
382void ShillClientUnittestBase::OnCallMethodWithErrorCallback(
383    dbus::MethodCall* method_call,
384    int timeout_ms,
385    const dbus::ObjectProxy::ResponseCallback& response_callback,
386    const dbus::ObjectProxy::ErrorCallback& error_callback) {
387  OnCallMethod(method_call, timeout_ms, response_callback);
388}
389
390}  // namespace chromeos
391