eranpeer / FakeIt

C++ mocking made easy. A simple yet very expressive, headers only library for c++ mocking.
MIT License
1.23k stars 169 forks source link

Cannot mock single virtual inherited class #180

Closed oriolarcas closed 4 years ago

oriolarcas commented 4 years ago

Hi,

I have the following interfaces:

struct I1 {
    virtual int get() = 0;

    virtual ~I1() = default;
};

struct I2 : virtual I1 {
    using I1::I1;

    virtual ~I2() = default;
};

I need virtual inheritance for subclasses of I2, but the interfaces I1 and I2 themselves have no multiple inheritance. However, when I compile this code:

TEST_CASE( "interfaces", "[ifc]" ) {
    Mock<I2> i2_mock;
    When(Method(i2_mock,get)).AlwaysReturn(1);
}

I get the following error:

.../fakeit/fakeit.hpp: In instantiation of ‘fakeit::MockingContext<R, arglist ...> fakeit::MockImpl<C, baseclasses>::stubMethod(R (T::*)(arglist ...)) [with int id = 3; R = int; T = I1; arglist = {}; <template-parameter-2-5> = void; C = I2; baseclasses = {}]’:
.../fakeit/fakeit.hpp:8369:56:   required from ‘fakeit::MockingContext<R, arglist ...> fakeit::Mock<C, baseclasses>::stub(R (T::*)(arglist ...)) [with int id = 3; R = int; T = I1; arglist = {}; <template-parameter-2-5> = void; C = I2; baseclasses = {}]’
.../tests/test.cc:60:9:   required from here
.../fakeit/fakeit.hpp:8032:50: error: pointer to member conversion via virtual base ‘I1’
             return MockingContext<R, arglist...>(new UniqueMethodMockingContextImpl < id, R, arglist... >
                                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                    (*this, vMethod));
                    ~~~~~~~~~~~~~~~~

Any ideas?

oriolarcas commented 4 years ago

Just found a workaround while playing with the example. If the method is overridden in the derived interface, it will compile:

struct I1 {
    virtual int get() = 0;

    virtual ~I1() = default;
};

struct I2 : virtual I1 {
    using I1::I1;

    virtual int get() override = 0;
    virtual ~I2() = default;
};

TEST_CASE( "interfaces", "[ifc]" ) {
    Mock<I2> i2_mock;
    When(Method(i2_mock,get)).AlwaysReturn(1);
}

However, if I try to call the virtual method in the abstract interface the program will crash...

TEST_CASE( "interfaces", "[ifc]" ) {
    Mock<I2> i2_mock;
    When(Method(i2_mock,get)).AlwaysReturn(1);

    I2& i2 = i2_mock.get();
    REQUIRE(i2.get() == 1); /* works OK */

    I1& i1 = static_cast<I1&>(i2);
    REQUIRE(i1.get() == 1); /* causes SIGSEGV */
}
alibabashack commented 4 years ago

The Limitation section of https://github.com/eranpeer/FakeIt clearly states:

Can't mock classes with virtual inheritance.

oriolarcas commented 4 years ago

My bad. Thanks!