Jesse Ryan
Jesse Ryan

Reputation: 73

Why is my Hippomock expectation failing when using multiple inheritance

I am using Hippomocks and have a class that implements an generic interface. When I place expectations on this class I do not get the expected behaviour.

This is my minimum "working" example

template <class T>
struct Foo {
  virtual ~Foo() = default;
  virtual void bar(const T& t) = 0;
};

struct Baz : public Foo<int>, public Foo<double> {
  void bar(const int& t) override = 0;
  void bar(const double& t) override = 0;
};

TEST_CASE("Foo")
{
  MockRepository mocks;

  auto baz = mocks.Mock<Baz>();

  mocks.ExpectCall(baz, Foo<int>::bar);
  baz->bar(12);

  mocks.ExpectCall(baz, Foo<double>::bar);
  baz->bar(234.3);
}

I am expecting this test to pass without any problems. However the test fails with the following message (slightly edited to remove project names):

test_foo.cpp|28| FAILED:
|| due to unexpected exception with message:
||   Function called without expectation!
||   Expectations set:
||   test_foo.cpp(31)
||   : Expectation for Foo<int>::bar(...) on the mock at 0x0x5569df8f3400 was
||   satisfied.
||   test_foo.cpp(34)
||   : Expectation for Foo<double>::bar(...) on the mock at 0x0x5569df8f3400 was
||   not satisfied.
I am expecting the bar() belonging to Foo<double> to be invoked.

Upvotes: 1

Views: 653

Answers (2)

Jesse Ryan
Jesse Ryan

Reputation: 73

Hippomocks takes care of the case in which there are overloaded class functions.

The expectations I should have used are the following

  mocks.ExpectCallOverload(baz, static_cast<void (Baz::*)(const int&)>(&Baz::bar));
  baz->bar(12);

  mocks.ExpectCallOverload(baz, static_cast<void (Baz::*)(const double&)>(&Baz::bar));
  baz->bar(234.3);

The syntax is horrible, but this now behaves as expected.

I should have RTFM...

Upvotes: 0

user7860670
user7860670

Reputation: 37485

I was curious how Mock could be possibly implemented without manually defining all the methods (like other mocking libraries do), but it turns out that it does not work. Mock implementation employs Undefined Behavior because it just reinterpret_cast unrelated class to Baz:

template <typename base>
base *MockRepository::Mock() {
    mock<base> *m = new mock<base>(this);
        mocks.push_back(m);
    return reinterpret_cast<base *>(m);
}

It does various other cheesy things, such as messing with vtable. None of that stuff can work reliably.

Upvotes: 1

Related Questions