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: 226 void SetUp() override { 227 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 228 } 229 230 protected: 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 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