diff --git a/inc/trompeloeil.hpp b/inc/trompeloeil.hpp index 4f2ed76f..45ec5d70 100644 --- a/inc/trompeloeil.hpp +++ b/inc/trompeloeil.hpp @@ -32,8 +32,15 @@ #include "trompeloeil/matcher/any.hpp" #include "trompeloeil/matcher/compare.hpp" #include "trompeloeil/matcher/deref.hpp" +#if TROMPELOEIL_CPLUSPLUS >= 201402L +#include "trompeloeil/matcher/member_is.hpp" +#endif #include "trompeloeil/matcher/not.hpp" +#if TROMPELOEIL_CPLUSPLUS >= 201402L +#include "trompeloeil/matcher/range.hpp" +#endif #include "trompeloeil/matcher/re.hpp" +#include "trompeloeil/matcher/set_predicate.hpp" #include "trompeloeil/sequence.hpp" #include "trompeloeil/stream_tracer.hpp" #ifdef __cpp_impl_coroutine diff --git a/inc/trompeloeil/matcher/member_is.hpp b/inc/trompeloeil/matcher/member_is.hpp new file mode 100644 index 00000000..1a217815 --- /dev/null +++ b/inc/trompeloeil/matcher/member_is.hpp @@ -0,0 +1,61 @@ +/* +* Trompeloeil C++ mocking framework +* +* Copyright (C) Björn Fahller +* Copyright (C) Andrew Paxie +* +* Use, modification and distribution is subject to the +* Boost Software License, Version 1.0. (See accompanying +* file LICENSE_1_0.txt or copy atl +* http://www.boost.org/LICENSE_1_0.txt) +* +* Project home: https://github.com/rollbear/trompeloeil + */ + +#ifndef TROMPELOEIL_MEMBER_IS_HPP +#define TROMPELOEIL_MEMBER_IS_HPP + +#ifndef TROMPELOEIL_MATCHER_HPP +#include "../matcher.hpp" +#endif + +namespace trompeloeil +{ + +namespace impl { +template +struct member_is_matcher +{ + template + bool operator()(const V& v, const C& c) const + { + return trompeloeil::param_matches(c, std::ref(m(v))); + } + M m; +}; +} + +template +auto match_member_is(M m, const char* name, C&& c) +{ + return trompeloeil::make_matcher( + impl::member_is_matcher{m}, + [name](std::ostream& os, const C& compare) { + os << ' ' << name << compare; + }, + std::forward(c) + ); +} +} + +#define TROMPELOEIL_MEMBER_IS(member_name, compare) \ + trompeloeil::match_member_is( \ + std::mem_fn(member_name), \ + #member_name, \ + compare) + +#ifndef TROMPELOEIL_LONG_MACROS +#define MEMBER_IS TROMPELOEIL_MEMBER_IS +#endif + +#endif // TROMPELOEIL_MEMBER_IS_HPP diff --git a/inc/trompeloeil/matcher/range.hpp b/inc/trompeloeil/matcher/range.hpp new file mode 100644 index 00000000..f9c2b096 --- /dev/null +++ b/inc/trompeloeil/matcher/range.hpp @@ -0,0 +1,830 @@ +/* +* Trompeloeil C++ mocking framework +* +* Copyright (C) Björn Fahller +* Copyright (C) Andrew Paxie +* +* Use, modification and distribution is subject to the +* Boost Software License, Version 1.0. (See accompanying +* file LICENSE_1_0.txt or copy atl +* http://www.boost.org/LICENSE_1_0.txt) +* +* Project home: https://github.com/rollbear/trompeloeil +*/ + + +#ifndef TROMPELOEIL_RANGE_HPP +#define TROMPELOEIL_RANGE_HPP + +#ifndef TROMPELOEIL_MATCHER_HPP +#include "../matcher.hpp" +#endif + +#include + +namespace trompeloeil { + +namespace impl { + +template +struct disjunction +{ + static constexpr bool test() { + bool all_false = false; + ignore(std::initializer_list{(all_false = all_false || Ts::value)...}); + return all_false; + } + static constexpr bool value = test(); +}; + +template +auto make_predicate_matcher(M &m) { + return std::function([&m](const E &value) { + return trompeloeil::param_matches(m, std::ref(value)); + }); +} + +template +struct store_as +{ + using type = T; + template + static type make(C&& c) { return T(std::forward(c));} +}; + +template +struct store_as +{ + using type = mini_span; + static type make(T* p) { return type(p, N);} +}; + +template +using store_as_t = typename store_as::type; + +template +struct value_type {}; + +template +struct value_type +{ + using type = T&; +}; + + +template +struct value_type().begin())>> { + using type = decltype(*std::declval().begin()); +}; + +template +using value_type_t = typename value_type::type; + +template +struct is_range : std::false_type {}; + +template +struct is_range>> : std::true_type {}; + +template +constexpr bool is_range_v = is_range::value; +} + +namespace impl { +struct is_elements_checker +{ + template + bool operator()(const R& range, const Es& ... elements) const + { + using std::begin; + using std::end; + auto it = begin(range); + const auto e = end(range); + bool all_true = true; + const auto match = [&](const auto& compare) + { + if (it == e) return false; + const auto& v = *it++; + return trompeloeil::param_matches(compare, std::ref(v)); + }; + trompeloeil::ignore(std::initializer_list{ + (all_true = all_true && match(elements)) ...}); + return all_true && it == e; + } +}; + +struct is_elements_printer +{ + template + void operator()(std::ostream& os, const Es& ... elements) const + { + os << " range is {"; + const char* sep = ""; + const auto print = [&](const auto& v) { + os << std::exchange(sep, ", ") << v; + return 0; + }; + trompeloeil::ignore(std::initializer_list{ + (print(elements))... + }); + os << " }"; + } +}; + +} +template < + typename Type = trompeloeil::wildcard, + typename ... Es, + typename = typename std::enable_if...>::value>::type, + typename R = make_matcher_return< + Type, + impl::is_elements_checker, + impl::is_elements_printer, + impl::store_as_t...> + > +R range_is(Es&& ... es) +{ + return trompeloeil::make_matcher( + impl::is_elements_checker{}, + impl::is_elements_printer{}, + std::forward(es)...); +} +namespace impl { +struct is_range_checker{ + template + bool operator()(const R& r, const C& cs) const + { + using std::begin; + using std::end; + return std::equal(begin(r), end(r), begin(cs), end(cs), [](const auto& rv, const auto& cv) + { + return trompeloeil::param_matches(cv, std::ref(rv)); + }); + } +}; +struct is_range_printer{ + template + void operator()(std::ostream& os, const C& cs) const + { + os << " range is {"; + const char* sep = " "; + for (auto& c : cs) { + os << std::exchange(sep, ", ") << c; + } + os << " }"; + } +}; +} +template < + typename Type = trompeloeil::wildcard, + typename C, + typename = impl::value_type_t, + typename R = make_matcher_return< + Type, + impl::is_range_checker, + impl::is_range_printer, + impl::store_as_t> +> +R range_is(C&& c) +{ + return trompeloeil::make_matcher( + impl::is_range_checker{}, + impl::is_range_printer{}, + impl::store_as::make(std::forward(c)) + ); +} + +namespace impl { +struct is_permutation_elements_checker +{ + template + bool operator()(const R& range, const Es& ... elements) const + { + using std::begin; + using std::end; + auto it = begin(range); + const auto e = end(range); + using element_type = decltype(*it); + std::vector> matchers{ + make_predicate_matcher(elements)... + }; + while (it != e) { + auto found = std::find_if(matchers.begin(), matchers.end(), + [it](const auto& matcher) + { + return matcher(*it); + }); + if (found == matchers.end()) + { + break; + } + *found = std::move(matchers.back()); + matchers.pop_back(); + ++it; + } + return it == e && matchers.empty(); + } +}; + +struct is_permutation_elements_printer +{ + template + void operator()(std::ostream& os, const Es& ... elements) const + { + os << " range is permutation of {"; + const char* sep = ""; + const auto print = [&](const auto& v) { + os << std::exchange(sep, ", ") << v; + return 0; + }; + trompeloeil::ignore(std::initializer_list{ + (print(elements))... + }); + os << " }"; + } +}; + +} +template < + typename Type = trompeloeil::wildcard, + typename ... Es, + typename = typename std::enable_if...>::value>::type, + typename R = make_matcher_return< + Type, + impl::is_permutation_elements_checker, + impl::is_permutation_elements_printer, + Es...> + > +R range_is_permutation(Es&& ... es) +{ + return trompeloeil::make_matcher( + impl::is_permutation_elements_checker{}, + impl::is_permutation_elements_printer{}, + std::forward(es)...); +} + +namespace impl { +struct is_permutation_range_checker { + template + bool operator()(const R& range, const C& elements) const { + using std::begin; + using std::end; + auto it = begin(range); + const auto e = end(range); + using element_type = decltype(*it); + std::vector> matchers; + for (const auto& element : elements) { + matchers.push_back(impl::make_predicate_matcher(element)); + } + while (it != e) { + auto found = + std::find_if(matchers.begin(), matchers.end(), + [it](const auto &matcher) { return matcher(*it); }); + if (found == matchers.end()) { + break; + } + *found = std::move(matchers.back()); + matchers.pop_back(); + ++it; + } + return it == e && matchers.empty(); + } +}; + +struct is_permutation_range_printer { + template + void operator()(std::ostream& os, const C& c) const + { + os << " range is permutation of {"; + const char* sep = " "; + for (const auto& v : c) + { + os << std::exchange(sep, ", ") << v; + }; + + os << " }"; + } + +}; +} + +template < + typename Type = trompeloeil::wildcard, + typename C, + typename R = make_matcher_return< + Type, + impl::is_permutation_range_checker, + impl::is_permutation_range_printer, + impl::store_as_t> + > +R range_is_permutation(C&& c) +{ + return trompeloeil::make_matcher( + impl::is_permutation_range_checker{}, + impl::is_permutation_range_printer{}, + impl::store_as::make(std::forward(c))); +} + +namespace impl { +struct includes_elements_checker +{ + template + bool operator()(const R& range, const Es& ... elements) const + { + using std::begin; + using std::end; + auto it = begin(range); + const auto e = end(range); + using element_type = decltype(*it); + std::vector> matchers{ + make_predicate_matcher(elements)... + }; + while (it != e) + { + auto found = std::find_if(matchers.begin(), matchers.end(), + [it](const auto& matcher) { + return matcher(*it); + }); + if (found != matchers.end()) { + *found = std::move(matchers.back()); + matchers.pop_back(); + } + ++it; + } + return matchers.empty(); + } +}; + +struct includes_elements_printer +{ + template + void operator()(std::ostream& os, const Es& ... elements) const + { + os << " range has {"; + const char* sep = ""; + const auto print = [&](const auto& v) { + os << std::exchange(sep, ", ") << v; + return 0; + }; + trompeloeil::ignore(std::initializer_list{ + (print(elements))... + }); + os << " }"; + } +}; + +} +template < + typename Type = trompeloeil::wildcard, + typename ... Es, + typename = typename std::enable_if...>::value>::type, + typename R = make_matcher_return< + Type, + impl::includes_elements_checker, + impl::includes_elements_printer, + Es...> + > +R range_includes(Es&& ... es) +{ + return trompeloeil::make_matcher( + impl::includes_elements_checker{}, + impl::includes_elements_printer{}, + std::forward(es)...); +} + +namespace impl { +struct includes_range_checker +{ + template + bool operator()(const R& range, const C& elements) const + { + using std::begin; + using std::end; + auto it = begin(range); + const auto e = end(range); + using element_type = decltype(*it); + std::vector> matchers; + for (auto& element : elements) + { + matchers.push_back(make_predicate_matcher(element)); + } + while (it != e) + { + auto found = std::find_if(matchers.begin(), matchers.end(), + [it](const auto& matcher) { + return matcher(*it); + }); + if (found != matchers.end()) { + *found = std::move(matchers.back()); + matchers.pop_back(); + } + ++it; + } + return matchers.empty(); + } + +}; +struct includes_range_printer +{ + template + void operator()(std::ostream& os, const E& elements) const + { + os << " range has {"; + const char* sep = " "; + for (const auto& v : elements) { + os << std::exchange(sep, ", ") << v; + }; + os << " }"; + } + +}; +} +template < + typename Type = trompeloeil::wildcard, + typename C, + typename = typename std::enable_if>::type, + typename R = make_matcher_return< + Type, + impl::includes_range_checker, + impl::includes_range_printer, + impl::store_as_t> + > +R range_includes(C&& c) +{ + return trompeloeil::make_matcher( + impl::includes_range_checker{}, + impl::includes_range_printer{}, + impl::store_as::make(std::forward(c))); +} + +namespace impl +{ +struct range_all_of_checker { + template + bool operator()(const R& range, const C& comp) const + { + using std::begin; + using std::end; + auto it = begin(range); + const auto e = end(range); + return std::all_of(it, e, + [&](const auto& t){ + return trompeloeil::param_matches(comp, std::ref(t)); + }); + + } +}; + +struct range_all_of_printer { + template + void operator()(std::ostream& os, const C& comp) const + { + os << " range is all"; + trompeloeil::print_expectation(os, comp); + } +}; +} + +template + > +R range_all_of(C&& compare) +{ + return trompeloeil::make_matcher( + impl::range_all_of_checker{}, + impl::range_all_of_printer{}, + std::forward(compare)); +} + +namespace impl +{ +struct range_none_of_checker +{ + template + bool operator()(const R& range, const C& comp) const + { + using std::begin; + using std::end; + auto it = begin(range); + const auto e = end(range); + return std::none_of(it, e, + [&](const auto& t){ + return trompeloeil::param_matches(comp, std::ref(t)); + }); + } +}; + +struct range_none_of_printer { + template + void operator()(std::ostream& os, const C& comp) const + { + os << " range is none"; + trompeloeil::print_expectation(os, comp); + } +}; +} + +template < + typename Type = trompeloeil::wildcard, + typename C, + typename R = make_matcher_return< + Type, + impl::range_none_of_checker, + impl::range_none_of_printer, + C>> +R range_none_of(C&& compare) +{ + return trompeloeil::make_matcher( + impl::range_none_of_checker{}, + impl::range_none_of_printer{}, + std::forward(compare)); +} + + +namespace impl +{ +struct range_any_of_checker +{ + template + bool operator()(const R& range, const C& comp) const + { + using std::begin; + using std::end; + auto it = begin(range); + const auto e = end(range); + return std::any_of(it, e, + [&](const auto& t){ + return trompeloeil::param_matches(comp, std::ref(t)); + }); + } +}; + +struct range_any_of_printer +{ + template + void operator()(std::ostream& os, const C& comp) const + { + os << " range is any"; + trompeloeil::print_expectation(os, comp); + } +}; +} + +template < + typename Type = trompeloeil::wildcard, + typename C, + typename R = make_matcher_return< + Type, + impl::range_any_of_checker, + impl::range_any_of_printer, + C>> +R range_any_of(C&& compare) +{ + return trompeloeil::make_matcher( + impl::range_any_of_checker{}, + impl::range_any_of_printer{}, + std::forward(compare)); +} + +namespace impl +{ +struct starts_with_elements_checker +{ + template + bool operator()(const R& range, const Es& ... elements) const + { + using std::begin; + using std::end; + auto it = begin(range); + const auto e = end(range); + bool all_true = true; + const auto match = [&](const auto& compare) + { + if (it == e) return false; + const auto& v = *it++; + return trompeloeil::param_matches(compare, std::ref(v)); + }; + trompeloeil::ignore(std::initializer_list{ + (all_true = all_true && match(elements)) ...}); + return all_true; + } +}; + +struct starts_with_elements_printer +{ + template + void operator()(std::ostream& os, const Es& ... elements) const + { + os << " range starts with {"; + const char* sep = ""; + const auto print = [&](const auto& v) + { + os << std::exchange(sep, ", ") << v; + return 0; + }; + trompeloeil::ignore(std::initializer_list{ + (print(elements))... + }); + os << " }"; + + } +}; + +} + +template < + typename Type = trompeloeil::wildcard, + typename ... Es, + typename = typename std::enable_if...>::value>::type, + typename R = make_matcher_return< + Type, + impl::starts_with_elements_checker, + impl::starts_with_elements_printer, + Es...>> +R range_starts_with(Es&& ... es) +{ + return trompeloeil::make_matcher( + impl::starts_with_elements_checker{}, + impl::starts_with_elements_printer{}, + std::forward(es)...); +} + +namespace impl { +struct starts_with_range_checker{ + template + bool operator()(const R& range, const E& elements) const + { + using std::begin; + using std::end; + auto result = std::mismatch(begin(range), end(range), + begin(elements),end(elements), + [](const auto& t, const auto& c) { + return trompeloeil::param_matches(c, std::ref(t)); + }); + return result.second == end(elements); + } + +}; +struct starts_with_range_printer{ + template + void operator()(std::ostream& os, const E& elements) const + { + os << " range starts with {"; + const char* sep = " "; + for (const auto& v : elements) { + os << std::exchange(sep, ", ") << v; + } + os << " }"; + + } + +}; +} + +template < + typename Type = trompeloeil::wildcard, + typename C, + typename = typename std::enable_if>::type, + typename R = make_matcher_return< + Type, + impl::starts_with_range_checker, + impl::starts_with_range_printer, + impl::store_as_t>> +R range_starts_with(C&& c) +{ + return trompeloeil::make_matcher( + impl::starts_with_range_checker{}, + impl::starts_with_range_printer{}, + impl::store_as::make(std::forward(c))); +} + +namespace impl { +struct ends_with_checker +{ + template + bool operator()(const R &range, const Es &...elements) const + { + using std::begin; + using std::end; + auto it = begin(range); + const auto e = end(range); + const auto num_values = static_cast(sizeof...(elements)); + const auto size = std::distance(it, e); + if (size < num_values) + { + return false; + } + std::advance(it, size - num_values); + bool all_true = true; + const auto match = [&](const auto &compare) + { + const auto &v = *it++; + return trompeloeil::param_matches(compare, std::ref(v)); + }; + trompeloeil::ignore(std::initializer_list{ + (all_true = all_true && match(elements))...}); + return all_true; + } +}; + +struct ends_with_printer +{ + template + void operator()(std::ostream &os, const Es &...elements) const + { + os << " range ends with {"; + const char *sep = ""; + const auto print = [&](const auto &v) + { + os << std::exchange(sep, ", ") << v; + return 0; + }; + trompeloeil::ignore(std::initializer_list{(print(elements))...}); + os << " }"; + } +}; + +} +template < + typename Type = trompeloeil::wildcard, + typename ... Es, + typename = typename std::enable_if...>::value>::type, + typename R = make_matcher_return< + Type, + impl::ends_with_checker, + impl::ends_with_printer, + Es...> +> +R range_ends_with(Es&& ... es) +{ + return trompeloeil::make_matcher( + impl::ends_with_checker{}, + impl::ends_with_printer{}, + std::forward(es)...); +} + +namespace impl +{ +struct ends_with_range_checker{ + template + bool operator()(const R &range, const E& elements) const + { + using std::begin; + using std::end; + auto it = begin(range); + const auto e = end(range); + const auto num_values = static_cast(elements.size()); + const auto size = std::distance(it, e); + if (size < num_values) + { + return false; + } + std::advance(it, size - num_values); + auto result = std::mismatch(it, e, + begin(elements), end(elements), + [](const auto& v, const auto& c){ + return trompeloeil::param_matches(c, std::ref(v)); + }); + return result.second == elements.end(); + } +}; + +struct ends_with_range_printer{ + template + void operator()(std::ostream &os, const E& elements) const + { + os << " range ends with {"; + const char *sep = " "; + for (const auto& e : elements) { + os << std::exchange(sep, ", ") << e; + }; + os << " }"; + } +}; +} + +template < + typename Type = trompeloeil::wildcard, + typename C, + typename = typename std::enable_if>::type, + typename R = make_matcher_return< + Type, + impl::ends_with_range_checker, + impl::ends_with_range_printer, + impl::store_as_t> + > +R range_ends_with(C&& c) +{ + return trompeloeil::make_matcher( + impl::ends_with_range_checker{}, + impl::ends_with_range_printer{}, + impl::store_as::make(std::forward(c))); +} + +} +#endif // TROMPELOEIL_RANGE_HPP diff --git a/inc/trompeloeil/matcher/set_predicate.hpp b/inc/trompeloeil/matcher/set_predicate.hpp new file mode 100644 index 00000000..de39aba5 --- /dev/null +++ b/inc/trompeloeil/matcher/set_predicate.hpp @@ -0,0 +1,161 @@ +/* +* Trompeloeil C++ mocking framework +* +* Copyright (C) Björn Fahller +* +* Use, modification and distribution is subject to the +* Boost Software License, Version 1.0. (See accompanying +* file LICENSE_1_0.txt or copy atl +* http://www.boost.org/LICENSE_1_0.txt) +* +* Project home: https://github.com/rollbear/trompeloeil +*/ + +#ifndef TROMPELOEIL_SET_PREDICATE_HPP +#define TROMPELOEIL_SET_PREDICATE_HPP + +#ifndef TROMPELOEIL_MATCHER_HPP +#include "../matcher.hpp" +#endif + +namespace trompeloeil { +namespace impl { +struct any_of_checker +{ + template + bool operator()(const T& t, const Cs& ... compare) const + { + bool any_true = false; + trompeloeil::ignore(std::initializer_list{ + (any_true = any_true || trompeloeil::param_matches(compare, std::ref(t)))... + }); + return any_true; + } +}; +struct any_of_printer +{ + template + void operator()(std::ostream& os, const Cs& ... compare) const + { + os << " to be any of {"; + const char* sep = " "; + trompeloeil::ignore(std::initializer_list{ + ((os << detail::exchange(sep, ", ") << compare),0)... + }); + os << " }"; + } +}; +} + +template < + typename Type = trompeloeil::wildcard, + typename ... Cs, + typename R = make_matcher_return< + Type, + impl::any_of_checker, + impl::any_of_printer, + Cs... + > +> +R any_of(Cs&& ... cs) +{ + return trompeloeil::make_matcher( + impl::any_of_checker{}, + impl::any_of_printer{}, + std::forward(cs)...); +} + +namespace impl { +struct none_of_checker +{ + template + bool operator()(const T& t, const Cs& ... compare) const + { + bool any_true = false; + trompeloeil::ignore(std::initializer_list{ + (any_true = any_true || trompeloeil::param_matches(compare, std::ref(t)))... + }); + return !any_true; + } +}; +struct none_of_printer +{ + template + void operator()(std::ostream& os, const Cs& ... compare) const + { + os << " to be none of {"; + const char* sep = " "; + trompeloeil::ignore(std::initializer_list{ + ((os << detail::exchange(sep, ", ") << compare),0)... + }); + os << " }"; + } +}; +} + +template < + typename Type = trompeloeil::wildcard, + typename ... Cs, + typename R = make_matcher_return< + Type, + impl::none_of_checker, + impl::none_of_printer, + Cs... + > + > +R none_of(Cs&& ... cs) +{ + return trompeloeil::make_matcher( + impl::none_of_checker{}, + impl::none_of_printer{}, + std::forward(cs)...); +} + +namespace impl { +struct all_of_checker +{ + template + bool operator()(const T& t, const Cs& ... compare) const + { + bool all_true = true; + trompeloeil::ignore(std::initializer_list{ + (all_true = all_true && trompeloeil::param_matches(compare, std::ref(t)))... + }); + return all_true; + } +}; +struct all_of_printer +{ + template + void operator()(std::ostream& os, const Cs& ... compare) const + { + os << " to be all of {"; + const char* sep = " "; + trompeloeil::ignore(std::initializer_list{ + ((os << detail::exchange(sep, ", ") << compare),0)... + }); + os << " }"; + } +}; +} + +template < + typename Type = trompeloeil::wildcard, + typename ... Cs, + typename R = make_matcher_return< + Type, + impl::all_of_checker, + impl::all_of_printer, + Cs... + > + > +R all_of(Cs&& ... cs) +{ + return trompeloeil::make_matcher( + impl::all_of_checker{}, + impl::all_of_printer{}, + std::forward(cs)...); +} + +} +#endif // TROMPELOEIL_SET_PREDICATE_HPP diff --git a/inc/trompeloeil/mock.hpp b/inc/trompeloeil/mock.hpp index bed7f7a4..21da87d9 100644 --- a/inc/trompeloeil/mock.hpp +++ b/inc/trompeloeil/mock.hpp @@ -122,6 +122,43 @@ #define TROMPELOEIL_NOT_IMPLEMENTED(...) __VA_ARGS__ #endif +#if defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL==0 +# if _MSC_VER >= 1940 +# define TROMPELOEIL_HAS_VA_OPT 1 +# else +# define TROMPELOEIL_HAS_VA_OPT 0 +# endif +# define TROMPELOEIL_MSVC_PREPROCESSOR 0 +#elif __cplusplus >= 202002L +# define TROMPELOEIL_HAS_VA_OPT 1 +#else +# define TROMPELOEIL_HAS_VA_OPT 0 +#endif + +#if TROMPELOEIL_MSVC +# if !defined(TROMPELOEIL_MSVC_PREPROCESSOR) +# define TROMPELOEIL_MSVC_PREPROCESSOR 1 +# endif +#else +# define TROMPELOEIL_MSVC_PREPROCESSOR 0 +#endif + +#define TROMPELOEIL_IDENTITY(...) __VA_ARGS__ +#define TROMPELOEIL_APPLY(f, ...) TROMPELOEIL_SEQUENCE(f, (__VA_ARGS__)) +#define TROMPELOEIL_SEQUENCE(a,b) a b +#if TROMPELOEIL_HAS_VA_OPT +# define TROMPELOEIL_COUNT(...) TROMPELOEIL_COUNT_(__VA_OPT__(__VA_ARGS__,) 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0) +# define TROMPELOEIL_COUNT_(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,...) _15 +#else +# if defined (TROMPELOEIL_HAS_GCC_PP) +# define TROMPELOEIL_COUNT(...) TROMPELOEIL_APPLY(TROMPELOEIL_COUNT_,TROMPELOEIL_IDENTITY(,## __VA_ARGS__,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) +# else +# define TROMPELOEIL_COUNT(...) TROMPELOEIL_APPLY(TROMPELOEIL_COUNT_,TROMPELOEIL_IDENTITY(__VA_ARGS__,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) +# endif +# define TROMPELOEIL_COUNT_(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,...) _16 +#endif + + #include #include #include @@ -173,25 +210,20 @@ namespace trompeloeil { using std::unique_lock; } #define TROMPELOEIL_ASSERT(x) do {} while (false) #endif -#define TROMPELOEIL_IDENTITY(...) __VA_ARGS__ // work around stupid MS VS2015 RC bug - #define TROMPELOEIL_ARG16(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15, ...) _15 -#define TROMPELOEIL_COUNT(...) \ - TROMPELOEIL_IDENTITY(TROMPELOEIL_ARG16(__VA_ARGS__, \ - 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) -#if TROMPELOEIL_MSVC +#if TROMPELOEIL_MSVC_PREPROCESSOR #define TROMPELOEIL_CONCAT_(x, y, ...) x ## y __VA_ARGS__ #define TROMPELOEIL_CONCAT(x, ...) TROMPELOEIL_CONCAT_(x, __VA_ARGS__) -#else /* TROMPELOEIL_MSVC */ +#else /* TROMPELOEIL_MSVC_PREPROCESSOR */ #define TROMPELOEIL_CONCAT_(x, ...) x ## __VA_ARGS__ #define TROMPELOEIL_CONCAT(x, ...) TROMPELOEIL_CONCAT_(x, __VA_ARGS__) -#endif /* !TROMPELOEIL_MSVC */ +#endif /* !TROMPELOEIL_MSVC_PREPROCESSOR */ #define TROMPELOEIL_SEPARATE1(p1) p1 #define TROMPELOEIL_SEPARATE2(p1,p2) p1 p2 @@ -203,8 +235,9 @@ namespace trompeloeil { using std::unique_lock; } #define TROMPELOEIL_SEPARATE8(p1,...) p1 TROMPELOEIL_SEPARATE7(__VA_ARGS__) #define TROMPELOEIL_SEPARATE9(p1,...) p1 TROMPELOEIL_SEPARATE8(__VA_ARGS__) #define TROMPELOEIL_SEPARATE(...) \ - TROMPELOEIL_CONCAT(TROMPELOEIL_SEPARATE,\ - TROMPELOEIL_COUNT(__VA_ARGS__))(__VA_ARGS__) + TROMPELOEIL_APPLY(TROMPELOEIL_CONCAT, \ + TROMPELOEIL_SEPARATE, \ + TROMPELOEIL_COUNT(__VA_ARGS__))(__VA_ARGS__) #define TROMPELOEIL_REMOVE_PAREN(...) TROMPELOEIL_CONCAT(TROMPELOEIL_CLEAR_, \ @@ -263,8 +296,9 @@ namespace trompeloeil { using std::unique_lock; } #define TROMPELOEIL_INIT_WITH_STR0(base) #define TROMPELOEIL_INIT_WITH_STR(base, ...) \ - TROMPELOEIL_CONCAT(TROMPELOEIL_INIT_WITH_STR, \ - TROMPELOEIL_COUNT(__VA_ARGS__))(base, __VA_ARGS__) + TROMPELOEIL_APPLY(TROMPELOEIL_CONCAT, \ + TROMPELOEIL_INIT_WITH_STR, \ + TROMPELOEIL_COUNT(__VA_ARGS__))(base, __VA_ARGS__) #define TROMPELOEIL_PARAM_LIST15(...) \ TROMPELOEIL_PARAM_LIST14(__VA_ARGS__), \ @@ -516,6 +550,7 @@ namespace trompeloeil { mini_span(T* address, size_t size) noexcept : begin_(address), end_(address + size) {} T* begin() const noexcept { return begin_; } T* end() const noexcept { return end_; } + size_t size() const { return static_cast(end_ - begin_); } private: T* begin_; T* end_; @@ -2506,6 +2541,24 @@ template template struct multiplicity { }; + struct rt_multiplicity + { + std::size_t low{}; + std::size_t high{}; + + explicit rt_multiplicity(std::size_t _low) noexcept + : low{_low} + , high{_low} + { + } + + explicit rt_multiplicity(std::size_t _low, std::size_t _high) noexcept + : low{_low} + , high{_high} + { + } + }; + template struct co_return_injector : Parent { @@ -2801,6 +2854,29 @@ template } }; + struct runtime_times + { + template < + typename Matcher, typename modifier_tag, typename Parent, + bool times_set = Parent::call_limit_set> + static + call_modifier::max()>> + action(call_modifier&& m, + rt_multiplicity bounds) + { + static_assert(!times_set, + "Only one RT_TIMES call limit is allowed, but it can express an interval"); + + if (bounds.high < bounds.low) + { + throw std::logic_error{"In RT_TIMES the first value must not exceed the second"}; + } + + m.matcher->sequences->set_limits(bounds.low, bounds.high); + return std::move(m).matcher; + } + }; + inline void report_unfulfilled( @@ -3038,6 +3114,7 @@ template if (!cond.check(params)) { os << "\n Failed WITH(" << cond.name() << ')'; + break; } } } @@ -3289,14 +3366,10 @@ template call_matcher_list saturated{}; }; - template - return_of_t mock_func(std::false_type, P&& ...); - template return_of_t - mock_func(std::true_type, - expectations& e, + mock_func(expectations& e, char const *func_name, char const *sig_name, P&& ... p) @@ -3361,210 +3434,210 @@ template #define TROMPELOEIL_COUNT_ID(name) \ TROMPELOEIL_CONCAT(trompeloeil_c_ ## name ## _, __COUNTER__) -#if TROMPELOEIL_MSVC +#if TROMPELOEIL_MSVC_PREPROCESSOR #define TROMPELOEIL_MAKE_MOCK0(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,0, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,0, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK1(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,1, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,1, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK2(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,2, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,2, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK3(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,3, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,3, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK4(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,4, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,4, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK5(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,5, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,5, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK6(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,6, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,6, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK7(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,7, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,7, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK8(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,8, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,8, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK9(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,9, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,9, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK10(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,10, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,10, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK11(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,11, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,11, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK12(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,12, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,12, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK13(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,13, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,13, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK14(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,14, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,14, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK15(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,15, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,15, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK0(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,0, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,0, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK1(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,1, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,1, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK2(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,2, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,2, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK3(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,3, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,3, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK4(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,4, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,4, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK5(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,5, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,5, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK6(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,6, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,6, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK7(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,7, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,7, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK8(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,8, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,8, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK9(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,9, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,9, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK10(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,10, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,10, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK11(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,11, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,11, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK12(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,12, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,12, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK13(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,13, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,13, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK14(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,14, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,14, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK15(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,15, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,15, sig, __VA_ARGS__,,) #ifdef STDMETHODCALLTYPE #define TROMPELOEIL_MAKE_STDMETHOD_MOCK0(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,0, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,0, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK1(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,1, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,1, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK2(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,2, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,2, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK3(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,3, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,3, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK4(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,4, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,4, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK5(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,5, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,5, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK6(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,6, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,6, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK7(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,7, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,7, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK8(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,8, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,8, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK9(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,9, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,9, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK10(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,10, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,10, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK11(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,11, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,11, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK12(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,12, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,12, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK13(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,13, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,13, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK14(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,14, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,14, sig, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK15(name, sig, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,15, sig, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,15, sig, __VA_ARGS__,,) #endif #else // sane standards compliant preprocessor #define TROMPELOEIL_MAKE_MOCK0(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,0, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,0, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK1(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,1, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,1, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK2(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,2, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,2, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK3(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,3, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,3, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK4(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,4, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,4, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK5(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,5, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,5, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK6(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,6, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,6, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK7(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,7, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,7, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK8(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,8, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,8, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK9(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,9, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,9, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK10(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,10, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,10, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK11(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,11, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,11, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK12(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,12, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,12, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK13(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,13, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,13, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK14(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,14,__VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,14,__VA_ARGS__,,) #define TROMPELOEIL_MAKE_MOCK15(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,,15, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,,15, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK0(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,0, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,0, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK1(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,1, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,1, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK2(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,2, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,2, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK3(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,3, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,3, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK4(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,4, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,4, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK5(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,5, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,5, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK6(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,6, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,6, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK7(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,7, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,7, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK8(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,8, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,8, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK9(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,9, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,9, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK10(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,10, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,10, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK11(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,11, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,11, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK12(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,12, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,12, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK13(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,13, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,13, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK14(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,14, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,14, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_CONST_MOCK15(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,const,,15, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,const,,15, __VA_ARGS__,,) #ifdef STDMETHODCALLTYPE #define TROMPELOEIL_MAKE_STDMETHOD_MOCK0(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,0, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,0, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK1(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,1, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,1, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK2(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,2, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,2, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK3(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,3, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,3, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK4(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,4, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,4, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK5(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,5, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,5, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK6(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,6, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,6, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK7(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,7, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,7, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK8(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,8, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,8, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK9(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,9, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,9, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK10(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,10, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,10, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK11(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,11, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,11, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK12(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,12, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,12, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK13(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,13, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,13, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK14(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,14, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,14, __VA_ARGS__,,) #define TROMPELOEIL_MAKE_STDMETHOD_MOCK15(name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,,STDMETHODCALLTYPE,15, __VA_ARGS__,,) + TROMPELOEIL_MAKE_MOCK_CHECKED(name,,STDMETHODCALLTYPE,15, __VA_ARGS__,,) #endif #endif @@ -3685,7 +3758,7 @@ template TROMPELOEIL_IDENTITY(TROMPELOEIL_IMPLEMENT_STDMETHOD_MOCK_(15, __VA_ARGS__,override)) #define TROMPELOEIL_IMPLEMENT_STDMETHOD_MOCK_(num, name, ...) \ - TROMPELOEIL_MAKE_MOCK_(name,\ + TROMPELOEIL_MAKE_MOCK_CHECKED(name,\ ,\ STDMETHODCALLTYPE,\ num,\ @@ -3693,13 +3766,28 @@ template TROMPELOEIL_SEPARATE(__VA_ARGS__),) #endif +#define TROMPELOEIL_FIRST(a,...) a +#define TROMPELOEIL_COUNT_COMMA(sig) TROMPELOEIL_IDENTITY(TROMPELOEIL_COUNT_COMMA_ ## sig) +#define TROMPELOEIL_COUNT_COMMA_auto(...) TROMPELOEIL_COUNT(__VA_ARGS__), + +#define TROMPELOEIL_CARDINALITY(sig) TROMPELOEIL_APPLY(TROMPELOEIL_FIRST, TROMPELOEIL_COUNT_COMMA(sig)) + +#define TROMPELOEIL_MAKE_MOCK(name, ...) \ + TROMPELOEIL_APPLY(TROMPELOEIL_MAKE_MOCK_, name,,,TROMPELOEIL_CARDINALITY(TROMPELOEIL_FIRST(__VA_ARGS__,)), __VA_ARGS__,,) +#define TROMPELOEIL_MAKE_CONST_MOCK(name, ...) \ + TROMPELOEIL_APPLY(TROMPELOEIL_MAKE_MOCK_, name,const,,TROMPELOEIL_CARDINALITY(TROMPELOEIL_FIRST(__VA_ARGS__,)), __VA_ARGS__,,) +#ifdef STDMETHODCALLTYPE +# define TROMPELOEIL_MAKE_STDMETHOD_MOCK(name, ...) \ + TROMPELOEIL_APPLY(TROMPELOEIL_MAKE_MOCK_, name,,STDMETHODCALLTYPE,TROMPELOEIL_CARDINALITY(TROMPELOEIL_FIRST(__VA_ARGS__,)), __VA_ARGS__,,) +#endif + +#define TROMPELOEIL_MAKE_MOCK_CHECKED(name, constness, callconv, num, sig, spec, ...) \ + static_assert(num == ::trompeloeil::param_list::size, \ + "Function signature does not have " #num " parameters"); \ + TROMPELOEIL_MAKE_MOCK_(name, constness, callconv, num, sig, spec, __VA_ARGS__) + #define TROMPELOEIL_MAKE_MOCK_(name, constness, callconv, num, sig, spec, ...) \ private: \ - using TROMPELOEIL_LINE_ID(cardinality_match) = \ - std::integral_constant::size>; \ - static_assert(TROMPELOEIL_LINE_ID(cardinality_match)::value, \ - "Function signature does not have " #num " parameters"); \ using TROMPELOEIL_LINE_ID(matcher_list_t) = \ ::trompeloeil::call_matcher_list; \ using TROMPELOEIL_LINE_ID(expectation_list_t) = \ @@ -3762,10 +3850,9 @@ template spec \ { \ return ::trompeloeil::mock_func( \ - TROMPELOEIL_LINE_ID(cardinality_match){}, \ TROMPELOEIL_LINE_ID(expectations), \ -#name, \ -#sig \ + #name, \ + #sig \ TROMPELOEIL_PARAMS(num)); \ } \ \ @@ -4123,6 +4210,7 @@ template #define TROMPELOEIL_TIMES(...) template action(::trompeloeil::multiplicity<__VA_ARGS__>{}) +#define TROMPELOEIL_RT_TIMES(...) template action(::trompeloeil::rt_multiplicity{__VA_ARGS__}) #define TROMPELOEIL_INFINITY_TIMES() TROMPELOEIL_TIMES(0, ~static_cast(0)) #define TROMPELOEIL_AT_LEAST(num) num, ~static_cast(0) @@ -4130,6 +4218,7 @@ template #ifndef TROMPELOEIL_LONG_MACROS +#define MAKE_MOCK TROMPELOEIL_MAKE_MOCK #define MAKE_MOCK0 TROMPELOEIL_MAKE_MOCK0 #define MAKE_MOCK1 TROMPELOEIL_MAKE_MOCK1 #define MAKE_MOCK2 TROMPELOEIL_MAKE_MOCK2 @@ -4147,6 +4236,7 @@ template #define MAKE_MOCK14 TROMPELOEIL_MAKE_MOCK14 #define MAKE_MOCK15 TROMPELOEIL_MAKE_MOCK15 +#define MAKE_CONST_MOCK TROMPELOEIL_MAKE_CONST_MOCK #define MAKE_CONST_MOCK0 TROMPELOEIL_MAKE_CONST_MOCK0 #define MAKE_CONST_MOCK1 TROMPELOEIL_MAKE_CONST_MOCK1 #define MAKE_CONST_MOCK2 TROMPELOEIL_MAKE_CONST_MOCK2 @@ -4164,6 +4254,7 @@ template #define MAKE_CONST_MOCK14 TROMPELOEIL_MAKE_CONST_MOCK14 #define MAKE_CONST_MOCK15 TROMPELOEIL_MAKE_CONST_MOCK15 +#define MAKE_STDMETHOD_MOCK TROMPELOEIL_MAKE_STDMETHOD_MOCK #define MAKE_STDMETHOD_MOCK0 TROMPELOEIL_MAKE_STDMETHOD_MOCK0 #define MAKE_STDMETHOD_MOCK1 TROMPELOEIL_MAKE_STDMETHOD_MOCK1 #define MAKE_STDMETHOD_MOCK2 TROMPELOEIL_MAKE_STDMETHOD_MOCK2 @@ -4259,6 +4350,7 @@ template #define THROW TROMPELOEIL_THROW #define LR_THROW TROMPELOEIL_LR_THROW #define TIMES TROMPELOEIL_TIMES +#define RT_TIMES TROMPELOEIL_RT_TIMES #define AT_LEAST TROMPELOEIL_AT_LEAST #define AT_MOST TROMPELOEIL_AT_MOST