I have an interface function that has a constant array and an anonymous function as parameters:
TCodeword = array[0..7] of Char;
TIntFunc = reference to function: Integer;
IMyInterface = interface(IInvokable)
function DoSomething(const codeword: TCodeword; func: TIntFunc): Boolean;
end;
I want to mock that interface to test an object, that is using it:
function IntFunc: Integer;
begin
Result := 5;
end;
procedure Test;
var
MyInterfaceMock: Mock<IMyInterface>;
MyInterface: IMyInterface;
begin
MyInterfaceMock := Mock<IMyInterface>.Create(TMockbehavior.Strict);
MyInterfaceMock.Setup.Returns(true).When.DoSomething(arg.IsAny<TCodeword>, arg.IsAny<TIntFunc>());
MyInterface := MyInterfaceMock;
MyInterface.DoSomething('12345678', IntFunc);
end;
When running, an ENotSupportedException: ‚Type is not supported: TCodeword‘ is raised when Setup. Can somebody explain why this is a not supported type? How can I pass a not specified TCodeword to mock that function correctly?
Alternatively I tried to pass explicit arguments in Setup:
procedure Test;
var
MyInterfaceMock: Mock<IMyInterface>;
MyInterface: IMyInterface;
begin
MyInterfaceMock := Mock<IMyInterface>.Create(TMockbehavior.Strict);
MyInterfaceMock.Setup.Returns(true).When.DoSomething('12345678', IntFunc);
MyInterface := MyInterfaceMock;
MyInterface.DoSomething('12345678', IntFunc);
end;
That way it will work for the constant array but not for the anonymous function. I get an EMockException: 'unexpected call of function DoSomething(const codeword: TCodeword; func: TIntFunc): Boolean with arguments: nil, (array)';
How can I make this work? I am glad for any help!
There are multiple issues:
as the exception states the TCodeword
type is not supported - that is because types of typeKind tkArray
are not supported - I don't remember exactly why that is because internally the handling is very similar to tkDynArray. I will fix that and put an edit to this answer once done.
when passing a regular function to a method reference parameter the compiler builds the necessary code to wrap the regular function into a method reference and it uses an interfaced object for that which implements the interface of the method reference (after all anonymous methods are just interfaces). It however does that for every time this happens which means that two lines that pass IntFunc
to an TIntFunc
parameter are two different pointers. That is why internally the parameter matcher returns False. If you want to avoid that you need to put IntFunc
into a local variable of type TIntFunc
and pass that. Because then the compiler only builds that wrapping code once and in both cases the value of the local variable gets passed to the DoSomething
call.
Update: fixed in develop branch