Files
UnrealEngine/Engine/Source/ThirdParty/FakeIt/2.0.2/include/fakeit/MethodMockingContext.hpp
2025-05-18 13:04:45 +08:00

412 lines
14 KiB
C++

/*
* Copyright (c) 2014 Eran Pe'er.
*
* This program is made available under the terms of the MIT License.
*
* Created on Mar 10, 2014
*/
#pragma once
#include <functional>
#include <utility>
#include <type_traits>
#include <tuple>
#include <memory>
#include <vector>
#include <unordered_set>
#include <set>
#include <iosfwd>
#include "fakeit/RecordedMethodBody.hpp"
#include "fakeit/StubbingProgress.hpp"
#include "fakeit/Sequence.hpp"
#include "fakeit/ActualInvocation.hpp"
#include "fakeit/EventHandler.hpp"
#include "fakeit/ActionSequence.hpp"
#include "fakeit/DomainObjects.hpp"
#include "fakeit/SpyingContext.hpp"
#include "fakeit/StubbingContext.hpp"
#include "fakeit/MatchersCollector.hpp"
#include "mockutils/type_utils.hpp"
namespace fakeit {
/**
* Build recorded sequence and the matching criteria.
* For example, for the following line:
* When(Method(mock,foo)).Return(1).Return(2_Times(2)).Throw(e1);
* The matching criteria is: Any invocation of mock.foo
* The recorded sequence is: {Return(1), Return(2), Return(2), Throw(e1)}
*/
template<typename R, typename ... arglist>
class MethodMockingContext :
public Sequence, // For use in Verify(sequence1,...)... phrases.
public ActualInvocationsSource, // For use in Using(source1,souece2,...) and VerifyNoOtherInvocations(source1,souece2...) phrases.
public virtual StubbingContext<R, arglist...>, // For use in Fake & When phrases
public virtual SpyingContext<R, arglist...>, // For use in Spy phrases
private Invocation::Matcher {
public:
struct Context : public Destructible {
virtual ~Context() = default;
/**
* Return the original method. not the mock.
*/
virtual std::function<R(arglist &...)> getOriginalMethod() = 0;
virtual std::string getMethodName() = 0;
virtual void addMethodInvocationHandler(typename ActualInvocation<arglist...>::Matcher *matcher,
MethodInvocationHandler<R, arglist...> *invocationHandler) = 0;
virtual void scanActualInvocations(const std::function<void(ActualInvocation<arglist...> &)> &scanner) = 0;
virtual void setMethodDetails(std::string mockName, std::string methodName) = 0;
virtual bool isOfMethod(MethodInfo &method) = 0;
virtual ActualInvocationsSource &getInvolvedMock() = 0;
};
private:
class Implementation {
Context *_stubbingContext;
ActionSequence<R, arglist...> *_recordedActionSequence;
typename ActualInvocation<arglist...>::Matcher *_invocationMatcher;
bool _commited;
Context &getStubbingContext() const {
return *_stubbingContext;
}
public:
Implementation(Context *stubbingContext)
: _stubbingContext(stubbingContext),
_recordedActionSequence(new ActionSequence<R, arglist...>()),
_invocationMatcher
{
new DefaultInvocationMatcher<arglist...>()}, _commited(false) {
}
~Implementation() {
delete _stubbingContext;
if (!_commited) {
// no commit. delete the created objects.
delete _recordedActionSequence;
delete _invocationMatcher;
}
}
ActionSequence<R, arglist...> &getRecordedActionSequence() {
return *_recordedActionSequence;
}
std::string format() const {
std::string s = getStubbingContext().getMethodName();
s += _invocationMatcher->format();
return s;
}
void getActualInvocations(std::unordered_set<Invocation *> &into) const {
auto scanner = [&](ActualInvocation<arglist...> &a) {
if (_invocationMatcher->matches(a)) {
into.insert(&a);
}
};
getStubbingContext().scanActualInvocations(scanner);
}
/**
* Used only by Verify phrase.
*/
bool matches(Invocation &invocation) {
MethodInfo &actualMethod = invocation.getMethod();
if (!getStubbingContext().isOfMethod(actualMethod)) {
return false;
}
ActualInvocation<arglist...> &actualInvocation = dynamic_cast<ActualInvocation<arglist...> &>(invocation);
return _invocationMatcher->matches(actualInvocation);
}
void commit() {
getStubbingContext().addMethodInvocationHandler(_invocationMatcher, _recordedActionSequence);
_commited = true;
}
void appendAction(Action<R, arglist...> *action) {
getRecordedActionSequence().AppendDo(action);
}
void setMethodBodyByAssignment(std::function<R(arglist &...)> method) {
appendAction(new RepeatForever<R, arglist...>(method));
commit();
}
void setMethodDetails(std::string mockName, std::string methodName) {
getStubbingContext().setMethodDetails(mockName, methodName);
}
void getInvolvedMocks(std::vector<ActualInvocationsSource *> &into) const {
into.push_back(&getStubbingContext().getInvolvedMock());
}
typename std::function<R(arglist &...)> getOriginalMethod() {
return getStubbingContext().getOriginalMethod();
}
void setInvocationMatcher(typename ActualInvocation<arglist...>::Matcher *matcher) {
delete _invocationMatcher;
_invocationMatcher = matcher;
}
};
protected:
MethodMockingContext(Context *stubbingContext)
: _impl{new Implementation(stubbingContext)} {
}
MethodMockingContext(MethodMockingContext &) = default;
//we have to write move ctor by hand since VC 2013 doesn't support defaulted
//move constructor and move assignment
MethodMockingContext(MethodMockingContext &&other)
: _impl(std::move(other._impl)) {
}
virtual ~MethodMockingContext() { }
std::string format() const {
return _impl->format();
}
unsigned int size() const override {
return 1;
}
/**
* Used only by Verify phrase.
*/
void getInvolvedMocks(std::vector<ActualInvocationsSource *> &into) const override {
_impl->getInvolvedMocks(into);
}
void getExpectedSequence(std::vector<Invocation::Matcher *> &into) const override {
const Invocation::Matcher *b = this;
Invocation::Matcher *c = const_cast<Invocation::Matcher *>(b);
into.push_back(c);
}
/**
* Used only by Verify phrase.
*/
void getActualInvocations(std::unordered_set<Invocation *> &into) const override {
_impl->getActualInvocations(into);
}
/**
* Used only by Verify phrase.
*/
bool matches(Invocation &invocation) override {
return _impl->matches(invocation);
}
void commit() override {
_impl->commit();
}
void setMethodDetails(std::string mockName, std::string methodName) {
_impl->setMethodDetails(mockName, methodName);
}
void setMatchingCriteria(std::function<bool(arglist &...)> predicate) {
typename ActualInvocation<arglist...>::Matcher *matcher{
new UserDefinedInvocationMatcher<arglist...>(predicate)};
_impl->setInvocationMatcher(matcher);
}
void setMatchingCriteria(const std::vector<Destructible *> &matchers) {
typename ActualInvocation<arglist...>::Matcher *matcher{
new ArgumentsMatcherInvocationMatcher<arglist...>(matchers)};
_impl->setInvocationMatcher(matcher);
}
/**
* Used by Fake, Spy & When functors
*/
void appendAction(Action<R, arglist...> *action) override {
_impl->appendAction(action);
}
void setMethodBodyByAssignment(std::function<R(arglist &...)> method) {
_impl->setMethodBodyByAssignment(method);
}
template<class ...matcherCreators, class = typename std::enable_if<
sizeof...(matcherCreators) == sizeof...(arglist)>::type>
void setMatchingCriteria(const matcherCreators &... matcherCreator) {
std::vector<Destructible *> matchers;
MatchersCollector<0, arglist...> c(matchers);
c.CollectMatchers(matcherCreator...);
MethodMockingContext<R, arglist...>::setMatchingCriteria(matchers);
}
private:
std::function<R(arglist &...)> getOriginalMethod() override {
return _impl->getOriginalMethod();
}
std::shared_ptr<Implementation> _impl;
};
template<typename R, typename ... arglist>
class MockingContext :
public MethodMockingContext<R, arglist...> {
MockingContext &operator=(const MockingContext &) = delete;
public:
MockingContext(typename MethodMockingContext<R, arglist...>::Context *stubbingContext)
: MethodMockingContext<R, arglist...>(stubbingContext) {
}
MockingContext(MockingContext &) = default;
MockingContext(MockingContext &&other)
: MethodMockingContext<R, arglist...>(std::move(other)) {
}
MockingContext<R, arglist...> &setMethodDetails(std::string mockName, std::string methodName) {
MethodMockingContext<R, arglist...>::setMethodDetails(mockName, methodName);
return *this;
}
MockingContext<R, arglist...> &Using(const arglist &... args) {
MethodMockingContext<R, arglist...>::setMatchingCriteria(args...);
return *this;
}
template<class ...arg_matcher>
MockingContext<R, arglist...> &Using(const arg_matcher &... arg_matchers) {
MethodMockingContext<R, arglist...>::setMatchingCriteria(arg_matchers...);
return *this;
}
MockingContext<R, arglist...> &Matching(std::function<bool(arglist &...)> matcher) {
MethodMockingContext<R, arglist...>::setMatchingCriteria(matcher);
return *this;
}
MockingContext<R, arglist...> &operator()(const arglist &... args) {
MethodMockingContext<R, arglist...>::setMatchingCriteria(args...);
return *this;
}
MockingContext<R, arglist...> &operator()(std::function<bool(arglist &...)> matcher) {
MethodMockingContext<R, arglist...>::setMatchingCriteria(matcher);
return *this;
}
void operator=(std::function<R(arglist &...)> method) {
MethodMockingContext<R, arglist...>::setMethodBodyByAssignment(method);
}
template<typename U = R>
typename std::enable_if<!std::is_reference<U>::value, void>::type operator=(const R &r) {
auto method = [r](arglist &...) -> R { return r; };
MethodMockingContext<R, arglist...>::setMethodBodyByAssignment(method);
}
template<typename U = R>
typename std::enable_if<std::is_reference<U>::value, void>::type operator=(const R &r) {
auto method = [&r](arglist &...) -> R { return r; };
MethodMockingContext<R, arglist...>::setMethodBodyByAssignment(method);
}
};
template<typename ... arglist>
class MockingContext<void, arglist...> :
public MethodMockingContext<void, arglist...> {
MockingContext &operator=(const MockingContext &) = delete;
public:
MockingContext(typename MethodMockingContext<void, arglist...>::Context *stubbingContext)
: MethodMockingContext<void, arglist...>(stubbingContext) {
}
MockingContext(MockingContext &) = default;
MockingContext(MockingContext &&other)
: MethodMockingContext<void, arglist...>(std::move(other)) {
}
MockingContext<void, arglist...> &setMethodDetails(std::string mockName, std::string methodName) {
MethodMockingContext<void, arglist...>::setMethodDetails(mockName, methodName);
return *this;
}
MockingContext<void, arglist...> &Using(const arglist &... args) {
MethodMockingContext<void, arglist...>::setMatchingCriteria(args...);
return *this;
}
template<class ...arg_matcher>
MockingContext<void, arglist...> &Using(const arg_matcher &... arg_matchers) {
MethodMockingContext<void, arglist...>::setMatchingCriteria(arg_matchers...);
return *this;
}
MockingContext<void, arglist...> &Matching(std::function<bool(arglist &...)> matcher) {
MethodMockingContext<void, arglist...>::setMatchingCriteria(matcher);
return *this;
}
MockingContext<void, arglist...> &operator()(const arglist &... args) {
MethodMockingContext<void, arglist...>::setMatchingCriteria(args...);
return *this;
}
MockingContext<void, arglist...> &operator()(std::function<bool(arglist &...)> matcher) {
MethodMockingContext<void, arglist...>::setMatchingCriteria(matcher);
return *this;
}
void operator=(std::function<void(arglist &...)> method) {
MethodMockingContext<void, arglist...>::setMethodBodyByAssignment(method);
}
};
class DtorMockingContext : public MethodMockingContext<void> {
public:
DtorMockingContext(MethodMockingContext<void>::Context *stubbingContext)
: MethodMockingContext<void>(stubbingContext) {
}
DtorMockingContext(DtorMockingContext &other) : MethodMockingContext<void>(other) {
}
DtorMockingContext(DtorMockingContext &&other) : MethodMockingContext<void>(std::move(other)) {
}
void operator=(std::function<void()> method) {
MethodMockingContext<void>::setMethodBodyByAssignment(method);
}
DtorMockingContext &setMethodDetails(std::string mockName, std::string methodName) {
MethodMockingContext<void>::setMethodDetails(mockName, methodName);
return *this;
}
};
}