1// Copyright 2015 The Chromium OS 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-bindings/proxy_generator.h"
6
7#include <string>
8#include <vector>
9
10#include <base/files/file_path.h>
11#include <base/files/file_util.h>
12#include <base/files/scoped_temp_dir.h>
13#include <gtest/gtest.h>
14
15#include "chromeos-dbus-bindings/interface.h"
16#include "chromeos-dbus-bindings/test_utils.h"
17
18using std::string;
19using std::vector;
20using testing::Test;
21
22namespace chromeos_dbus_bindings {
23
24namespace {
25
26const char kDBusTypeArryOfObjects[] = "ao";
27const char kDBusTypeArryOfStrings[] = "as";
28const char kDBusTypeBool[] = "b";
29const char kDBusTypeByte[] = "y";
30const char kDBusTypeInt32[] = "i";
31const char kDBusTypeInt64[] = "x";
32const char kDBusTypeString[] = "s";
33
34const char kExpectedContent[] = R"literal_string(
35#include <string>
36#include <vector>
37
38#include <base/callback_forward.h>
39#include <base/logging.h>
40#include <base/macros.h>
41#include <brillo/any.h>
42#include <brillo/errors/error.h>
43#include <brillo/variant_dictionary.h>
44#include <gmock/gmock.h>
45
46#include "proxies.h"
47
48namespace org {
49namespace chromium {
50
51// Mock object for TestInterfaceProxyInterface.
52class TestInterfaceProxyMock : public TestInterfaceProxyInterface {
53 public:
54  TestInterfaceProxyMock() = default;
55
56  MOCK_METHOD5(Elements,
57               bool(const std::string& /*in_space_walk*/,
58                    const std::vector<dbus::ObjectPath>& /*in_ramblin_man*/,
59                    std::string*,
60                    brillo::ErrorPtr* /*error*/,
61                    int /*timeout_ms*/));
62  MOCK_METHOD5(ElementsAsync,
63               void(const std::string& /*in_space_walk*/,
64                    const std::vector<dbus::ObjectPath>& /*in_ramblin_man*/,
65                    const base::Callback<void(const std::string&)>& /*success_callback*/,
66                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
67                    int /*timeout_ms*/));
68  MOCK_METHOD3(ReturnToPatagonia,
69               bool(int64_t*,
70                    brillo::ErrorPtr* /*error*/,
71                    int /*timeout_ms*/));
72  MOCK_METHOD3(ReturnToPatagoniaAsync,
73               void(const base::Callback<void(int64_t)>& /*success_callback*/,
74                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
75                    int /*timeout_ms*/));
76  MOCK_METHOD3(NiceWeatherForDucks,
77               bool(bool,
78                    brillo::ErrorPtr* /*error*/,
79                    int /*timeout_ms*/));
80  MOCK_METHOD4(NiceWeatherForDucksAsync,
81               void(bool,
82                    const base::Callback<void()>& /*success_callback*/,
83                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
84                    int /*timeout_ms*/));
85  MOCK_METHOD2(ExperimentNumberSix,
86               bool(brillo::ErrorPtr* /*error*/,
87                    int /*timeout_ms*/));
88  MOCK_METHOD3(ExperimentNumberSixAsync,
89               void(const base::Callback<void()>& /*success_callback*/,
90                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
91                    int /*timeout_ms*/));
92  bool AllTheWayUpToEleven(bool /*in_arg1*/,
93                           bool /*in_arg2*/,
94                           bool /*in_arg3*/,
95                           bool /*in_arg4*/,
96                           bool /*in_arg5*/,
97                           bool /*in_arg6*/,
98                           bool /*in_arg7*/,
99                           bool /*in_arg8*/,
100                           bool* /*out_arg9*/,
101                           brillo::ErrorPtr* /*error*/,
102                           int /*timeout_ms*/) override {
103    LOG(WARNING) << "AllTheWayUpToEleven(): gmock can't handle methods with 11 arguments. You can override this method in a subclass if you need to.";
104    return false;
105  }
106  void AllTheWayUpToElevenAsync(bool /*in_arg1*/,
107                                bool /*in_arg2*/,
108                                bool /*in_arg3*/,
109                                bool /*in_arg4*/,
110                                bool /*in_arg5*/,
111                                bool /*in_arg6*/,
112                                bool /*in_arg7*/,
113                                bool /*in_arg8*/,
114                                const base::Callback<void(bool /*arg9*/)>& /*success_callback*/,
115                                const base::Callback<void(brillo::Error*)>& /*error_callback*/,
116                                int /*timeout_ms*/) override {
117    LOG(WARNING) << "AllTheWayUpToElevenAsync(): gmock can't handle methods with 11 arguments. You can override this method in a subclass if you need to.";
118  }
119  MOCK_METHOD2(RegisterCloserSignalHandler,
120               void(const base::Closure& /*signal_callback*/,
121                    dbus::ObjectProxy::OnConnectedCallback /*on_connected_callback*/));
122  MOCK_METHOD2(RegisterTheCurseOfKaZarSignalHandler,
123               void(const base::Callback<void(const std::vector<std::string>&,
124                                              uint8_t)>& /*signal_callback*/,
125                    dbus::ObjectProxy::OnConnectedCallback /*on_connected_callback*/));
126  MOCK_CONST_METHOD0(GetObjectPath, const dbus::ObjectPath&());
127
128 private:
129  DISALLOW_COPY_AND_ASSIGN(TestInterfaceProxyMock);
130};
131}  // namespace chromium
132}  // namespace org
133
134namespace org {
135namespace chromium {
136
137// Mock object for TestInterface2ProxyInterface.
138class TestInterface2ProxyMock : public TestInterface2ProxyInterface {
139 public:
140  TestInterface2ProxyMock() = default;
141
142  MOCK_METHOD4(GetPersonInfo,
143               bool(std::string* /*out_name*/,
144                    int32_t* /*out_age*/,
145                    brillo::ErrorPtr* /*error*/,
146                    int /*timeout_ms*/));
147  MOCK_METHOD3(GetPersonInfoAsync,
148               void(const base::Callback<void(const std::string& /*name*/, int32_t /*age*/)>& /*success_callback*/,
149                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
150                    int /*timeout_ms*/));
151  MOCK_CONST_METHOD0(data, const std::string&());
152  MOCK_CONST_METHOD0(name, const std::string&());
153  MOCK_METHOD2(set_name, void(const std::string&, const base::Callback<bool>&));
154  MOCK_CONST_METHOD0(GetObjectPath, const dbus::ObjectPath&());
155  MOCK_METHOD1(SetPropertyChangedCallback,
156               void(const base::Callback<void(TestInterface2ProxyInterface*, const std::string&)>&));
157
158 private:
159  DISALLOW_COPY_AND_ASSIGN(TestInterface2ProxyMock);
160};
161}  // namespace chromium
162}  // namespace org
163)literal_string";
164
165}  // namespace
166
167class ProxyGeneratorMockTest : public Test {
168 public:
169  void SetUp() override {
170    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
171  }
172
173 protected:
174  base::FilePath CreateInputFile(const string& contents) {
175    base::FilePath path;
176    EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &path));
177    int written = base::WriteFile(path, contents.c_str(), contents.size());
178    EXPECT_EQ(contents.size(), static_cast<size_t>(written));
179    return path;
180  }
181
182  base::ScopedTempDir temp_dir_;
183};
184
185TEST_F(ProxyGeneratorMockTest, GenerateMocks) {
186  Interface interface;
187  interface.name = "org.chromium.TestInterface";
188  interface.path = "/org/chromium/Test";
189  interface.methods.emplace_back(
190      "Elements",
191      vector<Interface::Argument>{
192          {"space_walk", kDBusTypeString},
193          {"ramblin_man", kDBusTypeArryOfObjects}},
194      vector<Interface::Argument>{{"", kDBusTypeString}});
195  interface.methods.emplace_back(
196      "ReturnToPatagonia",
197      vector<Interface::Argument>{},
198      vector<Interface::Argument>{{"", kDBusTypeInt64}});
199  interface.methods.emplace_back(
200      "NiceWeatherForDucks",
201      vector<Interface::Argument>{{"", kDBusTypeBool}},
202      vector<Interface::Argument>{});
203  interface.methods.emplace_back("ExperimentNumberSix");
204  // gmock can't handle more than 10 args. The generated method will also
205  // include the timeout and error arguments in the synchronous case, and two
206  // callbacks and the timeout in the asynchronous case.
207  interface.methods.emplace_back(
208      "AllTheWayUpToEleven",
209      vector<Interface::Argument>{
210          {"arg1", kDBusTypeBool},
211          {"arg2", kDBusTypeBool},
212          {"arg3", kDBusTypeBool},
213          {"arg4", kDBusTypeBool},
214          {"arg5", kDBusTypeBool},
215          {"arg6", kDBusTypeBool},
216          {"arg7", kDBusTypeBool},
217          {"arg8", kDBusTypeBool}},
218      vector<Interface::Argument>{{"arg9", kDBusTypeBool}});
219  interface.signals.emplace_back("Closer");
220  interface.signals.emplace_back(
221      "TheCurseOfKaZar",
222      vector<Interface::Argument>{
223          {"", kDBusTypeArryOfStrings},
224          {"", kDBusTypeByte}});
225  interface.methods.back().doc_string = "Comment line1\nline2";
226  Interface interface2;
227  interface2.name = "org.chromium.TestInterface2";
228  interface2.methods.emplace_back(
229      "GetPersonInfo",
230      vector<Interface::Argument>{},
231      vector<Interface::Argument>{
232          {"name", kDBusTypeString},
233          {"age", kDBusTypeInt32}});
234  interface2.properties.emplace_back("Data", "s", "read");
235  interface2.properties.emplace_back("Name", "s", "readwrite");
236  vector<Interface> interfaces{interface, interface2};
237  base::FilePath output_path = temp_dir_.path().Append("output.h");
238  base::FilePath proxy_path = temp_dir_.path().Append("proxies.h");
239  ServiceConfig config;
240  config.object_manager.name = "ObjectManager";
241  EXPECT_TRUE(ProxyGenerator::GenerateMocks(config, interfaces, output_path,
242                                            proxy_path, false));
243  string contents;
244  EXPECT_TRUE(base::ReadFileToString(output_path, &contents));
245  // The header guards contain the (temporary) filename, so we search for
246  // the content we need within the string.
247  test_utils::EXPECT_TEXT_CONTAINED(kExpectedContent, contents);
248}
249
250}  // namespace chromeos_dbus_bindings
251