mimic++ v10.0.1
Loading...
Searching...
No Matches
Mock.hpp
Go to the documentation of this file.
1// Copyright Dominic (DNKpp) Koepke 2024-2026.
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"
12#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(... && expectation::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(... && expectation::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(... && expectation::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(... && expectation::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(... && expectation::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(... && expectation::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, typename ParamList = signature_param_list_t<Signature>>
297 class BasicMock;
298
299 template <typename Signature, typename... Params>
300 class BasicMock<Signature, util::type_list<Params...>>
301 : public MockFrontend<
302 // MockFrontend doesn't need to know about the call-convention, thus remove it
303 BasicMock<Signature, util::type_list<Params...>>,
304 signature_remove_call_convention_t<Signature>>,
305 public call_interface_t<
306 BasicMock<Signature, util::type_list<Params...>>,
307 Signature>
308 {
311 using ArgRefList = typename CallInfo::ArgListT;
312 using ReturnType = signature_return_type_t<SignatureT>;
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 [[nodiscard]]
322 explicit BasicMock(expectation::Registry::Ptr registry, MockSettings settings) noexcept
323 : m_Registry{std::move(registry)},
324 m_Settings{std::move(settings)}
325 {
326 MIMICPP_ASSERT(m_Registry, "Null registry is not allowed.");
327 MIMICPP_ASSERT(m_Settings.name, "Empty mock-name.");
328 m_Settings.stacktraceSkip += 2u; // skips the operator() and the handle_call from the stacktrace
329 }
330
331 private:
333 MockSettings m_Settings;
334
335 [[nodiscard]]
336 constexpr ReturnType handle_call(reporting::TypeReport overloadReport, ArgRefList&& params, util::SourceLocation from) const
337 {
338 return m_Registry->handle_call<SignatureT>(
339 reporting::TargetReport{
340 .name{*m_Settings.name},
341 .overloadReport{std::move(overloadReport)}},
342 CallInfo{
343 .args{std::move(params)},
344 .fromCategory{refQualification},
345 .fromConstness{constQualification},
346 .fromSourceLocation{std::move(from)},
347 .baseStacktraceSkip{m_Settings.stacktraceSkip}});
348 }
349
350 template <typename... Args>
351 [[nodiscard]]
352 constexpr auto make_expectation_builder(reporting::TypeReport overloadReport, Args&&... args) const
353 {
354 return expectation::detail::make_builder<Signature>(
355 m_Registry,
356 reporting::TargetReport{.name = *m_Settings.name, .overloadReport = std::move(overloadReport)},
357 std::forward<Args>(args)...)
358 && expectation::policies::Category<refQualification>{}
359 && expectation::policies::Constness<constQualification>{};
360 }
361 };
362
363 template <typename... Signatures>
364 [[nodiscard]]
365 StringT generate_mock_name()
366 {
367 StringStreamT out{};
368 out << "Mock<";
369 printing::type::detail::print_separated(
370 std::ostreambuf_iterator{out},
371 ", ",
372 util::type_list<Signatures...>{});
373 out << ">";
374
375 return std::move(out).str();
376 }
377}
378
380{
431
437 template <typename FirstSignature, typename... OtherSignatures>
438 requires is_overload_set_v<FirstSignature, OtherSignatures...>
439 class Mock
440 : public detail::BasicMock<FirstSignature>,
441 public detail::BasicMock<OtherSignatures>...
442 {
443 public:
444 using detail::BasicMock<FirstSignature>::operator();
445 using detail::BasicMock<FirstSignature>::expect_call;
446 using detail::BasicMock<OtherSignatures>::operator()...;
447 using detail::BasicMock<OtherSignatures>::expect_call...;
448
452 ~Mock() = default;
453
457 [[nodiscard]]
459 : Mock{MockSettings{}}
460 {
461 }
462
467 [[nodiscard]]
469 : Mock{std::make_shared<expectation::Registry>(), complete_settings(std::move(settings))}
470 {
471 }
472
476 Mock(const Mock&) = delete;
477
481 Mock& operator=(const Mock&) = delete;
482
486 [[nodiscard]]
487 Mock(Mock&&) = default;
488
492 Mock& operator=(Mock&&) = default;
493
494 private:
495 [[nodiscard]]
496 explicit Mock(expectation::Registry::Ptr const& registry, MockSettings const& settings) noexcept
497 : detail::BasicMock<FirstSignature>{registry, settings},
498 detail::BasicMock<OtherSignatures>{registry, settings}...
499 {
500 }
501
502 [[nodiscard]]
503 static MockSettings complete_settings(MockSettings settings)
504 {
505 if (!settings.name)
506 {
507 settings.name = detail::generate_mock_name<FirstSignature, OtherSignatures...>();
508 }
509
510 return settings;
511 }
512 };
513
517}
518
519#endif
#define MIMICPP_ASSERT(condition, msg)
Definition Config.hpp:54
#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:468
Mock(const Mock &)=delete
Deleted copy constructor.
Mock & operator=(const Mock &)=delete
Deleted copy assignment operator.
Mock()
Default constructor.
Definition Mock.hpp:458
Definition Mock.hpp:35
std::optional< StringT > name
Definition Mock.hpp:37
std::size_t stacktraceSkip
Definition Mock.hpp:38
std::shared_ptr< Registry > Ptr
Definition Registry.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:363
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
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 Builder.hpp:33
Definition Settings.hpp:16
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:38
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:397