blob: 0cd61dcc2eac4b6a542c6ceb40dd0356517c852c [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 ZIRCON_KERNEL_LIB_EFI_TESTING_INCLUDE_LIB_EFI_TESTING_MOCK_PROTOCOL_BASE_H_
#define ZIRCON_KERNEL_LIB_EFI_TESTING_INCLUDE_LIB_EFI_TESTING_MOCK_PROTOCOL_BASE_H_
#include <type_traits>
#include <efi/types.h>
#include <gmock/gmock.h>
namespace efi {
// Base class to help wrap EFI protocols in gmock classes.
//
// This does a few nice things that we would otherwise have to repeat in each mock:
// 1. Provides a protocol() function to access the raw EFI protocol.
// 2. Provides a mechanism to bounce the C function into the C++ mock class
//
// Example usage:
// ==============
// // Given this EFI protocol:
// typedef struct efi_foo_protocol {
// efi_status (*Foo)(struct efi_foo_protocol* self, char foo) EFIAPI;
// efi_status (*Bar)(struct efi_foo_protocol* self, uint32_t* bar) EFIAPI;
// } efi_foo_protocol;
//
// // Defining the mock looks like this:
// // 1. Use CRTP to make a MockProtocolBase sub-class.
// class MockFooProtocol : public MockProtocolBase<MockFooProtocol, efi_foo_protocol> {
// public:
// // 2. In the constructor, use Bounce<> to set up each protocol function.
// MockFooProtocol() : MockProtocolBase(
// {.Foo = Bounce<&MockFooProtocol::Foo>,
// .Bar = Bounce<&MockFooProtocol::Bar>}) {}
//
// // 3. Wrap the protocol functions in MOCK_METHOD(), omitting the |self| param.
// MOCK_METHOD(efi_status, Foo, (char foo));
// MOCK_METHOD(efi_status, Bar, (uint32_t* bar));
// };
// ==============
template <typename Derived, typename Protocol>
class MockProtocolBase {
public:
explicit MockProtocolBase(const Protocol& protocol)
: wrapper_{protocol, static_cast<Derived*>(this)} {}
virtual ~MockProtocolBase() = default;
Protocol* protocol() { return &wrapper_; }
protected:
// Wraps the C protocol struct with a pointer to our C++ object so we can
// locate the mock object from the C protocol pointer.
struct Wrapper : public Protocol {
constexpr explicit Wrapper(const Protocol& protocol, Derived* mock)
: Protocol(protocol), mock_(mock) {}
Derived* mock_ = nullptr;
};
// Bounces the EFI C function pointer into the mock function..
template <auto Method, typename... Args>
EFIAPI static efi_status Bounce(Protocol* self, Args... args) {
return (static_cast<Wrapper*>(self)->mock_->*Method)(args...);
}
Wrapper wrapper_;
};
} // namespace efi
#endif // ZIRCON_KERNEL_LIB_EFI_TESTING_INCLUDE_LIB_EFI_TESTING_MOCK_PROTOCOL_BASE_H_