mimic++ v9.2.1
Loading...
Searching...
No Matches
Mock.hpp
Go to the documentation of this file.
1// Copyright Dominic (DNKpp) Koepke 2024 - 2025.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at
4// https://www.boost.org/LICENSE_1_0.txt)
5
6#ifndef MIMICPP_MOCK_HPP
7#define MIMICPP_MOCK_HPP
8
9#pragma once
10
11#include "mimic++/Call.hpp"
14#include "mimic++/Fwd.hpp"
22
23#ifndef MIMICPP_DETAIL_IS_MODULE
24 #include <cstddef>
25 #include <functional>
26 #include <optional>
27 #include <tuple>
28 #include <type_traits>
29 #include <utility>
30#endif
31
33{
35 {
36 public:
37 std::optional<StringT> name{};
38 std::size_t stacktraceSkip{};
39 };
40}
41
42namespace mimicpp::detail
43{
44 template <typename Derived, typename Signature>
45 using call_interface_t = typename call_convention_traits<
46 signature_call_convention_t<Signature>>::template call_interface_t<Derived, Signature>;
47
48 template <typename Derived, typename Signature, typename... Params>
49 class DefaultCallInterface<
50 Derived,
51 Signature,
54 util::type_list<Params...>>
55 {
56 public:
57 constexpr signature_return_type_t<Signature> operator()(
58 Params... params,
59 util::SourceLocation from = {}) noexcept(signature_is_noexcept_v<Signature>)
60 {
61 return static_cast<Derived const&>(*this)
62 .handle_call(
64 std::tuple{std::ref(params)...},
65 std::move(from));
66 }
67 };
68
69 template <typename Derived, typename Signature, typename... Params>
70 class DefaultCallInterface<
71 Derived,
72 Signature,
75 util::type_list<Params...>>
76 {
77 public:
78 constexpr signature_return_type_t<Signature> operator()(
79 Params... params,
80 util::SourceLocation from = {}) const noexcept(signature_is_noexcept_v<Signature>)
81 {
82 return static_cast<Derived const&>(*this)
83 .handle_call(
85 std::tuple{std::ref(params)...},
86 std::move(from));
87 }
88 };
89
90 template <typename Derived, typename Signature, typename... Params>
91 class DefaultCallInterface<
92 Derived,
93 Signature,
96 util::type_list<Params...>>
97 {
98 public:
99 constexpr signature_return_type_t<Signature> operator()(
100 Params... params,
101 util::SourceLocation from = {}) & noexcept(signature_is_noexcept_v<Signature>)
102 {
103 return static_cast<Derived const&>(*this)
104 .handle_call(
106 std::tuple{std::ref(params)...},
107 std::move(from));
108 }
109 };
110
111 template <typename Derived, typename Signature, typename... Params>
112 class DefaultCallInterface<
113 Derived,
114 Signature,
117 util::type_list<Params...>>
118 {
119 public:
120 constexpr signature_return_type_t<Signature> operator()(
121 Params... params,
122 util::SourceLocation from = {}) const& noexcept(signature_is_noexcept_v<Signature>)
123 {
124 return static_cast<Derived const&>(*this)
125 .handle_call(
127 std::tuple{std::ref(params)...},
128 std::move(from));
129 }
130 };
131
132 template <typename Derived, typename Signature, typename... Params>
133 class DefaultCallInterface<
134 Derived,
135 Signature,
138 util::type_list<Params...>>
139 {
140 public:
141 constexpr signature_return_type_t<Signature> operator()(
142 Params... params,
143 util::SourceLocation from = {}) && noexcept(signature_is_noexcept_v<Signature>)
144 {
145 return static_cast<Derived const&>(*this)
146 .handle_call(
148 std::tuple{std::ref(params)...},
149 std::move(from));
150 }
151 };
152
153 template <typename Derived, typename Signature, typename... Params>
154 class DefaultCallInterface<
155 Derived,
156 Signature,
159 util::type_list<Params...>>
160 {
161 public:
162 constexpr signature_return_type_t<Signature> operator()(
163 Params... params,
164 util::SourceLocation from = {}) const&& noexcept(signature_is_noexcept_v<Signature>)
165 {
166 return static_cast<Derived const&>(*this)
167 .handle_call(
169 std::tuple{std::ref(params)...},
170 std::move(from));
171 }
172 };
173
174 template <
175 typename Derived,
176 typename Signature,
179 typename ParamList = signature_param_list_t<Signature>>
180 class MockFrontend;
181
182 template <typename Derived, typename Signature, typename... Params>
183 class MockFrontend<
184 Derived,
185 Signature,
188 util::type_list<Params...>>
189 {
190 public:
191 template <typename... Args>
192 requires(... && requirement_for<Args, Params>)
193 [[nodiscard]]
194 constexpr auto expect_call(Args&&... args)
195 {
196 return static_cast<Derived const&>(*this)
197 .make_expectation_builder(reporting::TypeReport::make<Signature>(), std::forward<Args>(args)...);
198 }
199 };
200
201 template <typename Derived, typename Signature, typename... Params>
202 class MockFrontend<
203 Derived,
204 Signature,
207 util::type_list<Params...>>
208 {
209 public:
210 template <typename... Args>
211 requires(... && requirement_for<Args, Params>)
212 [[nodiscard]]
213 constexpr auto expect_call(Args&&... args) const
214 {
215 return static_cast<Derived const&>(*this)
216 .make_expectation_builder(reporting::TypeReport::make<Signature>(), std::forward<Args>(args)...);
217 }
218 };
219
220 template <typename Derived, typename Signature, typename... Params>
221 class MockFrontend<
222 Derived,
223 Signature,
226 util::type_list<Params...>>
227 {
228 public:
229 template <typename... Args>
230 requires(... && requirement_for<Args, Params>)
231 [[nodiscard]]
232 constexpr auto expect_call(Args&&... args) &
233 {
234 return static_cast<Derived const&>(*this)
235 .make_expectation_builder(reporting::TypeReport::make<Signature>(), std::forward<Args>(args)...);
236 }
237 };
238
239 template <typename Derived, typename Signature, typename... Params>
240 class MockFrontend<
241 Derived,
242 Signature,
245 util::type_list<Params...>>
246 {
247 public:
248 template <typename... Args>
249 requires(... && requirement_for<Args, Params>)
250 [[nodiscard]]
251 constexpr auto expect_call(Args&&... args) const&
252 {
253 return static_cast<Derived const&>(*this)
254 .make_expectation_builder(reporting::TypeReport::make<Signature>(), std::forward<Args>(args)...);
255 }
256 };
257
258 template <typename Derived, typename Signature, typename... Params>
259 class MockFrontend<
260 Derived,
261 Signature,
264 util::type_list<Params...>>
265 {
266 public:
267 template <typename... Args>
268 requires(... && requirement_for<Args, Params>)
269 [[nodiscard]]
270 constexpr auto expect_call(Args&&... args) &&
271 {
272 return static_cast<Derived const&>(*this)
273 .make_expectation_builder(reporting::TypeReport::make<Signature>(), std::forward<Args>(args)...);
274 }
275 };
276
277 template <typename Derived, typename Signature, typename... Params>
278 class MockFrontend<
279 Derived,
280 Signature,
283 util::type_list<Params...>>
284 {
285 public:
286 template <typename... Args>
287 requires(... && requirement_for<Args, Params>)
288 [[nodiscard]]
289 constexpr auto expect_call(Args&&... args) const&&
290 {
291 return static_cast<Derived const&>(*this)
292 .make_expectation_builder(reporting::TypeReport::make<Signature>(), std::forward<Args>(args)...);
293 }
294 };
295
296 template <typename Signature>
297 using expectation_collection_ptr_for = std::shared_ptr<ExpectationCollection<signature_decay_t<Signature>>>;
298
299 template <typename Signature, typename ParamList = signature_param_list_t<Signature>>
300 class BasicMock;
301
302 template <typename Signature, typename... Params>
303 class BasicMock<Signature, util::type_list<Params...>>
304 : public MockFrontend<
305 // MockFrontend doesn't need to know about the call-convention, thus remove it
306 BasicMock<Signature, util::type_list<Params...>>,
307 signature_remove_call_convention_t<Signature>>,
308 public call_interface_t<
309 BasicMock<Signature, util::type_list<Params...>>,
310 Signature>
311 {
313
314 friend class MockFrontend<BasicMock, SignatureT>;
315 friend call_interface_t<BasicMock, Signature>;
316
317 static constexpr Constness constQualification = signature_const_qualification_v<SignatureT>;
318 static constexpr ValueCategory refQualification = signature_ref_qualification_v<SignatureT>;
319
320 protected:
321 using ExpectationCollectionPtrT = expectation_collection_ptr_for<SignatureT>;
322
323 [[nodiscard]]
324 explicit BasicMock(
325 ExpectationCollectionPtrT collection,
326 MockSettings settings) noexcept
327 : m_Expectations{std::move(collection)},
328 m_Settings{std::move(settings)}
329 {
330 MIMICPP_ASSERT(m_Settings.name, "Empty mock-name.");
331
332 m_Settings.stacktraceSkip += 2u; // skips the operator() and the handle_call from the stacktrace
333 }
334
335 private:
336 ExpectationCollectionPtrT m_Expectations;
337 MockSettings m_Settings;
338
339 [[nodiscard]]
340 constexpr signature_return_type_t<SignatureT> handle_call(
341 reporting::TypeReport overloadReport,
342 std::tuple<std::reference_wrapper<std::remove_reference_t<Params>>...>&& params,
343 util::SourceLocation from) const
344 {
345 return m_Expectations->handle_call(
346 reporting::TargetReport{
347 .name{*m_Settings.name},
348 .overloadReport{std::move(overloadReport)}},
350 .args{std::move(params)},
351 .fromCategory{refQualification},
352 .fromConstness{constQualification},
353 .fromSourceLocation{std::move(from)},
354 .baseStacktraceSkip{m_Settings.stacktraceSkip}});
355 }
356
357 template <typename... Args>
358 [[nodiscard]]
359 constexpr auto make_expectation_builder(reporting::TypeReport overloadReport, Args&&... args) const
360 {
361 return detail::make_expectation_builder(
362 m_Expectations,
363 reporting::TargetReport{.name = *m_Settings.name, .overloadReport = std::move(overloadReport)},
364 std::forward<Args>(args)...)
365 && expectation_policies::Category<refQualification>{}
366 && expectation_policies::Constness<constQualification>{};
367 }
368 };
369
370 template <typename List>
371 struct expectation_collection_factory;
372
373 template <typename... UniqueSignatures>
374 struct expectation_collection_factory<util::type_list<UniqueSignatures...>>
375 {
376 [[nodiscard]]
377 static auto make()
378 {
379 return std::tuple{
380 std::make_shared<ExpectationCollection<UniqueSignatures>>()...};
381 }
382 };
383
384 template <typename... Signatures>
385 [[nodiscard]]
386 StringT generate_mock_name()
387 {
388 StringStreamT out{};
389 out << "Mock<";
390 printing::type::detail::print_separated(
391 std::ostreambuf_iterator{out},
392 ", ",
393 util::type_list<Signatures...>{});
394 out << ">";
395
396 return std::move(out).str();
397 }
398}
399
401{
452
458 template <typename FirstSignature, typename... OtherSignatures>
459 requires is_overload_set_v<FirstSignature, OtherSignatures...>
460 class Mock
461 : public detail::BasicMock<FirstSignature>,
462 public detail::BasicMock<OtherSignatures>...
463 {
464 public:
465 using detail::BasicMock<FirstSignature>::operator();
466 using detail::BasicMock<FirstSignature>::expect_call;
467 using detail::BasicMock<OtherSignatures>::operator()...;
468 using detail::BasicMock<OtherSignatures>::expect_call...;
469
473 ~Mock() = default;
474
478 [[nodiscard]]
480 : Mock{MockSettings{}}
481 {
482 }
483
488 [[nodiscard]]
490 : Mock{
491 detail::expectation_collection_factory<
492 util::detail::unique_list_t<
493 signature_decay_t<FirstSignature>,
494 signature_decay_t<OtherSignatures>...>>::make(),
495 complete_settings(std::move(settings))}
496 {
497 }
498
502 Mock(const Mock&) = delete;
503
507 Mock& operator=(const Mock&) = delete;
508
512 [[nodiscard]]
513 Mock(Mock&&) = default;
514
518 Mock& operator=(Mock&&) = default;
519
520 private:
521 template <typename... Collections>
522 [[nodiscard]]
523 explicit Mock(std::tuple<Collections...> collections, MockSettings const& settings) noexcept
524 // clang-format off
525 : detail::BasicMock<FirstSignature>{
526 util::detail::get<detail::expectation_collection_ptr_for<FirstSignature>>(collections),
527 settings},
528 detail::BasicMock<OtherSignatures>{
529 util::detail::get<detail::expectation_collection_ptr_for<OtherSignatures>>(collections),
530 settings}...
531 // clang-format on
532 {
533 }
534
535 [[nodiscard]]
536 static MockSettings complete_settings(MockSettings settings)
537 {
538 if (!settings.name)
539 {
540 settings.name = detail::generate_mock_name<FirstSignature, OtherSignatures...>();
541 }
542
543 return settings;
544 }
545 };
546
550}
551
552#endif
#define MIMICPP_ASSERT(condition, msg)
Definition Config.hpp:51
#define MIMICPP_DETAIL_MODULE_EXPORT
Definition Config.hpp:19
~Mock()=default
Defaulted destructor.
Mock & operator=(Mock &&)=default
Defaulted move assignment operator.
Mock(Mock &&)=default
Defaulted move constructor.
Mock(MockSettings settings)
Constructor, applying customized settings.
Definition Mock.hpp:489
Mock(const Mock &)=delete
Deleted copy constructor.
Mock & operator=(const Mock &)=delete
Deleted copy assignment operator.
Mock()
Default constructor.
Definition Mock.hpp:479
Definition Mock.hpp:35
std::optional< StringT > name
Definition Mock.hpp:37
std::size_t stacktraceSkip
Definition Mock.hpp:38
static constexpr TypeReport make() noexcept
Definition TypeReport.hpp:39
constexpr bool is_overload_set_v
Convenience constant, exposing the value member of the actual type-trait.
Definition Fwd.hpp:347
typename signature_call_convention< Signature >::type signature_call_convention_t
Convenience alias, exposing the type member alias of the actual type-trait.
Definition Fwd.hpp:102
constexpr Constness signature_const_qualification_v
Convenience constant, exposing the value member of the actual type-trait.
Definition Fwd.hpp:246
typename signature_decay< Signature >::type signature_decay_t
Convenience alias, exposing the type member alias of the actual type-trait.
Definition Fwd.hpp:214
constexpr bool signature_is_noexcept_v
Convenience constant, exposing the value member of the actual type-trait.
Definition Fwd.hpp:86
typename signature_param_list< Signature >::type signature_param_list_t
Convenience alias, exposing the type member alias of the actual type-trait.
Definition Fwd.hpp:294
constexpr ValueCategory signature_ref_qualification_v
Convenience constant, exposing the value member of the actual type-trait.
Definition Fwd.hpp:262
typename signature_remove_call_convention< Signature >::type signature_remove_call_convention_t
Convenience alias, exposing the type member alias of the actual type-trait.
Definition Fwd.hpp:118
typename signature_return_type< Signature >::type signature_return_type_t
Convenience alias, exposing the type member alias of the actual type-trait.
Definition Fwd.hpp:230
typename info_for_signature< Signature >::type info_for_signature_t
Definition Call.hpp:47
Definition Settings.hpp:16
Definition Fwd.hpp:445
Definition Call.hpp:24
ValueCategory
Definition Fwd.hpp:34
@ any
Definition Fwd.hpp:37
@ lvalue
Definition Fwd.hpp:35
@ rvalue
Definition Fwd.hpp:36
std::basic_ostringstream< CharT, CharTraitsT > StringStreamT
Definition Format.hpp:35
Constness
Definition Fwd.hpp:27
@ as_const
Definition Fwd.hpp:29
@ non_const
Definition Fwd.hpp:28
std::basic_string< CharT, CharTraitsT > StringT
Definition Fwd.hpp:391