// Copyright (c) 2012 The Chromium 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 <memory>

#include "base/memory/ref_counted.h"
#include "dbus/bus.h"
#include "dbus/message.h"
#include "dbus/object_path.h"
#include "dbus/object_proxy.h"
#include "dbus/test_service.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace dbus {

// The end-to-end test exercises the synchronous APIs in ObjectProxy and
// ExportedObject. The test will launch a thread for the service side
// operations (i.e. ExportedObject side).
class EndToEndSyncTest : public testing::Test {
 public:
  EndToEndSyncTest() {
  }

  void SetUp() override {
    // Start the test service;
    TestService::Options options;
    test_service_.reset(new TestService(options));
    ASSERT_TRUE(test_service_->StartService());
    ASSERT_TRUE(test_service_->WaitUntilServiceIsStarted());
    ASSERT_FALSE(test_service_->HasDBusThread());

    // Create the client.
    Bus::Options client_bus_options;
    client_bus_options.bus_type = Bus::SESSION;
    client_bus_options.connection_type = Bus::PRIVATE;
    client_bus_ = new Bus(client_bus_options);
    object_proxy_ = client_bus_->GetObjectProxy(
        test_service_->service_name(),
        ObjectPath("/org/chromium/TestObject"));
    ASSERT_FALSE(client_bus_->HasDBusThread());
  }

  void TearDown() override {
    test_service_->ShutdownAndBlock();
    test_service_->Stop();
    client_bus_->ShutdownAndBlock();
  }

 protected:
  std::unique_ptr<TestService> test_service_;
  scoped_refptr<Bus> client_bus_;
  ObjectProxy* object_proxy_;
};

TEST_F(EndToEndSyncTest, Echo) {
  const std::string kHello = "hello";

  // Create the method call.
  MethodCall method_call("org.chromium.TestInterface", "Echo");
  MessageWriter writer(&method_call);
  writer.AppendString(kHello);

  // Call the method.
  const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
  std::unique_ptr<Response> response(
      object_proxy_->CallMethodAndBlock(&method_call, timeout_ms));
  ASSERT_TRUE(response.get());

  // Check the response. kHello should be echoed back.
  MessageReader reader(response.get());
  std::string returned_message;
  ASSERT_TRUE(reader.PopString(&returned_message));
  EXPECT_EQ(kHello, returned_message);
}

TEST_F(EndToEndSyncTest, Timeout) {
  const std::string kHello = "hello";

  // Create the method call.
  MethodCall method_call("org.chromium.TestInterface", "DelayedEcho");
  MessageWriter writer(&method_call);
  writer.AppendString(kHello);

  // Call the method with timeout of 0ms.
  const int timeout_ms = 0;
  std::unique_ptr<Response> response(
      object_proxy_->CallMethodAndBlock(&method_call, timeout_ms));
  // Should fail because of timeout.
  ASSERT_FALSE(response.get());
}

TEST_F(EndToEndSyncTest, NonexistentMethod) {
  MethodCall method_call("org.chromium.TestInterface", "Nonexistent");

  const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
  std::unique_ptr<Response> response(
      object_proxy_->CallMethodAndBlock(&method_call, timeout_ms));
  ASSERT_FALSE(response.get());
}

TEST_F(EndToEndSyncTest, BrokenMethod) {
  MethodCall method_call("org.chromium.TestInterface", "BrokenMethod");

  const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
  std::unique_ptr<Response> response(
      object_proxy_->CallMethodAndBlock(&method_call, timeout_ms));
  ASSERT_FALSE(response.get());
}

TEST_F(EndToEndSyncTest, InvalidObjectPath) {
  // Trailing '/' is only allowed for the root path.
  const ObjectPath invalid_object_path("/org/chromium/TestObject/");

  // Replace object proxy with new one.
  object_proxy_ = client_bus_->GetObjectProxy(test_service_->service_name(),
                                              invalid_object_path);

  MethodCall method_call("org.chromium.TestInterface", "Echo");

  const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
  std::unique_ptr<Response> response(
      object_proxy_->CallMethodAndBlock(&method_call, timeout_ms));
  ASSERT_FALSE(response.get());
}

TEST_F(EndToEndSyncTest, InvalidServiceName) {
  // Bus name cannot contain '/'.
  const std::string invalid_service_name = ":1/2";

  // Replace object proxy with new one.
  object_proxy_ = client_bus_->GetObjectProxy(
      invalid_service_name, ObjectPath("org.chromium.TestObject"));

  MethodCall method_call("org.chromium.TestInterface", "Echo");

  const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
  std::unique_ptr<Response> response(
      object_proxy_->CallMethodAndBlock(&method_call, timeout_ms));
  ASSERT_FALSE(response.get());
}

}  // namespace dbus
