blob: bdfc3a7c9e102f0e0a57d5c48946caa9fc032c4d [file] [log] [blame]
// Copyright 2019 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.
#pragma once
#include <tuple>
#include <fbl/vector.h>
#include <zxtest/zxtest.h>
namespace mock_function {
// This class mocks a single function. The first template argument is the return type (or void), and
// the rest are the function arguments. ExpectCall(return_value, arg1, arg2, ...) and
// ExpectNoCall() are used by the test to set expectations, and Call(arg1, arg2, ...) is used by
// the code under test. See the following example:
//
// class SomeClassTest : SomeClass {
// public:
// zx_status_t CallsSomeMethod();
//
// mock_function::MockFunction<zx_status_t, uint32_t, uint32_t>& mock_SomeMethod() {
// return mock_some_method_;
// }
//
// private:
// zx_status_t SomeMethod(uint32_t a, uint32_t b) override {
// return mock_some_method_.Call(a, b);
// }
//
// mock_function::MockFunction<zx_status_t, uint32_t, uint32_t> mock_some_method_;
// };
//
// TEST(SomeDriver, SomeTest) {
// SomeClassTest test;
// test.mock_SomeMethod().ExpectCall(ZX_OK, 100, 30);
//
// EXPECT_OK(test.CallsSomeMethod());
//
// test.mock_SomeMethod().VerifyAndClear();
// }
template <typename R, typename... Ts>
class MockFunction {
public:
MockFunction& ExpectCall(R ret, Ts... args) {
has_expectations_ = true;
expectations_.push_back(Expectation{ret, std::make_tuple(args...)});
return *this;
}
MockFunction& ExpectNoCall() {
has_expectations_ = true;
return *this;
}
R Call(Ts... args) {
R ret = {};
CallHelper(&ret, args...);
return ret;
}
bool HasExpectations() const { return has_expectations_; }
void VerifyAndClear() {
EXPECT_EQ(expectation_index_, expectations_.size());
expectations_.reset();
expectation_index_ = 0;
}
private:
struct Expectation {
R ret_value;
std::tuple<Ts...> args;
};
void CallHelper(R* ret, Ts... args) {
ASSERT_LT(expectation_index_, expectations_.size());
Expectation exp = expectations_[expectation_index_++];
EXPECT_TRUE(exp.args == std::make_tuple(args...));
*ret = exp.ret_value;
}
bool has_expectations_ = false;
fbl::Vector<Expectation> expectations_;
size_t expectation_index_ = 0;
};
template <typename... Ts>
class MockFunction<void, Ts...> {
public:
MockFunction& ExpectCall(Ts... args) {
has_expectations_ = true;
expectations_.push_back(std::make_tuple(args...));
return *this;
}
MockFunction& ExpectNoCall() {
has_expectations_ = true;
return *this;
}
void Call(Ts... args) { CallHelper(args...); }
bool HasExpectations() const { return has_expectations_; }
void VerifyAndClear() {
ASSERT_EQ(expectation_index_, expectations_.size());
expectations_.reset();
expectation_index_ = 0;
}
private:
void CallHelper(Ts... args) {
ASSERT_LT(expectation_index_, expectations_.size());
EXPECT_TRUE(expectations_[expectation_index_++] == std::make_tuple(args...));
}
bool has_expectations_ = false;
fbl::Vector<std::tuple<Ts...>> expectations_;
size_t expectation_index_ = 0;
};
} // namespace mock_function