Memoryleak when dynamically mocked interface is passed as result of function for the same mock
Tested with https://bitbucket.org/sglienke/spring4d/commits/121f07661f77e8e14581c5bc1d4089e4cf2cd95c
A memory leak occurs when setting up a mock to return itself as a result of a function call.
parentMock.Setup.Returns(TValue.From<IParent>(parentMock.AsType<IParent>.Instance)).When.GetChild;
I attached a patch which contains a test demonstrating the problem.
Comments (6)
-
repo owner -
reporter Yes, parentMock.AsType<IChild> would be correct.
I also was quite surprised this didn’t result in a memory leak with the old develop version from 05.08.2020 (https://bitbucket.org/sglienke/spring4d/commits/c336b8dd39bfc30cbcf2fa1f6d8323e663bdcc05 - the link seems to be broken?!)
I wouldn’t have created the issue if this didn’t work before.
-
repo owner Not sure what commit that should be (maybe some that got lost due to a force push) but I went back to bba6f47 and it leaks there as well.
FWIW call Reset on the mock to clear its expectations and resolve the circular reference.
-
reporter Calling Reset does only help if you didn’t call parentMock.AsType<IChild>() before. Not sure why. So this still results in a memory leak:
var parentMock: Mock<IParent>; begin parentMock.AsType<IChild>(); parentMock.Setup.Returns(TValue.From<IChild>(parentMock.AsType<IChild>.Instance)).When.GetChild; parentMock.Reset; Check(True); // no fail condition; check for memory leaks end;
Btw. the use case is for a workaround of multiple inheritance on interfaces. I’m not quite sure if this still satisfies good code architecture but we have a codebase with interfaces inheriting multiple interfaces (which is not possible natively in Delphi) by using functions.
type IBase1 = interface function BaseFunction: Boolean; end; IBase2 = interface function BaseFunction2: Boolean; end; IImplementBothBases = interface(IBase1) function AsBase2: IBase2; end;
If you have an instance of
IImplementBothBases
you can now accessIBase1
andIBase2
without having to deal with the situation the class might not implementIBase2
, as these are always implemented by simply returning Self.And this is exactly the behavior we replicated with
parentMock.Setup.Returns(TValue.From<IChild>(parentMock.AsType<IChild>.Instance)).When.GetChild;
orimplementBothBases.Setup.Returns(TValue.From<IBase2>(implementBothBases.AsType<IBase2>.Instance)).When.AsBase2;
-
repo owner
var parentMock: Mock<IParent>; childMock: Mock<IChild>; begin childMock := parentMock.AsType<IChild>; parentMock.Setup.Returns(childMock.Instance).When.GetChild; parentMock.Reset;
-
repo owner - changed status to resolved
fixed
#362→ <<cset dbbe1568529a>>
- Log in to comment
Well, yes, duh - circular reference.
I think you meant parentMock.AsType<IChild> because that code would fail anyway.
I don’t see the use case of this - mocks automatically return mocks for interface returning methods so this is not necessary at all. They are different instances though but I doubt the code under test would fail in that case.