chromium/chromecast/mojo/binder_factory_test.cc

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

#include "chromecast/mojo/binder_factory.h"

#include <string>

#include "base/functional/bind.h"
#include "base/test/task_environment.h"
#include "chromecast/mojo/test/test_interfaces.test-mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using testing::_;

namespace chromecast {

class MockInterface : public test::mojom::StringInterface,
                      public test::mojom::IntInterface,
                      public test::mojom::BoolInterface {
 public:
  MOCK_METHOD(void, StringMethod, (const std::string& s), (override));
  MOCK_METHOD(void, IntMethod, (int32_t i), (override));
  MOCK_METHOD(void, BoolMethod, (bool b), (override));
};

class MockErrorHandler {
 public:
  MOCK_METHOD(void, OnError, ());
};

class BinderFactoryTest : public testing::Test {
 protected:
  BinderFactoryTest() {}

  base::test::TaskEnvironment task_environment_;

  MockInterface mock_interface_;
};

TEST_F(BinderFactoryTest, BinderFactoryBind) {
  BinderFactory<test::mojom::StringInterface> s_factory(&mock_interface_);

  mojo::Remote<test::mojom::StringInterface> s_remote;
  s_factory.Bind(s_remote.BindNewPipeAndPassReceiver());

  // Verify implementation is connected.
  std::string s = "Hello, world!";
  EXPECT_CALL(mock_interface_, StringMethod(s));
  s_remote->StringMethod(s);
  task_environment_.RunUntilIdle();
}

TEST_F(BinderFactoryTest, BinderFactoryGetBinder) {
  BinderFactory<test::mojom::StringInterface> s_factory(&mock_interface_);

  auto binder = s_factory.GetBinder();
  ASSERT_TRUE(!binder.is_null());

  mojo::Remote<test::mojom::StringInterface> s_remote;
  s_factory.Bind(s_remote.BindNewPipeAndPassReceiver());

  // Verify implementation is connected.
  std::string s = "Hello, world!";
  EXPECT_CALL(mock_interface_, StringMethod(s));
  s_remote->StringMethod(s);
  task_environment_.RunUntilIdle();
}

TEST_F(BinderFactoryTest, BinderFactoryLifetime) {
  MockErrorHandler s_handler;
  auto s_factory =
      std::make_unique<BinderFactory<test::mojom::StringInterface>>(
          &mock_interface_);

  auto binder = s_factory->GetBinder();
  ASSERT_TRUE(!binder.is_null());

  mojo::Remote<test::mojom::StringInterface> s_remote;
  s_factory->Bind(s_remote.BindNewPipeAndPassReceiver());

  s_remote.set_disconnect_handler(
      base::BindOnce(&MockErrorHandler::OnError, base::Unretained(&s_handler)));

  // Remotes which were bound via the BinderFactory will invalidated when the
  // factory is destroyed.
  EXPECT_CALL(s_handler, OnError()).Times(1);

  s_factory.reset();
  task_environment_.RunUntilIdle();
}

TEST_F(BinderFactoryTest, MultiBinderFactory) {
  MockErrorHandler s_handler;
  MockErrorHandler i_handler;
  auto factory = std::make_unique<MultiBinderFactory>();
  factory->AddInterface<test::mojom::StringInterface>(&mock_interface_);
  factory->AddInterface<test::mojom::IntInterface>(&mock_interface_);

  auto s_binder = factory->GetBinder<test::mojom::StringInterface>();
  ASSERT_FALSE(s_binder.is_null());
  auto i_binder = factory->GetBinder<test::mojom::IntInterface>();
  ASSERT_FALSE(i_binder.is_null());

  // There is no binder for BoolInterface.
  ASSERT_TRUE(factory->GetBinder<test::mojom::BoolInterface>().is_null());

  mojo::Remote<test::mojom::StringInterface> s_remote;
  s_binder.Run(s_remote.BindNewPipeAndPassReceiver());

  mojo::Remote<test::mojom::IntInterface> i_remote;
  i_binder.Run(i_remote.BindNewPipeAndPassReceiver());

  std::string s = "Hello, world!";
  EXPECT_CALL(mock_interface_, StringMethod(s));
  s_remote->StringMethod(s);
  task_environment_.RunUntilIdle();

  int i = 1234;
  EXPECT_CALL(mock_interface_, IntMethod(i));
  i_remote->IntMethod(i);
  task_environment_.RunUntilIdle();

  s_remote.set_disconnect_handler(
      base::BindOnce(&MockErrorHandler::OnError, base::Unretained(&s_handler)));
  i_remote.set_disconnect_handler(
      base::BindOnce(&MockErrorHandler::OnError, base::Unretained(&i_handler)));

  // Pointers which were bound via the MultiBinderFactory will invalidated when
  // the factory is destroyed.
  EXPECT_CALL(s_handler, OnError()).Times(1);
  EXPECT_CALL(i_handler, OnError()).Times(1);

  factory.reset();
  task_environment_.RunUntilIdle();
}

}  // namespace chromecast