Search code examples
c++testingboosthippomocks

HippoMocks: mocking boost::chrono::steady_clock::now


I have some code:

boost::system::error_code clock_error;
const boost::chrono::steady_clock::time_point START = 
boost::chrono::steady_clock::now(clock_error);

and I want to mock the now() function so my test code contains this:

boost::chrono::steady_clock::time_point start(boost::chrono::seconds(0));
boost::system::system_error clock_error(1, BOOST_CHRONO_SYSTEM_CATEGORY, "foo");
mocks.ExpectCallFuncOverload( (boost::chrono::steady_clock::time_point (boost::chrono::steady_clock::*) (boost::system::error_code& clock_error))
                                        &boost::chrono::steady_clock::now)    
                    .With(Out(clock_error))
                    .Return(start);

but this doesn't compile. I get this error:

error: no matches converting function ‘now’ to type ‘boost::chrono::steady_clock::time_point (class boost::chrono::steady_clock::)(class boost::system::error_code&) {aka class boost::chrono::time_pointboost::chrono::steady_clock (class boost::chrono::steady_clock::)(class boost::system::error_code&)}’ mocks.ExpectCallFuncOverload(

In file included from ...

note: candidates are: static boost::chrono::steady_clock::time_point boost::chrono::steady_clock::now(boost::system::error_code&)

   static BOOST_CHRONO_INLINE time_point  now(system::error_code & ec);

                                          ^

../../../KACotsCode/boost/boost/chrono/system_clocks.hpp:162:46: note: static boost::chrono::steady_clock::time_point boost::chrono::steady_clock::now() static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT;

                                          ^

Can anybody spot the problem?


Solution

  • I looked at HippoMocks. That stuff is very high-tech. I would probably not trust it for production code, since it is very intrusive and completely undocumented¹

    However, it does do some impressive stuff on GCC and - judging from the code - MSVC:

    Live On Compiler Explorer

    #define BOOST_CHRONO_HEADER_ONLY
    #include "https://raw.githubusercontent.com/dascandy/hippomocks/master/HippoMocks/hippomocks.h"
    #include <boost/chrono.hpp>
    #include <iostream>
    namespace chrono = boost::chrono;
    using Clock      = chrono::steady_clock;
    
    int main() {
        MockRepository mocks;
    
        boost::system::error_code clock_error = make_error_code(boost::system::errc::file_exists);
    
        mocks
            .ExpectCallFunc(Clock::now) //
            .With(Out(clock_error))     //
            .Return(Clock::time_point::max());
        auto START = Clock::now(clock_error);
    
        std::cout                            //
            << clock_error.message() << ": " //
            << std::hex << START.time_since_epoch().count() << std::endl;
    }
    

    Prints the expectable

    File exists: 7fffffffffffffff
    

    BONUS: Time Traveler Edition

    Going back to 2015 (Boost 1.59 August 13th and GCC 4.8.5 June 23rd):

    Live On Compiler Explorer²

    #define BOOST_CHRONO_HEADER_ONLY
    #include "https://raw.githubusercontent.com/dascandy/hippomocks/master/HippoMocks/hippomocks.h"
    #include <boost/chrono.hpp>
    #include <iostream>
    namespace chrono = boost::chrono;
    using Clock      = chrono::steady_clock;
    
    int main() {
        std::cout << "Boost version: " << BOOST_VERSION << std::endl;
        std::cout << "GCC version: " << __VERSION__ << std::endl;
        MockRepository mocks;
    
        boost::system::error_code clock_error = make_error_code(boost::system::errc::file_exists);
    
        mocks
            .ExpectCallFunc(static_cast<Clock::time_point (&)(boost::system::error_code&)>(Clock::now)) //
            .With(Out(clock_error))                                                                     //
            .Return(Clock::time_point::max());
        auto START = Clock::now(clock_error);
    
        std::cout                            //
            << clock_error.message() << ": " //
            << std::hex << START.time_since_epoch().count() << std::endl;
    }
    

    As you correctly surmised you have to explicitly coerce the overloaded function type. More importantly, HippoMocks doesn't like when you pass the function pointer here, so be sure to case to a function reference: static_cast<Clock::time_point (&)(boost::system::error_code&)>(Clock::now)

    Proof of the pudding:

    Boost version: 105900
    GCC version: 4.8.5
    File exists: 7fffffffffffffff
    

    enter image description here


    ¹ the devs believing that somehow "unfortunately, concise documents restrict access and hinder progress for some developers" [sic]

    ² Compiler Explorer cannot execute the code because Boost System only became header-only in Boost 1.69.0