普通文本  |  1424行  |  43.49 KB

// Copyright 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos-dbus-bindings/proxy_generator.h"

#include <string>
#include <vector>

#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/files/scoped_temp_dir.h>
#include <gtest/gtest.h>

#include "chromeos-dbus-bindings/interface.h"
#include "chromeos-dbus-bindings/test_utils.h"

using std::string;
using std::vector;
using testing::Test;

namespace chromeos_dbus_bindings {

namespace {

const char kDBusTypeArryOfObjects[] = "ao";
const char kDBusTypeArryOfStrings[] = "as";
const char kDBusTypeBool[] = "b";
const char kDBusTypeByte[] = "y";
const char kDBusTypeInt32[] = "i";
const char kDBusTypeInt64[] = "x";
const char kDBusTypeString[] = "s";

const char kExpectedContent[] = R"literal_string(
#include <memory>
#include <string>
#include <vector>

#include <base/bind.h>
#include <base/callback.h>
#include <base/logging.h>
#include <base/macros.h>
#include <base/memory/ref_counted.h>
#include <brillo/any.h>
#include <brillo/dbus/dbus_method_invoker.h>
#include <brillo/dbus/dbus_property.h>
#include <brillo/dbus/dbus_signal_handler.h>
#include <brillo/errors/error.h>
#include <brillo/variant_dictionary.h>
#include <dbus/bus.h>
#include <dbus/message.h>
#include <dbus/object_manager.h>
#include <dbus/object_path.h>
#include <dbus/object_proxy.h>

namespace org {
namespace chromium {

// Abstract interface proxy for org::chromium::TestInterface.
class TestInterfaceProxyInterface {
 public:
  virtual ~TestInterfaceProxyInterface() = default;

  virtual bool Elements(
      const std::string& in_space_walk,
      const std::vector<dbus::ObjectPath>& in_ramblin_man,
      std::string* out_3,
      brillo::ErrorPtr* error,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;

  virtual void ElementsAsync(
      const std::string& in_space_walk,
      const std::vector<dbus::ObjectPath>& in_ramblin_man,
      const base::Callback<void(const std::string&)>& success_callback,
      const base::Callback<void(brillo::Error*)>& error_callback,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;

  virtual bool ReturnToPatagonia(
      int64_t* out_1,
      brillo::ErrorPtr* error,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;

  virtual void ReturnToPatagoniaAsync(
      const base::Callback<void(int64_t)>& success_callback,
      const base::Callback<void(brillo::Error*)>& error_callback,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;

  virtual bool NiceWeatherForDucks(
      bool in_1,
      brillo::ErrorPtr* error,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;

  virtual void NiceWeatherForDucksAsync(
      bool in_1,
      const base::Callback<void()>& success_callback,
      const base::Callback<void(brillo::Error*)>& error_callback,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;

  // Comment line1
  // line2
  virtual bool ExperimentNumberSix(
      brillo::ErrorPtr* error,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;

  // Comment line1
  // line2
  virtual void ExperimentNumberSixAsync(
      const base::Callback<void()>& success_callback,
      const base::Callback<void(brillo::Error*)>& error_callback,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;

  virtual void RegisterCloserSignalHandler(
      const base::Closure& signal_callback,
      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) = 0;

  virtual void RegisterTheCurseOfKaZarSignalHandler(
      const base::Callback<void(const std::vector<std::string>&,
                                uint8_t)>& signal_callback,
      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) = 0;

  virtual const dbus::ObjectPath& GetObjectPath() const = 0;
};

}  // namespace chromium
}  // namespace org

namespace org {
namespace chromium {

// Interface proxy for org::chromium::TestInterface.
class TestInterfaceProxy final : public TestInterfaceProxyInterface {
 public:
  TestInterfaceProxy(
      const scoped_refptr<dbus::Bus>& bus,
      const std::string& service_name) :
          bus_{bus},
          service_name_{service_name},
          dbus_object_proxy_{
              bus_->GetObjectProxy(service_name_, object_path_)} {
  }

  ~TestInterfaceProxy() override {
  }

  void RegisterCloserSignalHandler(
      const base::Closure& signal_callback,
      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) override {
    brillo::dbus_utils::ConnectToSignal(
        dbus_object_proxy_,
        "org.chromium.TestInterface",
        "Closer",
        signal_callback,
        on_connected_callback);
  }

  void RegisterTheCurseOfKaZarSignalHandler(
      const base::Callback<void(const std::vector<std::string>&,
                                uint8_t)>& signal_callback,
      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) override {
    brillo::dbus_utils::ConnectToSignal(
        dbus_object_proxy_,
        "org.chromium.TestInterface",
        "TheCurseOfKaZar",
        signal_callback,
        on_connected_callback);
  }

  void ReleaseObjectProxy(const base::Closure& callback) {
    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
  }

  const dbus::ObjectPath& GetObjectPath() const override {
    return object_path_;
  }

  dbus::ObjectProxy* GetObjectProxy() const { return dbus_object_proxy_; }

  bool Elements(
      const std::string& in_space_walk,
      const std::vector<dbus::ObjectPath>& in_ramblin_man,
      std::string* out_3,
      brillo::ErrorPtr* error,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
    auto response = brillo::dbus_utils::CallMethodAndBlockWithTimeout(
        timeout_ms,
        dbus_object_proxy_,
        "org.chromium.TestInterface",
        "Elements",
        error,
        in_space_walk,
        in_ramblin_man);
    return response && brillo::dbus_utils::ExtractMethodCallResults(
        response.get(), error, out_3);
  }

  void ElementsAsync(
      const std::string& in_space_walk,
      const std::vector<dbus::ObjectPath>& in_ramblin_man,
      const base::Callback<void(const std::string&)>& success_callback,
      const base::Callback<void(brillo::Error*)>& error_callback,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
    brillo::dbus_utils::CallMethodWithTimeout(
        timeout_ms,
        dbus_object_proxy_,
        "org.chromium.TestInterface",
        "Elements",
        success_callback,
        error_callback,
        in_space_walk,
        in_ramblin_man);
  }

  bool ReturnToPatagonia(
      int64_t* out_1,
      brillo::ErrorPtr* error,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
    auto response = brillo::dbus_utils::CallMethodAndBlockWithTimeout(
        timeout_ms,
        dbus_object_proxy_,
        "org.chromium.TestInterface",
        "ReturnToPatagonia",
        error);
    return response && brillo::dbus_utils::ExtractMethodCallResults(
        response.get(), error, out_1);
  }

  void ReturnToPatagoniaAsync(
      const base::Callback<void(int64_t)>& success_callback,
      const base::Callback<void(brillo::Error*)>& error_callback,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
    brillo::dbus_utils::CallMethodWithTimeout(
        timeout_ms,
        dbus_object_proxy_,
        "org.chromium.TestInterface",
        "ReturnToPatagonia",
        success_callback,
        error_callback);
  }

  bool NiceWeatherForDucks(
      bool in_1,
      brillo::ErrorPtr* error,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
    auto response = brillo::dbus_utils::CallMethodAndBlockWithTimeout(
        timeout_ms,
        dbus_object_proxy_,
        "org.chromium.TestInterface",
        "NiceWeatherForDucks",
        error,
        in_1);
    return response && brillo::dbus_utils::ExtractMethodCallResults(
        response.get(), error);
  }

  void NiceWeatherForDucksAsync(
      bool in_1,
      const base::Callback<void()>& success_callback,
      const base::Callback<void(brillo::Error*)>& error_callback,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
    brillo::dbus_utils::CallMethodWithTimeout(
        timeout_ms,
        dbus_object_proxy_,
        "org.chromium.TestInterface",
        "NiceWeatherForDucks",
        success_callback,
        error_callback,
        in_1);
  }

  // Comment line1
  // line2
  bool ExperimentNumberSix(
      brillo::ErrorPtr* error,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
    auto response = brillo::dbus_utils::CallMethodAndBlockWithTimeout(
        timeout_ms,
        dbus_object_proxy_,
        "org.chromium.TestInterface",
        "ExperimentNumberSix",
        error);
    return response && brillo::dbus_utils::ExtractMethodCallResults(
        response.get(), error);
  }

  // Comment line1
  // line2
  void ExperimentNumberSixAsync(
      const base::Callback<void()>& success_callback,
      const base::Callback<void(brillo::Error*)>& error_callback,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
    brillo::dbus_utils::CallMethodWithTimeout(
        timeout_ms,
        dbus_object_proxy_,
        "org.chromium.TestInterface",
        "ExperimentNumberSix",
        success_callback,
        error_callback);
  }

 private:
  scoped_refptr<dbus::Bus> bus_;
  std::string service_name_;
  const dbus::ObjectPath object_path_{"/org/chromium/Test"};
  dbus::ObjectProxy* dbus_object_proxy_;

  DISALLOW_COPY_AND_ASSIGN(TestInterfaceProxy);
};

}  // namespace chromium
}  // namespace org

namespace org {
namespace chromium {

// Abstract interface proxy for org::chromium::TestInterface2.
class TestInterface2ProxyInterface {
 public:
  virtual ~TestInterface2ProxyInterface() = default;

  virtual bool GetPersonInfo(
      std::string* out_name,
      int32_t* out_age,
      brillo::ErrorPtr* error,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;

  virtual void GetPersonInfoAsync(
      const base::Callback<void(const std::string& /*name*/, int32_t /*age*/)>& success_callback,
      const base::Callback<void(brillo::Error*)>& error_callback,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) = 0;

  virtual const dbus::ObjectPath& GetObjectPath() const = 0;
};

}  // namespace chromium
}  // namespace org

namespace org {
namespace chromium {

// Interface proxy for org::chromium::TestInterface2.
class TestInterface2Proxy final : public TestInterface2ProxyInterface {
 public:
  TestInterface2Proxy(
      const scoped_refptr<dbus::Bus>& bus,
      const std::string& service_name,
      const dbus::ObjectPath& object_path) :
          bus_{bus},
          service_name_{service_name},
          object_path_{object_path},
          dbus_object_proxy_{
              bus_->GetObjectProxy(service_name_, object_path_)} {
  }

  ~TestInterface2Proxy() override {
  }

  void ReleaseObjectProxy(const base::Closure& callback) {
    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
  }

  const dbus::ObjectPath& GetObjectPath() const override {
    return object_path_;
  }

  dbus::ObjectProxy* GetObjectProxy() const { return dbus_object_proxy_; }

  bool GetPersonInfo(
      std::string* out_name,
      int32_t* out_age,
      brillo::ErrorPtr* error,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
    auto response = brillo::dbus_utils::CallMethodAndBlockWithTimeout(
        timeout_ms,
        dbus_object_proxy_,
        "org.chromium.TestInterface2",
        "GetPersonInfo",
        error);
    return response && brillo::dbus_utils::ExtractMethodCallResults(
        response.get(), error, out_name, out_age);
  }

  void GetPersonInfoAsync(
      const base::Callback<void(const std::string& /*name*/, int32_t /*age*/)>& success_callback,
      const base::Callback<void(brillo::Error*)>& error_callback,
      int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) override {
    brillo::dbus_utils::CallMethodWithTimeout(
        timeout_ms,
        dbus_object_proxy_,
        "org.chromium.TestInterface2",
        "GetPersonInfo",
        success_callback,
        error_callback);
  }

 private:
  scoped_refptr<dbus::Bus> bus_;
  std::string service_name_;
  dbus::ObjectPath object_path_;
  dbus::ObjectProxy* dbus_object_proxy_;

  DISALLOW_COPY_AND_ASSIGN(TestInterface2Proxy);
};

}  // namespace chromium
}  // namespace org
)literal_string";

const char kExpectedContentWithService[] = R"literal_string(
#include <memory>
#include <string>
#include <vector>

#include <base/bind.h>
#include <base/callback.h>
#include <base/logging.h>
#include <base/macros.h>
#include <base/memory/ref_counted.h>
#include <brillo/any.h>
#include <brillo/dbus/dbus_method_invoker.h>
#include <brillo/dbus/dbus_property.h>
#include <brillo/dbus/dbus_signal_handler.h>
#include <brillo/errors/error.h>
#include <brillo/variant_dictionary.h>
#include <dbus/bus.h>
#include <dbus/message.h>
#include <dbus/object_manager.h>
#include <dbus/object_path.h>
#include <dbus/object_proxy.h>

namespace org {
namespace chromium {

// Abstract interface proxy for org::chromium::TestInterface.
class TestInterfaceProxyInterface {
 public:
  virtual ~TestInterfaceProxyInterface() = default;

  virtual void RegisterCloserSignalHandler(
      const base::Closure& signal_callback,
      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) = 0;

  virtual const dbus::ObjectPath& GetObjectPath() const = 0;
};

}  // namespace chromium
}  // namespace org

namespace org {
namespace chromium {

// Interface proxy for org::chromium::TestInterface.
class TestInterfaceProxy final : public TestInterfaceProxyInterface {
 public:
  TestInterfaceProxy(const scoped_refptr<dbus::Bus>& bus) :
      bus_{bus},
      dbus_object_proxy_{
          bus_->GetObjectProxy(service_name_, object_path_)} {
  }

  ~TestInterfaceProxy() override {
  }

  void RegisterCloserSignalHandler(
      const base::Closure& signal_callback,
      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) override {
    brillo::dbus_utils::ConnectToSignal(
        dbus_object_proxy_,
        "org.chromium.TestInterface",
        "Closer",
        signal_callback,
        on_connected_callback);
  }

  void ReleaseObjectProxy(const base::Closure& callback) {
    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
  }

  const dbus::ObjectPath& GetObjectPath() const override {
    return object_path_;
  }

  dbus::ObjectProxy* GetObjectProxy() const { return dbus_object_proxy_; }

 private:
  scoped_refptr<dbus::Bus> bus_;
  const std::string service_name_{"org.chromium.Test"};
  const dbus::ObjectPath object_path_{"/org/chromium/Test"};
  dbus::ObjectProxy* dbus_object_proxy_;

  DISALLOW_COPY_AND_ASSIGN(TestInterfaceProxy);
};

}  // namespace chromium
}  // namespace org

namespace org {
namespace chromium {

// Abstract interface proxy for org::chromium::TestInterface2.
class TestInterface2ProxyInterface {
 public:
  virtual ~TestInterface2ProxyInterface() = default;

  virtual const dbus::ObjectPath& GetObjectPath() const = 0;
};

}  // namespace chromium
}  // namespace org

namespace org {
namespace chromium {

// Interface proxy for org::chromium::TestInterface2.
class TestInterface2Proxy final : public TestInterface2ProxyInterface {
 public:
  TestInterface2Proxy(
      const scoped_refptr<dbus::Bus>& bus,
      const dbus::ObjectPath& object_path) :
          bus_{bus},
          object_path_{object_path},
          dbus_object_proxy_{
              bus_->GetObjectProxy(service_name_, object_path_)} {
  }

  ~TestInterface2Proxy() override {
  }

  void ReleaseObjectProxy(const base::Closure& callback) {
    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
  }

  const dbus::ObjectPath& GetObjectPath() const override {
    return object_path_;
  }

  dbus::ObjectProxy* GetObjectProxy() const { return dbus_object_proxy_; }

 private:
  scoped_refptr<dbus::Bus> bus_;
  const std::string service_name_{"org.chromium.Test"};
  dbus::ObjectPath object_path_;
  dbus::ObjectProxy* dbus_object_proxy_;

  DISALLOW_COPY_AND_ASSIGN(TestInterface2Proxy);
};

}  // namespace chromium
}  // namespace org
)literal_string";

const char kExpectedContentWithObjectManager[] = R"literal_string(
#include <memory>
#include <string>
#include <vector>

#include <base/bind.h>
#include <base/callback.h>
#include <base/logging.h>
#include <base/macros.h>
#include <base/memory/ref_counted.h>
#include <brillo/any.h>
#include <brillo/dbus/dbus_method_invoker.h>
#include <brillo/dbus/dbus_property.h>
#include <brillo/dbus/dbus_signal_handler.h>
#include <brillo/errors/error.h>
#include <brillo/variant_dictionary.h>
#include <dbus/bus.h>
#include <dbus/message.h>
#include <dbus/object_manager.h>
#include <dbus/object_path.h>
#include <dbus/object_proxy.h>

namespace org {
namespace chromium {
class ObjectManagerProxy;
}  // namespace chromium
}  // namespace org

namespace org {
namespace chromium {

// Abstract interface proxy for org::chromium::Itf1.
class Itf1ProxyInterface {
 public:
  virtual ~Itf1ProxyInterface() = default;

  virtual void RegisterCloserSignalHandler(
      const base::Closure& signal_callback,
      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) = 0;

  static const char* DataName() { return "Data"; }
  virtual const std::string& data() const = 0;
  static const char* NameName() { return "Name"; }
  virtual const std::string& name() const = 0;
  virtual void set_name(const std::string& value,
                        const base::Callback<void(bool)>& callback) = 0;

  virtual const dbus::ObjectPath& GetObjectPath() const = 0;

  virtual void SetPropertyChangedCallback(
      const base::Callback<void(Itf1ProxyInterface*, const std::string&)>& callback) = 0;
};

}  // namespace chromium
}  // namespace org

namespace org {
namespace chromium {

// Interface proxy for org::chromium::Itf1.
class Itf1Proxy final : public Itf1ProxyInterface {
 public:
  class PropertySet : public dbus::PropertySet {
   public:
    PropertySet(dbus::ObjectProxy* object_proxy,
                const PropertyChangedCallback& callback)
        : dbus::PropertySet{object_proxy,
                            "org.chromium.Itf1",
                            callback} {
      RegisterProperty(DataName(), &data);
      RegisterProperty(NameName(), &name);
    }

    brillo::dbus_utils::Property<std::string> data;
    brillo::dbus_utils::Property<std::string> name;

   private:
    DISALLOW_COPY_AND_ASSIGN(PropertySet);
  };

  Itf1Proxy(
      const scoped_refptr<dbus::Bus>& bus,
      const std::string& service_name,
      PropertySet* property_set) :
          bus_{bus},
          service_name_{service_name},
          property_set_{property_set},
          dbus_object_proxy_{
              bus_->GetObjectProxy(service_name_, object_path_)} {
  }

  ~Itf1Proxy() override {
  }

  void RegisterCloserSignalHandler(
      const base::Closure& signal_callback,
      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) override {
    brillo::dbus_utils::ConnectToSignal(
        dbus_object_proxy_,
        "org.chromium.Itf1",
        "Closer",
        signal_callback,
        on_connected_callback);
  }

  void ReleaseObjectProxy(const base::Closure& callback) {
    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
  }

  const dbus::ObjectPath& GetObjectPath() const override {
    return object_path_;
  }

  dbus::ObjectProxy* GetObjectProxy() const { return dbus_object_proxy_; }

  void SetPropertyChangedCallback(
      const base::Callback<void(Itf1ProxyInterface*, const std::string&)>& callback) override {
    on_property_changed_ = callback;
  }

  const PropertySet* GetProperties() const { return property_set_; }
  PropertySet* GetProperties() { return property_set_; }

  const std::string& data() const override {
    return property_set_->data.value();
  }

  const std::string& name() const override {
    return property_set_->name.value();
  }

  void set_name(const std::string& value,
                const base::Callback<void(bool)>& callback) override {
    property_set_->name.Set(value, callback);
  }

 private:
  void OnPropertyChanged(const std::string& property_name) {
    if (!on_property_changed_.is_null())
      on_property_changed_.Run(this, property_name);
  }

  scoped_refptr<dbus::Bus> bus_;
  std::string service_name_;
  const dbus::ObjectPath object_path_{"/org/chromium/Test/Object"};
  PropertySet* property_set_;
  base::Callback<void(Itf1ProxyInterface*, const std::string&)> on_property_changed_;
  dbus::ObjectProxy* dbus_object_proxy_;

  friend class org::chromium::ObjectManagerProxy;
  DISALLOW_COPY_AND_ASSIGN(Itf1Proxy);
};

}  // namespace chromium
}  // namespace org

namespace org {
namespace chromium {

// Abstract interface proxy for org::chromium::Itf2.
class Itf2ProxyInterface {
 public:
  virtual ~Itf2ProxyInterface() = default;

  virtual const dbus::ObjectPath& GetObjectPath() const = 0;
};

}  // namespace chromium
}  // namespace org

namespace org {
namespace chromium {

// Interface proxy for org::chromium::Itf2.
class Itf2Proxy final : public Itf2ProxyInterface {
 public:
  class PropertySet : public dbus::PropertySet {
   public:
    PropertySet(dbus::ObjectProxy* object_proxy,
                const PropertyChangedCallback& callback)
        : dbus::PropertySet{object_proxy,
                            "org.chromium.Itf2",
                            callback} {
    }


   private:
    DISALLOW_COPY_AND_ASSIGN(PropertySet);
  };

  Itf2Proxy(
      const scoped_refptr<dbus::Bus>& bus,
      const std::string& service_name,
      const dbus::ObjectPath& object_path) :
          bus_{bus},
          service_name_{service_name},
          object_path_{object_path},
          dbus_object_proxy_{
              bus_->GetObjectProxy(service_name_, object_path_)} {
  }

  ~Itf2Proxy() override {
  }

  void ReleaseObjectProxy(const base::Closure& callback) {
    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
  }

  const dbus::ObjectPath& GetObjectPath() const override {
    return object_path_;
  }

  dbus::ObjectProxy* GetObjectProxy() const { return dbus_object_proxy_; }

 private:
  scoped_refptr<dbus::Bus> bus_;
  std::string service_name_;
  dbus::ObjectPath object_path_;
  dbus::ObjectProxy* dbus_object_proxy_;

  DISALLOW_COPY_AND_ASSIGN(Itf2Proxy);
};

}  // namespace chromium
}  // namespace org

namespace org {
namespace chromium {

class ObjectManagerProxy : public dbus::ObjectManager::Interface {
 public:
  ObjectManagerProxy(const scoped_refptr<dbus::Bus>& bus,
                     const std::string& service_name)
      : bus_{bus},
        service_name_{service_name},
        dbus_object_manager_{bus->GetObjectManager(
            service_name,
            dbus::ObjectPath{"/org/chromium/Test"})} {
    dbus_object_manager_->RegisterInterface("org.chromium.Itf1", this);
    dbus_object_manager_->RegisterInterface("org.chromium.Itf2", this);
  }

  ~ObjectManagerProxy() override {
    dbus_object_manager_->UnregisterInterface("org.chromium.Itf1");
    dbus_object_manager_->UnregisterInterface("org.chromium.Itf2");
  }

  dbus::ObjectManager* GetObjectManagerProxy() const {
    return dbus_object_manager_;
  }

  org::chromium::Itf1ProxyInterface* GetItf1Proxy() {
    if (itf1_instances_.empty())
      return nullptr;
    return itf1_instances_.begin()->second.get();
  }
  std::vector<org::chromium::Itf1ProxyInterface*> GetItf1Instances() const {
    std::vector<org::chromium::Itf1ProxyInterface*> values;
    values.reserve(itf1_instances_.size());
    for (const auto& pair : itf1_instances_)
      values.push_back(pair.second.get());
    return values;
  }
  void SetItf1AddedCallback(
      const base::Callback<void(org::chromium::Itf1ProxyInterface*)>& callback) {
    on_itf1_added_ = callback;
  }
  void SetItf1RemovedCallback(
      const base::Callback<void(const dbus::ObjectPath&)>& callback) {
    on_itf1_removed_ = callback;
  }

  org::chromium::Itf2ProxyInterface* GetItf2Proxy(
      const dbus::ObjectPath& object_path) {
    auto p = itf2_instances_.find(object_path);
    if (p != itf2_instances_.end())
      return p->second.get();
    return nullptr;
  }
  std::vector<org::chromium::Itf2ProxyInterface*> GetItf2Instances() const {
    std::vector<org::chromium::Itf2ProxyInterface*> values;
    values.reserve(itf2_instances_.size());
    for (const auto& pair : itf2_instances_)
      values.push_back(pair.second.get());
    return values;
  }
  void SetItf2AddedCallback(
      const base::Callback<void(org::chromium::Itf2ProxyInterface*)>& callback) {
    on_itf2_added_ = callback;
  }
  void SetItf2RemovedCallback(
      const base::Callback<void(const dbus::ObjectPath&)>& callback) {
    on_itf2_removed_ = callback;
  }

 private:
  void OnPropertyChanged(const dbus::ObjectPath& object_path,
                         const std::string& interface_name,
                         const std::string& property_name) {
    if (interface_name == "org.chromium.Itf1") {
      auto p = itf1_instances_.find(object_path);
      if (p == itf1_instances_.end())
        return;
      p->second->OnPropertyChanged(property_name);
      return;
    }
  }

  void ObjectAdded(
      const dbus::ObjectPath& object_path,
      const std::string& interface_name) override {
    if (interface_name == "org.chromium.Itf1") {
      auto property_set =
          static_cast<org::chromium::Itf1Proxy::PropertySet*>(
              dbus_object_manager_->GetProperties(object_path, interface_name));
      std::unique_ptr<org::chromium::Itf1Proxy> itf1_proxy{
        new org::chromium::Itf1Proxy{bus_, service_name_, property_set}
      };
      auto p = itf1_instances_.emplace(object_path, std::move(itf1_proxy));
      if (!on_itf1_added_.is_null())
        on_itf1_added_.Run(p.first->second.get());
      return;
    }
    if (interface_name == "org.chromium.Itf2") {
      std::unique_ptr<org::chromium::Itf2Proxy> itf2_proxy{
        new org::chromium::Itf2Proxy{bus_, service_name_, object_path}
      };
      auto p = itf2_instances_.emplace(object_path, std::move(itf2_proxy));
      if (!on_itf2_added_.is_null())
        on_itf2_added_.Run(p.first->second.get());
      return;
    }
  }

  void ObjectRemoved(
      const dbus::ObjectPath& object_path,
      const std::string& interface_name) override {
    if (interface_name == "org.chromium.Itf1") {
      auto p = itf1_instances_.find(object_path);
      if (p != itf1_instances_.end()) {
        if (!on_itf1_removed_.is_null())
          on_itf1_removed_.Run(object_path);
        itf1_instances_.erase(p);
      }
      return;
    }
    if (interface_name == "org.chromium.Itf2") {
      auto p = itf2_instances_.find(object_path);
      if (p != itf2_instances_.end()) {
        if (!on_itf2_removed_.is_null())
          on_itf2_removed_.Run(object_path);
        itf2_instances_.erase(p);
      }
      return;
    }
  }

  dbus::PropertySet* CreateProperties(
      dbus::ObjectProxy* object_proxy,
      const dbus::ObjectPath& object_path,
      const std::string& interface_name) override {
    if (interface_name == "org.chromium.Itf1") {
      return new org::chromium::Itf1Proxy::PropertySet{
          object_proxy,
          base::Bind(&ObjectManagerProxy::OnPropertyChanged,
                     weak_ptr_factory_.GetWeakPtr(),
                     object_path,
                     interface_name)
      };
    }
    if (interface_name == "org.chromium.Itf2") {
      return new org::chromium::Itf2Proxy::PropertySet{
          object_proxy,
          base::Bind(&ObjectManagerProxy::OnPropertyChanged,
                     weak_ptr_factory_.GetWeakPtr(),
                     object_path,
                     interface_name)
      };
    }
    LOG(FATAL) << "Creating properties for unsupported interface "
               << interface_name;
    return nullptr;
  }

  scoped_refptr<dbus::Bus> bus_;
  std::string service_name_;
  dbus::ObjectManager* dbus_object_manager_;
  std::map<dbus::ObjectPath,
           std::unique_ptr<org::chromium::Itf1Proxy>> itf1_instances_;
  base::Callback<void(org::chromium::Itf1ProxyInterface*)> on_itf1_added_;
  base::Callback<void(const dbus::ObjectPath&)> on_itf1_removed_;
  std::map<dbus::ObjectPath,
           std::unique_ptr<org::chromium::Itf2Proxy>> itf2_instances_;
  base::Callback<void(org::chromium::Itf2ProxyInterface*)> on_itf2_added_;
  base::Callback<void(const dbus::ObjectPath&)> on_itf2_removed_;
  base::WeakPtrFactory<ObjectManagerProxy> weak_ptr_factory_{this};

  DISALLOW_COPY_AND_ASSIGN(ObjectManagerProxy);
};

}  // namespace chromium
}  // namespace org
)literal_string";

const char kExpectedContentWithObjectManagerAndServiceName[] = R"literal_string(
#include <memory>
#include <string>
#include <vector>

#include <base/bind.h>
#include <base/callback.h>
#include <base/logging.h>
#include <base/macros.h>
#include <base/memory/ref_counted.h>
#include <brillo/any.h>
#include <brillo/dbus/dbus_method_invoker.h>
#include <brillo/dbus/dbus_property.h>
#include <brillo/dbus/dbus_signal_handler.h>
#include <brillo/errors/error.h>
#include <brillo/variant_dictionary.h>
#include <dbus/bus.h>
#include <dbus/message.h>
#include <dbus/object_manager.h>
#include <dbus/object_path.h>
#include <dbus/object_proxy.h>

namespace org {
namespace chromium {
class ObjectManagerProxy;
}  // namespace chromium
}  // namespace org

namespace org {
namespace chromium {

// Abstract interface proxy for org::chromium::Itf1.
class Itf1ProxyInterface {
 public:
  virtual ~Itf1ProxyInterface() = default;

  virtual void RegisterCloserSignalHandler(
      const base::Closure& signal_callback,
      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) = 0;

  virtual const dbus::ObjectPath& GetObjectPath() const = 0;
};

}  // namespace chromium
}  // namespace org

namespace org {
namespace chromium {

// Interface proxy for org::chromium::Itf1.
class Itf1Proxy final : public Itf1ProxyInterface {
 public:
  class PropertySet : public dbus::PropertySet {
   public:
    PropertySet(dbus::ObjectProxy* object_proxy,
                const PropertyChangedCallback& callback)
        : dbus::PropertySet{object_proxy,
                            "org.chromium.Itf1",
                            callback} {
    }


   private:
    DISALLOW_COPY_AND_ASSIGN(PropertySet);
  };

  Itf1Proxy(const scoped_refptr<dbus::Bus>& bus) :
      bus_{bus},
      dbus_object_proxy_{
          bus_->GetObjectProxy(service_name_, object_path_)} {
  }

  ~Itf1Proxy() override {
  }

  void RegisterCloserSignalHandler(
      const base::Closure& signal_callback,
      dbus::ObjectProxy::OnConnectedCallback on_connected_callback) override {
    brillo::dbus_utils::ConnectToSignal(
        dbus_object_proxy_,
        "org.chromium.Itf1",
        "Closer",
        signal_callback,
        on_connected_callback);
  }

  void ReleaseObjectProxy(const base::Closure& callback) {
    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
  }

  const dbus::ObjectPath& GetObjectPath() const override {
    return object_path_;
  }

  dbus::ObjectProxy* GetObjectProxy() const { return dbus_object_proxy_; }

 private:
  scoped_refptr<dbus::Bus> bus_;
  const std::string service_name_{"org.chromium.Test"};
  const dbus::ObjectPath object_path_{"/org/chromium/Test/Object"};
  dbus::ObjectProxy* dbus_object_proxy_;

  DISALLOW_COPY_AND_ASSIGN(Itf1Proxy);
};

}  // namespace chromium
}  // namespace org

namespace org {
namespace chromium {

// Abstract interface proxy for org::chromium::Itf2.
class Itf2ProxyInterface {
 public:
  virtual ~Itf2ProxyInterface() = default;

  virtual const dbus::ObjectPath& GetObjectPath() const = 0;
};

}  // namespace chromium
}  // namespace org

namespace org {
namespace chromium {

// Interface proxy for org::chromium::Itf2.
class Itf2Proxy final : public Itf2ProxyInterface {
 public:
  class PropertySet : public dbus::PropertySet {
   public:
    PropertySet(dbus::ObjectProxy* object_proxy,
                const PropertyChangedCallback& callback)
        : dbus::PropertySet{object_proxy,
                            "org.chromium.Itf2",
                            callback} {
    }


   private:
    DISALLOW_COPY_AND_ASSIGN(PropertySet);
  };

  Itf2Proxy(
      const scoped_refptr<dbus::Bus>& bus,
      const dbus::ObjectPath& object_path) :
          bus_{bus},
          object_path_{object_path},
          dbus_object_proxy_{
              bus_->GetObjectProxy(service_name_, object_path_)} {
  }

  ~Itf2Proxy() override {
  }

  void ReleaseObjectProxy(const base::Closure& callback) {
    bus_->RemoveObjectProxy(service_name_, object_path_, callback);
  }

  const dbus::ObjectPath& GetObjectPath() const override {
    return object_path_;
  }

  dbus::ObjectProxy* GetObjectProxy() const { return dbus_object_proxy_; }

 private:
  scoped_refptr<dbus::Bus> bus_;
  const std::string service_name_{"org.chromium.Test"};
  dbus::ObjectPath object_path_;
  dbus::ObjectProxy* dbus_object_proxy_;

  DISALLOW_COPY_AND_ASSIGN(Itf2Proxy);
};

}  // namespace chromium
}  // namespace org

namespace org {
namespace chromium {

class ObjectManagerProxy : public dbus::ObjectManager::Interface {
 public:
  ObjectManagerProxy(const scoped_refptr<dbus::Bus>& bus)
      : bus_{bus},
        dbus_object_manager_{bus->GetObjectManager(
            "org.chromium.Test",
            dbus::ObjectPath{"/org/chromium/Test"})} {
    dbus_object_manager_->RegisterInterface("org.chromium.Itf1", this);
    dbus_object_manager_->RegisterInterface("org.chromium.Itf2", this);
  }

  ~ObjectManagerProxy() override {
    dbus_object_manager_->UnregisterInterface("org.chromium.Itf1");
    dbus_object_manager_->UnregisterInterface("org.chromium.Itf2");
  }

  dbus::ObjectManager* GetObjectManagerProxy() const {
    return dbus_object_manager_;
  }

  org::chromium::Itf1ProxyInterface* GetItf1Proxy() {
    if (itf1_instances_.empty())
      return nullptr;
    return itf1_instances_.begin()->second.get();
  }
  std::vector<org::chromium::Itf1ProxyInterface*> GetItf1Instances() const {
    std::vector<org::chromium::Itf1ProxyInterface*> values;
    values.reserve(itf1_instances_.size());
    for (const auto& pair : itf1_instances_)
      values.push_back(pair.second.get());
    return values;
  }
  void SetItf1AddedCallback(
      const base::Callback<void(org::chromium::Itf1ProxyInterface*)>& callback) {
    on_itf1_added_ = callback;
  }
  void SetItf1RemovedCallback(
      const base::Callback<void(const dbus::ObjectPath&)>& callback) {
    on_itf1_removed_ = callback;
  }

  org::chromium::Itf2ProxyInterface* GetItf2Proxy(
      const dbus::ObjectPath& object_path) {
    auto p = itf2_instances_.find(object_path);
    if (p != itf2_instances_.end())
      return p->second.get();
    return nullptr;
  }
  std::vector<org::chromium::Itf2ProxyInterface*> GetItf2Instances() const {
    std::vector<org::chromium::Itf2ProxyInterface*> values;
    values.reserve(itf2_instances_.size());
    for (const auto& pair : itf2_instances_)
      values.push_back(pair.second.get());
    return values;
  }
  void SetItf2AddedCallback(
      const base::Callback<void(org::chromium::Itf2ProxyInterface*)>& callback) {
    on_itf2_added_ = callback;
  }
  void SetItf2RemovedCallback(
      const base::Callback<void(const dbus::ObjectPath&)>& callback) {
    on_itf2_removed_ = callback;
  }

 private:
  void OnPropertyChanged(const dbus::ObjectPath& /* object_path */,
                         const std::string& /* interface_name */,
                         const std::string& /* property_name */) {}

  void ObjectAdded(
      const dbus::ObjectPath& object_path,
      const std::string& interface_name) override {
    if (interface_name == "org.chromium.Itf1") {
      std::unique_ptr<org::chromium::Itf1Proxy> itf1_proxy{
        new org::chromium::Itf1Proxy{bus_}
      };
      auto p = itf1_instances_.emplace(object_path, std::move(itf1_proxy));
      if (!on_itf1_added_.is_null())
        on_itf1_added_.Run(p.first->second.get());
      return;
    }
    if (interface_name == "org.chromium.Itf2") {
      std::unique_ptr<org::chromium::Itf2Proxy> itf2_proxy{
        new org::chromium::Itf2Proxy{bus_, object_path}
      };
      auto p = itf2_instances_.emplace(object_path, std::move(itf2_proxy));
      if (!on_itf2_added_.is_null())
        on_itf2_added_.Run(p.first->second.get());
      return;
    }
  }

  void ObjectRemoved(
      const dbus::ObjectPath& object_path,
      const std::string& interface_name) override {
    if (interface_name == "org.chromium.Itf1") {
      auto p = itf1_instances_.find(object_path);
      if (p != itf1_instances_.end()) {
        if (!on_itf1_removed_.is_null())
          on_itf1_removed_.Run(object_path);
        itf1_instances_.erase(p);
      }
      return;
    }
    if (interface_name == "org.chromium.Itf2") {
      auto p = itf2_instances_.find(object_path);
      if (p != itf2_instances_.end()) {
        if (!on_itf2_removed_.is_null())
          on_itf2_removed_.Run(object_path);
        itf2_instances_.erase(p);
      }
      return;
    }
  }

  dbus::PropertySet* CreateProperties(
      dbus::ObjectProxy* object_proxy,
      const dbus::ObjectPath& object_path,
      const std::string& interface_name) override {
    if (interface_name == "org.chromium.Itf1") {
      return new org::chromium::Itf1Proxy::PropertySet{
          object_proxy,
          base::Bind(&ObjectManagerProxy::OnPropertyChanged,
                     weak_ptr_factory_.GetWeakPtr(),
                     object_path,
                     interface_name)
      };
    }
    if (interface_name == "org.chromium.Itf2") {
      return new org::chromium::Itf2Proxy::PropertySet{
          object_proxy,
          base::Bind(&ObjectManagerProxy::OnPropertyChanged,
                     weak_ptr_factory_.GetWeakPtr(),
                     object_path,
                     interface_name)
      };
    }
    LOG(FATAL) << "Creating properties for unsupported interface "
               << interface_name;
    return nullptr;
  }

  scoped_refptr<dbus::Bus> bus_;
  dbus::ObjectManager* dbus_object_manager_;
  std::map<dbus::ObjectPath,
           std::unique_ptr<org::chromium::Itf1Proxy>> itf1_instances_;
  base::Callback<void(org::chromium::Itf1ProxyInterface*)> on_itf1_added_;
  base::Callback<void(const dbus::ObjectPath&)> on_itf1_removed_;
  std::map<dbus::ObjectPath,
           std::unique_ptr<org::chromium::Itf2Proxy>> itf2_instances_;
  base::Callback<void(org::chromium::Itf2ProxyInterface*)> on_itf2_added_;
  base::Callback<void(const dbus::ObjectPath&)> on_itf2_removed_;
  base::WeakPtrFactory<ObjectManagerProxy> weak_ptr_factory_{this};

  DISALLOW_COPY_AND_ASSIGN(ObjectManagerProxy);
};

}  // namespace chromium
}  // namespace org
)literal_string";
}  // namespace

class ProxyGeneratorTest : public Test {
 public:
  void SetUp() override {
    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
  }

 protected:
  base::FilePath CreateInputFile(const string& contents) {
    base::FilePath path;
    EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &path));
    int written = base::WriteFile(path, contents.c_str(), contents.size());
    EXPECT_EQ(contents.size(), static_cast<size_t>(written));
    return path;
  }

  base::ScopedTempDir temp_dir_;
};

TEST_F(ProxyGeneratorTest, GenerateAdaptors) {
  Interface interface;
  interface.name = "org.chromium.TestInterface";
  interface.path = "/org/chromium/Test";
  interface.methods.emplace_back(
      "Elements",
      vector<Interface::Argument>{
          {"space_walk", kDBusTypeString},
          {"ramblin_man", kDBusTypeArryOfObjects}},
      vector<Interface::Argument>{{"", kDBusTypeString}});
  interface.methods.emplace_back(
      "ReturnToPatagonia",
      vector<Interface::Argument>{},
      vector<Interface::Argument>{{"", kDBusTypeInt64}});
  interface.methods.emplace_back(
      "NiceWeatherForDucks",
      vector<Interface::Argument>{{"", kDBusTypeBool}},
      vector<Interface::Argument>{});
  interface.methods.emplace_back("ExperimentNumberSix");
  interface.signals.emplace_back("Closer");
  interface.signals.emplace_back(
      "TheCurseOfKaZar",
      vector<Interface::Argument>{
          {"", kDBusTypeArryOfStrings},
          {"", kDBusTypeByte}});
  interface.methods.back().doc_string = "Comment line1\nline2";
  Interface interface2;
  interface2.name = "org.chromium.TestInterface2";
  interface2.methods.emplace_back(
      "GetPersonInfo",
      vector<Interface::Argument>{},
      vector<Interface::Argument>{
          {"name", kDBusTypeString},
          {"age", kDBusTypeInt32}});
  vector<Interface> interfaces{interface, interface2};
  base::FilePath output_path = temp_dir_.path().Append("output.h");
  ServiceConfig config;
  EXPECT_TRUE(ProxyGenerator::GenerateProxies(config, interfaces, output_path));
  string contents;
  EXPECT_TRUE(base::ReadFileToString(output_path, &contents));
  // The header guards contain the (temporary) filename, so we search for
  // the content we need within the string.
  test_utils::EXPECT_TEXT_CONTAINED(kExpectedContent, contents);
}

TEST_F(ProxyGeneratorTest, GenerateAdaptorsWithServiceName) {
  Interface interface;
  interface.name = "org.chromium.TestInterface";
  interface.path = "/org/chromium/Test";
  interface.signals.emplace_back("Closer");
  Interface interface2;
  interface2.name = "org.chromium.TestInterface2";
  vector<Interface> interfaces{interface, interface2};
  base::FilePath output_path = temp_dir_.path().Append("output2.h");
  ServiceConfig config;
  config.service_name = "org.chromium.Test";
  EXPECT_TRUE(ProxyGenerator::GenerateProxies(config, interfaces, output_path));
  string contents;
  EXPECT_TRUE(base::ReadFileToString(output_path, &contents));
  // The header guards contain the (temporary) filename, so we search for
  // the content we need within the string.
  test_utils::EXPECT_TEXT_CONTAINED(kExpectedContentWithService, contents);
}

TEST_F(ProxyGeneratorTest, GenerateAdaptorsWithObjectManager) {
  Interface interface;
  interface.name = "org.chromium.Itf1";
  interface.path = "/org/chromium/Test/Object";
  interface.signals.emplace_back("Closer");
  interface.properties.emplace_back("Data", "s", "read");
  interface.properties.emplace_back("Name", "s", "readwrite");
  Interface interface2;
  interface2.name = "org.chromium.Itf2";
  vector<Interface> interfaces{interface, interface2};
  base::FilePath output_path = temp_dir_.path().Append("output3.h");
  ServiceConfig config;
  config.object_manager.name = "org.chromium.ObjectManager";
  config.object_manager.object_path = "/org/chromium/Test";
  EXPECT_TRUE(ProxyGenerator::GenerateProxies(config, interfaces, output_path));
  string contents;
  EXPECT_TRUE(base::ReadFileToString(output_path, &contents));
  // The header guards contain the (temporary) filename, so we search for
  // the content we need within the string.
  test_utils::EXPECT_TEXT_CONTAINED(
      kExpectedContentWithObjectManager, contents);
}

TEST_F(ProxyGeneratorTest, GenerateAdaptorsWithObjectManagerAndServiceName) {
  Interface interface;
  interface.name = "org.chromium.Itf1";
  interface.path = "/org/chromium/Test/Object";
  interface.signals.emplace_back("Closer");
  Interface interface2;
  interface2.name = "org.chromium.Itf2";
  vector<Interface> interfaces{interface, interface2};
  base::FilePath output_path = temp_dir_.path().Append("output4.h");
  ServiceConfig config;
  config.service_name = "org.chromium.Test";
  config.object_manager.name = "org.chromium.ObjectManager";
  config.object_manager.object_path = "/org/chromium/Test";
  EXPECT_TRUE(ProxyGenerator::GenerateProxies(config, interfaces, output_path));
  string contents;
  EXPECT_TRUE(base::ReadFileToString(output_path, &contents));
  // The header guards contain the (temporary) filename, so we search for
  // the content we need within the string.
  test_utils::EXPECT_TEXT_CONTAINED(
      kExpectedContentWithObjectManagerAndServiceName, contents);
}

}  // namespace chromeos_dbus_bindings