blob: bf1bf622bc02178005078d2dbc814bf4c513dfed [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_LIB_FIDL_LLCPP_TESTS_DISPATCHER_MOCK_CLIENT_IMPL_H_
#define SRC_LIB_FIDL_LLCPP_TESTS_DISPATCHER_MOCK_CLIENT_IMPL_H_
#include <lib/fidl/cpp/wire/client.h>
#include <lib/fidl/cpp/wire/client_base.h>
#include <lib/fidl/cpp/wire/wire_messaging.h>
#include <unordered_set>
#include <zxtest/zxtest.h>
#include "client_checkers.h"
namespace fidl_testing {
class TestProtocol {
public:
using Transport = fidl::internal::ChannelTransport;
TestProtocol() = delete;
};
// |ClientBaseSpy| delegates calls to |ClientBase| but in addition records
// extra information about the transactions which are useful for unit testing.
class ClientBaseSpy {
public:
// In cases the spy needs bound client, but the client also needs a spy,
// construct an empty |ClientBaseSpy| first, then call |set_client|.
ClientBaseSpy() : client_base_(nullptr) {}
explicit ClientBaseSpy(fidl::internal::ClientBase* client_base) : client_base_(client_base) {
ZX_ASSERT(client_base != nullptr);
}
template <typename ClientLike>
explicit ClientBaseSpy(ClientLike&& client)
: ClientBaseSpy(ClientChecker::GetClientBase(client)) {}
template <typename ClientLike>
void set_client(ClientLike&& client) {
client_base_ = ClientChecker::GetClientBase(client);
}
void PrepareAsyncTxn(fidl::internal::ResponseContext* context) {
client_base_->PrepareAsyncTxn(context);
std::unique_lock lock(lock_);
EXPECT_FALSE(txids_.count(context->Txid()));
txids_.insert(context->Txid());
}
void ForgetAsyncTxn(fidl::internal::ResponseContext* context) {
{
std::unique_lock lock(lock_);
txids_.erase(context->Txid());
}
client_base_->ForgetAsyncTxn(context);
}
void EraseTxid(fidl::internal::ResponseContext* context) {
{
std::unique_lock lock(lock_);
txids_.erase(context->Txid());
}
}
template <typename Callable>
auto MakeSyncCallWith(Callable&& sync_call) {
return client_base_->MakeSyncCallWith(std::forward<Callable>(sync_call));
}
bool IsPending(zx_txid_t txid) {
std::unique_lock lock(lock_);
return txids_.count(txid);
}
size_t GetTxidCount() {
std::unique_lock lock(lock_);
EXPECT_EQ(client_base_->GetTransactionCount(), txids_.size());
return txids_.size();
}
private:
fidl::internal::ClientBase* client_base_;
std::mutex lock_;
std::unordered_set<zx_txid_t> txids_;
};
} // namespace fidl_testing
template <>
struct ::fidl::IsProtocol<fidl_testing::TestProtocol> : public std::true_type {};
template <>
class ::fidl::WireAsyncEventHandler<fidl_testing::TestProtocol>
: public fidl::internal::AsyncEventHandler, public fidl::internal::BaseEventHandlerInterface {
public:
WireAsyncEventHandler() = default;
~WireAsyncEventHandler() override = default;
void on_fidl_error(::fidl::UnbindInfo info) override {}
void LogEvent() { event_count_++; }
uint32_t event_count() const { return event_count_; }
private:
uint32_t event_count_ = 0;
};
template <>
class ::fidl::internal::WireEventDispatcher<fidl_testing::TestProtocol>
: public ::fidl::internal::IncomingEventDispatcher<
::fidl::WireAsyncEventHandler<fidl_testing::TestProtocol>> {
public:
explicit WireEventDispatcher(
::fidl::WireAsyncEventHandler<fidl_testing::TestProtocol>* event_handler)
: IncomingEventDispatcher(event_handler) {}
private:
// For each event, increment the event count.
::fidl::Status DispatchEvent(fidl::IncomingHeaderAndMessage& msg,
internal::MessageStorageViewBase* storage_view) override {
event_handler()->LogEvent();
return ::fidl::Status::Ok();
}
};
template <>
class ::fidl::internal::WireWeakAsyncClientImpl<fidl_testing::TestProtocol>
: public fidl::internal::ClientImplBase {
public:
using ClientImplBase::ClientImplBase;
fidl::Status OneWayMethod(fidl::OutgoingMessage& message) {
return _client_base()->SendOneWay(message);
}
};
template <>
class ::fidl::internal::WireWeakOnewayBufferClientImpl<fidl_testing::TestProtocol>
: public ::fidl::internal::BufferClientImplBase {
public:
using BufferClientImplBase::BufferClientImplBase;
};
template <>
class ::fidl::internal::WireWeakAsyncBufferClientImpl<fidl_testing::TestProtocol>
: public ::fidl::internal::WireWeakOnewayBufferClientImpl<fidl_testing::TestProtocol> {
public:
using WireWeakOnewayBufferClientImpl::WireWeakOnewayBufferClientImpl;
};
template <>
class ::fidl::internal::WireWeakOnewayClientImpl<fidl_testing::TestProtocol>
: public ::fidl::internal::ClientImplBase {
public:
using ClientImplBase::ClientImplBase;
};
template <>
class ::fidl::internal::WireWeakSyncClientImpl<fidl_testing::TestProtocol>
: public ::fidl::internal::WireWeakOnewayClientImpl<fidl_testing::TestProtocol> {
public:
using WireWeakOnewayClientImpl::WireWeakOnewayClientImpl;
};
namespace fidl_testing {
class TestResponseContext : public fidl::internal::ResponseContext {
public:
explicit TestResponseContext(ClientBaseSpy* spy)
: fidl::internal::ResponseContext(0), spy_(spy) {}
std::optional<fidl::UnbindInfo> OnRawResult(
fidl::IncomingHeaderAndMessage&& msg,
fidl::internal::MessageStorageViewBase* storage_view) override {
spy_->EraseTxid(this);
return std::nullopt;
}
private:
ClientBaseSpy* spy_;
};
} // namespace fidl_testing
#endif // SRC_LIB_FIDL_LLCPP_TESTS_DISPATCHER_MOCK_CLIENT_IMPL_H_