mimic++ v5
Loading...
Searching...
No Matches
mimicpp::LifetimeWatcher Class Reference

A watcher type, which reports it's destructor calls. More...

#include <ObjectWatcher.hpp>

Public Member Functions

 ~LifetimeWatcher () noexcept(false)
 Destructor, which reports the call.
 
 LifetimeWatcher ()=default
 Defaulted default constructor.
 
 LifetimeWatcher (const LifetimeWatcher &other)
 Copy-constructor.
 
LifetimeWatcheroperator= (const LifetimeWatcher &other)
 Copy-assignment-operator.
 
 LifetimeWatcher (LifetimeWatcher &&)=default
 Defaulted move-constructor.
 
LifetimeWatcheroperator= (LifetimeWatcher &&)=default
 Defaulted move-assignment-operator.
 
auto expect_destruct ()
 Begins a destruction-expectation construction.
 

Detailed Description

A watcher type, which reports it's destructor calls.

This watcher is designed to track, whether the destructor has been called. During its destructor call, it reports the destruction to the framework, which can be tracked by a previously created destruction-expectation.

namespace expect = mimicpp::expect;
// imagine this to be a function, we wanted to test
constexpr auto some_function = [](auto fun) {
fun(); // let's just invoke the given fun.
};
mimicpp::Mock<void()>,
watched{}; // let's create a watched mock
// Let's say, we are very suspicious and want to get sure, that ``some_function``
// invokes the provided functional, before its getting destroyed.
mimicpp::SequenceT sequence{};
SCOPED_EXP watched.expect_call()
and expect::in_sequence(sequence);
SCOPED_EXP watched.expect_destruct()
and expect::in_sequence(sequence);
// pass the mock to ``some_function`` and track from the outside, whether the expectations hold
some_function(std::move(watched));
// nothing to do here. Violations will be reported automatically (as usual).

Moving

This watcher can be freely moved around.

Copying

This watcher is copyable, but with very special behaviour.

As this watcher is generally designed to be part of a bigger object, it would be very limiting not supporting copy-operations at all. The question is, how should a copy look like?

In general a copy should be a logical duplicate of its source and the general expectation is: if B is a copy of A, then A == B should yield true.

Note
This doesn't say, that if B is not a copy of A, then A == B has to yield false!

This won't be the case for LifetimeWatchers, as active destruction-expectations won't be copied over to the target. In general, if a LifetimeWatcher is used, we want to be very precise with our object-lifetime, thus an implicit expectation copy would be against the purpose of this helper. Due to this, each LifetimeWatcher will be created as a fresh instance, when copy-construction is used. The same logic also applies to copy-assignment.

Constructor & Destructor Documentation

◆ ~LifetimeWatcher()

mimicpp::LifetimeWatcher::~LifetimeWatcher ( )
inline

Destructor, which reports the call.

Note
A no-match error may occur, if no destruction-expectation has been defined.
constexpr auto action = [] {
struct not_nothrow_destructible
{
// explicitly make the destructor throwable, this isn't necessarily required in real tests
~not_nothrow_destructible() noexcept(false)
{
}
};
not_nothrow_destructible,
watched{}; // let's create a watched instance
// We purposely forget to define a destruction expectation.
// Due to this, a no-match will be reported during destruction.
};
// Depending on the active reporter, this may either raise an exception or terminate the program.
// The default reporter simply throws an exception.
REQUIRE_THROWS(action());

◆ LifetimeWatcher() [1/3]

mimicpp::LifetimeWatcher::LifetimeWatcher ( )
nodiscarddefault

Defaulted default constructor.

◆ LifetimeWatcher() [2/3]

mimicpp::LifetimeWatcher::LifetimeWatcher ( const LifetimeWatcher & other)
inlinenodiscard

Copy-constructor.

Parameters
otherThe other object.

This copy-constructor's purpose is to provide syntactically correct copy operations, but semantically this does not copy anything. In fact, it simply default-constructs the new instance, without even touching the other.

Note
It is mandatory setting up a new destruction-expectation. Otherwise, a no-match will be reported during destruction.
constexpr auto action = [] {
struct my_copyable // Mock isn't a copyable type, thus use a custom one for this example
{
// explicitly make the destructor throwable, this isn't necessarily required in real tests
~my_copyable() noexcept(false)
{
}
};
my_copyable,
source{};
// setting up a destruction-expectation is mandatory to prevent violation reports during scope leave
// This is just a little trick for this small example. In real code,
// one would usually pass the ownership of the watched object somewhere else,
// but in this example we fake that by simply moving it below our expectation.
auto moved = std::move(source); // note: source is now a "moved-from"-object, which doesn't report any violations
mimicpp::Watched other{source}; // now create a "copy" of source
// other is a new instance without an existing destruction-expectation,
// because the copy-constructor doesn't semantically copy anything.
// As other goes out of scope without a destruction-expectation, a no-match is reported.
};
// Depending on the active reporter, this may either raise an exception or terminate the program.
// The default reporter simply throws an exception.
REQUIRE_THROWS(action());

◆ LifetimeWatcher() [3/3]

mimicpp::LifetimeWatcher::LifetimeWatcher ( LifetimeWatcher && )
nodiscarddefault

Defaulted move-constructor.

This move-constructor simply transfers everything from the source to the destination object. As source is then a "moved-from"-object, it doesn't require any destruction-expectations.

Member Function Documentation

◆ expect_destruct()

auto mimicpp::LifetimeWatcher::expect_destruct ( )
inlinenodiscard

Begins a destruction-expectation construction.

Returns
A newly created expectation-builder-instance.
Note
This function creates a new expectation-builder-instance, which isn't an expectation yet. User must convert this to an actual expectation, by handing it over to a new ScopedExpectation instance. This can either be done manually or via MIMICPP_SCOPED_EXPECTATION (or the shorthand version SCOPED_EXP).
Exceptions
std::logic_errorif a destruction-expectation has already been created for this instance.
Here is the call graph for this function:

◆ operator=() [1/2]

LifetimeWatcher & mimicpp::LifetimeWatcher::operator= ( const LifetimeWatcher & other)
inline

Copy-assignment-operator.

Parameters
otherThe other object.

This copy-assignment-operator's purpose is to provide syntactically correct copy operations, but semantically this does not copy anything. In fact, it simply deletes the previous content of this instance, default-constructs a new instance and move-assigns it to this instance, without even touching the other.

Note
It is mandatory setting up a new destruction-expectation. Otherwise, a no-match will be reported during destruction.
constexpr auto action = [] {
struct my_copyable // Mock isn't a copyable type, thus use a custom one for this example
{
// explicitly make the destructor throwable, this isn't necessarily required in real tests
~my_copyable() noexcept(false)
{
}
};
my_copyable,
source{};
// setting up a destruction-expectation is mandatory to prevent violation reports during scope leave
// This is just a little trick for this small example. In real code,
// one would usually pass the ownership of the watched object somewhere else,
// but in this example we fake that by simply moving it below our expectation.
auto moved = std::move(source); // note: source is now a "moved-from"-object, which doesn't report any violations
my_copyable,
other{}; // now create another watched object
// other will be destructed, but there is no existing destruction-expectation
other = source; // a no-match will be reported immediately
};
// Depending on the active reporter, this may either raise an exception or terminate the program.
// The default reporter simply throws an exception.
REQUIRE_THROWS(action());
As this actually destructs a LifetimeWatcher, violations will be reported, if the previous instance didn't have a valid destruction-expectation.
constexpr auto action = [] {
struct my_copyable // Mock isn't a copyable type, thus use a custom one for this example
{
// explicitly make the destructor throwable, this isn't necessarily required in real tests
~my_copyable() noexcept(false)
{
}
};
my_copyable,
source{};
// setting up a destruction-expectation is mandatory to prevent violation reports during scope leave
// This is just a little trick for this small example. In real code,
// one would usually pass the ownership of the watched object somewhere else,
// but in this example we fake that by simply moving it below our expectation.
auto moved = std::move(source); // note: source is now a "moved-from"-object, which doesn't report any violations
my_copyable,
other{}; // now create another watched object
SCOPED_EXP other.expect_destruct(); // setting it up accordingly
other = source; // other will be destructed and the expectation from the line above fulfilled
// other is now a new instance without an existing destruction-expectation,
// because the copy-operator doesn't semantically copy anything.
// As other goes out of scope without a destruction-expectation, a no-match is reported.
};
// Depending on the active reporter, this may either raise an exception or terminate the program.
// The default reporter simply throws an exception.
REQUIRE_THROWS(action());

◆ operator=() [2/2]

LifetimeWatcher & mimicpp::LifetimeWatcher::operator= ( LifetimeWatcher && )
default

Defaulted move-assignment-operator.

This move-assignment-operator simply transfers everything from the source to the destination object. As source is then a "moved-from"-object, it doesn't require any destruction-expectations.


The documentation for this class was generated from the following file: