1 // Copyright 2014 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/adaptor_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
18 using std::string;
19 using std::vector;
20 using testing::Test;
21
22 namespace chromeos_dbus_bindings {
23
24 namespace {
25
26 const char kDBusTypeArryOfObjects[] = "ao";
27 const char kDBusTypeBool[] = "b";
28 const char kDBusTypeInt32[] = "i";
29 const char kDBusTypeInt64[] = "x";
30 const char kDBusTypeString[] = "s";
31
32 const char kPropertyAccessReadOnly[] = "read";
33 const char kPropertyAccessReadWrite[] = "readwrite";
34
35 const char kInterfaceName[] = "org.chromium.Test";
36 const char kInterfaceName2[] = "org.chromium.Test2";
37
38 const char kExpectedContent[] = R"literal_string(
39 #include <memory>
40 #include <string>
41 #include <tuple>
42 #include <vector>
43
44 #include <base/macros.h>
45 #include <dbus/object_path.h>
46 #include <brillo/any.h>
47 #include <brillo/dbus/dbus_object.h>
48 #include <brillo/dbus/exported_object_manager.h>
49 #include <brillo/variant_dictionary.h>
50
51 namespace org {
52 namespace chromium {
53
54 // Interface definition for org::chromium::Test.
55 class TestInterface {
56 public:
57 virtual ~TestInterface() = default;
58
59 virtual bool Kaneda(
60 brillo::ErrorPtr* error,
61 dbus::Message* message,
62 const std::string& in_iwata,
63 const std::vector<dbus::ObjectPath>& in_clarke,
64 std::string* out_3) = 0;
65 virtual bool Tetsuo(
66 brillo::ErrorPtr* error,
67 int32_t in_1,
68 int64_t* out_2) = 0;
69 virtual bool Kei(
70 brillo::ErrorPtr* error) = 0;
71 virtual bool Kiyoko(
72 brillo::ErrorPtr* error,
73 int64_t* out_akira,
74 std::string* out_2) = 0;
75 };
76
77 // Interface adaptor for org::chromium::Test.
78 class TestAdaptor {
79 public:
80 TestAdaptor(TestInterface* interface) : interface_(interface) {}
81
82 void RegisterWithDBusObject(brillo::dbus_utils::DBusObject* object) {
83 brillo::dbus_utils::DBusInterface* itf =
84 object->AddOrGetInterface("org.chromium.Test");
85
86 itf->AddSimpleMethodHandlerWithErrorAndMessage(
87 "Kaneda",
88 base::Unretained(interface_),
89 &TestInterface::Kaneda);
90 itf->AddSimpleMethodHandlerWithError(
91 "Tetsuo",
92 base::Unretained(interface_),
93 &TestInterface::Tetsuo);
94 itf->AddSimpleMethodHandlerWithError(
95 "Kei",
96 base::Unretained(interface_),
97 &TestInterface::Kei);
98 itf->AddSimpleMethodHandlerWithError(
99 "Kiyoko",
100 base::Unretained(interface_),
101 &TestInterface::Kiyoko);
102
103 signal_Update_ = itf->RegisterSignalOfType<SignalUpdateType>("Update");
104 signal_Mapping_ = itf->RegisterSignalOfType<SignalMappingType>("Mapping");
105
106 itf->AddProperty(CharacterNameName(), &character_name_);
107 write_property_.SetAccessMode(
108 brillo::dbus_utils::ExportedPropertyBase::Access::kReadWrite);
109 write_property_.SetValidator(
110 base::Bind(&TestAdaptor::ValidateWriteProperty,
111 base::Unretained(this)));
112 itf->AddProperty(WritePropertyName(), &write_property_);
113 }
114
115 void SendUpdateSignal() {
116 auto signal = signal_Update_.lock();
117 if (signal)
118 signal->Send();
119 }
120 void SendMappingSignal(
121 const std::string& in_key,
122 const std::vector<dbus::ObjectPath>& in_2) {
123 auto signal = signal_Mapping_.lock();
124 if (signal)
125 signal->Send(in_key, in_2);
126 }
127
128 static const char* CharacterNameName() { return "CharacterName"; }
129 std::string GetCharacterName() const {
130 return character_name_.GetValue().Get<std::string>();
131 }
132 void SetCharacterName(const std::string& character_name) {
133 character_name_.SetValue(character_name);
134 }
135
136 static const char* WritePropertyName() { return "WriteProperty"; }
137 std::string GetWriteProperty() const {
138 return write_property_.GetValue().Get<std::string>();
139 }
140 void SetWriteProperty(const std::string& write_property) {
141 write_property_.SetValue(write_property);
142 }
143 virtual bool ValidateWriteProperty(
144 brillo::ErrorPtr* /*error*/, const std::string& /*value*/) {
145 return true;
146 }
147
148 static dbus::ObjectPath GetObjectPath() {
149 return dbus::ObjectPath{"/org/chromium/Test"};
150 }
151
152 private:
153 using SignalUpdateType = brillo::dbus_utils::DBusSignal<>;
154 std::weak_ptr<SignalUpdateType> signal_Update_;
155
156 using SignalMappingType = brillo::dbus_utils::DBusSignal<
157 std::string /*key*/,
158 std::vector<dbus::ObjectPath>>;
159 std::weak_ptr<SignalMappingType> signal_Mapping_;
160
161 brillo::dbus_utils::ExportedProperty<std::string> character_name_;
162 brillo::dbus_utils::ExportedProperty<std::string> write_property_;
163
164 TestInterface* interface_; // Owned by container of this adapter.
165
166 DISALLOW_COPY_AND_ASSIGN(TestAdaptor);
167 };
168
169 } // namespace chromium
170 } // namespace org
171
172 namespace org {
173 namespace chromium {
174
175 // Interface definition for org::chromium::Test2.
176 class Test2Interface {
177 public:
178 virtual ~Test2Interface() = default;
179
180 virtual std::string Kaneda2(
181 const std::string& in_iwata) const = 0;
182 virtual void Tetsuo2(
183 std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<int64_t>> response,
184 int32_t in_1) = 0;
185 virtual void Kei2(
186 std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<bool>> response,
187 dbus::Message* message) = 0;
188 };
189
190 // Interface adaptor for org::chromium::Test2.
191 class Test2Adaptor {
192 public:
193 Test2Adaptor(Test2Interface* interface) : interface_(interface) {}
194
195 void RegisterWithDBusObject(brillo::dbus_utils::DBusObject* object) {
196 brillo::dbus_utils::DBusInterface* itf =
197 object->AddOrGetInterface("org.chromium.Test2");
198
199 itf->AddSimpleMethodHandler(
200 "Kaneda2",
201 base::Unretained(interface_),
202 &Test2Interface::Kaneda2);
203 itf->AddMethodHandler(
204 "Tetsuo2",
205 base::Unretained(interface_),
206 &Test2Interface::Tetsuo2);
207 itf->AddMethodHandlerWithMessage(
208 "Kei2",
209 base::Unretained(interface_),
210 &Test2Interface::Kei2);
211 }
212
213 private:
214 Test2Interface* interface_; // Owned by container of this adapter.
215
216 DISALLOW_COPY_AND_ASSIGN(Test2Adaptor);
217 };
218
219 } // namespace chromium
220 } // namespace org
221 )literal_string";
222
223 } // namespace
224 class AdaptorGeneratorTest : public Test {
225 public:
SetUp()226 void SetUp() override {
227 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
228 }
229
230 protected:
CreateInputFile(const string & contents)231 base::FilePath CreateInputFile(const string& contents) {
232 base::FilePath path;
233 EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &path));
234 int written = base::WriteFile(path, contents.c_str(), contents.size());
235 EXPECT_EQ(contents.size(), static_cast<size_t>(written));
236 return path;
237 }
238
239 base::ScopedTempDir temp_dir_;
240 };
241
TEST_F(AdaptorGeneratorTest,GenerateAdaptors)242 TEST_F(AdaptorGeneratorTest, GenerateAdaptors) {
243 Interface interface;
244 interface.name = kInterfaceName;
245 interface.path = "/org/chromium/Test";
246 interface.methods.emplace_back(
247 "Kaneda",
248 vector<Interface::Argument>{
249 {"iwata", kDBusTypeString},
250 {"clarke", kDBusTypeArryOfObjects}},
251 vector<Interface::Argument>{{"", kDBusTypeString}});
252 interface.methods.back().include_dbus_message = true;
253 interface.methods.emplace_back(
254 "Tetsuo",
255 vector<Interface::Argument>{{"", kDBusTypeInt32}},
256 vector<Interface::Argument>{{"", kDBusTypeInt64}});
257 interface.methods.emplace_back("Kei");
258 // Interface methods with more than one return argument should be ignored.
259 interface.methods.emplace_back(
260 "Kiyoko",
261 vector<Interface::Argument>{},
262 vector<Interface::Argument>{
263 {"akira", kDBusTypeInt64},
264 {"", kDBusTypeString}});
265 // Signals generate helper methods to send them.
266 interface.signals.emplace_back(
267 "Update",
268 vector<Interface::Argument>{});
269 interface.signals.emplace_back(
270 "Mapping",
271 vector<Interface::Argument>{
272 {"key", kDBusTypeString},
273 {"", kDBusTypeArryOfObjects}});
274 interface.properties.emplace_back(
275 "CharacterName",
276 kDBusTypeString,
277 kPropertyAccessReadOnly);
278 interface.properties.emplace_back(
279 "WriteProperty",
280 kDBusTypeString,
281 kPropertyAccessReadWrite);
282
283 Interface interface2;
284 interface2.name = kInterfaceName2;
285 interface2.methods.emplace_back(
286 "Kaneda2",
287 vector<Interface::Argument>{{"iwata", kDBusTypeString}},
288 vector<Interface::Argument>{{"", kDBusTypeString}});
289 interface2.methods.back().is_const = true;
290 interface2.methods.back().kind = Interface::Method::Kind::kSimple;
291 interface2.methods.emplace_back(
292 "Tetsuo2",
293 vector<Interface::Argument>{{"", kDBusTypeInt32}},
294 vector<Interface::Argument>{{"", kDBusTypeInt64}});
295 interface2.methods.back().kind = Interface::Method::Kind::kAsync;
296 interface2.methods.emplace_back(
297 "Kei2",
298 vector<Interface::Argument>{},
299 vector<Interface::Argument>{{"", kDBusTypeBool}});
300 interface2.methods.back().kind = Interface::Method::Kind::kAsync;
301 interface2.methods.back().include_dbus_message = true;
302
303 base::FilePath output_path = temp_dir_.path().Append("output.h");
304 EXPECT_TRUE(AdaptorGenerator::GenerateAdaptors({interface, interface2},
305 output_path));
306 string contents;
307 EXPECT_TRUE(base::ReadFileToString(output_path, &contents));
308 // The header guards contain the (temporary) filename, so we search for
309 // the content we need within the string.
310 test_utils::EXPECT_TEXT_CONTAINED(kExpectedContent, contents);
311 }
312
313 } // namespace chromeos_dbus_bindings
314