| // 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_ |