diff options
-rw-r--r-- | chromeos-dbus-bindings/adaptor_generator.cc | 464 | ||||
-rw-r--r-- | chromeos-dbus-bindings/adaptor_generator.h | 32 | ||||
-rw-r--r-- | chromeos-dbus-bindings/adaptor_generator_unittest.cc | 217 | ||||
-rw-r--r-- | chromeos-dbus-bindings/generate_chromeos_dbus_bindings.cc | 20 | ||||
-rw-r--r-- | chromeos-dbus-bindings/header_generator.cc | 16 | ||||
-rw-r--r-- | chromeos-dbus-bindings/header_generator.h | 14 | ||||
-rw-r--r-- | chromeos-dbus-bindings/interface.h | 8 | ||||
-rw-r--r-- | chromeos-dbus-bindings/method_name_generator.cc | 34 | ||||
-rw-r--r-- | chromeos-dbus-bindings/method_name_generator.h | 7 | ||||
-rw-r--r-- | chromeos-dbus-bindings/method_name_generator_unittest.cc | 17 | ||||
-rw-r--r-- | chromeos-dbus-bindings/proxy_generator.cc | 176 | ||||
-rw-r--r-- | chromeos-dbus-bindings/proxy_generator.h | 8 | ||||
-rw-r--r-- | chromeos-dbus-bindings/proxy_generator_unittest.cc | 79 | ||||
-rw-r--r-- | chromeos-dbus-bindings/xml_interface_parser.cc | 114 | ||||
-rw-r--r-- | chromeos-dbus-bindings/xml_interface_parser.h | 20 | ||||
-rw-r--r-- | chromeos-dbus-bindings/xml_interface_parser_unittest.cc | 47 |
16 files changed, 795 insertions, 478 deletions
diff --git a/chromeos-dbus-bindings/adaptor_generator.cc b/chromeos-dbus-bindings/adaptor_generator.cc index 990976a..5f71816 100644 --- a/chromeos-dbus-bindings/adaptor_generator.cc +++ b/chromeos-dbus-bindings/adaptor_generator.cc @@ -9,6 +9,7 @@ #include <base/logging.h> #include <base/strings/string_util.h> #include <base/strings/stringprintf.h> +#include <chromeos/strings/string_utils.h> #include "chromeos-dbus-bindings/dbus_signature.h" #include "chromeos-dbus-bindings/indented_text.h" @@ -21,15 +22,20 @@ using std::vector; namespace chromeos_dbus_bindings { // static -bool AdaptorGenerator::GenerateAdaptor( - const Interface& interface, +bool AdaptorGenerator::GenerateAdaptors( + const std::vector<Interface>& interfaces, const base::FilePath& output_file) { IndentedText text; - text.AddLine(StringPrintf("// Automatic generation of interface for %s", - interface.name.c_str())); - string header_guard = GenerateHeaderGuard(output_file, interface.name); + CHECK(!interfaces.empty()) << "At least one interface must be provided"; + + text.AddLine("// Automatic generation of D-Bus interfaces:"); + for (const auto& interface : interfaces) { + text.AddLine(StringPrintf("// - %s", interface.name.c_str())); + } + string header_guard = GenerateHeaderGuard(output_file, ""); text.AddLine(StringPrintf("#ifndef %s", header_guard.c_str())); text.AddLine(StringPrintf("#define %s", header_guard.c_str())); + text.AddLine("#include <memory>"); text.AddLine("#include <string>"); text.AddLine("#include <vector>"); text.AddBlankLine(); @@ -39,209 +45,282 @@ bool AdaptorGenerator::GenerateAdaptor( text.AddLine("#include <chromeos/dbus/dbus_object.h>"); text.AddLine("#include <chromeos/dbus/exported_object_manager.h>"); text.AddLine("#include <chromeos/variant_dictionary.h>"); - text.AddBlankLine(); - - vector<string> namespaces; - string class_name; - CHECK(GetNamespacesAndClassName(interface.name, &namespaces, &class_name)); - for (const auto& space : namespaces) { - text.AddLine(StringPrintf("namespace %s {", space.c_str())); - } - text.AddBlankLine(); - string adaptor_name = StringPrintf("%sAdaptor", class_name.c_str()); - text.AddLine(StringPrintf("class %s {", adaptor_name.c_str())); - text.AddLineWithOffset("public:", kScopeOffset); + for (const auto& interface : interfaces) + GenerateInterfaceAdaptor(interface, &text); - text.PushOffset(kBlockOffset); - AddMethodInterface(interface, &text); - AddConstructor(interface, adaptor_name, &text); - AddSendSignalMethods(interface, &text); - text.AddLine(StringPrintf("virtual ~%s() = default;", adaptor_name.c_str())); - text.AddLine("virtual void OnRegisterComplete(bool success) {}"); + text.AddLine(StringPrintf("#endif // %s", header_guard.c_str())); - text.AddBlankLine(); - AddPropertyMethods(interface, &text); - text.PopOffset(); - - text.AddLineWithOffset("protected:", kScopeOffset); - text.PushOffset(kBlockOffset); - text.AddLine("chromeos::dbus_utils::DBusInterface* dbus_interface() {"); - text.PushOffset(kBlockOffset); - text.AddLine("return dbus_interface_;"); - text.PopOffset(); - text.AddLine("}"); - text.PopOffset(); + return WriteTextToFile(output_file, text); +} - text.AddBlankLine(); - text.AddLineWithOffset("private:", kScopeOffset); - - text.PushOffset(kBlockOffset); - text.AddLine("// Exported properties"); - AddPropertyDataMembers(interface, &text); - text.AddLine("MethodInterface* interface_; // Owned by caller."); - text.AddLine("chromeos::dbus_utils::DBusObject dbus_object_;"); - AddSignalDataMembers(interface, &text); - text.AddLine("// Owned by |dbus_object_|."); - text.AddLine("chromeos::dbus_utils::DBusInterface* dbus_interface_;"); - text.AddLine(StringPrintf( - "DISALLOW_COPY_AND_ASSIGN(%s);", adaptor_name.c_str())); - text.PopOffset(); - - text.AddLine("};"); - text.AddBlankLine(); +// static +void AdaptorGenerator::GenerateInterfaceAdaptor( + const Interface& interface, + IndentedText *text) { + vector<string> namespaces; + string itf_name; + CHECK(GetNamespacesAndClassName(interface.name, &namespaces, &itf_name)); + string class_name = itf_name + "Adaptor"; + string full_itf_name = GetFullClassName(namespaces, itf_name); + itf_name += "Interface"; + + text->AddBlankLine(); + for (const auto& ns : namespaces) { + text->AddLine(StringPrintf("namespace %s {", ns.c_str())); + } + text->AddBlankLine(); + text->AddLine(StringPrintf("// Interface definition for %s.", + full_itf_name.c_str())); + text->AddLine(StringPrintf("class %s {", itf_name.c_str())); + text->AddLineWithOffset("public:", kScopeOffset); + text->PushOffset(kBlockOffset); + text->AddLine(StringPrintf("virtual ~%s() = default;", itf_name.c_str())); + AddInterfaceMethods(interface, text); + text->PopOffset(); + text->AddLine("};"); + + text->AddBlankLine(); + text->AddLine(StringPrintf("// Interface adaptor for %s.", + full_itf_name.c_str())); + text->AddLine(StringPrintf("class %s {", class_name.c_str())); + text->AddLineWithOffset("public:", kScopeOffset); + text->PushOffset(kBlockOffset); + AddConstructor(class_name, itf_name, text); + AddRegisterWithDBusObject(itf_name, interface, text); + AddSendSignalMethods(interface, text); + AddPropertyMethodImplementation(interface, text); + text->PopOffset(); + + text->AddBlankLine(); + text->AddLineWithOffset("private:", kScopeOffset); + text->PushOffset(kBlockOffset); + AddSignalDataMembers(interface, text); + AddPropertyDataMembers(interface, text); + + text->AddBlankLine(); + text->AddLine(StringPrintf( + "%s* interface_; // Owned by container of this adapter.", + itf_name.c_str())); + + text->AddBlankLine(); + text->AddLine(StringPrintf("DISALLOW_COPY_AND_ASSIGN(%s);", + class_name.c_str())); + text->PopOffset(); + text->AddLine("};"); + + text->AddBlankLine(); for (auto it = namespaces.rbegin(); it != namespaces.rend(); ++it) { - text.AddLine(StringPrintf("} // namespace %s", it->c_str())); + text->AddLine(StringPrintf("} // namespace %s", it->c_str())); } - text.AddLine(StringPrintf("#endif // %s", header_guard.c_str())); - - return WriteTextToFile(output_file, text); } // static -void AdaptorGenerator::AddConstructor(const Interface& interface, - const string& class_name, +void AdaptorGenerator::AddConstructor(const string& class_name, + const string& itf_name, IndentedText *text) { - IndentedText block; - block.AddLine(StringPrintf("%s(", class_name.c_str())); - block.PushOffset(kLineContinuationOffset); - block.AddLine("chromeos::dbus_utils::ExportedObjectManager* object_manager,"); - block.AddLine("const scoped_refptr<dbus::Bus>& bus,"); - block.AddLine("const std::string& object_path,"); - block.AddLine("MethodInterface* interface) // Owned by caller."); - block.AddLine(": interface_(interface),"); - block.PushOffset(kBlockOffset); - block.AddLine("dbus_object_("); - block.PushOffset(kLineContinuationOffset); - block.AddLine("object_manager,"); - block.AddLine("bus,"); - block.AddLine("dbus::ObjectPath(object_path)),"); - block.PopOffset(); - - // Signal constructors. - for (const auto& signal : interface.signals) { - block.AddLine(StringPrintf("signal_%s_(", signal.name.c_str())); - block.PushOffset(kLineContinuationOffset); - block.AddLine("&dbus_object_,"); - block.AddLine(StringPrintf("\"%s\",", interface.name.c_str())); - block.AddLine(StringPrintf("\"%s\"),", signal.name.c_str())); - block.PopOffset(); - } + text->AddLine(StringPrintf("%s(%s* interface) : interface_(interface) {}", + class_name.c_str(), itf_name.c_str())); +} + +// static +void AdaptorGenerator::AddRegisterWithDBusObject( + const std::string& itf_name, + const Interface& interface, + IndentedText *text) { + text->AddBlankLine(); + text->AddLine( + "void RegisterWithDBusObject(chromeos::dbus_utils::DBusObject* object) {"); + text->PushOffset(kBlockOffset); + text->AddLine("chromeos::dbus_utils::DBusInterface* itf ="); + text->AddLineWithOffset( + StringPrintf("object->AddOrGetInterface(\"%s\");", + interface.name.c_str()), kLineContinuationOffset); + RegisterInterface(itf_name, interface, text); + text->PopOffset(); + text->AddLine("}"); +} - block.AddLine("dbus_interface_("); - block.PushOffset(kLineContinuationOffset); - block.AddLine(StringPrintf( - "dbus_object_.AddOrGetInterface(\"%s\")) {", interface.name.c_str())); - block.PopOffset(); - block.PopOffset(); - block.PopOffset(); - block.PushOffset(kBlockOffset); +// static +void AdaptorGenerator::RegisterInterface(const string& itf_name, + const Interface& interface, + IndentedText *text) { + if (!interface.methods.empty()) + text->AddBlankLine(); for (const auto& method : interface.methods) { - if (method.output_arguments.size() > 1) { - // TODO(pstew): Accept multiple output arguments. crbug.com/419271 - continue; + string add_handler_name; + switch (method.kind) { + case Interface::Method::Kind::kSimple: + add_handler_name = "AddSimpleMethodHandler"; + break; + case Interface::Method::Kind::kNormal: + add_handler_name = "AddSimpleMethodHandlerWithError"; + break; + case Interface::Method::Kind::kAsync: + add_handler_name = "AddMethodHandler"; + break; + case Interface::Method::Kind::kRaw: + add_handler_name = "AddRawMethodHandler"; + break; } - block.AddLine("dbus_interface_->AddMethodHandler("); - block.PushOffset(kLineContinuationOffset); - block.AddLine(StringPrintf("\"%s\",", method.name.c_str())); - block.AddLine("base::Unretained(interface_),"); - block.AddLine(StringPrintf("&MethodInterface::%s);", method.name.c_str())); - block.PopOffset(); + + text->AddLine(StringPrintf("itf->%s(", add_handler_name.c_str())); + text->PushOffset(kLineContinuationOffset); + text->AddLine(StringPrintf("\"%s\",", method.name.c_str())); + text->AddLine("base::Unretained(interface_),"); + text->AddLine(StringPrintf("&%s::%s);", itf_name.c_str(), + method.name.c_str())); + text->PopOffset(); + } + + // Register signals. + if (!interface.signals.empty()) + text->AddBlankLine(); + for (const auto& signal : interface.signals) { + string signal_var_name = StringPrintf("signal_%s_", signal.name.c_str()); + string signal_type_name = StringPrintf("Signal%sType", signal.name.c_str()); + text->AddLine(StringPrintf("%s = itf->RegisterSignalOfType<%s>(\"%s\");", + signal_var_name.c_str(), + signal_type_name.c_str(), + signal.name.c_str())); } + // Register exported properties. + if (!interface.properties.empty()) + text->AddBlankLine(); for (const auto& property : interface.properties) { string variable_name = GetPropertyVariableName(property.name); - block.AddLine("dbus_interface_->AddProperty("); - block.PushOffset(kLineContinuationOffset); - block.AddLine(StringPrintf("\"%s\",", property.name.c_str())); - block.AddLine(StringPrintf("&%s_);", variable_name.c_str())); - block.PopOffset(); + text->AddLine(StringPrintf("itf->AddProperty(\"%s\", &%s_);", + property.name.c_str(), variable_name.c_str())); } - block.AddLine("dbus_object_.RegisterAsync(base::Bind("); - block.AddLineWithOffset( - StringPrintf("&%s::OnRegisterComplete, base::Unretained(this)));", - class_name.c_str()), - kLineContinuationOffset); - block.PopOffset(); - block.AddLine("}"); - text->AddBlock(block); } // static -void AdaptorGenerator::AddMethodInterface(const Interface& interface, - IndentedText *text) { +void AdaptorGenerator::AddInterfaceMethods(const Interface& interface, + IndentedText *text) { IndentedText block; - block.AddLine("class MethodInterface {"); - block.AddLineWithOffset("public:", kScopeOffset); DbusSignature signature; - block.PushOffset(kBlockOffset); + if (!interface.methods.empty()) + block.AddBlankLine(); + for (const auto& method : interface.methods) { - string return_type("void"); - if (!method.output_arguments.empty()) { - if (method.output_arguments.size() > 1) { - // TODO(pstew): Accept multiple output arguments. crbug.com://419271 - LOG(WARNING) << "Method " << method.name << " has " - << method.output_arguments.size() - << " output arguments which is unsupported."; - continue; - } - CHECK(signature.Parse(method.output_arguments[0].type, &return_type)); + string const_method; + if (method.is_const) + const_method = " const"; + + string return_type = "void"; + vector<string> method_params; + auto input_arguments_copy = method.input_arguments; + auto output_arguments_copy = method.output_arguments; + switch (method.kind) { + case Interface::Method::Kind::kSimple: + if (output_arguments_copy.size() == 1) { + CHECK(signature.Parse(output_arguments_copy[0].type, &return_type)); + output_arguments_copy.clear(); + } + break; + case Interface::Method::Kind::kNormal: + method_params.push_back("chromeos::ErrorPtr* error"); + return_type = "bool"; + break; + case Interface::Method::Kind::kAsync: + method_params.push_back( + "scoped_ptr<chromeos::dbus_utils::DBusMethodResponse> response"); + // Async methods don't return values directly. + output_arguments_copy.clear(); + break; + case Interface::Method::Kind::kRaw: + method_params.push_back("dbus::MethodCall* method_call"); + method_params.push_back("chromeos::dbus_utils::ResponseSender sender"); + // Raw methods don't take static parameters or return values directly. + input_arguments_copy.clear(); + output_arguments_copy.clear(); + break; } - block.AddLine(StringPrintf("virtual %s %s(", - return_type.c_str(), method.name.c_str())); - block.PushOffset(kLineContinuationOffset); - string last_argument = "chromeos::ErrorPtr* /* error */"; - for (const auto& argument : method.input_arguments) { - block.AddLine(last_argument + ","); - CHECK(signature.Parse(argument.type, &last_argument)); - if (!IsIntegralType(last_argument)) { - last_argument = StringPrintf("const %s&", last_argument.c_str()); - } - if (!argument.name.empty()) { - last_argument.append(StringPrintf(" /* %s */", argument.name.c_str())); + string method_start = StringPrintf("virtual %s %s(", + return_type.c_str(), + method.name.c_str()); + string method_end = StringPrintf(")%s = 0;", const_method.c_str()); + int index = 0; + for (const auto& argument : input_arguments_copy) { + string param_type; + CHECK(signature.Parse(argument.type, ¶m_type)); + if (!IsIntegralType(param_type)) { + param_type = StringPrintf("const %s&", param_type.c_str()); } + string param_name = GetArgName("in", argument.name, ++index); + method_params.push_back(param_type + ' ' + param_name); + } + + for (const auto& argument : output_arguments_copy) { + string param_type; + CHECK(signature.Parse(argument.type, ¶m_type)); + string param_name = GetArgName("out", argument.name, ++index); + method_params.push_back(param_type + "* " + param_name); } - block.AddLine(last_argument + ") = 0;"); - block.PopOffset(); - } - block.PopOffset(); - block.AddLine("};"); + if (method_params.empty()) { + block.AddLine(method_start + method_end); + } else { + block.AddLine(method_start); + block.PushOffset(kLineContinuationOffset); + for (size_t i = 0; i < method_params.size() - 1; i++) + block.AddLine(method_params[i] + ','); + block.AddLine(method_params.back() + method_end); + block.PopOffset(); + } + } text->AddBlock(block); } // static -void AdaptorGenerator::AddSendSignalMethods(const Interface& interface, - IndentedText *text) { +void AdaptorGenerator::AddSendSignalMethods( + const Interface& interface, + IndentedText *text) { IndentedText block; DbusSignature signature; + if (!interface.signals.empty()) + block.AddBlankLine(); + for (const auto& signal : interface.signals) { - block.AddLine(StringPrintf("void Send%sSignal(", signal.name.c_str())); - block.PushOffset(kLineContinuationOffset); - string last_argument; - int unnamed_args = 0; - string call_arguments; // The arguments to pass to the Send() call. + string method_start = StringPrintf("void Send%sSignal(", + signal.name.c_str()); + string method_end = ") {"; + + int index = 0; + vector<string> method_params; + vector<string> param_names; for (const auto& argument : signal.arguments) { - if (!last_argument.empty()) - block.AddLine(last_argument + ","); - CHECK(signature.Parse(argument.type, &last_argument)); - if (!IsIntegralType(last_argument)) - last_argument = StringPrintf("const %s&", last_argument.c_str()); - string argument_name = argument.name; - if (argument.name.empty()) - argument_name = StringPrintf("_arg_%d", ++unnamed_args); - last_argument.append(" " + argument_name); - if (!call_arguments.empty()) - call_arguments.append(", "); - call_arguments.append(argument_name); + string param_type; + CHECK(signature.Parse(argument.type, ¶m_type)); + if (!IsIntegralType(param_type)) { + param_type = StringPrintf("const %s&", param_type.c_str()); + } + string param_name = GetArgName("in", argument.name, ++index); + param_names.push_back(param_name); + method_params.push_back(param_type + ' ' + param_name); } - block.AddLine(last_argument + ") {"); - block.PopOffset(); + + if (method_params.empty()) { + block.AddLine(method_start + method_end); + } else { + block.AddLine(method_start); + block.PushOffset(kLineContinuationOffset); + for (size_t i = 0; i < method_params.size() - 1; i++) + block.AddLine(method_params[i] + ','); + block.AddLine(method_params.back() + method_end); + block.PopOffset(); + } + + string args = chromeos::string_utils::Join(", ", param_names); block.PushOffset(kBlockOffset); - block.AddLine(StringPrintf( - "signal_%s_.Send(%s);", signal.name.c_str(), call_arguments.c_str())); + block.AddLine(StringPrintf("auto signal = signal_%s_.lock();", + signal.name.c_str())); + block.AddLine("if (signal)"); + block.AddLineWithOffset(StringPrintf("signal->Send(%s);", args.c_str()), + kBlockOffset); block.PopOffset(); block.AddLine("}"); } @@ -255,30 +334,46 @@ void AdaptorGenerator::AddSignalDataMembers(const Interface& interface, DbusSignature signature; for (const auto& signal : interface.signals) { - block.AddLine("chromeos::dbus_utils::DBusSignal<"); - block.PushOffset(kLineContinuationOffset); - string last_argument; + string signal_type_name = StringPrintf("Signal%sType", signal.name.c_str()); + string signal_type_alias_begin = + StringPrintf("using %s = chromeos::dbus_utils::DBusSignal<", + signal_type_name.c_str()); + string signal_type_alias_end = ">;"; + vector<string> params; for (const auto& argument : signal.arguments) { - if (!last_argument.empty()) - block.AddLine(last_argument + ","); - CHECK(signature.Parse(argument.type, &last_argument)); + string param; + CHECK(signature.Parse(argument.type, ¶m)); if (!argument.name.empty()) - last_argument.append(StringPrintf(" /* %s */", argument.name.c_str())); + base::StringAppendF(¶m, " /*%s*/", argument.name.c_str()); + params.push_back(param); } - block.AddLine(StringPrintf( - "%s> signal_%s_;", last_argument.c_str(), signal.name.c_str())); - block.PopOffset(); + if (params.empty()) { + block.AddLine(signal_type_alias_begin + signal_type_alias_end); + } else { + block.AddLine(signal_type_alias_begin); + block.PushOffset(kLineContinuationOffset); + for (size_t i = 0; i < params.size() - 1; i++) + block.AddLine(params[i] + ','); + block.AddLine(params.back() + signal_type_alias_end); + block.PopOffset(); + } + block.AddLine( + StringPrintf("std::weak_ptr<%s> signal_%s_;", + signal_type_name.c_str(), signal.name.c_str())); + block.AddBlankLine(); } text->AddBlock(block); } // static -void AdaptorGenerator::AddPropertyMethods(const Interface& interface, - IndentedText *text) { +void AdaptorGenerator::AddPropertyMethodImplementation( + const Interface& interface, + IndentedText *text) { IndentedText block; DbusSignature signature; for (const auto& property : interface.properties) { + block.AddBlankLine(); string type; CHECK(signature.Parse(property.type, &type)); string variable_name = GetPropertyVariableName(property.name); @@ -295,19 +390,18 @@ void AdaptorGenerator::AddPropertyMethods(const Interface& interface, block.AddLine("}"); // Setter method. - block.AddLine(StringPrintf("void Set%s(", property.name.c_str())); - block.PushOffset(kLineContinuationOffset); - block.AddLine(StringPrintf("const %s& %s) {", + if (!IsIntegralType(type)) + type = StringPrintf("const %s&", type.c_str()); + block.AddLine(StringPrintf("void Set%s(%s %s) {", + property.name.c_str(), type.c_str(), variable_name.c_str())); - block.PopOffset(); block.PushOffset(kBlockOffset); block.AddLine(StringPrintf("%s_.SetValue(%s);", variable_name.c_str(), variable_name.c_str())); block.PopOffset(); block.AddLine("}"); - block.AddBlankLine(); } text->AddBlock(block); } diff --git a/chromeos-dbus-bindings/adaptor_generator.h b/chromeos-dbus-bindings/adaptor_generator.h index 84adec7..87e1b26 100644 --- a/chromeos-dbus-bindings/adaptor_generator.h +++ b/chromeos-dbus-bindings/adaptor_generator.h @@ -26,20 +26,34 @@ struct Interface; class AdaptorGenerator : public HeaderGenerator { public: - static bool GenerateAdaptor(const Interface& interface, - const base::FilePath& output_file); + static bool GenerateAdaptors(const std::vector<Interface>& interfaces, + const base::FilePath& output_file); private: friend class AdaptorGeneratorTest; + // Generates one interface adaptor. + static void GenerateInterfaceAdaptor(const Interface& interface, + IndentedText *text); + + // Generates the method prototypes for an interface declaration. + static void AddInterfaceMethods(const Interface& interface, + IndentedText *text); + // Generates the constructor for the adaptor. - static void AddConstructor(const Interface& interface, - const std::string& class_name, + static void AddConstructor(const std::string& class_name, + const std::string& itf_name, IndentedText *text); - // Generates the method interface class. - static void AddMethodInterface(const Interface& interface, - IndentedText *text); + // Generates RegisterWithDBusObject() method. + static void AddRegisterWithDBusObject(const std::string& itf_name, + const Interface& interface, + IndentedText *text); + + // Generates the code to register the interface with a D-Bus object. + static void RegisterInterface(const std::string& itf_name, + const Interface& interface, + IndentedText *text); // Generates adaptor methods to send the signals. static void AddSendSignalMethods(const Interface& interface, @@ -50,8 +64,8 @@ class AdaptorGenerator : public HeaderGenerator { IndentedText *text); // Generates adaptor accessor methods for the properties. - static void AddPropertyMethods(const Interface& interface, - IndentedText *text); + static void AddPropertyMethodImplementation(const Interface& interface, + IndentedText *text); // Generate ExportProperty data members for the properties. static void AddPropertyDataMembers(const Interface& interface, diff --git a/chromeos-dbus-bindings/adaptor_generator_unittest.cc b/chromeos-dbus-bindings/adaptor_generator_unittest.cc index 41aeeb2..2646c26 100644 --- a/chromeos-dbus-bindings/adaptor_generator_unittest.cc +++ b/chromeos-dbus-bindings/adaptor_generator_unittest.cc @@ -33,6 +33,7 @@ const char kMethod1Argument1[] = "i"; const char kMethod1Return[] = "x"; const char kMethod2Name[] = "Kei"; const char kMethod3Name[] = "Kiyoko"; +const char kMethod3ReturnName0[] = "akira"; const char kMethod3Return0[] = "x"; const char kMethod3Return1[] = "s"; const char kSignal0Name[] = "Update"; @@ -40,12 +41,16 @@ const char kSignal1Name[] = "Mapping"; const char kSignal1Argument0[] = "s"; const char kSignal1ArgumentName0[] = "key"; const char kSignal1Argument1[] = "ao"; -const char kProperty0Name[] = "InterfaceName"; +const char kProperty0Name[] = "CharacterName"; const char kProperty0Type[] = "s"; const char kProperty0Access[] = "read"; -const char kInterfaceName[] = "org.chromium.TestInterface"; +const char kInterfaceName[] = "org.chromium.Test"; +const char kInterfaceName2[] = "org.chromium.Test2"; +const char kMethod0Name2[] = "Kaneda2"; +const char kMethod1Name2[] = "Tetsuo2"; const char kExpectedContent[] = R"literal_string( +#include <memory> #include <string> #include <vector> @@ -59,97 +64,139 @@ const char kExpectedContent[] = R"literal_string( namespace org { namespace chromium { -class TestInterfaceAdaptor { +// Interface definition for org::chromium::Test. +class TestInterface { public: - class MethodInterface { - public: - virtual std::string Kaneda( - chromeos::ErrorPtr* /* error */, - const std::string& /* iwata */, - const std::vector<dbus::ObjectPath>& /* clarke */) = 0; - virtual int64_t Tetsuo( - chromeos::ErrorPtr* /* error */, - int32_t) = 0; - virtual void Kei( - chromeos::ErrorPtr* /* error */) = 0; - }; - TestInterfaceAdaptor( - chromeos::dbus_utils::ExportedObjectManager* object_manager, - const scoped_refptr<dbus::Bus>& bus, - const std::string& object_path, - MethodInterface* interface) // Owned by caller. - : interface_(interface), - dbus_object_( - object_manager, - bus, - dbus::ObjectPath(object_path)), - signal_Update_( - &dbus_object_, - "org.chromium.TestInterface", - "Update"), - signal_Mapping_( - &dbus_object_, - "org.chromium.TestInterface", - "Mapping"), - dbus_interface_( - dbus_object_.AddOrGetInterface("org.chromium.TestInterface")) { - dbus_interface_->AddMethodHandler( + virtual ~TestInterface() = default; + + virtual bool Kaneda( + chromeos::ErrorPtr* error, + const std::string& in_iwata, + const std::vector<dbus::ObjectPath>& in_clarke, + std::string* out_3) = 0; + virtual bool Tetsuo( + chromeos::ErrorPtr* error, + int32_t in_1, + int64_t* out_2) = 0; + virtual bool Kei( + chromeos::ErrorPtr* error) = 0; + virtual bool Kiyoko( + chromeos::ErrorPtr* error, + int64_t* out_akira, + std::string* out_2) = 0; +}; + +// Interface adaptor for org::chromium::Test. +class TestAdaptor { + public: + TestAdaptor(TestInterface* interface) : interface_(interface) {} + + void RegisterWithDBusObject(chromeos::dbus_utils::DBusObject* object) { + chromeos::dbus_utils::DBusInterface* itf = + object->AddOrGetInterface("org.chromium.Test"); + + itf->AddSimpleMethodHandlerWithError( "Kaneda", base::Unretained(interface_), - &MethodInterface::Kaneda); - dbus_interface_->AddMethodHandler( + &TestInterface::Kaneda); + itf->AddSimpleMethodHandlerWithError( "Tetsuo", base::Unretained(interface_), - &MethodInterface::Tetsuo); - dbus_interface_->AddMethodHandler( + &TestInterface::Tetsuo); + itf->AddSimpleMethodHandlerWithError( "Kei", base::Unretained(interface_), - &MethodInterface::Kei); - dbus_interface_->AddProperty( - "InterfaceName", - &interface_name_); - dbus_object_.RegisterAsync(base::Bind( - &TestInterfaceAdaptor::OnRegisterComplete, base::Unretained(this))); + &TestInterface::Kei); + itf->AddSimpleMethodHandlerWithError( + "Kiyoko", + base::Unretained(interface_), + &TestInterface::Kiyoko); + + signal_Update_ = itf->RegisterSignalOfType<SignalUpdateType>("Update"); + signal_Mapping_ = itf->RegisterSignalOfType<SignalMappingType>("Mapping"); + + itf->AddProperty("CharacterName", &character_name_); } - void SendUpdateSignal( - ) { - signal_Update_.Send(); + + void SendUpdateSignal() { + auto signal = signal_Update_.lock(); + if (signal) + signal->Send(); } void SendMappingSignal( - const std::string& key, - const std::vector<dbus::ObjectPath>& _arg_1) { - signal_Mapping_.Send(key, _arg_1); + const std::string& in_key, + const std::vector<dbus::ObjectPath>& in_2) { + auto signal = signal_Mapping_.lock(); + if (signal) + signal->Send(in_key, in_2); } - virtual ~TestInterfaceAdaptor() = default; - virtual void OnRegisterComplete(bool success) {} - std::string GetInterfaceName() const { - return interface_name_.GetValue().Get<std::string>(); + std::string GetCharacterName() const { + return character_name_.GetValue().Get<std::string>(); } - void SetInterfaceName( - const std::string& interface_name) { - interface_name_.SetValue(interface_name); + void SetCharacterName(const std::string& character_name) { + character_name_.SetValue(character_name); } - protected: - chromeos::dbus_utils::DBusInterface* dbus_interface() { - return dbus_interface_; + private: + using SignalUpdateType = chromeos::dbus_utils::DBusSignal<>; + std::weak_ptr<SignalUpdateType> signal_Update_; + + using SignalMappingType = chromeos::dbus_utils::DBusSignal< + std::string /*key*/, + std::vector<dbus::ObjectPath>>; + std::weak_ptr<SignalMappingType> signal_Mapping_; + + chromeos::dbus_utils::ExportedProperty<std::string> + character_name_; + + TestInterface* interface_; // Owned by container of this adapter. + + DISALLOW_COPY_AND_ASSIGN(TestAdaptor); +}; + +} // namespace chromium +} // namespace org + +namespace org { +namespace chromium { + +// Interface definition for org::chromium::Test2. +class Test2Interface { + public: + virtual ~Test2Interface() = default; + + virtual std::string Kaneda2( + const std::string& in_iwata) const = 0; + virtual void Tetsuo2( + scoped_ptr<chromeos::dbus_utils::DBusMethodResponse> response, + int32_t in_1) = 0; +}; + +// Interface adaptor for org::chromium::Test2. +class Test2Adaptor { + public: + Test2Adaptor(Test2Interface* interface) : interface_(interface) {} + + void RegisterWithDBusObject(chromeos::dbus_utils::DBusObject* object) { + chromeos::dbus_utils::DBusInterface* itf = + object->AddOrGetInterface("org.chromium.Test2"); + + itf->AddSimpleMethodHandler( + "Kaneda2", + base::Unretained(interface_), + &Test2Interface::Kaneda2); + itf->AddMethodHandler( + "Tetsuo2", + base::Unretained(interface_), + &Test2Interface::Tetsuo2); } private: - // Exported properties - chromeos::dbus_utils::ExportedProperty<std::string> - interface_name_; - MethodInterface* interface_; // Owned by caller. - chromeos::dbus_utils::DBusObject dbus_object_; - chromeos::dbus_utils::DBusSignal< - > signal_Update_; - chromeos::dbus_utils::DBusSignal< - std::string /* key */, - std::vector<dbus::ObjectPath>> signal_Mapping_; - // Owned by |dbus_object_|. - chromeos::dbus_utils::DBusInterface* dbus_interface_; - DISALLOW_COPY_AND_ASSIGN(TestInterfaceAdaptor); + + Test2Interface* interface_; // Owned by container of this adapter. + + DISALLOW_COPY_AND_ASSIGN(Test2Adaptor); }; } // namespace chromium @@ -194,7 +241,7 @@ TEST_F(AdaptorGeneratorTest, GenerateAdaptors) { kMethod3Name, vector<Interface::Argument>{}, vector<Interface::Argument>{ - {"", kMethod3Return0}, + {kMethod3ReturnName0, kMethod3Return0}, {"", kMethod3Return1}}); // Signals generate helper methods to send them. interface.signals.emplace_back( @@ -210,8 +257,24 @@ TEST_F(AdaptorGeneratorTest, GenerateAdaptors) { kProperty0Type, kProperty0Access); + Interface interface2; + interface2.name = kInterfaceName2; + interface2.methods.emplace_back( + kMethod0Name2, + vector<Interface::Argument>{ + {kMethod0ArgumentName0, kMethod0Argument0}}, + vector<Interface::Argument>{{"", kMethod0Return}}); + interface2.methods.back().is_const = true; + interface2.methods.back().kind = Interface::Method::Kind::kSimple; + interface2.methods.emplace_back( + kMethod1Name2, + vector<Interface::Argument>{{"", kMethod1Argument1}}, + vector<Interface::Argument>{}); + interface2.methods.back().kind = Interface::Method::Kind::kAsync; + base::FilePath output_path = temp_dir_.path().Append("output.h"); - EXPECT_TRUE(AdaptorGenerator::GenerateAdaptor(interface, output_path)); + EXPECT_TRUE(AdaptorGenerator::GenerateAdaptors({interface, interface2}, + output_path)); string contents; EXPECT_TRUE(base::ReadFileToString(output_path, &contents)); // The header guards contain the (temporary) filename, so we search for diff --git a/chromeos-dbus-bindings/generate_chromeos_dbus_bindings.cc b/chromeos-dbus-bindings/generate_chromeos_dbus_bindings.cc index 5bf35e1..c53168c 100644 --- a/chromeos-dbus-bindings/generate_chromeos_dbus_bindings.cc +++ b/chromeos-dbus-bindings/generate_chromeos_dbus_bindings.cc @@ -14,6 +14,10 @@ #include "chromeos-dbus-bindings/proxy_generator.h" #include "chromeos-dbus-bindings/xml_interface_parser.h" +using chromeos_dbus_bindings::AdaptorGenerator; +using chromeos_dbus_bindings::MethodNameGenerator; +using chromeos_dbus_bindings::ProxyGenerator; + namespace switches { static const char kHelp[] = "help"; @@ -65,20 +69,19 @@ int main(int argc, char** argv) { std::string method_name_file = cl->GetSwitchValueASCII(switches::kMethodNames); VLOG(1) << "Outputting method names to " << method_name_file; - if (!chromeos_dbus_bindings::MethodNameGenerator::GenerateMethodNames( - parser.interface(), + if (!MethodNameGenerator::GenerateMethodNames( + parser.interfaces(), base::FilePath(method_name_file))) { LOG(ERROR) << "Failed to output method names."; return 1; - } + } } if (cl->HasSwitch(switches::kAdaptor)) { std::string adaptor_file = cl->GetSwitchValueASCII(switches::kAdaptor); VLOG(1) << "Outputting adaptor to " << adaptor_file; - if (!chromeos_dbus_bindings::AdaptorGenerator::GenerateAdaptor( - parser.interface(), - base::FilePath(adaptor_file))) { + if (!AdaptorGenerator::GenerateAdaptors(parser.interfaces(), + base::FilePath(adaptor_file))) { LOG(ERROR) << "Failed to output adaptor."; return 1; } @@ -87,9 +90,8 @@ int main(int argc, char** argv) { if (cl->HasSwitch(switches::kProxy)) { std::string proxy_file = cl->GetSwitchValueASCII(switches::kProxy); LOG(INFO) << "Outputting proxy to " << proxy_file; - if (!chromeos_dbus_bindings::ProxyGenerator::GenerateProxy( - parser.interface(), - base::FilePath(proxy_file))) { + if (!ProxyGenerator::GenerateProxy(parser.interfaces(), + base::FilePath(proxy_file))) { LOG(ERROR) << "Failed to output proxy."; return 1; } diff --git a/chromeos-dbus-bindings/header_generator.cc b/chromeos-dbus-bindings/header_generator.cc index c339c13..da4bc74 100644 --- a/chromeos-dbus-bindings/header_generator.cc +++ b/chromeos-dbus-bindings/header_generator.cc @@ -11,6 +11,7 @@ #include <base/strings/string_split.h> #include <base/strings/string_util.h> #include <base/strings/stringprintf.h> +#include <chromeos/strings/string_utils.h> #include "chromeos-dbus-bindings/indented_text.h" @@ -53,6 +54,14 @@ bool HeaderGenerator::GetNamespacesAndClassName( return true; } +std::string HeaderGenerator::GetFullClassName( + const std::vector<std::string>& namespaces, + const std::string& class_name) { + std::vector<std::string> parts = namespaces; + parts.push_back(class_name); + return chromeos::string_utils::Join("::", parts); +} + // static bool HeaderGenerator::IsIntegralType(const string& type) { return type.find("::") == std::string::npos; @@ -71,4 +80,11 @@ bool HeaderGenerator::WriteTextToFile( return true; } +string HeaderGenerator::GetArgName(const char* prefix, + const string& arg_name, + int arg_index) { + string name = arg_name.empty() ? std::to_string(arg_index) : arg_name; + return base::StringPrintf("%s_%s", prefix, name.c_str()); +} + } // namespace chromeos_dbus_bindings diff --git a/chromeos-dbus-bindings/header_generator.h b/chromeos-dbus-bindings/header_generator.h index 7be8d5b..b4f521d 100644 --- a/chromeos-dbus-bindings/header_generator.h +++ b/chromeos-dbus-bindings/header_generator.h @@ -27,11 +27,16 @@ class HeaderGenerator { static std::string GenerateHeaderGuard(const base::FilePath& output_file, const std::string& interface_name); - // Returns a vector of nesting namepsaces. + // Returns a vector of nesting namespaces. static bool GetNamespacesAndClassName(const std::string& interface_name, std::vector<std::string>* namespaces, std::string* class_name); + // Returns a fully-qualified class name like "ns1::ns2::class_name". + static std::string GetFullClassName( + const std::vector<std::string>& namespaces, + const std::string& class_name); + // Used to decide whether the argument should be a const reference. static bool IsIntegralType(const std::string& type); @@ -39,6 +44,13 @@ class HeaderGenerator { static bool WriteTextToFile(const base::FilePath& output_file, const IndentedText& text); + // Generate a name of a method/signal argument based on the name provided in + // the XML file. If |arg_name| is empty, it generates a name using + // the |arg_index| counter. + static std::string GetArgName(const char* prefix, + const std::string& arg_name, + int arg_index); + static const int kScopeOffset = 1; static const int kBlockOffset = 2; static const int kLineContinuationOffset = 4; diff --git a/chromeos-dbus-bindings/interface.h b/chromeos-dbus-bindings/interface.h index 627dce4..214511b 100644 --- a/chromeos-dbus-bindings/interface.h +++ b/chromeos-dbus-bindings/interface.h @@ -18,6 +18,12 @@ struct Interface { std::string type; }; struct Method { + enum class Kind { + kSimple, + kNormal, + kAsync, + kRaw + }; Method(const std::string& name_in, const std::vector<Argument>& input_arguments_in, const std::vector<Argument>& output_arguments_in) @@ -32,6 +38,8 @@ struct Interface { std::string name; std::vector<Argument> input_arguments; std::vector<Argument> output_arguments; + Kind kind{Kind::kNormal}; + bool is_const{false}; }; struct Signal { Signal(const std::string& name_in, diff --git a/chromeos-dbus-bindings/method_name_generator.cc b/chromeos-dbus-bindings/method_name_generator.cc index 4b4154e..d35f058 100644 --- a/chromeos-dbus-bindings/method_name_generator.cc +++ b/chromeos-dbus-bindings/method_name_generator.cc @@ -4,16 +4,14 @@ #include "chromeos-dbus-bindings/method_name_generator.h" -#include <string> - -#include <base/file_util.h> #include <base/files/file_path.h> -#include <base/logging.h> #include <base/strings/stringprintf.h> +#include "chromeos-dbus-bindings/indented_text.h" #include "chromeos-dbus-bindings/interface.h" using std::string; +using std::vector; namespace chromeos_dbus_bindings { @@ -25,23 +23,23 @@ string MethodNameGenerator::GenerateMethodNameConstant( // static bool MethodNameGenerator::GenerateMethodNames( - const Interface& interface, + const vector<Interface>& interfaces, const base::FilePath& output_file) { string contents; - for (const auto& method : interface.methods) { - contents.append( - base::StringPrintf("const char %s[] = \"%s\";\n", - GenerateMethodNameConstant(method.name).c_str(), - method.name.c_str())); - } - - int expected_write_return = contents.size(); - if (base::WriteFile(output_file, contents.c_str(), contents.size()) != - expected_write_return) { - LOG(ERROR) << "Failed to write file " << output_file.value(); - return false; + IndentedText text; + for (const auto& interface : interfaces) { + text.AddBlankLine(); + text.AddLine(base::StringPrintf("namespace %s {", interface.name.c_str())); + for (const auto& method : interface.methods) { + text.AddLine( + base::StringPrintf("const char %s[] = \"%s\";", + GenerateMethodNameConstant(method.name).c_str(), + method.name.c_str())); + } + text.AddLine(base::StringPrintf("} // namespace %s", + interface.name.c_str())); } - return true; + return HeaderGenerator::WriteTextToFile(output_file, text); } } // namespace chromeos_dbus_bindings diff --git a/chromeos-dbus-bindings/method_name_generator.h b/chromeos-dbus-bindings/method_name_generator.h index 59ca890..24a3dc1 100644 --- a/chromeos-dbus-bindings/method_name_generator.h +++ b/chromeos-dbus-bindings/method_name_generator.h @@ -6,9 +6,12 @@ #define CHROMEOS_DBUS_BINDINGS_METHOD_NAME_GENERATOR_H_ #include <string> +#include <vector> #include <base/macros.h> +#include "chromeos-dbus-bindings/header_generator.h" + namespace base { class FilePath; @@ -19,9 +22,9 @@ namespace chromeos_dbus_bindings { struct Interface; -class MethodNameGenerator { +class MethodNameGenerator : public HeaderGenerator { public: - static bool GenerateMethodNames(const Interface &interface, + static bool GenerateMethodNames(const std::vector<Interface>& interfaces, const base::FilePath& output_file); static std::string GenerateMethodNameConstant(const std::string& method_name); diff --git a/chromeos-dbus-bindings/method_name_generator_unittest.cc b/chromeos-dbus-bindings/method_name_generator_unittest.cc index dc461d6..d237350 100644 --- a/chromeos-dbus-bindings/method_name_generator_unittest.cc +++ b/chromeos-dbus-bindings/method_name_generator_unittest.cc @@ -5,6 +5,7 @@ #include "chromeos-dbus-bindings/method_name_generator.h" #include <string> +#include <vector> #include <base/file_util.h> #include <base/files/file_path.h> @@ -23,10 +24,14 @@ namespace { const char kMethodName0[] = "Zircon"; const char kMethodName1[] = "Encrusted"; const char kMethodName2[] = "Tweezers"; -const char kExpectedOutput[] = - "const char kZirconMethod[] = \"Zircon\";\n" - "const char kEncrustedMethod[] = \"Encrusted\";\n" - "const char kTweezersMethod[] = \"Tweezers\";\n"; +const char kExpectedOutput[] = R"( +namespace MyInterface { +const char kZirconMethod[] = "Zircon"; +const char kEncrustedMethod[] = "Encrusted"; +const char kTweezersMethod[] = "Tweezers"; +} // namespace MyInterface +)"; + } // namespace class MethodNameGeneratorTest : public Test { @@ -49,11 +54,13 @@ class MethodNameGeneratorTest : public Test { TEST_F(MethodNameGeneratorTest, GnerateMethodNames) { Interface interface; + interface.name = "MyInterface"; interface.methods.emplace_back(kMethodName0); interface.methods.emplace_back(kMethodName1); interface.methods.emplace_back(kMethodName2); base::FilePath output_path = temp_dir_.path().Append("output.h"); - EXPECT_TRUE(MethodNameGenerator::GenerateMethodNames(interface, output_path)); + EXPECT_TRUE(MethodNameGenerator::GenerateMethodNames({interface}, + output_path)); string contents; EXPECT_TRUE(base::ReadFileToString(output_path, &contents)); EXPECT_STREQ(kExpectedOutput, contents.c_str()); diff --git a/chromeos-dbus-bindings/proxy_generator.cc b/chromeos-dbus-bindings/proxy_generator.cc index 34b44c0..67cba22 100644 --- a/chromeos-dbus-bindings/proxy_generator.cc +++ b/chromeos-dbus-bindings/proxy_generator.cc @@ -6,6 +6,7 @@ #include <base/logging.h> #include <base/strings/stringprintf.h> +#include <chromeos/strings/string_utils.h> #include "chromeos-dbus-bindings/dbus_signature.h" #include "chromeos-dbus-bindings/indented_text.h" @@ -18,12 +19,22 @@ namespace chromeos_dbus_bindings { // static bool ProxyGenerator::GenerateProxy( - const Interface& interface, + const std::vector<Interface>& interfaces, const base::FilePath& output_file) { IndentedText text; - text.AddLine(StringPrintf("// Automatic generation of interface for %s", - interface.name.c_str())); - string header_guard = GenerateHeaderGuard(output_file, interface.name); + CHECK(!interfaces.empty()) << "At least one interface must be provided"; + vector<string> namespaces; + string proxy_name; + CHECK(GetNamespacesAndClassName(interfaces.front().name, + &namespaces, + &proxy_name)); + proxy_name += "Proxy"; + + text.AddLine("// Automatic generation of D-Bus interfaces:"); + for (const auto& interface : interfaces) { + text.AddLine(StringPrintf("// - %s", interface.name.c_str())); + } + string header_guard = GenerateHeaderGuard(output_file, proxy_name); text.AddLine(StringPrintf("#ifndef %s", header_guard.c_str())); text.AddLine(StringPrintf("#define %s", header_guard.c_str())); text.AddLine("#include <string>"); @@ -44,24 +55,22 @@ bool ProxyGenerator::GenerateProxy( text.AddLine("#include <dbus/object_proxy.h>"); text.AddBlankLine(); - vector<string> namespaces; - string class_name; - CHECK(GetNamespacesAndClassName(interface.name, &namespaces, &class_name)); for (const auto& space : namespaces) { text.AddLine(StringPrintf("namespace %s {", space.c_str())); } text.AddBlankLine(); - string proxy_name = StringPrintf("%sProxy", class_name.c_str()); text.AddLine(StringPrintf("class %s {", proxy_name.c_str())); text.AddLineWithOffset("public:", kScopeOffset); text.PushOffset(kBlockOffset); - AddMethodInterface(interface, &text); - AddConstructor(interface, proxy_name, &text); + AddSignalReceiver(interfaces, &text); + AddConstructor(interfaces, proxy_name, &text); AddDestructor(proxy_name, &text); AddSignalConnectedCallback(&text); - for (const auto& method : interface.methods) { - AddMethodProxy(method, interface.name, &text); + for (const auto& interface : interfaces) { + for (const auto& method : interface.methods) { + AddMethodProxy(method, interface.name, &text); + } } text.PopOffset(); @@ -91,9 +100,9 @@ bool ProxyGenerator::GenerateProxy( } // static -void ProxyGenerator::AddConstructor(const Interface& interface, - const string& class_name, - IndentedText* text) { +void ProxyGenerator::AddConstructor(const vector<Interface>& interfaces, + const string& class_name, + IndentedText* text) { IndentedText block; block.AddLine(StringPrintf("%s(", class_name.c_str())); block.PushOffset(kLineContinuationOffset); @@ -112,26 +121,28 @@ void ProxyGenerator::AddConstructor(const Interface& interface, block.PopOffset(); block.PopOffset(); block.PushOffset(kBlockOffset); - for (const auto& signal : interface.signals) { - block.AddLine("chromeos::dbus_utils::ConnectToSignal("); - block.PushOffset(kLineContinuationOffset); - block.AddLine("dbus_object_proxy_,"); - block.AddLine(StringPrintf("\"%s\",", interface.name.c_str())); - block.AddLine(StringPrintf("\"%s\",", signal.name.c_str())); - block.AddLine("base::Bind("); - block.PushOffset(kLineContinuationOffset); - block.AddLine(StringPrintf( + for (const auto& interface : interfaces) { + for (const auto& signal : interface.signals) { + block.AddLine("chromeos::dbus_utils::ConnectToSignal("); + block.PushOffset(kLineContinuationOffset); + block.AddLine("dbus_object_proxy_,"); + block.AddLine(StringPrintf("\"%s\",", interface.name.c_str())); + block.AddLine(StringPrintf("\"%s\",", signal.name.c_str())); + block.AddLine("base::Bind("); + block.PushOffset(kLineContinuationOffset); + block.AddLine(StringPrintf( "&SignalReceiver::%s,", GetHandlerNameForSignal(signal.name).c_str())); - block.AddLine("base::Unretained(signal_receiver)),"); - block.PopOffset(); - block.AddLine("base::Bind("); - block.PushOffset(kLineContinuationOffset); - block.AddLine(StringPrintf( + block.AddLine("base::Unretained(signal_receiver)),"); + block.PopOffset(); + block.AddLine("base::Bind("); + block.PushOffset(kLineContinuationOffset); + block.AddLine(StringPrintf( "&%s::OnDBusSignalConnected,", class_name.c_str())); - block.AddLine("base::Unretained(this)));"); - block.PopOffset(); - block.PopOffset(); + block.AddLine("base::Unretained(this)));"); + block.PopOffset(); + block.PopOffset(); + } } block.PopOffset(); block.AddLine("}"); @@ -179,35 +190,44 @@ void ProxyGenerator::AddSignalConnectedCallback(IndentedText* text) { } // static -void ProxyGenerator::AddMethodInterface(const Interface& interface, - IndentedText* text) { +void ProxyGenerator::AddSignalReceiver(const vector<Interface>& interfaces, + IndentedText* text) { IndentedText block; block.AddLine("class SignalReceiver {"); block.AddLineWithOffset("public:", kScopeOffset); block.PushOffset(kBlockOffset); DbusSignature signature; - for (const auto& signal : interface.signals) { - if (signal.arguments.empty()) { - block.AddLine(StringPrintf("virtual void %s() {}", - GetHandlerNameForSignal(signal.name).c_str())); - continue; - } - block.AddLine(StringPrintf("virtual void %s(", - GetHandlerNameForSignal(signal.name).c_str())); - block.PushOffset(kLineContinuationOffset); - string last_argument; - vector<string> argument_types; - for (const auto& argument : signal.arguments) { - if (!last_argument.empty()) { - block.AddLine(StringPrintf("%s,", last_argument.c_str())); + for (const auto& interface : interfaces) { + for (const auto& signal : interface.signals) { + string signal_begin = StringPrintf( + "virtual void %s(", + GetHandlerNameForSignal(signal.name).c_str()); + string signal_end = ") {}"; + + if (signal.arguments.empty()) { + block.AddLine(signal_begin + signal_end); + continue; } - CHECK(signature.Parse(argument.type, &last_argument)); - if (!IsIntegralType(last_argument)) { - last_argument = StringPrintf("const %s&", last_argument.c_str()); + block.AddLine(signal_begin); + block.PushOffset(kLineContinuationOffset); + string last_argument; + vector<string> argument_types; + for (const auto& argument : signal.arguments) { + if (!last_argument.empty()) { + block.AddLine(StringPrintf("%s,", last_argument.c_str())); + } + CHECK(signature.Parse(argument.type, &last_argument)); + if (!IsIntegralType(last_argument)) { + last_argument = StringPrintf("const %s&", last_argument.c_str()); + } + if (!argument.name.empty()) { + last_argument += ' '; + last_argument += argument.name; + } } + block.AddLine(last_argument + signal_end); + block.PopOffset(); } - block.AddLine(StringPrintf("%s) {}", last_argument.c_str())); - block.PopOffset(); } block.PopOffset(); block.AddLine("};"); @@ -220,21 +240,8 @@ void ProxyGenerator::AddMethodProxy(const Interface::Method& method, const string& interface_name, IndentedText* text) { IndentedText block; - string return_type("void"); - bool is_void_method = true; DbusSignature signature; - if (!method.output_arguments.empty()) { - if (method.output_arguments.size() > 1) { - LOG(WARNING) << "Method " << method.name << " has " - << method.output_arguments.size() - << " output arguments which is unsupported."; - return; - } - CHECK(signature.Parse(method.output_arguments[0].type, &return_type)); - is_void_method = false; - } - block.AddLine(StringPrintf("virtual %s %s(", - return_type.c_str(), method.name.c_str())); + block.AddLine(StringPrintf("virtual bool %s(", method.name.c_str())); block.PushOffset(kLineContinuationOffset); vector<string> argument_names; int argument_number = 0; @@ -244,15 +251,20 @@ void ProxyGenerator::AddMethodProxy(const Interface::Method& method, if (!IsIntegralType(argument_type)) { argument_type = StringPrintf("const %s&", argument_type.c_str()); } - ++argument_number; - string argument_prefix(argument.name.empty() ? - StringPrintf("argument%d", argument_number) : - argument.name); - string argument_name(StringPrintf("%s_in", argument_prefix.c_str())); + string argument_name = GetArgName("in", argument.name, ++argument_number); argument_names.push_back(argument_name); block.AddLine(StringPrintf( "%s %s,", argument_type.c_str(), argument_name.c_str())); } + vector<string> out_param_names{"response.get()", "error"}; + for (const auto& argument : method.output_arguments) { + string argument_type; + CHECK(signature.Parse(argument.type, &argument_type)); + string argument_name = GetArgName("out", argument.name, ++argument_number); + out_param_names.push_back(argument_name); + block.AddLine(StringPrintf( + "%s* %s,", argument_type.c_str(), argument_name.c_str())); + } block.AddLine("chromeos::ErrorPtr* error) {"); block.PopOffset(); block.PushOffset(kBlockOffset); @@ -270,21 +282,11 @@ void ProxyGenerator::AddMethodProxy(const Interface::Method& method, block.AddLine(StringPrintf("%s);", last_argument.c_str())); block.PopOffset(); - if (!is_void_method) { - block.AddLine(StringPrintf("%s result{};", return_type.c_str())); - } - block.AddLine("if (!response) {"); - block.AddLineWithOffset(StringPrintf( - "return%s;", is_void_method ? "" : " result"), kBlockOffset); - block.AddLine("}"); - block.AddLine("chromeos::dbus_utils::ExtractMethodCallResults("); - block.AddLineWithOffset(StringPrintf("response.get(), error%s);", - is_void_method ? "" : ", &result"), - kLineContinuationOffset); - if (!is_void_method) { - block.AddLine("return result;"); - } - + block.AddLine("return response && " + "chromeos::dbus_utils::ExtractMethodCallResults("); + block.PushOffset(kLineContinuationOffset); + block.AddLine(chromeos::string_utils::Join(", ", out_param_names) + ");"); + block.PopOffset(); block.PopOffset(); block.AddLine("}"); diff --git a/chromeos-dbus-bindings/proxy_generator.h b/chromeos-dbus-bindings/proxy_generator.h index 66dd8ba..b8f7e7b 100644 --- a/chromeos-dbus-bindings/proxy_generator.h +++ b/chromeos-dbus-bindings/proxy_generator.h @@ -27,14 +27,14 @@ struct Interface; class ProxyGenerator : public HeaderGenerator { public: - static bool GenerateProxy(const Interface& interface, + static bool GenerateProxy(const std::vector<Interface>& interfaces, const base::FilePath& output_file); private: friend class ProxyGeneratorTest; // Generates the constructor and destructor for the proxy. - static void AddConstructor(const Interface& interface, + static void AddConstructor(const std::vector<Interface>& interfaces, const std::string& class_name, IndentedText* text); static void AddDestructor(const std::string& class_name, @@ -44,8 +44,8 @@ class ProxyGenerator : public HeaderGenerator { static void AddSignalConnectedCallback(IndentedText *text); // Generates the method signatures for signal receivers. - static void AddMethodInterface(const Interface& interface, - IndentedText* text); + static void AddSignalReceiver(const std::vector<Interface>& interfaces, + IndentedText* text); // Generates a native C++ method which calls a D-Bus method on the proxy. static void AddMethodProxy(const Interface::Method& interface, diff --git a/chromeos-dbus-bindings/proxy_generator_unittest.cc b/chromeos-dbus-bindings/proxy_generator_unittest.cc index 1149de9..7bb1ab9 100644 --- a/chromeos-dbus-bindings/proxy_generator_unittest.cc +++ b/chromeos-dbus-bindings/proxy_generator_unittest.cc @@ -23,6 +23,7 @@ namespace chromeos_dbus_bindings { namespace { const char kInterfaceName[] = "org.chromium.TestInterface"; +const char kInterfaceName2[] = "org.chromium.TestInterface2"; const char kMethod1Name[] = "Elements"; const char kMethod1Return[] = "s"; const char kMethod1Argument1[] = "s"; @@ -34,6 +35,11 @@ const char kMethod2Return[] = "x"; const char kMethod3Name[] = "NiceWeatherForDucks"; const char kMethod3Argument1[] = "b"; const char kMethod4Name[] = "ExperimentNumberSix"; +const char kMethod5Name[] = "GetPersonInfo"; +const char kMethod5Argument1[] = "s"; +const char kMethod5ArgumentName1[] = "name"; +const char kMethod5Argument2[] = "i"; +const char kMethod5ArgumentName2[] = "age"; const char kSignal1Name[] = "Closer"; const char kSignal2Name[] = "TheCurseOfKaZar"; const char kSignal2Argument1[] = "as"; @@ -114,68 +120,66 @@ class TestInterfaceProxy { << object_path_.value(); } } - virtual std::string Elements( - const std::string& space_walk_in, - const std::vector<dbus::ObjectPath>& ramblin_man_in, + virtual bool Elements( + const std::string& in_space_walk, + const std::vector<dbus::ObjectPath>& in_ramblin_man, + std::string* out_3, chromeos::ErrorPtr* error) { auto response = chromeos::dbus_utils::CallMethodAndBlock( dbus_object_proxy_, "org.chromium.TestInterface", "Elements", error, - space_walk_in, - ramblin_man_in); - std::string result{}; - if (!response) { - return result; - } - chromeos::dbus_utils::ExtractMethodCallResults( - response.get(), error, &result); - return result; + in_space_walk, + in_ramblin_man); + return response && chromeos::dbus_utils::ExtractMethodCallResults( + response.get(), error, out_3); } - virtual int64_t ReturnToPatagonia( + virtual bool ReturnToPatagonia( + int64_t* out_1, chromeos::ErrorPtr* error) { auto response = chromeos::dbus_utils::CallMethodAndBlock( dbus_object_proxy_, "org.chromium.TestInterface", "ReturnToPatagonia", error); - int64_t result{}; - if (!response) { - return result; - } - chromeos::dbus_utils::ExtractMethodCallResults( - response.get(), error, &result); - return result; + return response && chromeos::dbus_utils::ExtractMethodCallResults( + response.get(), error, out_1); } - virtual void NiceWeatherForDucks( - bool argument1_in, + virtual bool NiceWeatherForDucks( + bool in_1, chromeos::ErrorPtr* error) { auto response = chromeos::dbus_utils::CallMethodAndBlock( dbus_object_proxy_, "org.chromium.TestInterface", "NiceWeatherForDucks", error, - argument1_in); - if (!response) { - return; - } - chromeos::dbus_utils::ExtractMethodCallResults( + in_1); + return response && chromeos::dbus_utils::ExtractMethodCallResults( response.get(), error); } - virtual void ExperimentNumberSix( + virtual bool ExperimentNumberSix( chromeos::ErrorPtr* error) { auto response = chromeos::dbus_utils::CallMethodAndBlock( dbus_object_proxy_, "org.chromium.TestInterface", "ExperimentNumberSix", error); - if (!response) { - return; - } - chromeos::dbus_utils::ExtractMethodCallResults( + return response && chromeos::dbus_utils::ExtractMethodCallResults( response.get(), error); } + virtual bool GetPersonInfo( + std::string* out_name, + int32_t* out_age, + chromeos::ErrorPtr* error) { + auto response = chromeos::dbus_utils::CallMethodAndBlock( + dbus_object_proxy_, + "org.chromium.TestInterface2", + "GetPersonInfo", + error); + return response && chromeos::dbus_utils::ExtractMethodCallResults( + response.get(), error, out_name, out_age); + } private: scoped_refptr<dbus::Bus> bus_; @@ -234,8 +238,17 @@ TEST_F(ProxyGeneratorTest, GenerateAdaptors) { vector<Interface::Argument>{ {"", kSignal2Argument1}, {"", kSignal2Argument2}}); + Interface interface2; + interface2.name = kInterfaceName2; + interface2.methods.emplace_back( + kMethod5Name, + vector<Interface::Argument>{}, + vector<Interface::Argument>{ + {kMethod5ArgumentName1, kMethod5Argument1}, + {kMethod5ArgumentName2, kMethod5Argument2}}); + vector<Interface> interfaces{interface, interface2}; base::FilePath output_path = temp_dir_.path().Append("output.h"); - EXPECT_TRUE(ProxyGenerator::GenerateProxy(interface, output_path)); + EXPECT_TRUE(ProxyGenerator::GenerateProxy(interfaces, output_path)); string contents; EXPECT_TRUE(base::ReadFileToString(output_path, &contents)); // The header guards contain the (temporary) filename, so we search for diff --git a/chromeos-dbus-bindings/xml_interface_parser.cc b/chromeos-dbus-bindings/xml_interface_parser.cc index 7189ec4..3baef84 100644 --- a/chromeos-dbus-bindings/xml_interface_parser.cc +++ b/chromeos-dbus-bindings/xml_interface_parser.cc @@ -23,13 +23,27 @@ const char XmlInterfaceParser::kMethodTag[] = "method"; const char XmlInterfaceParser::kNodeTag[] = "node"; const char XmlInterfaceParser::kSignalTag[] = "signal"; const char XmlInterfaceParser::kPropertyTag[] = "property"; +const char XmlInterfaceParser::kAnnotationTag[] = "annotation"; const char XmlInterfaceParser::kNameAttribute[] = "name"; const char XmlInterfaceParser::kTypeAttribute[] = "type"; +const char XmlInterfaceParser::kValueAttribute[] = "value"; const char XmlInterfaceParser::kDirectionAttribute[] = "direction"; const char XmlInterfaceParser::kAccessAttribute[] = "access"; const char XmlInterfaceParser::kArgumentDirectionIn[] = "in"; const char XmlInterfaceParser::kArgumentDirectionOut[] = "out"; +const char XmlInterfaceParser::kTrue[] = "true"; +const char XmlInterfaceParser::kFalse[] = "false"; + +const char XmlInterfaceParser::kMethodConst[] = + "org.chromium.DBus.Method.Const"; + +const char XmlInterfaceParser::kMethodKind[] = "org.chromium.DBus.Method.Kind"; +const char XmlInterfaceParser::kMethodKindSimple[] = "simple"; +const char XmlInterfaceParser::kMethodKindNormal[] = "normal"; +const char XmlInterfaceParser::kMethodKindAsync[] = "async"; +const char XmlInterfaceParser::kMethodKindRaw[] = "raw"; + bool XmlInterfaceParser::ParseXmlInterfaceFile( const base::FilePath& interface_file) { string contents; @@ -62,36 +76,84 @@ bool XmlInterfaceParser::ParseXmlInterfaceFile( void XmlInterfaceParser::OnOpenElement( const string& element_name, const XmlAttributeMap& attributes) { + string prev_element; + if (!element_path_.empty()) + prev_element = element_path_.back(); element_path_.push_back(element_name); - if (element_path_ == vector<string> { kNodeTag, kInterfaceTag }) { + if (element_name == kNodeTag) { + CHECK(prev_element.empty()) + << "Unexpected tag " << element_name << " inside " << prev_element; + } else if (element_name == kInterfaceTag) { + CHECK_EQ(kNodeTag, prev_element) + << "Unexpected tag " << element_name << " inside " << prev_element; string interface_name = GetValidatedElementName(attributes, kInterfaceTag); - CHECK(interface_.name.empty()) - << "Found a second interface named " << interface_name << ". " - << "Interface " << interface_.name << " has already been parsed."; - interface_.name = interface_name; - } else if (element_path_ == vector<string> { - kNodeTag, kInterfaceTag, kMethodTag }) { - interface_.methods.push_back( + interfaces_.emplace_back(interface_name, + std::vector<Interface::Method>{}, + std::vector<Interface::Signal>{}, + std::vector<Interface::Property>{}); + } else if (element_name == kMethodTag) { + CHECK_EQ(kInterfaceTag, prev_element) + << "Unexpected tag " << element_name << " inside " << prev_element; + interfaces_.back().methods.push_back( Interface::Method(GetValidatedElementName(attributes, kMethodTag))); - } else if (element_path_ == vector<string> { - kNodeTag, kInterfaceTag, kMethodTag, kArgumentTag }) { - AddMethodArgument(attributes); - } else if (element_path_ == vector<string> { - kNodeTag, kInterfaceTag, kSignalTag }) { - interface_.signals.push_back( + } else if (element_name == kSignalTag) { + CHECK_EQ(kInterfaceTag, prev_element) + << "Unexpected tag " << element_name << " inside " << prev_element; + interfaces_.back().signals.push_back( Interface::Signal(GetValidatedElementName(attributes, kSignalTag))); - } else if (element_path_ == vector<string> { - kNodeTag, kInterfaceTag, kSignalTag, kArgumentTag }) { - AddSignalArgument(attributes); - } else if (element_path_ == vector<string> { - kNodeTag, kInterfaceTag, kPropertyTag }) { - interface_.properties.push_back(ParseProperty(attributes)); + } else if (element_name == kPropertyTag) { + CHECK_EQ(kInterfaceTag, prev_element) + << "Unexpected tag " << element_name << " inside " << prev_element; + interfaces_.back().properties.push_back(ParseProperty(attributes)); + } else if (element_name == kArgumentTag) { + if (prev_element == kMethodTag) { + AddMethodArgument(attributes); + } else if (prev_element == kSignalTag) { + AddSignalArgument(attributes); + } else { + LOG(FATAL) << "Unexpected tag " << element_name + << " inside " << prev_element; + } + } else if (element_name == kAnnotationTag) { + string element_path = prev_element + " " + element_name; + string name = GetValidatedElementAttribute(attributes, element_path, + kNameAttribute); + // Value is optional. Default to empty string if omitted. + string value; + GetElementAttribute(attributes, element_path, kValueAttribute, &value); + if (prev_element == kInterfaceTag) { + // Parse interface annotations... + } else if (prev_element == kMethodTag) { + // Parse method annotations... + Interface::Method& method = interfaces_.back().methods.back(); + if (name == kMethodConst) { + CHECK(value == kTrue || value == kFalse); + method.is_const = (value == kTrue); + } else if (name == kMethodKind) { + if (value == kMethodKindSimple) { + method.kind = Interface::Method::Kind::kSimple; + } else if (value == kMethodKindNormal) { + method.kind = Interface::Method::Kind::kNormal; + } else if (value == kMethodKindAsync) { + method.kind = Interface::Method::Kind::kAsync; + } else if (value == kMethodKindRaw) { + method.kind = Interface::Method::Kind::kRaw; + } else { + LOG(FATAL) << "Invalid method kind: " << value; + } + } + } else if (prev_element == kSignalTag) { + // Parse signal annotations... + } else if (prev_element == kPropertyTag) { + // Parse property annotations... + } else { + LOG(FATAL) << "Unexpected tag " << element_name + << " inside " << prev_element; + } } } void XmlInterfaceParser::AddMethodArgument(const XmlAttributeMap& attributes) { - CHECK(!interface_.methods.empty()) - << " we have a method argument but the interface has no methods"; string argument_direction; bool is_direction_paramter_present = GetElementAttribute( attributes, @@ -101,9 +163,9 @@ void XmlInterfaceParser::AddMethodArgument(const XmlAttributeMap& attributes) { vector<Interface::Argument>* argument_list = nullptr; if (!is_direction_paramter_present || argument_direction == kArgumentDirectionIn) { - argument_list = &interface_.methods.back().input_arguments; + argument_list = &interfaces_.back().methods.back().input_arguments; } else if (argument_direction == kArgumentDirectionOut) { - argument_list = &interface_.methods.back().output_arguments; + argument_list = &interfaces_.back().methods.back().output_arguments; } else { LOG(FATAL) << "Unknown method argument direction " << argument_direction; } @@ -111,9 +173,7 @@ void XmlInterfaceParser::AddMethodArgument(const XmlAttributeMap& attributes) { } void XmlInterfaceParser::AddSignalArgument(const XmlAttributeMap& attributes) { - CHECK(interface_.signals.size()) - << " we have a signal argument but the interface has no signals"; - interface_.signals.back().arguments.push_back( + interfaces_.back().signals.back().arguments.push_back( ParseArgument(attributes, kSignalTag)); } diff --git a/chromeos-dbus-bindings/xml_interface_parser.h b/chromeos-dbus-bindings/xml_interface_parser.h index f890806..059f1d6 100644 --- a/chromeos-dbus-bindings/xml_interface_parser.h +++ b/chromeos-dbus-bindings/xml_interface_parser.h @@ -31,7 +31,7 @@ class XmlInterfaceParser { virtual ~XmlInterfaceParser() = default; virtual bool ParseXmlInterfaceFile(const base::FilePath& interface_file); - const Interface& interface() const { return interface_; } + const std::vector<Interface>& interfaces() const { return interfaces_; } private: friend class XmlInterfaceParserTest; @@ -43,17 +43,31 @@ class XmlInterfaceParser { static const char kNodeTag[]; static const char kSignalTag[]; static const char kPropertyTag[]; + static const char kAnnotationTag[]; // XML attribute names. static const char kNameAttribute[]; static const char kTypeAttribute[]; static const char kDirectionAttribute[]; static const char kAccessAttribute[]; + static const char kValueAttribute[]; // XML argument directions. static const char kArgumentDirectionIn[]; static const char kArgumentDirectionOut[]; + // XML annotations. + static const char kTrue[]; + static const char kFalse[]; + + static const char kMethodConst[]; + + static const char kMethodKind[]; + static const char kMethodKindSimple[]; + static const char kMethodKindNormal[]; + static const char kMethodKindAsync[]; + static const char kMethodKindRaw[]; + // Element callbacks on |this| called by HandleElementStart() and // HandleElementEnd(), respectively. void OnOpenElement(const std::string& element_name, @@ -78,7 +92,7 @@ class XmlInterfaceParser { const std::string& element_type, const std::string& element_key); - // Calls GetValidatedElementAttribute() for for the "name" property. + // Calls GetValidatedElementAttribute() for the "name" property. static std::string GetValidatedElementName( const XmlAttributeMap& attributes, const std::string& element_type); @@ -97,7 +111,7 @@ class XmlInterfaceParser { static void HandleElementEnd(void* user_data, const XML_Char* element); // The output of the parse. - Interface interface_; + std::vector<Interface> interfaces_; // Tracks where in the element traversal our parse has taken us. std::vector<std::string> element_path_; diff --git a/chromeos-dbus-bindings/xml_interface_parser_unittest.cc b/chromeos-dbus-bindings/xml_interface_parser_unittest.cc index 9c61253..7f861e3 100644 --- a/chromeos-dbus-bindings/xml_interface_parser_unittest.cc +++ b/chromeos-dbus-bindings/xml_interface_parser_unittest.cc @@ -12,6 +12,7 @@ #include "chromeos-dbus-bindings/interface.h" using std::string; +using std::vector; using testing::Test; namespace chromeos_dbus_bindings { @@ -20,22 +21,25 @@ namespace { const char kBadInterfaceFileContents0[] = "This has no resemblance to XML"; const char kBadInterfaceFileContents1[] = "<node>"; -const char kGoodInterfaceFileContents[] = - "<node>\n" - " <interface name=\"fi.w1.wpa_supplicant1.Interface\">\n" - " <method name=\"Scan\">\n" - " <arg name=\"args\" type=\"a{sv}\" direction=\"in\"/>\n" - " </method>\n" - " <method name=\"GetBlob\">\n" - " <arg name=\"name\" type=\"s\"/>\n" - " <arg name=\"data\" type=\"ay\" direction=\"out\"/>\n" - " </method>\n" - " <property name=\"Capabilities\" type=\"a{sv}\" access=\"read\"/>\n" - " <signal name=\"BSSRemoved\">\n" - " <arg name=\"BSS\" type=\"o\"/>\n" - " </signal>\n" - " </interface>\n" - "</node>\n"; +const char kGoodInterfaceFileContents[] = R"literal_string( +<node> + <interface name="fi.w1.wpa_supplicant1.Interface"> + <method name="Scan"> + <arg name="args" type="a{sv}" direction="in"/> + <annotation name="org.chromium.DBus.Method.Kind" value="async"/> + </method> + <method name="GetBlob"> + <arg name="name" type="s"/> + <arg name="data" type="ay" direction="out"/> + <annotation name="org.chromium.DBus.Method.Const" value="true"/> + </method> + <property name="Capabilities" type="a{sv}" access="read"/> + <signal name="BSSRemoved"> + <arg name="BSS" type="o"/> + </signal> + </interface> +</node> +)literal_string"; const char kInterfaceName[] = "fi.w1.wpa_supplicant1.Interface"; const char kScanMethod[] = "Scan"; const char kArgsArgument[] = "args"; @@ -77,13 +81,18 @@ TEST_F(XmlInterfaceParserTest, BadInputFile) { TEST_F(XmlInterfaceParserTest, GoodInputFile) { EXPECT_TRUE(ParseXmlContents(kGoodInterfaceFileContents)); - const Interface& interface = parser_.interface(); + const vector<Interface>& interfaces = parser_.interfaces(); + ASSERT_EQ(1, interfaces.size()); + const Interface& interface = interfaces.back(); + EXPECT_EQ(kInterfaceName, interface.name); ASSERT_EQ(2, interface.methods.size()); ASSERT_EQ(1, interface.signals.size()); // <method name="Scan"> EXPECT_EQ(kScanMethod, interface.methods[0].name); + EXPECT_EQ(Interface::Method::Kind::kAsync, interface.methods[0].kind); + EXPECT_FALSE(interface.methods[0].is_const); ASSERT_EQ(1, interface.methods[0].input_arguments.size()); // <arg name="args" type="a{sv}" direction="in"/> @@ -94,10 +103,12 @@ TEST_F(XmlInterfaceParserTest, GoodInputFile) { // <method name="GetBlob"> EXPECT_EQ(kGetBlobMethod, interface.methods[1].name); + EXPECT_EQ(Interface::Method::Kind::kNormal, interface.methods[1].kind); + EXPECT_TRUE(interface.methods[1].is_const); EXPECT_EQ(1, interface.methods[1].input_arguments.size()); EXPECT_EQ(1, interface.methods[1].output_arguments.size()); - // <arg name="name" type="s"/> (direciton="in" is implicit) + // <arg name="name" type="s"/> (direction="in" is implicit) EXPECT_EQ(kNameArgument, interface.methods[1].input_arguments[0].name); EXPECT_EQ(kStringType, interface.methods[1].input_arguments[0].type); |