eranpeer / FakeIt

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

Cannot mock destructors in Visual Studio 2015 C++ #54

Closed francoisgenolini closed 1 year ago

francoisgenolini commented 8 years ago

On Windows 10 (latest update), I have a Visual Studio 2015 native C++ unit test project and I am mocking destructors using FakeIt. This results in access violations: fakeit.hpp, line 5806. fakeit::MethodProxyCreator::methodProxy(unsigned int id) where invocationHandlerCollection is an invalid object

Here is my code:

        struct SomeInterface {
            virtual ~SomeInterface() {}
            virtual int SomeMethod(int someArgument) = 0;
        };

            Mock<SomeInterface> mock;
            When(Method(mock, SomeMethod)).AlwaysReturn(42);
            Fake(Dtor(mock));
            SomeInterface* someInterface = &mock.get();
            // This next line causes access violation
            delete someInterface;
Gerark commented 8 years ago

Hello, did you find any solution to this? I've a similar issue on visual studio 2013 but the crash happens on

        void *VirtualTableBase::getCookie(int index) {
            return _firstMethod[-2 - index];
        }
tnovotny commented 8 years ago

For me this is working. I am using the November 30 Update 1 and the MS testing tool. Test passes both x32 and x64. Dont't think its relevant, but OS is 8.1 Professional 64 bit.

alexey-malov commented 7 years ago

I have checked with Visual Studio 2015 update 3. It crashes if the destructor is not the very first method of the interfaces:

If I place SomeMethod after the destructor, everything is OK:

    struct SomeInterface
    {
        virtual ~SomeInterface() = default;
        virtual void SomeMethod(int someParam) = 0;
    };

    void mock_virtual_dtor_with_when() {
        int a = 0;
        Mock<SomeInterface> mock;
        When(Dtor(mock)).Return().Do([&](){a++; });
        SomeInterface * i = &(mock.get());
        delete i; // do nothing
        delete i; // a++
        ASSERT_EQUAL(1, a);
    }

However, if I put SomeMethod above the destructor, it crashes:

    struct SomeInterface
    {
        virtual void SomeMethod(int someParam) = 0;
        virtual ~SomeInterface() = default;
    };
    void mock_virtual_dtor_with_when() {
        int a = 0;
        Mock<SomeInterface> mock;
        When(Dtor(mock)).Return().Do([&](){a++; });
        SomeInterface * i = &(mock.get());
        delete i; // do nothing
        delete i; // a++
        ASSERT_EQUAL(1, a);
    }

Error message is:

Exception thrown: read access violation.

invocationHandler was nullptr.

If there is a handler for this exception, the program may be safely continued.

Stack track is:

>   all_tests.exe!fakeit::MethodProxyCreator<void>::methodProxy(unsigned int id) Line 45    C++
    all_tests.exe!fakeit::MethodProxyCreator<void>::methodProxyX<0>() Line 51   C++
    all_tests.exe!fakeit::VirtualTable<DtorMocking::SomeInterface>::dtor(int __formal) Line 219 C++
    all_tests.exe!DtorMocking::mock_virtual_dtor_with_when() Line 54    C++
    all_tests.exe!tpunit::TestFixture::__do_tests(tpunit::TestFixture::fixture * f) Line 500    C++
    all_tests.exe!tpunit::TestFixture::__do_run() Line 360  C++
    all_tests.exe!tpunit::Tests::Run() Line 550 C++
    all_tests.exe!main() Line 31    C++
FranckRJ commented 1 year ago

Should be fixed by #312, it will be available in FakeIt 2.3.3 or 2.4.0 depending on which is the first to be released.