Force sequence of EXPECT_CALLs
Asked Answered
B

0

7

I'm trying to test two serial port write+read calls. The first one has to block on read for 101ms and thus cause a timeout error. The second one should run fine. Based on the google mock manual the InSequence variable should ensure that. Here is the code:

  {
    // This variable ensures the sequence order
    InSequence s;

    EXPECT_CALL(serial_, Write(_, _))
        .With(ElementsAreArray(command1_))
        .WillOnce(Invoke(Write));

    EXPECT_CALL(serial_, Read(_, _, _))
        .WillOnce(Invoke(TimeoutRead));

    EXPECT_CALL(serial_, Write(_, _))
        .With(ElementsAreArray(command2_))
        .WillOnce(Invoke(Write));

    EXPECT_CALL(serial_, Read(_, _, _))
        .Times(1)
        .WillOnce(DoAll(SetArrayArgument<0>(response_begin, response_end),
                        SetArgumentPointee<2>(response_.size()),
                        Return(true)));
  }

TimeoutRead is just a function that causes current thread to sleep for 101ms. However, I keep getting this runtime error:

[ RUN      ] MasterTest.LostReply
/host/Users/blah/work/bitbucket/master_test.cc:631: Failure
Mock function called more times than expected - returning default value.
    Function call: Read(0x5652c3f31120 pointing to "\xFF\xFF", 4096, 0x7ffda19d2960)
          Returns: false
         Expected: to be called once
           Actual: called twice - over-saturated and active

It seems that GTest is trying to call the last EXPECT_CALL designed for the second read.

Is there a way to enforce this sequence of calls?


[THIS IS TEMPORARY EDIT TO PRESENT SSCCE YOU NEED TO PROVIDE TO GET ANSWER]
This is SSCCE I expect you update appropriately to get error you are mentioning in your question. The code below works and passes:

class Serial_
{
public:
    MOCK_METHOD2(Write, void(int* elems, size_t n));
    MOCK_METHOD3(Read, bool(int* elems, int dummy, size_t* n));
};

int command1_[] = {1,2,3};
int command2_[] = {4,5};
std::array<int, 4> response_{{ 6, 7, 8, 9 }};

void testScenario(Serial_& serial_)
{
    int dummy_arr[100];
    size_t dummy_size;
    serial_.Write(command1_, 3);
    serial_.Read(dummy_arr, 123, &dummy_size);
    serial_.Write(command2_, 2);
    serial_.Read(dummy_arr, 123, &dummy_size);
}

bool TimeoutRead(int* elems, int dummy, size_t* n)
{
    return true;
}

void Write(int* elems, size_t n)
{}


TEST(A,A)
{
    Serial_ serial_;

    // This variable ensures the sequence order
    InSequence s;

    EXPECT_CALL(serial_, Write(_, _))
        .With(ElementsAreArray(command1_))
        .WillOnce(Invoke(Write));

    EXPECT_CALL(serial_, Read(_, _, _))
        .WillOnce(Invoke(TimeoutRead));

    EXPECT_CALL(serial_, Write(_, _))
        .With(ElementsAreArray(command2_))
        .WillOnce(Invoke(Write));

    EXPECT_CALL(serial_, Read(_, _, _))
        .Times(1)
        .WillOnce(DoAll(SetArrayArgument<0>(response_.begin(), response_.end()),
                        SetArgumentPointee<2>(response_.size()),
                        Return(true)));

    testScenario(serial_);
}
Bulldoze answered 21/3, 2017 at 22:20 Comment(5)
Check if this With(ElementsAreArray(command2_)) constraint to second Write happens or not. Or - just check if second write happens. E.g. remove all ElementsAreArray checks... ?Metrorrhagia
@Metrorrhagia How will missing second write will cause the second EXPECT_CALL(Read) to be matched twice? It seems to me that the sequence requirement isn't working.Bulldoze
This is much too small information. Please present the code you are testing. And the serial_ mock definition and the best would be sscce.orgMetrorrhagia
@Metrorrhagia Thanks for taking a stab at it. TimeoutRead has std::this_thread::sleep_for(11ms) in it to cause the wrapper of the serial_ mock functions to timeout and fail.Bulldoze
@Metrorrhagia I found the bug in my own code, thanks to your hints. Not sure how to award the bounty then.Bulldoze

© 2022 - 2024 — McMap. All rights reserved.