sleep() call inside gmock's EXPECT_CALL
Asked Answered
P

3

6

I'm trying to do some sleep inside .WillOnce before invoking FuncHelper. So I need something similar to the following:

EXPECT_CALL(*_mock, Func(_,_,_)).Times(1)
  .WillOnce(DoAll(InvokeWithoutArgs(sleep(TimeToSleep)), 
                  Invoke(_mock, &M_MyMock::FuncHelper)));

Is it possible to call sleep() with an arg inside .DoAll? C++98 is preferrable.

UPD:

The solution is based on @Smeeheey answer and uses C++98.

template <int N> void Sleep ()
{
  sleep(N);
}
...
EXPECT_CALL(*_mock, Func(_,_,_)).Times(1)
  .WillOnce(DoAll(InvokeWithoutArgs(Sleep<TimeToSleep>), 
                  Invoke(_mock, &M_MyMock::FuncHelper)));
Plague answered 7/6, 2016 at 12:2 Comment(1)
There is no need to define your own function, just use what STL has to offer. See my answer, hope it helps!Monah
L
6

Since you said C++98 is preferable rather than compulsory, first I'll give a nice neat C++11 answer:

EXPECT_CALL(*_mock, Func(_,_,_)).Times(1)
  .WillOnce(DoAll(InvokeWithoutArgs([TimeToSleep](){sleep(TimeToSleep);}), 
                  Invoke(_mock, &M_MyMock::FuncHelper)));

Otherwise (for C++98), define a wrapper function elsewhere in the code:

void sleepForTime()
{
    sleep(TimeToSleep);
}

And then:

EXPECT_CALL(*_mock, Func(_,_,_)).Times(1)
  .WillOnce(DoAll(InvokeWithoutArgs(sleepForTime), 
                  Invoke(_mock, &M_MyMock::FuncHelper)));

Note that here, TimeToSleep will have to be a global variable.

EDIT: As per suggestion from OP in comments, if TimeToSleep is a compile-time constant you can avoid the global variable:

template <int Duration>
void sleepForTime()
{
    sleep(Duration);
}

...

EXPECT_CALL(*_mock, Func(_,_,_)).Times(1)
  .WillOnce(DoAll(InvokeWithoutArgs(sleepForTime<TimeToSleep>), 
                  Invoke(_mock, &M_MyMock::FuncHelper)));
Lontson answered 7/6, 2016 at 12:20 Comment(2)
I didn't want to use a global var to keep tests flexible. However your answer suggests another solution. Thanks)) I'd create a template function with a value param. "template <int N> void Sleep () { sleep(N); }" It'd solve my problem.Plague
Oh yes, I didn't know that TimeToSleep is a compile-time constant. I updated the answer to incorporate this suggestion.Lontson
M
1

If you prefer C++98 solution, I would suggest using std::bind1st:

EXPECT_CALL(*_mock, Func(_,_,_)).Times(1)
  .WillOnce(DoAll(InvokeWithoutArgs(std::bind1st(sleep, TimeToSleep)), 
                  Invoke(_mock, &M_MyMock::FuncHelper)));
Monah answered 7/6, 2016 at 12:44 Comment(5)
I'm afraid that std::bind is not a part of C++98 standard.Plague
You might try std::bind1st - that was c++98 solution - see en.cppreference.com/w/cpp/utility/functional/bind12 But you must hurry - it is already deprecated since C++11 - will be removed in C++17...Ametropia
@Plague I forgot that there were only bind1st and bind2nd in C++98. I've updated my answer to use bind1st.Monah
@Ametropia You are right, thank you for reminding me. As far as the deprecation goes, since he wants a C++98 solution, I doubt he will be upgrading to a C++17 compliant compiler next year ...Monah
@MarkoPopovic @Ametropia I'd avoid using bind1st since it's deprecated now. Moreover the solution I choose looks more elegant and easy to read. But anyway I already tried the solution with std::bind1st(sleep, TimeToSleep) before I posted the question. This solution doesn't compile at all, GCC 4.8 fails with the error "no matching function for call to ‘bind1st(<unresolved overloaded function type>, const int&)’".Plague
H
1

Define gmock action

ACTION_P(Wait, seconds)
{
  ::sleep(seconds)
}

And then use it in short, clean way:

EXPECT_CALL(...).WillOnce(Wait(3));

I think it is the most "gmockish" and the cleanest way to wait in gmock tests, especially if one needs to do wait in several places of a test.

Haldas answered 20/8, 2020 at 10:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.