mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
302 lines
10 KiB
C++
302 lines
10 KiB
C++
// Copyright 2015 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 "build/build_config.h"
|
|
#include "mojo/public/cpp/bindings/binding.h"
|
|
#include "mojo/public/cpp/bindings/interface_ptr.h"
|
|
#include "mojo/public/cpp/bindings/string.h"
|
|
#include "mojo/public/cpp/environment/environment.h"
|
|
#include "mojo/public/cpp/system/message_pipe.h"
|
|
#include "mojo/public/cpp/test_support/test_support.h"
|
|
#include "mojo/public/cpp/utility/run_loop.h"
|
|
#include "mojo/public/interfaces/bindings/tests/sample_interfaces.mojom.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// The tests in this file are designed to test the interaction between a
|
|
// Callback and its associated Binding. If a Callback is deleted before
|
|
// being used we DCHECK fail--unless the associated Binding has already
|
|
// been closed or deleted. This contract must be explained to the Mojo
|
|
// application developer. For example it is the developer's responsibility to
|
|
// ensure that the Binding is destroyed before an unused Callback is destroyed.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace mojo {
|
|
namespace test {
|
|
namespace {
|
|
|
|
// A Runnable object that saves the last value it sees via the
|
|
// provided int32_t*. Used on the client side.
|
|
class ValueSaver {
|
|
public:
|
|
explicit ValueSaver(int32_t* last_value_seen)
|
|
: last_value_seen_(last_value_seen) {}
|
|
void Run(int32_t x) const { *last_value_seen_ = x; }
|
|
|
|
private:
|
|
int32_t* const last_value_seen_;
|
|
};
|
|
|
|
// An implementation of sample::Provider used on the server side.
|
|
// It only implements one of the methods: EchoInt().
|
|
// All it does is save the values and Callbacks it sees.
|
|
class InterfaceImpl : public sample::Provider {
|
|
public:
|
|
InterfaceImpl()
|
|
: last_server_value_seen_(0),
|
|
callback_saved_(new Callback<void(int32_t)>()) {}
|
|
|
|
~InterfaceImpl() override {
|
|
if (callback_saved_) {
|
|
delete callback_saved_;
|
|
}
|
|
}
|
|
|
|
// Run's the callback previously saved from the last invocation
|
|
// of |EchoInt()|.
|
|
bool RunCallback() {
|
|
if (callback_saved_) {
|
|
callback_saved_->Run(last_server_value_seen_);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Delete's the previously saved callback.
|
|
void DeleteCallback() {
|
|
delete callback_saved_;
|
|
callback_saved_ = nullptr;
|
|
}
|
|
|
|
// sample::Provider implementation
|
|
|
|
// Saves its two input values in member variables and does nothing else.
|
|
void EchoInt(int32_t x, const Callback<void(int32_t)>& callback) override {
|
|
last_server_value_seen_ = x;
|
|
*callback_saved_ = callback;
|
|
}
|
|
|
|
void EchoString(const String& a,
|
|
const Callback<void(String)>& callback) override {
|
|
MOJO_CHECK(false) << "Not implemented.";
|
|
}
|
|
|
|
void EchoStrings(const String& a,
|
|
const String& b,
|
|
const Callback<void(String, String)>& callback) override {
|
|
MOJO_CHECK(false) << "Not implemented.";
|
|
}
|
|
|
|
void EchoMessagePipeHandle(
|
|
ScopedMessagePipeHandle a,
|
|
const Callback<void(ScopedMessagePipeHandle)>& callback) override {
|
|
MOJO_CHECK(false) << "Not implemented.";
|
|
}
|
|
|
|
void EchoEnum(sample::Enum a,
|
|
const Callback<void(sample::Enum)>& callback) override {
|
|
MOJO_CHECK(false) << "Not implemented.";
|
|
}
|
|
|
|
void resetLastServerValueSeen() { last_server_value_seen_ = 0; }
|
|
|
|
int32_t last_server_value_seen() const { return last_server_value_seen_; }
|
|
|
|
private:
|
|
int32_t last_server_value_seen_;
|
|
Callback<void(int32_t)>* callback_saved_;
|
|
};
|
|
|
|
class BindingCallbackTest : public testing::Test {
|
|
public:
|
|
~BindingCallbackTest() override {}
|
|
|
|
protected:
|
|
int32_t last_client_callback_value_seen_;
|
|
sample::ProviderPtr interface_ptr_;
|
|
|
|
void PumpMessages() { loop_.RunUntilIdle(); }
|
|
|
|
private:
|
|
Environment env_;
|
|
RunLoop loop_;
|
|
};
|
|
|
|
// Tests that the InterfacePtr and the Binding can communicate with each
|
|
// other normally.
|
|
TEST_F(BindingCallbackTest, Basic) {
|
|
// Create the ServerImpl and the Binding.
|
|
InterfaceImpl server_impl;
|
|
Binding<sample::Provider> binding(&server_impl, GetProxy(&interface_ptr_));
|
|
|
|
// Initialize the test values.
|
|
server_impl.resetLastServerValueSeen();
|
|
last_client_callback_value_seen_ = 0;
|
|
|
|
// Invoke the Echo method.
|
|
interface_ptr_->EchoInt(7, ValueSaver(&last_client_callback_value_seen_));
|
|
PumpMessages();
|
|
|
|
// Check that server saw the correct value, but the client has not yet.
|
|
EXPECT_EQ(7, server_impl.last_server_value_seen());
|
|
EXPECT_EQ(0, last_client_callback_value_seen_);
|
|
|
|
// Now run the Callback.
|
|
server_impl.RunCallback();
|
|
PumpMessages();
|
|
|
|
// Check that the client has now seen the correct value.
|
|
EXPECT_EQ(7, last_client_callback_value_seen_);
|
|
|
|
// Initialize the test values again.
|
|
server_impl.resetLastServerValueSeen();
|
|
last_client_callback_value_seen_ = 0;
|
|
|
|
// Invoke the Echo method again.
|
|
interface_ptr_->EchoInt(13, ValueSaver(&last_client_callback_value_seen_));
|
|
PumpMessages();
|
|
|
|
// Check that server saw the correct value, but the client has not yet.
|
|
EXPECT_EQ(13, server_impl.last_server_value_seen());
|
|
EXPECT_EQ(0, last_client_callback_value_seen_);
|
|
|
|
// Now run the Callback again.
|
|
server_impl.RunCallback();
|
|
PumpMessages();
|
|
|
|
// Check that the client has now seen the correct value again.
|
|
EXPECT_EQ(13, last_client_callback_value_seen_);
|
|
}
|
|
|
|
// Tests that running the Callback after the Binding has been deleted
|
|
// results in a clean failure.
|
|
TEST_F(BindingCallbackTest, DeleteBindingThenRunCallback) {
|
|
// Create the ServerImpl.
|
|
InterfaceImpl server_impl;
|
|
{
|
|
// Create the binding in an inner scope so it can be deleted first.
|
|
Binding<sample::Provider> binding(&server_impl, GetProxy(&interface_ptr_));
|
|
|
|
// Initialize the test values.
|
|
server_impl.resetLastServerValueSeen();
|
|
last_client_callback_value_seen_ = 0;
|
|
|
|
// Invoke the Echo method.
|
|
interface_ptr_->EchoInt(7, ValueSaver(&last_client_callback_value_seen_));
|
|
PumpMessages();
|
|
}
|
|
// The binding has now been destroyed and the pipe is closed.
|
|
|
|
// Check that server saw the correct value, but the client has not yet.
|
|
EXPECT_EQ(7, server_impl.last_server_value_seen());
|
|
EXPECT_EQ(0, last_client_callback_value_seen_);
|
|
|
|
// Now try to run the Callback. This should do nothing since the pipe
|
|
// is closed.
|
|
EXPECT_TRUE(server_impl.RunCallback());
|
|
PumpMessages();
|
|
|
|
// Check that the client has still not seen the correct value.
|
|
EXPECT_EQ(0, last_client_callback_value_seen_);
|
|
|
|
// Attempt to invoke the method again and confirm that an error was
|
|
// encountered.
|
|
interface_ptr_->EchoInt(13, ValueSaver(&last_client_callback_value_seen_));
|
|
PumpMessages();
|
|
EXPECT_TRUE(interface_ptr_.encountered_error());
|
|
}
|
|
|
|
// Tests that deleting a Callback without running it after the corresponding
|
|
// binding has already been deleted does not result in a crash.
|
|
TEST_F(BindingCallbackTest, DeleteBindingThenDeleteCallback) {
|
|
// Create the ServerImpl.
|
|
InterfaceImpl server_impl;
|
|
{
|
|
// Create the binding in an inner scope so it can be deleted first.
|
|
Binding<sample::Provider> binding(&server_impl, GetProxy(&interface_ptr_));
|
|
|
|
// Initialize the test values.
|
|
server_impl.resetLastServerValueSeen();
|
|
last_client_callback_value_seen_ = 0;
|
|
|
|
// Invoke the Echo method.
|
|
interface_ptr_->EchoInt(7, ValueSaver(&last_client_callback_value_seen_));
|
|
PumpMessages();
|
|
}
|
|
// The binding has now been destroyed and the pipe is closed.
|
|
|
|
// Check that server saw the correct value, but the client has not yet.
|
|
EXPECT_EQ(7, server_impl.last_server_value_seen());
|
|
EXPECT_EQ(0, last_client_callback_value_seen_);
|
|
|
|
// Delete the callback without running it. This should not
|
|
// cause a problem because the insfrastructure can detect that the
|
|
// binding has already been destroyed and the pipe is closed.
|
|
server_impl.DeleteCallback();
|
|
}
|
|
|
|
// Tests that closing a Binding allows us to delete a callback
|
|
// without running it without encountering a crash.
|
|
TEST_F(BindingCallbackTest, CloseBindingBeforeDeletingCallback) {
|
|
// Create the ServerImpl and the Binding.
|
|
InterfaceImpl server_impl;
|
|
Binding<sample::Provider> binding(&server_impl, GetProxy(&interface_ptr_));
|
|
|
|
// Initialize the test values.
|
|
server_impl.resetLastServerValueSeen();
|
|
last_client_callback_value_seen_ = 0;
|
|
|
|
// Invoke the Echo method.
|
|
interface_ptr_->EchoInt(7, ValueSaver(&last_client_callback_value_seen_));
|
|
PumpMessages();
|
|
|
|
// Check that server saw the correct value, but the client has not yet.
|
|
EXPECT_EQ(7, server_impl.last_server_value_seen());
|
|
EXPECT_EQ(0, last_client_callback_value_seen_);
|
|
|
|
// Now close the Binding.
|
|
binding.Close();
|
|
|
|
// Delete the callback without running it. This should not
|
|
// cause a crash because the insfrastructure can detect that the
|
|
// binding has already been closed.
|
|
server_impl.DeleteCallback();
|
|
|
|
// Check that the client has still not seen the correct value.
|
|
EXPECT_EQ(0, last_client_callback_value_seen_);
|
|
}
|
|
|
|
// Tests that deleting a Callback without using it before the
|
|
// Binding has been destroyed or closed results in a DCHECK.
|
|
TEST_F(BindingCallbackTest, DeleteCallbackBeforeBindingDeathTest) {
|
|
// Create the ServerImpl and the Binding.
|
|
InterfaceImpl server_impl;
|
|
Binding<sample::Provider> binding(&server_impl, GetProxy(&interface_ptr_));
|
|
|
|
// Initialize the test values.
|
|
server_impl.resetLastServerValueSeen();
|
|
last_client_callback_value_seen_ = 0;
|
|
|
|
// Invoke the Echo method.
|
|
interface_ptr_->EchoInt(7, ValueSaver(&last_client_callback_value_seen_));
|
|
PumpMessages();
|
|
|
|
// Check that server saw the correct value, but the client has not yet.
|
|
EXPECT_EQ(7, server_impl.last_server_value_seen());
|
|
EXPECT_EQ(0, last_client_callback_value_seen_);
|
|
|
|
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
|
|
// Delete the callback without running it. This should cause a crash in debug
|
|
// builds due to a DCHECK.
|
|
EXPECT_DEATH_IF_SUPPORTED(server_impl.DeleteCallback(),
|
|
"Check failed: !callback_was_dropped.");
|
|
#endif
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace test
|
|
} // namespace mojo
|