7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-18 20:49:24 +00:00

qa: Add Turtle 1.3.2 mocking framework

This commit is contained in:
Sylwester Kocjan 2021-01-25 22:16:58 +01:00 committed by Seth Hillbrand
parent dc39703d0e
commit a65999b063
55 changed files with 4435 additions and 0 deletions

View File

@ -24,7 +24,10 @@
#ifndef UNIT_TEST_UTILS__H
#define UNIT_TEST_UTILS__H
#define BOOST_NO_AUTO_PTR
#include <boost/test/unit_test.hpp>
#include <turtle/mock.hpp>
#include <qa_utils/wx_utils/wx_assert.h>

View File

@ -41,3 +41,4 @@ add_subdirectory( picosha2 )
add_subdirectory( json_schema_validator )
add_subdirectory( pegtl )
add_subdirectory( 3dxware_sdk )
add_subdirectory( turtle )

23
thirdparty/turtle/BOOST.LICENSE_1_0.txt vendored Normal file
View File

@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

3
thirdparty/turtle/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,3 @@
add_library( turtle INTERFACE )
target_include_directories( turtle INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} )

6
thirdparty/turtle/README.txt vendored Normal file
View File

@ -0,0 +1,6 @@
This directory contains the Turtle Mocking Framework version 1.3.2 (0dd0dfa15fbc2774213523fb3a65bc1acb2857b3)
from https://github.com/mat007/turtle
Turtle is a C++ mock object library based on Boost with a focus on usability, simplicity and flexibility.
Distributed under the Boost Software License, Version 1.0, with license text in this directory.

46
thirdparty/turtle/turtle/catch.hpp vendored Normal file
View File

@ -0,0 +1,46 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon and Ovanes Markarian 2017
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_CATCH_HPP_INCLUDED
#define MOCK_CATCH_HPP_INCLUDED
#include <catch.hpp>
template<typename Result>
struct catch_mock_error_policy
{
static Result abort()
{
FAIL("Aborted");
throw std::runtime_error("unreachable");
}
template<typename Context>
static void fail(const char* message,
const Context& context,
const char* file = "file://unknown-location",
int line = 0)
{
CAPTURE(context);
FAIL_CHECK(message << " in: " << file << ":" << line);
}
template<typename Context>
static void call(const Context& context, const char* file, int line)
{
CAPTURE(context);
INFO(file << ":" << line);
}
static void pass(const char* file, int line) { INFO(file << ":" << line); }
};
#define MOCK_ERROR_POLICY catch_mock_error_policy
#include "mock.hpp"
#endif // MOCK_CATCH_HPP_INCLUDED

34
thirdparty/turtle/turtle/cleanup.hpp vendored Normal file
View File

@ -0,0 +1,34 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2011
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_CLEANUP_HPP_INCLUDED
#define MOCK_CLEANUP_HPP_INCLUDED
#include "config.hpp"
#include "reset.hpp"
#include "verify.hpp"
#ifdef MOCK_USE_BOOST_TEST
# include <boost/test/unit_test_suite.hpp>
#endif
namespace mock {
struct cleanup
{
~cleanup() { mock::reset(); }
};
#ifdef MOCK_USE_BOOST_TEST
BOOST_GLOBAL_FIXTURE(cleanup)
# if BOOST_VERSION >= 105900
;
# endif
#endif
} // namespace mock
#endif // MOCK_CLEANUP_HPP_INCLUDED

33
thirdparty/turtle/turtle/config.hpp vendored Normal file
View File

@ -0,0 +1,33 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2009
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// boost-no-inspect
#ifndef MOCK_CONFIG_HPP_INCLUDED
#define MOCK_CONFIG_HPP_INCLUDED
#include <boost/config.hpp>
#ifndef MOCK_ERROR_POLICY
# define MOCK_ERROR_POLICY mock::error
# define MOCK_USE_BOOST_TEST
#endif
#if !defined(BOOST_NO_CXX11_HDR_MUTEX) && !defined(BOOST_NO_0X_HDR_MUTEX)
# ifndef MOCK_NO_HDR_MUTEX
# define MOCK_HDR_MUTEX
# endif
#endif
#if defined(__cpp_lib_uncaught_exceptions) || defined(_MSC_VER) && (_MSC_VER >= 1900)
# ifndef MOCK_NO_UNCAUGHT_EXCEPTIONS
# define MOCK_UNCAUGHT_EXCEPTIONS
# endif
#endif
#endif // MOCK_CONFIG_HPP_INCLUDED

188
thirdparty/turtle/turtle/constraint.hpp vendored Normal file
View File

@ -0,0 +1,188 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2008
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_CONSTRAINT_HPP_INCLUDED
#define MOCK_CONSTRAINT_HPP_INCLUDED
#include "config.hpp"
#include "log.hpp"
#include "unwrap_reference.hpp"
#include <boost/preprocessor/array.hpp>
#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/variadic/size.hpp>
#include <functional>
#include <type_traits>
namespace mock {
template<typename Constraint>
struct constraint
{
constraint() {}
constraint(const Constraint& c) : c_(c) {}
Constraint c_;
};
namespace detail {
template<typename Lhs, typename Rhs>
class and_
{
public:
and_(const Lhs& lhs, const Rhs& rhs) : lhs_(lhs), rhs_(rhs) {}
template<typename Actual>
bool operator()(const Actual& actual) const
{
return lhs_(actual) && rhs_(actual);
}
friend std::ostream& operator<<(std::ostream& s, const and_& a)
{
return s << "( " << mock::format(a.lhs_) << " && " << mock::format(a.rhs_) << " )";
}
private:
Lhs lhs_;
Rhs rhs_;
};
template<typename Lhs, typename Rhs>
class or_
{
public:
or_(const Lhs& lhs, const Rhs& rhs) : lhs_(lhs), rhs_(rhs) {}
template<typename Actual>
bool operator()(const Actual& actual) const
{
return lhs_(actual) || rhs_(actual);
}
friend std::ostream& operator<<(std::ostream& s, const or_& o)
{
return s << "( " << mock::format(o.lhs_) << " || " << mock::format(o.rhs_) << " )";
}
private:
Lhs lhs_;
Rhs rhs_;
};
template<typename Constraint>
class not_
{
public:
explicit not_(const Constraint& c) : c_(c) {}
template<typename Actual>
bool operator()(const Actual& actual) const
{
return !c_(actual);
}
friend std::ostream& operator<<(std::ostream& s, const not_& n) { return s << "! " << mock::format(n.c_); }
private:
Constraint c_;
};
} // namespace detail
template<typename Lhs, typename Rhs>
const constraint<detail::or_<Lhs, Rhs>> operator||(const constraint<Lhs>& lhs, const constraint<Rhs>& rhs)
{
return detail::or_<Lhs, Rhs>(lhs.c_, rhs.c_);
}
template<typename Lhs, typename Rhs>
const constraint<detail::and_<Lhs, Rhs>> operator&&(const constraint<Lhs>& lhs, const constraint<Rhs>& rhs)
{
return detail::and_<Lhs, Rhs>(lhs.c_, rhs.c_);
}
template<typename Constraint>
const constraint<detail::not_<Constraint>> operator!(const constraint<Constraint>& c)
{
return detail::not_<Constraint>(c.c_);
}
} // namespace mock
#define MOCK_UNARY_CONSTRAINT(Name, n, Args, Expr) \
namespace detail { \
struct Name \
{ \
template<typename Actual> \
bool operator()(const Actual& actual) const \
{ \
(void)actual; \
return Expr; \
} \
friend std::ostream& operator<<(std::ostream& s, const Name&) { return s << BOOST_STRINGIZE(Name); } \
}; \
} \
const mock::constraint<detail::Name> Name;
#define MOCK_CONSTRAINT_ASSIGN(z, n, d) expected##n(std::forward<T##n>(e##n))
#define MOCK_CONSTRAINT_UNWRAP_REF(z, n, d) mock::unwrap_ref(expected##n)
#define MOCK_CONSTRAINT_FORMAT(z, n, d) BOOST_PP_IF(n, << ", " <<, ) mock::format(c.expected##n)
#define MOCK_CONSTRAINT_MEMBER(z, n, d) Expected_##n expected##n;
#define MOCK_CONSTRAINT_TPL_TYPE(z, n, d) std::decay_t<const T##n>
#define MOCK_CONSTRAINT_CREF_PARAM(z, n, Args) \
const mock::unwrap_reference_t<Expected_##n>& BOOST_PP_ARRAY_ELEM(n, Args)
#define MOCK_CONSTRAINT_ARG(z, n, Args) T##n&& BOOST_PP_ARRAY_ELEM(n, Args)
#define MOCK_CONSTRAINT_ARGS(z, n, Args) T##n&& e##n
#define MOCK_CONSTRAINT_PARAM(z, n, Args) std::forward<T##n>(BOOST_PP_ARRAY_ELEM(n, Args))
#define MOCK_NARY_CONSTRAINT(Name, n, Args, Expr) \
namespace detail { \
template<BOOST_PP_ENUM_PARAMS(n, typename Expected_)> \
struct Name \
{ \
template<BOOST_PP_ENUM_PARAMS(n, typename T)> \
explicit Name(BOOST_PP_ENUM(n, MOCK_CONSTRAINT_ARGS, _)) : BOOST_PP_ENUM(n, MOCK_CONSTRAINT_ASSIGN, _) \
{} \
template<typename Actual> \
bool operator()(const Actual& actual) const \
{ \
return test(actual, BOOST_PP_ENUM(n, MOCK_CONSTRAINT_UNWRAP_REF, _)); \
} \
template<typename Actual> \
bool test(const Actual& actual, BOOST_PP_ENUM(n, MOCK_CONSTRAINT_CREF_PARAM, (n, Args))) const \
{ \
return Expr; \
} \
friend std::ostream& operator<<(std::ostream& s, const Name& c) \
{ \
return s << BOOST_STRINGIZE(Name) << "( " << BOOST_PP_REPEAT(n, MOCK_CONSTRAINT_FORMAT, _) << " )"; \
} \
BOOST_PP_REPEAT(n, MOCK_CONSTRAINT_MEMBER, _) \
}; \
} \
template<BOOST_PP_ENUM_PARAMS(n, typename T)> \
mock::constraint<detail::Name<BOOST_PP_ENUM(n, MOCK_CONSTRAINT_TPL_TYPE, _)>> Name( \
BOOST_PP_ENUM(n, MOCK_CONSTRAINT_ARG, (n, Args))) \
{ \
return detail::Name<BOOST_PP_ENUM(n, MOCK_CONSTRAINT_TPL_TYPE, _)>( \
BOOST_PP_ENUM(n, MOCK_CONSTRAINT_PARAM, (n, Args))); \
}
#define MOCK_CONSTRAINT_EXT(Name, n, Args, Expr) \
BOOST_PP_IF(n, MOCK_NARY_CONSTRAINT, MOCK_UNARY_CONSTRAINT)(Name, n, Args, Expr)
#define MOCK_CONSTRAINT_AUX_AUX(Name, n, Array) \
MOCK_CONSTRAINT_EXT(Name, n, BOOST_PP_ARRAY_TO_TUPLE(BOOST_PP_ARRAY_POP_BACK(Array)), BOOST_PP_ARRAY_ELEM(n, Array))
#define MOCK_CONSTRAINT_AUX(Name, Size, Tuple) MOCK_CONSTRAINT_AUX_AUX(Name, BOOST_PP_DEC(Size), (Size, Tuple))
#define MOCK_CONSTRAINT(Name, ...) MOCK_CONSTRAINT_AUX(Name, BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), (__VA_ARGS__))
#endif // MOCK_CONSTRAINT_HPP_INCLUDED

253
thirdparty/turtle/turtle/constraints.hpp vendored Normal file
View File

@ -0,0 +1,253 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2008
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_CONSTRAINTS_HPP_INCLUDED
#define MOCK_CONSTRAINTS_HPP_INCLUDED
#include "config.hpp"
#include "constraint.hpp"
#include "detail/void_t.hpp"
#include "unwrap_reference.hpp"
#include <boost/version.hpp>
#if BOOST_VERSION >= 107000
# include <boost/test/tools/floating_point_comparison.hpp>
#else
# include <boost/test/floating_point_comparison.hpp>
#endif
#include <functional>
#include <memory>
#include <type_traits>
namespace mock {
MOCK_UNARY_CONSTRAINT(any, 0, , ((void)actual, true))
MOCK_UNARY_CONSTRAINT(affirm, 0, , !!actual)
MOCK_UNARY_CONSTRAINT(negate, 0, , !actual)
MOCK_UNARY_CONSTRAINT(evaluate, 0, , actual())
MOCK_NARY_CONSTRAINT(less, 1, (expected), actual < expected)
MOCK_NARY_CONSTRAINT(greater, 1, (expected), actual > expected)
MOCK_NARY_CONSTRAINT(less_equal, 1, (expected), actual <= expected)
MOCK_NARY_CONSTRAINT(greater_equal, 1, (expected), actual >= expected)
#if BOOST_VERSION < 105900
# define MOCK_SMALL() boost::test_tools::check_is_small(actual, tolerance)
# define MOCK_PERCENT_TOLERANCE() \
boost::test_tools::check_is_close(actual, expected, boost::test_tools::percent_tolerance(tolerance))
# define MOCK_FRACTION_TOLERANCE() \
boost::test_tools::check_is_close(actual, expected, boost::test_tools::fraction_tolerance(tolerance))
#else // BOOST_VERSION < 105900
namespace detail {
template<typename T, typename Tolerance>
bool is_small(const T& t, const Tolerance& tolerance)
{
return boost::math::fpc::small_with_tolerance<T>(tolerance)(t);
}
template<typename T1, typename T2, typename Tolerance>
bool is_close(const T1& t1, const T2& t2, const Tolerance& tolerance)
{
typedef std::common_type_t<T1, T2> common_type;
return boost::math::fpc::close_at_tolerance<common_type>(tolerance, boost::math::fpc::FPC_STRONG)(t1, t2);
}
} // namespace detail
# define MOCK_SMALL() detail::is_small(actual, tolerance)
# define MOCK_PERCENT_TOLERANCE() detail::is_close(actual, expected, boost::math::fpc::percent_tolerance(tolerance))
# define MOCK_FRACTION_TOLERANCE() detail::is_close(actual, expected, tolerance)
#endif // BOOST_VERSION < 105900
#ifdef small
# pragma push_macro("small")
# undef small
# define MOCK_SMALL_DEFINED
#endif
MOCK_NARY_CONSTRAINT(small, 1, (tolerance), (MOCK_SMALL()))
#ifdef MOCK_SMALL_DEFINED
# pragma pop_macro("small")
#endif
MOCK_NARY_CONSTRAINT(close, 2, (expected, tolerance), (MOCK_PERCENT_TOLERANCE()))
MOCK_NARY_CONSTRAINT(close_fraction, 2, (expected, tolerance), (MOCK_FRACTION_TOLERANCE()))
#undef MOCK_PERCENT_TOLERANCE
#undef MOCK_FRACTION_TOLERANCE
#ifdef near
# pragma push_macro("near")
# undef near
# define MOCK_NEAR_DEFINED
#endif
MOCK_NARY_CONSTRAINT(near, 2, (expected, tolerance), std::abs(actual - expected) <= tolerance)
#ifdef MOCK_NEAR_DEFINED
# pragma pop_macro("near")
#endif
namespace detail {
template<class T, class U = T, class = void>
struct has_equal_to : std::false_type
{};
template<class T, class U>
struct has_equal_to<T, U, void_t<decltype(std::declval<T>() == std::declval<U>())>> : std::true_type
{};
template<typename Expected>
struct equal
{
explicit equal(Expected expected) : expected_(expected) {}
template<typename Actual>
bool operator()(const Actual& actual,
std::enable_if_t<has_equal_to<Actual, unwrap_reference_t<Expected>>::value>* = 0) const
{
return actual == unwrap_ref(expected_);
}
template<typename Actual>
bool operator()(const Actual& actual,
std::enable_if_t<!has_equal_to<Actual, unwrap_reference_t<Expected>>::value>* = 0) const
{
return actual && *actual == unwrap_ref(expected_);
}
friend std::ostream& operator<<(std::ostream& s, const equal& e)
{
return s << "equal( " << mock::format(e.expected_) << " )";
}
Expected expected_;
};
template<typename Expected>
struct same
{
explicit same(const Expected& expected) : expected_(std::addressof(unwrap_ref(expected))) {}
template<typename Actual>
bool operator()(const Actual& actual) const
{
return std::addressof(actual) == expected_;
}
friend std::ostream& operator<<(std::ostream& os, const same& s)
{
return os << "same( " << mock::format(*s.expected_) << " )";
}
const unwrap_reference_t<Expected>* expected_;
};
template<typename Expected>
struct retrieve
{
explicit retrieve(Expected& expected) : expected_(std::addressof(unwrap_ref(expected))) {}
template<typename Actual>
bool operator()(
const Actual& actual,
std::enable_if_t<!std::is_convertible<const Actual*, unwrap_reference_t<Expected>>::value>* = 0) const
{
*expected_ = actual;
return true;
}
template<typename Actual>
bool operator()(
Actual&& actual,
std::enable_if_t<!std::is_convertible<const Actual*, unwrap_reference_t<Expected>>::value>* = 0) const
{
*expected_ = std::move(actual);
return true;
}
template<typename Actual>
bool operator()(Actual& actual,
std::enable_if_t<std::is_convertible<Actual*, unwrap_reference_t<Expected>>::value>* = 0) const
{
*expected_ = std::addressof(actual);
return true;
}
friend std::ostream& operator<<(std::ostream& s, const retrieve& r)
{
return s << "retrieve( " << mock::format(*r.expected_) << " )";
}
unwrap_reference_t<Expected>* expected_;
};
template<typename Expected>
struct assign
{
explicit assign(const Expected& expected) : expected_(expected) {}
template<typename Actual>
bool operator()(Actual& actual) const
{
actual = unwrap_ref(expected_);
return true;
}
template<typename Actual>
bool operator()(Actual* actual,
std::enable_if_t<std::is_convertible<unwrap_reference_t<Expected>, Actual>::value>* = 0) const
{
if(!actual)
return false;
*actual = unwrap_ref(expected_);
return true;
}
friend std::ostream& operator<<(std::ostream& s, const assign& a)
{
return s << "assign( " << mock::format(a.expected_) << " )";
}
Expected expected_;
};
template<typename Expected>
struct contain
{
explicit contain(const Expected& expected) : expected_(expected) {}
bool operator()(const std::string& actual) const
{
return actual.find(unwrap_ref(expected_)) != std::string::npos;
}
friend std::ostream& operator<<(std::ostream& s, const contain& n)
{
return s << "contain( " << mock::format(n.expected_) << " )";
}
Expected expected_;
};
} // namespace detail
template<typename T>
constraint<detail::equal<T>> equal(T&& t)
{
return detail::equal<T>(std::forward<T>(t));
}
template<typename T>
constraint<detail::same<T>> same(T& t)
{
return detail::same<T>(t);
}
template<typename T>
constraint<detail::retrieve<T>> retrieve(T& t)
{
return detail::retrieve<T>(t);
}
template<typename T>
constraint<detail::assign<T>> assign(T t)
{
return detail::assign<T>(t);
}
template<typename T>
constraint<detail::contain<T>> contain(T t)
{
return detail::contain<T>(t);
}
template<typename T>
constraint<T> call(T t)
{
return constraint<T>(t);
}
} // namespace mock
#endif // MOCK_CONSTRAINTS_HPP_INCLUDED

View File

@ -0,0 +1,137 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2008
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_ACTION_HPP_INCLUDED
#define MOCK_ACTION_HPP_INCLUDED
#include "../config.hpp"
#include <functional>
#include <memory>
#include <type_traits>
namespace mock { namespace detail {
template<typename Result, typename Signature>
class action_base
{
private:
typedef std::function<Signature> functor_type;
typedef std::function<Result()> action_type;
protected:
// Meant to be subclassed and not be directly used
// Non-relocatable (contained functions may wrap references/pointers which could be invalidated)
action_base() = default;
action_base(const action_base&) = delete;
action_base(action_base&&) = delete;
action_base& operator=(const action_base&) = delete;
action_base& operator=(action_base&&) = delete;
public:
const functor_type& functor() const { return f_; }
bool valid() const { return f_ || a_; }
Result trigger() const { return a_(); }
void calls(const functor_type& f)
{
if(!f)
throw std::invalid_argument("null functor");
f_ = f;
}
template<typename Exception>
void throws(Exception e)
{
a_ = [e]() -> Result { throw e; };
}
protected:
void set(const action_type& a) { a_ = a; }
template<typename Y>
void set(const std::reference_wrapper<Y>& r)
{
a_ = [r]() -> Result { return r.get(); };
}
private:
functor_type f_;
action_type a_;
};
/// Type erased value storage
struct value
{
value() = default;
value(const value&) = delete;
value& operator=(const value&) = delete;
virtual ~value() = default;
};
/// Actual value storage,
/// holds an instance of T (stripped of reference qualifiers)
template<typename T>
struct value_imp : value
{
using type = std::remove_const_t<std::remove_reference_t<T>>;
template<typename U>
value_imp(U&& t) : t_(std::forward<U>(t))
{}
type t_;
};
template<typename Result, typename Signature>
class action : public action_base<Result, Signature>
{
public:
template<typename Value>
void returns(const Value& v)
{
this->set(std::ref(store(v)));
}
template<typename Y>
void returns(const std::reference_wrapper<Y>& r)
{
this->set(r);
}
template<typename Value>
void moves(Value&& v)
{
auto vRef = std::ref(store(std::move(v)));
this->set([vRef]() { return std::move(vRef.get()); });
}
private:
template<typename T>
typename value_imp<T>::type& store(T&& t)
{
v_ = std::make_unique<value_imp<T>>(std::forward<T>(t));
return static_cast<value_imp<T>&>(*v_).t_;
}
template<typename T>
std::remove_reference_t<Result>& store(T* t)
{
v_ = std::make_unique<value_imp<Result>>(t);
return static_cast<value_imp<Result>&>(*v_).t_;
}
std::unique_ptr<value> v_;
};
template<typename Signature>
class action<void, Signature> : public action_base<void, Signature>
{
public:
action()
{
this->set([]() {});
}
};
}} // namespace mock::detail
#endif // MOCK_ACTION_HPP_INCLUDED

View File

@ -0,0 +1,36 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2013
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_ADDRESSOF_HPP_INCLUDED
#define MOCK_ADDRESSOF_HPP_INCLUDED
#include "../config.hpp"
#include <boost/utility/addressof.hpp>
namespace mock
{
namespace detail
{
using boost::addressof;
#ifdef MOCK_NULLPTR
inline const std::nullptr_t* addressof( const std::nullptr_t& p )
{
return &p;
}
inline std::nullptr_t* addressof( std::nullptr_t& p )
{
return &p;
}
#endif
}
} // mock
#endif // MOCK_ADDRESSOF_HPP_INCLUDED

View File

@ -0,0 +1,47 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2011
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_CHILD_HPP_INCLUDED
#define MOCK_CHILD_HPP_INCLUDED
#include "../config.hpp"
#include "parent.hpp"
#include "type_name.hpp"
#include <boost/optional.hpp>
#include <boost/test/utils/basic_cstring/basic_cstring.hpp>
#include <ostream>
namespace mock { namespace detail {
class child
{
public:
child() : parent_(0) {}
void update(parent& p,
boost::unit_test::const_string instance,
boost::optional<type_name> type,
boost::unit_test::const_string name)
{
if(instance != "?." || name_.empty())
p = parent(instance, type);
parent_ = &p;
name_ = name;
}
friend std::ostream& operator<<(std::ostream& s, const child& c)
{
if(c.parent_)
s << *c.parent_;
return s << c.name_;
}
private:
const parent* parent_;
boost::unit_test::const_string name_;
};
}} // namespace mock::detail
#endif // MOCK_CHILD_HPP_INCLUDED

View File

@ -0,0 +1,42 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2011
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_CONTEXT_HPP_INCLUDED
#define MOCK_CONTEXT_HPP_INCLUDED
#include "../config.hpp"
#include "type_name.hpp"
#include <boost/optional.hpp>
#include <boost/test/utils/basic_cstring/basic_cstring.hpp>
#include <ostream>
namespace mock { namespace detail {
class verifiable;
class context
{
public:
context() = default;
context(const context&) = delete;
context& operator=(const context&) = delete;
virtual ~context() = default;
virtual void add(const void* p,
verifiable& v,
boost::unit_test::const_string instance,
boost::optional<type_name> type,
boost::unit_test::const_string name) = 0;
virtual void add(verifiable& v) = 0;
virtual void remove(verifiable& v) = 0;
virtual void serialize(std::ostream& s, const verifiable& v) const = 0;
};
}} // namespace mock::detail
#endif // MOCK_CONTEXT_HPP_INCLUDED

View File

@ -0,0 +1,183 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2012
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_EXPECTATION_HPP_INCLUDED
#define MOCK_EXPECTATION_HPP_INCLUDED
#include "../matcher.hpp"
#include "../sequence.hpp"
#include "action.hpp"
#include "invocation.hpp"
#include "matcher_base.hpp"
#include <memory>
#include <tuple>
#include <type_traits>
#include <vector>
namespace mock { namespace detail {
template<typename... Args>
class default_matcher : public matcher_base<Args...>
{
private:
bool operator()(ref_arg_t<Args>...) override { return true; }
void serialize(std::ostream& s) const override
{
constexpr auto arity = sizeof...(Args);
for(unsigned i = 0; i < arity; ++i)
{
if(i)
s << ", ";
s << "any";
}
}
};
template<typename ConstraintPack, typename... Args>
class single_matcher;
template<typename... Constraints, typename... Args>
class single_matcher<void(Constraints...), Args...> : public matcher_base<Args...>
{
static_assert(sizeof...(Args) > 0, "This class is only useful for functions with arguments");
static_assert(sizeof...(Constraints) == sizeof...(Args), "Need exactly 1 constraint per argument");
public:
single_matcher(Constraints... constraints) : matchers_(matcher<Args, Constraints>(constraints)...) {}
private:
template<std::size_t... I>
bool is_valid_impl(std::index_sequence<I...>, ref_arg_t<Args>... t)
{
using expander = bool[];
bool result = true;
(void)expander{ result &= std::get<I>(matchers_)(static_cast<ref_arg_t<Args>>(t))... };
return result;
}
bool operator()(ref_arg_t<Args>... t) override
{
return is_valid_impl(std::make_index_sequence<sizeof...(Args)>{}, static_cast<ref_arg_t<Args>>(t)...);
}
template<std::size_t... I>
void serialize_impl(std::index_sequence<I...>, std::ostream& s) const
{
using expander = int[];
s << std::get<0>(matchers_);
(void)expander{ 0, (s << ", " << std::get<I + 1>(matchers_), 0)... };
}
void serialize(std::ostream& s) const override
{
serialize_impl(std::make_index_sequence<sizeof...(Args) - 1>{}, s);
}
private:
std::tuple<matcher<Args, Constraints>...> matchers_;
};
template<typename F, typename... Args>
class multi_matcher : public matcher_base<Args...>
{
static_assert(sizeof...(Args) > 0, "This class is only useful for functions with arguments");
public:
multi_matcher(const F& f) : f_(f) {}
private:
bool operator()(ref_arg_t<Args>... t) override { return f_(static_cast<ref_arg_t<Args>>(t)...); }
void serialize(std::ostream& s) const override { s << mock::format(f_); }
private:
F f_;
};
template<typename Signature>
class expectation;
template<typename R, typename... Args>
class expectation<R(Args...)> : public action<R, R(Args...)>
{
static constexpr std::size_t arity = sizeof...(Args);
public:
expectation() : expectation("unknown location", 0) {}
expectation(const char* file, int line)
: invocation_(std::make_unique<unlimited>()), matcher_(std::make_unique<default_matcher<Args...>>()),
file_(file), line_(line)
{}
expectation(expectation&&) = default;
expectation(expectation const&) = default;
expectation& operator=(expectation&&) = default;
expectation& operator=(expectation const&) = default;
~expectation()
{
for(auto& sequence : sequences_)
sequence->remove(this);
}
void invoke(std::unique_ptr<invocation> i) { invocation_ = std::move(i); }
template<typename... Constraints>
std::enable_if_t<(arity > 0u) && sizeof...(Constraints) == arity> with(Constraints... c)
{
matcher_ = std::make_unique<single_matcher<void(Constraints...), Args...>>(c...);
}
template<typename Constraint, std::size_t Arity = arity>
std::enable_if_t<(Arity > 1u)> with(const Constraint& c)
{
matcher_ = std::make_unique<multi_matcher<Constraint, Args...>>(c);
}
void add(sequence& s)
{
s.impl_->add(this);
sequences_.push_back(s.impl_);
}
bool verify() const { return invocation_->verify(); }
bool is_valid(ref_arg_t<Args>... t) const
{
return !invocation_->exhausted() && (*matcher_)(static_cast<ref_arg_t<Args>>(t)...);
}
bool invoke() const
{
for(auto& sequence : sequences_)
{
if(!sequence->is_valid(this))
return false;
}
bool result = invocation_->invoke();
for(auto& sequence : sequences_)
sequence->invalidate(this);
return result;
}
const char* file() const { return file_; }
int line() const { return line_; }
friend std::ostream& operator<<(std::ostream& s, const expectation& e)
{
s << (e.invocation_->exhausted() ? 'v' : '.') << ' ' << *e.invocation_;
constexpr bool hasArguments = arity > 0u;
if(hasArguments)
s << ".with( " << *e.matcher_ << " )";
return s;
}
private:
std::unique_ptr<invocation> invocation_;
std::unique_ptr<matcher_base<Args...>> matcher_;
std::vector<std::shared_ptr<sequence_impl>> sequences_;
const char* file_;
int line_;
};
}} // namespace mock::detail
#endif // MOCK_EXPECTATION_HPP_INCLUDED

View File

@ -0,0 +1,276 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2012
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include "matcher_base_template.hpp"
#define MOCK_EXPECTATION_INITIALIZE(z, n, d) \
BOOST_PP_COMMA_IF(n) c##n##_( c##n )
#define MOCK_EXPECTATION_MEMBER(z, n, d) \
matcher< T##n, Constraint_##n > c##n##_;
#define MOCK_EXPECTATION_IS_VALID(z, n, d) \
BOOST_PP_IF(n, &&,) c##n##_( mock::detail::move_if_not_lvalue_reference< T##n >( a##n ) )
#define MOCK_EXPECTATION_SERIALIZE(z, n, d) \
BOOST_PP_IF(n, << ", " <<,) c##n##_
#define MOCK_EXPECTATION_SERIALIZE_ANY(z, n, d) \
BOOST_PP_IF(n, << ", " <<,) "any"
#define MOCK_EXPECTATION_PARAM(z, n, Args) \
mock::detail::move_if_not_lvalue_reference< T##n >( a##n )
#define MOCK_REF_ARG(z, n, d) \
typename ref_arg< T##n >::type a##n
#define MOCK_REF_ARG_T(z, n, d) \
typename ref_arg< T##n >::type
namespace mock
{
namespace detail
{
template< typename Signature > class default_matcher;
template<
BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename T) >
class default_matcher< void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) ) >
: public matcher_base< void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) ) >
{
private:
virtual bool operator()(
BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG_T, _) )
{
return true;
}
virtual void serialize( std::ostream& s ) const
{
s << "" BOOST_PP_REPEAT(MOCK_NUM_ARGS,
MOCK_EXPECTATION_SERIALIZE_ANY, _);
}
};
#ifndef MOCK_NUM_ARGS_0
template< typename Constraint, typename Signature > class single_matcher;
template<
BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename Constraint_),
BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename T)
>
class single_matcher<
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, Constraint_) ),
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
>
: public matcher_base< void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) ) >
{
public:
single_matcher(
BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, Constraint_, c) )
: BOOST_PP_REPEAT(MOCK_NUM_ARGS,
MOCK_EXPECTATION_INITIALIZE, _)
{}
private:
virtual bool operator()(
BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG, _) )
{
return BOOST_PP_REPEAT(MOCK_NUM_ARGS,
MOCK_EXPECTATION_IS_VALID, _);
}
virtual void serialize( std::ostream& s ) const
{
s << BOOST_PP_REPEAT(MOCK_NUM_ARGS,
MOCK_EXPECTATION_SERIALIZE, _);
}
private:
BOOST_PP_REPEAT(
MOCK_NUM_ARGS, MOCK_EXPECTATION_MEMBER, _)
};
template< typename F, typename Signature > class multi_matcher;
template< typename F,
BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename T) >
class multi_matcher< F, void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) ) >
: public matcher_base< void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) ) >
{
public:
multi_matcher( const F& f )
: f_( f )
{}
private:
virtual bool operator()(
BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG, _) )
{
return f_( BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_EXPECTATION_PARAM, _) );
}
virtual void serialize( std::ostream& s ) const
{
s << mock::format( f_ );
}
private:
F f_;
};
#endif
template< typename Signature > class expectation;
template< typename R
BOOST_PP_ENUM_TRAILING_PARAMS(MOCK_NUM_ARGS, typename T) >
class expectation< R (BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS,T)) >
: public action< R, R (BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS,T)) >
{
public:
expectation()
: invocation_( boost::make_shared< unlimited >() )
, matcher_(
boost::make_shared<
default_matcher<
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
>
> () )
, file_( "unknown location" )
, line_( 0 )
{}
expectation( const char* file, int line )
: invocation_( boost::make_shared< unlimited >() )
, matcher_(
boost::make_shared<
default_matcher<
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
>
> () )
, file_( file )
, line_( line )
{}
~expectation()
{
for( sequences_cit it = sequences_.begin();
it != sequences_.end(); ++it )
(*it)->remove( this );
}
void invoke( const boost::shared_ptr< invocation >& i )
{
invocation_ = i;
}
#ifndef MOCK_NUM_ARGS_0
template<
BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename Constraint_)
>
expectation& with(
BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, Constraint_, c) )
{
matcher_.reset(
new single_matcher<
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, Constraint_) ),
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
>( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, c) ) );
return *this;
}
#if MOCK_NUM_ARGS > 1
template< typename Constraint >
expectation& with( const Constraint& c )
{
matcher_.reset(
new multi_matcher<
Constraint,
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
>( c ) );
return *this;
}
#endif
#endif
void add( sequence& s )
{
s.impl_->add( this );
sequences_.push_back( s.impl_ );
}
bool verify() const
{
return invocation_->verify();
}
bool is_valid(
BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG, _) ) const
{
return !invocation_->exhausted()
&& (*matcher_)( BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_EXPECTATION_PARAM, _) );
}
bool invoke() const
{
for( sequences_cit it = sequences_.begin();
it != sequences_.end(); ++it )
if( ! (*it)->is_valid( this ) )
return false;
bool result = invocation_->invoke();
for( sequences_cit it = sequences_.begin();
it != sequences_.end(); ++it )
(*it)->invalidate( this );
return result;
}
const char* file() const
{
return file_;
}
int line() const
{
return line_;
}
friend std::ostream& operator<<(
std::ostream& s, const expectation& e )
{
return s << ( e.invocation_->exhausted() ? 'v' : '.' )
<< ' ' << *e.invocation_
#ifndef MOCK_NUM_ARGS_0
<< ".with( " << *e.matcher_ << " )"
#endif
;
}
private:
typedef std::vector<
boost::shared_ptr< sequence_impl >
> sequences_type;
typedef sequences_type::const_iterator sequences_cit;
boost::shared_ptr< invocation > invocation_;
boost::shared_ptr<
matcher_base<
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
>
> matcher_;
sequences_type sequences_;
const char* file_;
int line_;
};
}
} // mock
#undef MOCK_EXPECTATION_INITIALIZE
#undef MOCK_EXPECTATION_MEMBER
#undef MOCK_EXPECTATION_IS_VALID
#undef MOCK_EXPECTATION_SERIALIZE
#undef MOCK_EXPECTATION_SERIALIZE_ANY
#undef MOCK_EXPECTATION_PARAM
#undef MOCK_REF_ARG
#undef MOCK_REF_ARG_T
#undef MOCK_RV_REF

View File

@ -0,0 +1,41 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2012
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_FORMATTER_HPP_INCLUDED
#define MOCK_FORMATTER_HPP_INCLUDED
#include "../config.hpp"
#include "../stream.hpp"
#include <memory>
namespace mock { namespace detail {
template<typename T>
struct formatter
{
explicit formatter(const T& t) : t_(std::addressof(t)) {}
void serialize(stream& s) const { detail::serialize(s, *t_); }
const T* t_;
};
template<typename T>
stream& operator<<(stream& s, const formatter<T>& f)
{
f.serialize(s);
return s;
}
template<typename T>
std::ostream& operator<<(std::ostream& s, const formatter<T>& f)
{
stream ss(s);
f.serialize(ss);
return s;
}
}} // namespace mock::detail
#endif // MOCK_FORMATTER_HPP_INCLUDED

View File

@ -0,0 +1,81 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2008
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_FUNCTION_HPP_INCLUDED
#define MOCK_FUNCTION_HPP_INCLUDED
#include "../config.hpp"
#include "../log.hpp"
#include "../sequence.hpp"
#include "context.hpp"
#include "function_impl.hpp"
#include "type_name.hpp"
#include <boost/optional.hpp>
#include <boost/test/utils/basic_cstring/basic_cstring.hpp>
#include <ostream>
namespace mock { namespace detail {
template<typename Signature>
class function;
template<typename R, typename... Ts>
class function<R(Ts...)>
{
private:
typedef function_impl<R(Ts...)> impl_type;
typedef typename impl_type::wrapper_type expectation_type;
typedef typename impl_type::error_type error_type;
public:
function() : impl_(std::make_shared<impl_type>()) {}
bool verify() const { return impl_->verify(); }
bool verify(const char* file, int line) const
{
error_type::pass(file, line);
return impl_->verify();
}
void reset() { impl_->reset(); }
void reset(const char* file, int line)
{
error_type::pass(file, line);
impl_->reset();
}
expectation_type expect(const char* file, int line)
{
error_type::pass(file, line);
return impl_->expect(file, line);
}
expectation_type expect() { return impl_->expect(); }
R operator()(Ts... args) const { return (*impl_)(static_cast<ref_arg_t<Ts>>(args)...); }
friend std::ostream& operator<<(std::ostream& s, const function& f) { return s << *f.impl_; }
function& operator()(context& c, boost::unit_test::const_string instance)
{
impl_->add(c, impl_.get(), instance, boost::none, "");
return *this;
}
void configure(context& c,
const void* p,
boost::unit_test::const_string instance,
boost::optional<type_name> type,
boost::unit_test::const_string name) const
{
impl_->add(c, p, instance, type, name);
}
private:
std::shared_ptr<impl_type> impl_;
};
}} // namespace mock::detail
#endif // MOCK_FUNCTION_HPP_INCLUDED

View File

@ -0,0 +1,361 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2012
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_FUNCTION_IMPL_HPP_INCLUDED
#define MOCK_FUNCTION_IMPL_HPP_INCLUDED
#include "../error.hpp"
#include "expectation.hpp"
#include "mutex.hpp"
#include "verifiable.hpp"
#include <boost/test/utils/lazy_ostream.hpp>
#include <list>
#include <memory>
#ifndef MOCK_ERROR_POLICY
# error no error policy has been set
#endif
namespace mock { namespace detail {
template<typename R, typename E>
struct wrapper_base
{
wrapper_base(E& e) : e_(&e) {}
template<typename T>
void returns(T t)
{
e_->returns(t);
}
E* e_;
};
template<typename E>
struct wrapper_base<void, E>
{
wrapper_base(E& e) : e_(&e) {}
E* e_;
};
template<typename R, typename E>
struct wrapper_base<R*, E>
{
wrapper_base(E& e) : e_(&e) {}
void returns(R* r) { e_->returns(r); }
template<typename Y>
void returns(const std::reference_wrapper<Y>& r)
{
e_->returns(r);
}
E* e_;
};
inline int exceptions()
{
#ifdef MOCK_UNCAUGHT_EXCEPTIONS
using namespace std;
return uncaught_exceptions();
#else
return std::uncaught_exception() ? 1 : 0;
#endif
}
template<typename... Arg>
class lazy_args;
template<typename Signature>
class function_impl;
template<typename R, typename... Args>
class function_impl<R(Args...)> : public verifiable, public std::enable_shared_from_this<function_impl<R(Args...)>>
{
public:
typedef safe_error<R, MOCK_ERROR_POLICY<R>> error_type;
public:
function_impl() : context_(0), valid_(true), exceptions_(exceptions()), mutex_(std::make_shared<mutex>()) {}
virtual ~function_impl()
{
if(valid_ && exceptions_ >= exceptions())
{
for(const auto& expectation : expectations_)
{
if(!expectation.verify())
{
error_type::fail("untriggered expectation",
boost::unit_test::lazy_ostream::instance()
<< lazy_context(this) << lazy_expectations(this),
expectation.file(),
expectation.line());
}
}
}
if(context_)
context_->remove(*this);
}
virtual bool verify() const
{
lock _(mutex_);
for(const auto& expectation : expectations_)
{
if(!expectation.verify())
{
valid_ = false;
error_type::fail("verification failed",
boost::unit_test::lazy_ostream::instance()
<< lazy_context(this) << lazy_expectations(this),
expectation.file(),
expectation.line());
}
}
return valid_;
}
virtual void reset()
{
lock _(mutex_);
valid_ = true;
std::shared_ptr<function_impl> guard = this->shared_from_this();
expectations_.clear();
}
private:
typedef expectation<R(Args...)> expectation_type;
class wrapper : public wrapper_base<R, expectation_type>
{
private:
typedef wrapper_base<R, expectation_type> base_type;
static constexpr std::size_t arity = sizeof...(Args);
public:
wrapper(const std::shared_ptr<mutex>& m, expectation_type& e) : base_type(e), lock_(m) {}
wrapper(const wrapper&) = delete;
wrapper(wrapper&& x) = default;
wrapper& operator=(const wrapper&) = delete;
wrapper& operator=(wrapper&& x) = default;
wrapper& once()
{
this->e_->invoke(std::make_unique<detail::once>());
return *this;
}
wrapper& never()
{
this->e_->invoke(std::make_unique<detail::never>());
return *this;
}
wrapper& exactly(std::size_t count)
{
this->e_->invoke(std::make_unique<detail::exactly>(count));
return *this;
}
wrapper& at_least(std::size_t min)
{
this->e_->invoke(std::make_unique<detail::at_least>(min));
return *this;
}
wrapper& at_most(std::size_t max)
{
this->e_->invoke(std::make_unique<detail::at_most>(max));
return *this;
}
wrapper& between(std::size_t min, std::size_t max)
{
this->e_->invoke(std::make_unique<detail::between>(min, max));
return *this;
}
/// Callable only for functions taking arguments
/// Number of constraints must match the number of arguments
/// or a single constraint checking all arguments must be passed
template<typename... Constraints>
std::enable_if_t<(arity > 0u && (sizeof...(Constraints) == arity || sizeof...(Constraints) == 1u)),
wrapper&>
with(Constraints... c)
{
this->e_->with(c...);
return *this;
}
/// Ensure the expectation is met in the given sequence(s)
template<class... MockSequences>
wrapper& in(sequence& s0, MockSequences&... s)
{
using expander = int[];
(void)expander{ (this->e_->add(s0), 0), (this->e_->add(s), 0)... };
return *this;
}
template<typename TT>
void calls(TT t)
{
this->e_->calls(t);
}
template<typename TT>
void throws(TT t)
{
this->e_->throws(t);
}
template<typename TT>
void moves(TT&& t)
{
this->e_->moves(std::move(t));
}
lock lock_;
};
public:
typedef wrapper wrapper_type;
wrapper expect(const char* file, int line)
{
lock _(mutex_);
expectations_.emplace_back(file, line);
valid_ = true;
return wrapper(mutex_, expectations_.back());
}
wrapper expect()
{
lock _(mutex_);
expectations_.emplace_back();
valid_ = true;
return wrapper(mutex_, expectations_.back());
}
R operator()(Args... args) const
{
// Due to lifetime rules of references this must be created and consumed in one line
#define MOCK_FUNCTION_CONTEXT \
boost::unit_test::lazy_ostream::instance() \
<< lazy_context(this) << lazy_args<Args...>(args...) << lazy_expectations(this)
lock _(mutex_);
valid_ = false;
for(const auto& expectation : expectations_)
{
if(expectation.is_valid(static_cast<ref_arg_t<Args>>(args)...))
{
if(!expectation.invoke())
{
error_type::fail(
"sequence failed", MOCK_FUNCTION_CONTEXT, expectation.file(), expectation.line());
return error_type::abort();
}
if(!expectation.valid())
{
error_type::fail(
"missing action", MOCK_FUNCTION_CONTEXT, expectation.file(), expectation.line());
return error_type::abort();
}
valid_ = true;
error_type::call(MOCK_FUNCTION_CONTEXT, expectation.file(), expectation.line());
if(expectation.functor())
return expectation.functor()(static_cast<ref_arg_t<Args>>(args)...);
return expectation.trigger();
}
}
error_type::fail("unexpected call", MOCK_FUNCTION_CONTEXT);
return error_type::abort();
#undef MOCK_FUNCTION_CONTEXT
}
void add(context& c,
const void* p,
boost::unit_test::const_string instance,
boost::optional<type_name> type,
boost::unit_test::const_string name)
{
lock _(mutex_);
if(!context_)
c.add(*this);
c.add(p, *this, instance, type, name);
context_ = &c;
}
friend std::ostream& operator<<(std::ostream& s, const function_impl& impl)
{
lock _(impl.mutex_);
return s << lazy_context(&impl) << lazy_expectations(&impl);
}
struct lazy_context
{
lazy_context(const function_impl* impl) : impl_(impl) {}
friend std::ostream& operator<<(std::ostream& s, const lazy_context& c)
{
if(c.impl_->context_)
c.impl_->context_->serialize(s, *c.impl_);
else
s << '?';
return s;
}
const function_impl* impl_;
};
struct lazy_expectations
{
lazy_expectations(const function_impl* impl) : impl_(impl) {}
friend std::ostream& operator<<(std::ostream& s, const lazy_expectations& e)
{
for(const auto& expectation : e.impl_->expectations_)
s << std::endl << expectation;
return s;
}
const function_impl* impl_;
};
std::list<expectation_type> expectations_;
context* context_;
mutable bool valid_;
const int exceptions_;
const std::shared_ptr<mutex> mutex_;
};
template<typename ArgFirst, typename... ArgRest>
class lazy_args<ArgFirst, ArgRest...> : lazy_args<ArgRest...>
{
ArgFirst& arg_;
public:
lazy_args(ArgFirst& arg, std::add_lvalue_reference_t<ArgRest>... args)
: lazy_args<ArgRest...>(args...), arg_(arg)
{}
std::ostream& print(std::ostream& s) const
{
s << ' ' << mock::format(arg_) << ',';
return lazy_args<ArgRest...>::print(s);
}
};
template<typename ArgFirst>
class lazy_args<ArgFirst>
{
ArgFirst& arg_;
public:
lazy_args(ArgFirst& arg) : arg_(arg) {}
std::ostream& print(std::ostream& s) const { return s << ' ' << mock::format(arg_) << ' '; }
};
template<>
class lazy_args<>
{
public:
std::ostream& print(std::ostream& s) const { return s; }
};
template<typename... Args>
std::ostream& operator<<(std::ostream& s, const lazy_args<Args...>& a)
{
s << '(';
return a.print(s) << ')';
}
}} // namespace mock::detail
#endif // MOCK_FUNCTION_IMPL_HPP_INCLUDED

View File

@ -0,0 +1,329 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2012
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include "expectation_template.hpp"
#ifndef MOCK_ERROR_POLICY
# error no error policy has been set
#endif
#define MOCK_FUNCTION_FORMAT(z, n, N) \
<< ' ' << mock::format( t##n ) \
<< BOOST_PP_IF(BOOST_PP_EQUAL(N,n), ' ', ',')
#define MOCK_FUNCTION_CONTEXT \
boost::unit_test::lazy_ostream::instance() \
<< lazy_context( this ) \
<< '(' BOOST_PP_REPEAT(MOCK_NUM_ARGS, MOCK_FUNCTION_FORMAT, \
BOOST_PP_DEC(MOCK_NUM_ARGS)) \
<< ')' \
<< lazy_expectations( this )
#define MOCK_MOVE(z, n, d) \
mock::detail::move_if_not_lvalue_reference< T##n >( t##n )
namespace mock
{
namespace detail
{
template< typename Signature > class function_impl;
template< typename R
BOOST_PP_ENUM_TRAILING_PARAMS(MOCK_NUM_ARGS, typename T) >
class function_impl< R ( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) ) >
: public verifiable, public boost::enable_shared_from_this<
function_impl< R ( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )> >
{
public:
typedef safe_error< R, MOCK_ERROR_POLICY< R > > error_type;
public:
function_impl()
: context_( 0 )
, valid_( true )
, exceptions_( exceptions() )
, mutex_( boost::make_shared< mutex >() )
{}
virtual ~function_impl()
{
if( valid_ && exceptions_ >= exceptions() )
for( expectations_cit it = expectations_.begin();
it != expectations_.end(); ++it )
if( ! it->verify() )
error_type::fail( "untriggered expectation",
boost::unit_test::lazy_ostream::instance()
<< lazy_context( this )
<< lazy_expectations( this ),
it->file(), it->line() );
if( context_ )
context_->remove( *this );
}
virtual bool verify() const
{
lock _( mutex_ );
for( expectations_cit it = expectations_.begin();
it != expectations_.end(); ++it )
if( ! it->verify() )
{
valid_ = false;
error_type::fail( "verification failed",
boost::unit_test::lazy_ostream::instance()
<< lazy_context( this )
<< lazy_expectations( this ),
it->file(), it->line() );
}
return valid_;
}
virtual void reset()
{
lock _( mutex_ );
valid_ = true;
boost::shared_ptr< function_impl > guard =
this->shared_from_this();
expectations_.clear();
}
private:
typedef expectation<
R( BOOST_PP_ENUM_PARAMS( MOCK_NUM_ARGS, T ) )
> expectation_type;
class wrapper : public wrapper_base< R, expectation_type >
{
private:
typedef wrapper_base< R, expectation_type > base_type;
BOOST_MOVABLE_BUT_NOT_COPYABLE(wrapper)
public:
wrapper( const boost::shared_ptr< mutex >& m, expectation_type& e )
: base_type( e )
, lock_( m )
{}
wrapper( BOOST_RV_REF( wrapper ) x )
: base_type( x )
, lock_( boost::move( x.lock_) )
{}
wrapper& operator=( BOOST_RV_REF( wrapper ) x )
{
static_cast< base_type& >( *this ) = x;
lock_ = boost::move( x.lock_ );
return *this;
}
wrapper& once()
{
this->e_->invoke( boost::make_shared< detail::once >() );
return *this;
}
wrapper& never()
{
this->e_->invoke( boost::make_shared< detail::never >() );
return *this;
}
wrapper& exactly( std::size_t count )
{
this->e_->invoke(
boost::make_shared< detail::exactly >( count ) );
return *this;
}
wrapper& at_least( std::size_t min )
{
this->e_->invoke(
boost::make_shared< detail::at_least >( min ) );
return *this;
}
wrapper& at_most( std::size_t max )
{
this->e_->invoke(
boost::make_shared< detail::at_most >( max ) );
return *this;
}
wrapper& between( std::size_t min, std::size_t max )
{
this->e_->invoke(
boost::make_shared< detail::between >( min, max ) );
return *this;
}
#ifndef MOCK_NUM_ARGS_0
template<
BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename Constraint_)
>
wrapper& with(
BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, Constraint_, c) )
{
this->e_->with(
BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, c) );
return *this;
}
#if MOCK_NUM_ARGS > 1
template< typename Constraint >
wrapper& with( const Constraint& c )
{
this->e_->with( c );
return *this;
}
#endif
#endif
#define MOCK_FUNCTION_IN_ADD(z, n, d) \
this->e_->add( s##n );
#define MOCK_FUNCTION_IN(z, n, d) \
wrapper& in( BOOST_PP_ENUM_PARAMS(n, sequence& s) ) \
{ \
BOOST_PP_REPEAT(n, MOCK_FUNCTION_IN_ADD, _) \
return *this; \
}
BOOST_PP_REPEAT(MOCK_MAX_SEQUENCES,
MOCK_FUNCTION_IN, _)
#undef MOCK_FUNCTION_IN
#undef MOCK_FUNCTION_IN_ADD
template< typename TT >
void calls( TT t )
{
this->e_->calls( t );
}
template< typename TT >
void throws( TT t )
{
this->e_->throws( t );
}
template< typename TT >
void moves( BOOST_RV_REF(TT) t )
{
this->e_->moves( boost::move( t ) );
}
lock lock_;
};
public:
typedef wrapper wrapper_type;
wrapper expect( const char* file, int line )
{
lock _( mutex_ );
expectations_.push_back( expectation_type( file, line ) );
valid_ = true;
return wrapper( mutex_, expectations_.back() );
}
wrapper expect()
{
lock _( mutex_ );
expectations_.push_back( expectation_type() );
valid_ = true;
return wrapper( mutex_, expectations_.back() );
}
R operator()(
BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, T, t) ) const
{
lock _( mutex_ );
valid_ = false;
for( expectations_cit it = expectations_.begin();
it != expectations_.end(); ++it )
if( it->is_valid(
BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_MOVE, _) ) )
{
if( ! it->invoke() )
{
error_type::fail( "sequence failed",
MOCK_FUNCTION_CONTEXT, it->file(), it->line() );
return error_type::abort();
}
if( ! it->valid() )
{
error_type::fail( "missing action",
MOCK_FUNCTION_CONTEXT, it->file(), it->line() );
return error_type::abort();
}
valid_ = true;
error_type::call(
MOCK_FUNCTION_CONTEXT, it->file(), it->line() );
if( it->functor() )
return it->functor()(
BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_MOVE, _) );
return it->trigger();
}
error_type::fail( "unexpected call", MOCK_FUNCTION_CONTEXT );
return error_type::abort();
}
void add( context& c, const void* p,
boost::unit_test::const_string instance,
boost::optional< type_name > type,
boost::unit_test::const_string name )
{
lock _( mutex_ );
if( ! context_ )
c.add( *this );
c.add( p, *this, instance, type, name );
context_ = &c;
}
friend std::ostream& operator<<(
std::ostream& s, const function_impl& impl )
{
lock _( impl.mutex_ );
return s << lazy_context( &impl ) << lazy_expectations( &impl );
}
struct lazy_context
{
lazy_context( const function_impl* impl )
: impl_( impl )
{}
friend std::ostream& operator<<(
std::ostream& s, const lazy_context& c )
{
if( c.impl_->context_ )
c.impl_->context_->serialize( s, *c.impl_ );
else
s << '?';
return s;
}
const function_impl* impl_;
};
struct lazy_expectations
{
lazy_expectations( const function_impl* impl )
: impl_( impl )
{}
friend std::ostream& operator<<(
std::ostream& s, const lazy_expectations& e )
{
for( expectations_cit it = e.impl_->expectations_.begin();
it != e.impl_->expectations_.end(); ++it )
s << std::endl << *it;
return s;
}
const function_impl* impl_;
};
typedef std::list< expectation_type > expectations_type;
typedef typename expectations_type::const_iterator expectations_cit;
expectations_type expectations_;
context* context_;
mutable bool valid_;
const int exceptions_;
const boost::shared_ptr< mutex > mutex_;
};
}
} // mock
#undef MOCK_FUNCTION_FORMAT
#undef MOCK_FUNCTION_CONTEXT
#undef MOCK_MOVE

View File

@ -0,0 +1,11 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2012
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#define MOCK_NUM_ARGS BOOST_PP_ITERATION()
#include "function_template.hpp"
#undef MOCK_NUM_ARGS

View File

@ -0,0 +1,106 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2008
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include "function_impl_template.hpp"
#define MOCK_MOVE(z, n, d) \
mock::detail::move_if_not_lvalue_reference< T##n >( t##n )
namespace mock
{
namespace detail
{
template< typename Signature > class function;
template< typename R
BOOST_PP_ENUM_TRAILING_PARAMS(MOCK_NUM_ARGS, typename T) >
class function< R ( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) ) >
{
public:
typedef R result_type;
template< typename Args >
struct sig
{
typedef R type;
};
private:
typedef function_impl<
R ( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
> impl_type;
typedef typename impl_type::wrapper_type expectation_type;
typedef typename impl_type::error_type error_type;
public:
function()
: impl_( boost::make_shared< impl_type >() )
{}
bool verify() const
{
return impl_->verify();
}
bool verify( const char* file, int line ) const
{
error_type::pass( file, line );
return impl_->verify();
}
void reset()
{
impl_->reset();
}
void reset( const char* file, int line )
{
error_type::pass( file, line );
impl_->reset();
}
expectation_type expect( const char* file, int line )
{
error_type::pass( file, line );
return impl_->expect( file, line );
}
expectation_type expect()
{
return impl_->expect();
}
R operator()(
BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, T, t) ) const
{
return (*impl_)( BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_MOVE, _) );
}
friend std::ostream& operator<<( std::ostream& s, const function& f )
{
return s << *f.impl_;
}
function& operator()( context& c,
boost::unit_test::const_string instance )
{
impl_->add( c, impl_.get(), instance, boost::none, "" );
return *this;
}
void configure( context& c, const void* p,
boost::unit_test::const_string instance,
boost::optional< type_name > type,
boost::unit_test::const_string name ) const
{
impl_->add( c, p, instance, type, name );
}
private:
boost::shared_ptr< impl_type > impl_;
};
}
} // mock
#undef MOCK_MOVE

View File

@ -0,0 +1,54 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2012
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_FUNCTOR_HPP_INCLUDED
#define MOCK_FUNCTOR_HPP_INCLUDED
#include "../config.hpp"
#include "function.hpp"
#include "mutex.hpp"
#include "singleton.hpp"
namespace mock { namespace detail {
class functor_mutex_t : public singleton<functor_mutex_t>, public mutex
{
MOCK_SINGLETON_CONS(functor_mutex_t);
};
MOCK_SINGLETON_INST(functor_mutex)
template<typename Signature>
struct functor : function<Signature>
{
functor()
{
scoped_lock _(functor_mutex);
// MOCK_FUNCTOR creates 2 functor objects:
// The user-usable one with the passed name and a 2nd used by MOCK_EXPECT with a suffixed name
// We need the 2nd to be a copy of the first and use a static variable for storing a pointer to the first
static functor* f = nullptr;
if(f)
{
// Release the lock from the first call (see below) so other threads can create functors again
// after the function exits (the scoped_lock still holds the mutex)
functor_mutex.unlock();
// Copy the first functor to the current (2nd) one
*this = *f;
f = nullptr;
} else
{
// This is the first object, store its pointer
f = this;
// Lock the mutex again so only this thread can create new instances of a functor
// making sure that we copy the right instance above and not one from a concurrent thread
functor_mutex.lock();
}
}
};
}} // namespace mock::detail
#endif // MOCK_FUNCTOR_HPP_INCLUDED

View File

@ -0,0 +1,49 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2011
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_GROUP_HPP_INCLUDED
#define MOCK_GROUP_HPP_INCLUDED
#include "../config.hpp"
#include "verifiable.hpp"
#include <algorithm>
#include <functional>
#include <vector>
namespace mock { namespace detail {
class group
{
public:
void add(verifiable& v) { verifiables_.push_back(&v); }
void remove(verifiable& v)
{
verifiables_.erase(std::remove(verifiables_.begin(), verifiables_.end(), &v), verifiables_.end());
}
bool verify() const
{
bool valid = true;
for(const auto* verifiable : verifiables_)
if(!verifiable->verify())
valid = false;
return valid;
}
void reset()
{
const auto verifiables = verifiables_;
for(auto* verifiable : verifiables)
if(std::find(verifiables_.begin(), verifiables_.end(), verifiable) != verifiables_.end())
verifiable->reset();
}
private:
std::vector<verifiable*> verifiables_;
};
}} // namespace mock::detail
#endif // MOCK_GROUP_HPP_INCLUDED

View File

@ -0,0 +1,134 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2008
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_INVOCATION_HPP_INCLUDED
#define MOCK_INVOCATION_HPP_INCLUDED
#include "../config.hpp"
#include <limits>
#include <ostream>
#include <stdexcept>
namespace mock { namespace detail {
class invocation
{
public:
invocation() = default;
invocation(const invocation&) = delete;
invocation& operator=(const invocation&) = delete;
virtual ~invocation() = default;
virtual bool invoke() = 0;
virtual bool verify() const = 0;
virtual bool exhausted() const = 0;
friend std::ostream& operator<<(std::ostream& s, const invocation& i) { return i.serialize(s); }
private:
virtual std::ostream& serialize(std::ostream& s) const = 0;
};
class between : public invocation
{
public:
between(std::size_t min, std::size_t max) : min_(min), max_(max), count_(0)
{
if(min > max)
throw std::invalid_argument("'min' > 'max'");
}
virtual bool invoke()
{
if(count_ == max_)
return false;
++count_;
return true;
}
virtual bool exhausted() const { return count_ >= max_; }
virtual bool verify() const { return min_ <= count_ && count_ <= max_; }
protected:
const std::size_t min_, max_;
std::size_t count_;
private:
virtual std::ostream& serialize(std::ostream& s) const
{
return s << "between( " << count_ << "/[" << min_ << ',' << max_ << "] )";
}
};
class exactly : public between
{
public:
explicit exactly(std::size_t count) : between(count, count) {}
private:
virtual std::ostream& serialize(std::ostream& s) const
{
return s << "exactly( " << count_ << '/' << max_ << " )";
}
};
class never : public exactly
{
public:
never() : exactly(0) {}
private:
virtual std::ostream& serialize(std::ostream& s) const { return s << "never()"; }
};
class once : public exactly
{
public:
once() : exactly(1) {}
private:
virtual std::ostream& serialize(std::ostream& s) const { return s << "once()"; }
};
class at_least : public between
{
public:
explicit at_least(std::size_t min) : between(min, (std::numeric_limits<std::size_t>::max)()) {}
private:
virtual std::ostream& serialize(std::ostream& s) const
{
return s << "at_least( " << count_ << '/' << min_ << " )";
}
};
class at_most : public between
{
public:
explicit at_most(std::size_t max) : between(0, max) {}
private:
virtual std::ostream& serialize(std::ostream& s) const
{
return s << "at_most( " << count_ << '/' << max_ << " )";
}
};
class unlimited : public at_least
{
public:
unlimited() : at_least(0) {}
private:
virtual std::ostream& serialize(std::ostream& s) const { return s << "unlimited()"; }
};
}} // namespace mock::detail
#endif // MOCK_INVOCATION_HPP_INCLUDED

Some files were not shown because too many files have changed in this diff Show More