Search code examples
c++pointersgoogletestgooglemock

How to Increment Count of Shared Ptr from Raw Ptr


I am working on class unit testing and encountered this problem - a premature deletion of Device* device/mock:

Here is my SUT:

Effect::~Effect()
{
    for (auto it = infoList.begin(); it != infoList.end(); ++it)
    {
         (*it)->device->Remove(this, (*it)->position);
         delete *it;
    }
    infoList.clear();
}

HRESULT Effect::Add(Device* device, ULONG position)
{
    Info* info = new Info;
    info->device = device;
    info->position= position;

    auto result = device->Add(position);
    if (result == E_FAIL) return E_FAIL;

    //some other methods being called from 'device'

    infoList.push_back(info);
}

And my test:

class EffectTest: public ::testing::Test
{
public:
    void SetUp()
    {
        sut_ = std::make_unique<Effect>();
        deviceMock_ = std::make_shared<DeviceMock>();
    }

protected:
    std::unique_ptr<Effect> sut_;
    std::shared_ptr<DeviceMock> deviceMock_;
};


TEST_F(EffectTest, Add)
{
    EXPECT_CALL(*deviceMock_, Add(_).WillRepeatedly(Return(S_OK));
    EXPECT_CALL(*deviceMock_, Remove(_, _)).WillRepeatedly(Return(S_OK));

    sut_->Add(deviceMock_.get(), 90);
}

Since I am only passing a raw pointer (mock) deviceMock_.get() in Effect::Add(), reference count is not incremented. Test tears down earlier than the actual SUT so deviceMock_ is already deleted when Effect destructor is called. My problem is.. device is still being called in Effect's destructor and therefore causes a crash:

(*it)->device->Remove(this, (*it)->position);

Any thoughts on what I can do to force the deviceMock_ to stay alive when ~Effect is called? Can I force deviceMock_ reference count to increment only with the raw pointer Device* device??

Please do note though that I CANNOT CHANGE THE FUNCTION SIGNATURE OF:

HRESULT Effect::Add(Device* device, ULONG position)

Since this is an API.

Help please! Thanks!


Solution

  • Reverse the order of sut_ and deviceMock_ in EffectTest:

    class EffectTest: public ::testing::Test
    {
    public:
        void SetUp()
        {
            sut_ = std::make_unique<Effect>();
            deviceMock_ = std::make_shared<DeviceMock>();
        }
    
    protected:
        std::shared_ptr<DeviceMock> deviceMock_;
        std::unique_ptr<Effect> sut_;
    };
    

    Member variables are deleted from bottom to top. Changing this will cause Effect to be deleted before DeviceMock.