I depend on hardware that may or may not respond. As a consequence I frequently end up writing functions with timeouts. System time is a known source for brittle unit tests so injecting a controlled and stable time seems like a good idea for testing.
I wonder if there are any facilities in std::chrono that help with that. The alternative I see is to write a wrapper around the system time and depend on that adapter.
Here is a minimal example of how a wrapper could look like.
#pragma once
#include <memory>
#include <chrono>
#include <thread>
#include <iostream>
using std::chrono::system_clock;
using std::chrono::milliseconds;
using std::shared_ptr;
using std::make_shared;
class Wrapped_Clock
{
public:
    virtual system_clock::time_point Now() { return system_clock::now(); }
    virtual void Sleep(milliseconds ms) { std::this_thread::sleep_for(ms); }
};
class Mock_Clock : public Wrapped_Clock
{
private:
    system_clock::time_point now;
public:
    Mock_Clock() : now(system_clock::now()){}
    ~Mock_Clock() {}
    system_clock::time_point Now() { return now; }
    void Sleep(milliseconds ms) { }
};
class CanTimeOut
{
private:
    shared_ptr<Wrapped_Clock> sclock;
public:
    CanTimeOut(shared_ptr<Wrapped_Clock> sclock = make_shared<Wrapped_Clock>()) : sclock(sclock) {}
    ~CanTimeOut() {}
    milliseconds TimeoutAction(milliseconds maxtime)
    {
        using std::chrono::duration_cast;
        int x = 0;
        system_clock::time_point start = sclock->Now();
        system_clock::time_point timeout = sclock->Now() + maxtime;
        while (timeout > sclock->Now() && x != 2000)
        {
            sclock->Sleep(milliseconds(1));
            ++x;
        }
        milliseconds elapsed = duration_cast<milliseconds>(sclock->Now() - start);
        return elapsed;
    }
};
#define EXPECT_GE(left, right, test) \
{ if (!(left >= right)) { \
    std::cout << #test << " " << "!(" << left << " >= " << right << ")" << std::endl; \
} }
#define EXPECT_EQ(expected, actual, test) \
{ if (!(expected == actual)) { \
    std::cout << #test << " " << "!(" << expected << " == " << actual << ")" << std::endl; \
} }
void TestWithSystemClock()
{
    CanTimeOut cto;
    long long timeout = 1000;
    milliseconds actual = cto.TimeoutAction(milliseconds(timeout));
    EXPECT_GE(actual.count(), timeout, TestWithSystemClock);
}
void TestWithMockClock()
{
    CanTimeOut cto(make_shared<Mock_Clock>());
    milliseconds actual = cto.TimeoutAction(milliseconds(1000));
    EXPECT_EQ(0, actual.count(), TestWithMockClock);
}
int main()
{
    TestWithSystemClock();
    TestWithMockClock();
}
How much of this can be replaced with functionality from std::chrone?
std:: facilities.It looks, instead, that you are mocking std::this_thread::sleep.
That's a bit trickier, because it's a namespace with just free functions. It's hard to "inject" a namespace for testing purposes. So, you should, indeed, wrap the functions from that namespace with your own type.
I'd use static dependency injection, à la C++:
Live On Coliru
#include <memory>
#include <chrono>
#include <thread>
#include <iostream>
using std::chrono::system_clock;
using std::chrono::milliseconds;
struct production {
    using clock = std::chrono::system_clock;
    struct this_thread {
        template<typename... A> static auto sleep_for(A&&... a) { return std::this_thread::sleep_for(std::forward<A>(a)...); }
        template<typename... A> static auto sleep_until(A&&... a) { return std::this_thread::sleep_until(std::forward<A>(a)...); }
    };
};
struct mock {
    struct clock : std::chrono::system_clock {
        using base_type = std::chrono::system_clock;
        static time_point now() { static auto onetime = base_type::now(); return onetime; }
    };
    struct this_thread {
        template<typename... A> static auto sleep_for(A&&... a) {}
        template<typename... A> static auto sleep_until(A&&... a) {}
    };
};
template <typename services = production,
         typename clock = typename services::clock,
         typename this_thread = typename services::this_thread>
class CanTimeOut
{
public:
    milliseconds TimeoutAction(milliseconds maxtime)
    {
        using std::chrono::duration_cast;
        int x = 0;
        auto start   = clock::now();
        auto timeout = clock::now() + maxtime;
        while (timeout > clock::now() && x != 2000)
        {
            this_thread::sleep_for(milliseconds(1));
            ++x;
        }
        milliseconds elapsed = duration_cast<milliseconds>(clock::now() - start);
        return elapsed;
    }
};
#define EXPECT_GE(left, right, test) \
{ if (!(left >= right)) { \
    std::cout << #test << " " << "!(" << left << " >= " << right << ")" << std::endl; \
} }
#define EXPECT_EQ(expected, actual, test) \
{ if (!(expected == actual)) { \
    std::cout << #test << " " << "!(" << expected << " == " << actual << ")" << std::endl; \
} }
void TestWithSystemClock()
{
    CanTimeOut<> cto;
    long long timeout = 1000;
    milliseconds actual = cto.TimeoutAction(milliseconds(timeout));
    EXPECT_GE(actual.count(), timeout, TestWithSystemClock);
}
void TestWithMockClock()
{
    CanTimeOut<mock> cto;
    milliseconds actual = cto.TimeoutAction(milliseconds(1000));
    EXPECT_EQ(0, actual.count(), TestWithMockClock);
}
int main()
{
    TestWithSystemClock();
    TestWithMockClock();
}
Another way to handle this is to define a simulated clock and specify the type of clock to be used as a template parameter.
#include <chrono>
#include <iostream>
#include <thread>
#include "sim_clock.hpp"
using namespace std::chrono;
template <typename clock_t> void Sleep(milliseconds ms)
{
    std::this_thread::sleep_for(ms);
}
template <> void Sleep<sim_clock>(milliseconds ms)
{
    sim_clock::increment_by(ms);
}
template <typename clock_t = std::chrono::steady_clock> class CanTimeOut
{
  public:
    CanTimeOut() = default;
    ~CanTimeOut() = default;
    milliseconds TimeoutAction(milliseconds maxtime)
    {
        int x = 0;
        auto start = clock_t::now();
        auto timeout = start + maxtime;
        while(timeout > clock_t::now()) { Sleep<clock_t>(milliseconds(1)); }
        return duration_cast<milliseconds>(clock_t::now() - start);
    }
};
#define EXPECT_GE(left, right, test)                                           \
    {                                                                          \
        if(!(left >= right)) {                                                 \
            std::cout << #test << " "                                          \
                      << "!(" << left << " >= " << right << ")" << std::endl;  \
        }                                                                      \
    }
void TestWithSystemClock()
{
    CanTimeOut<> cto;
    long long timeout = 1000;
    milliseconds actual = cto.TimeoutAction(milliseconds(timeout));
    EXPECT_GE(actual.count(), timeout, TestWithSystemClock);
}
void TestWithMockClock()
{
    CanTimeOut<sim_clock> cto;
    long long timeout = 1000;
    milliseconds actual = cto.TimeoutAction(milliseconds(timeout));
    sim_clock::increment_by(milliseconds(timeout));
    EXPECT_GE(actual.count(), timeout, TestWithSystemClock);
}
int main()
{
    TestWithSystemClock();
    TestWithMockClock();
}
Here is the simulated clock definition based on steady_clock:
#pragma once
#include <chrono>
struct sim_clock {
    typedef std::chrono::steady_clock::rep rep;
    typedef std::chrono::steady_clock::period period;
    typedef std::chrono::steady_clock::duration duration;
    typedef std::chrono::steady_clock::time_point time_point;
    static time_point now() noexcept;
    static void increment_by(sim_clock::duration d) noexcept;
    static constexpr bool is_steady = true;
    static time_point _now;
};
and implementation:
#include "sim_clock.hpp"
sim_clock::time_point sim_clock::_now;
sim_clock::time_point sim_clock::now() noexcept
{
    return _now;
}
void sim_clock::increment_by(sim_clock::duration d) noexcept
{
    _now += d;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With