#include <stdint.h>
#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/notreached.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/gtest_util.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "mojo/public/cpp/test_support/test_support.h"
#include "mojo/public/interfaces/bindings/tests/sample_interfaces.test-mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
namespace test {
namespace {
class InterfaceImpl : public sample::Provider {
public:
InterfaceImpl() : last_server_value_seen_(0) {}
~InterfaceImpl() override {}
bool RunCallback() {
if (callback_saved_) {
std::move(callback_saved_).Run(last_server_value_seen_);
return true;
}
return false;
}
void DeleteCallback() { callback_saved_.Reset(); }
void EchoInt(int32_t x, EchoIntCallback callback) override {
last_server_value_seen_ = x;
callback_saved_ = std::move(callback);
if (closure_)
std::move(closure_).Run();
}
void EchoString(const std::string& a, EchoStringCallback callback) override {
NOTREACHED() << "Not implemented.";
}
void EchoStrings(const std::string& a,
const std::string& b,
EchoStringsCallback callback) override {
NOTREACHED() << "Not implemented.";
}
void EchoMessagePipeHandle(ScopedMessagePipeHandle a,
EchoMessagePipeHandleCallback callback) override {
NOTREACHED() << "Not implemented.";
}
void EchoEnum(sample::Enum a, EchoEnumCallback callback) override {
NOTREACHED() << "Not implemented.";
}
void ResetLastServerValueSeen() { last_server_value_seen_ = 0; }
int32_t last_server_value_seen() const { return last_server_value_seen_; }
void set_closure(base::OnceClosure closure) { closure_ = std::move(closure); }
private:
int32_t last_server_value_seen_;
EchoIntCallback callback_saved_;
base::OnceClosure closure_;
};
class ReceiverCallbackTest : public testing::Test {
public:
ReceiverCallbackTest() {}
~ReceiverCallbackTest() override {}
protected:
int32_t last_client_callback_value_seen_;
Remote<sample::Provider> remote_;
void PumpMessages() { base::RunLoop().RunUntilIdle(); }
private:
base::test::SingleThreadTaskEnvironment task_environment_;
};
TEST_F(ReceiverCallbackTest, Basic) {
InterfaceImpl server_impl;
Receiver<sample::Provider> receiver(&server_impl,
remote_.BindNewPipeAndPassReceiver());
server_impl.ResetLastServerValueSeen();
last_client_callback_value_seen_ = 0;
base::RunLoop run_loop, run_loop2;
server_impl.set_closure(run_loop.QuitClosure());
remote_->EchoInt(7, base::BindLambdaForTesting([&](int32_t value) {
last_client_callback_value_seen_ = value;
run_loop2.Quit();
}));
run_loop.Run();
EXPECT_EQ(7, server_impl.last_server_value_seen());
EXPECT_EQ(0, last_client_callback_value_seen_);
server_impl.RunCallback();
run_loop2.Run();
EXPECT_EQ(7, last_client_callback_value_seen_);
server_impl.ResetLastServerValueSeen();
last_client_callback_value_seen_ = 0;
base::RunLoop run_loop3, run_loop4;
server_impl.set_closure(run_loop3.QuitClosure());
remote_->EchoInt(13, base::BindLambdaForTesting([&](int32_t value) {
last_client_callback_value_seen_ = value;
run_loop4.Quit();
}));
run_loop3.Run();
EXPECT_EQ(13, server_impl.last_server_value_seen());
EXPECT_EQ(0, last_client_callback_value_seen_);
server_impl.RunCallback();
run_loop4.Run();
EXPECT_EQ(13, last_client_callback_value_seen_);
}
TEST_F(ReceiverCallbackTest, DeleteReceiverThenRunCallback) {
InterfaceImpl server_impl;
base::RunLoop run_loop;
{
Receiver<sample::Provider> receiver(&server_impl,
remote_.BindNewPipeAndPassReceiver());
remote_.set_disconnect_handler(run_loop.QuitClosure());
server_impl.ResetLastServerValueSeen();
last_client_callback_value_seen_ = 0;
base::RunLoop run_loop2;
server_impl.set_closure(run_loop2.QuitClosure());
remote_->EchoInt(7, base::BindLambdaForTesting([&](int32_t value) {
last_client_callback_value_seen_ = value;
}));
run_loop2.Run();
}
EXPECT_EQ(7, server_impl.last_server_value_seen());
EXPECT_EQ(0, last_client_callback_value_seen_);
EXPECT_TRUE(server_impl.RunCallback());
PumpMessages();
EXPECT_EQ(0, last_client_callback_value_seen_);
remote_->EchoInt(13, base::BindLambdaForTesting([&](int32_t value) {
last_client_callback_value_seen_ = value;
run_loop.Quit();
}));
run_loop.Run();
EXPECT_FALSE(remote_.is_connected());
}
TEST_F(ReceiverCallbackTest, DeleteReceiverThenDeleteCallback) {
InterfaceImpl server_impl;
{
Receiver<sample::Provider> receiver(&server_impl,
remote_.BindNewPipeAndPassReceiver());
server_impl.ResetLastServerValueSeen();
last_client_callback_value_seen_ = 0;
base::RunLoop run_loop;
server_impl.set_closure(run_loop.QuitClosure());
remote_->EchoInt(7, base::BindLambdaForTesting([&](int32_t value) {
last_client_callback_value_seen_ = value;
}));
run_loop.Run();
}
EXPECT_EQ(7, server_impl.last_server_value_seen());
EXPECT_EQ(0, last_client_callback_value_seen_);
server_impl.DeleteCallback();
}
TEST_F(ReceiverCallbackTest, ResetReceiverBeforeDeletingCallback) {
InterfaceImpl server_impl;
Receiver<sample::Provider> receiver(&server_impl,
remote_.BindNewPipeAndPassReceiver());
server_impl.ResetLastServerValueSeen();
last_client_callback_value_seen_ = 0;
base::RunLoop run_loop;
server_impl.set_closure(run_loop.QuitClosure());
remote_->EchoInt(7, base::BindLambdaForTesting([&](int32_t value) {
last_client_callback_value_seen_ = value;
}));
run_loop.Run();
EXPECT_EQ(7, server_impl.last_server_value_seen());
EXPECT_EQ(0, last_client_callback_value_seen_);
receiver.reset();
server_impl.DeleteCallback();
EXPECT_EQ(0, last_client_callback_value_seen_);
}
TEST_F(ReceiverCallbackTest, DeleteCallbackBeforeReceiverDeathTest) {
InterfaceImpl server_impl;
Receiver<sample::Provider> receiver(&server_impl,
remote_.BindNewPipeAndPassReceiver());
server_impl.ResetLastServerValueSeen();
last_client_callback_value_seen_ = 0;
base::RunLoop run_loop;
server_impl.set_closure(run_loop.QuitClosure());
remote_->EchoInt(7, base::BindLambdaForTesting([&](int32_t value) {
last_client_callback_value_seen_ = value;
}));
run_loop.Run();
EXPECT_EQ(7, server_impl.last_server_value_seen());
EXPECT_EQ(0, last_client_callback_value_seen_);
EXPECT_DCHECK_DEATH(server_impl.DeleteCallback());
}
}
}
}