chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
0 votes
There is a problem with the dynamic mocking when attempting to mock an interface (this bug is also present in NMock 1.1 and Rhino.Mocks!)

public interface IFoo
{
double[,] Foo();
}

If you try and create a MockObject of this interface it will fail:

'System.TypeLoadException : Method Foo in type MockIFoo from assembly DynamicMockAssembly, Version=0.0.0.0 does not have an implementation'

In the source for NMock 1.1 I believe it is the CastClass OpCode attempting to dereference the double[,] from the evaluation stack which is failing in the dynamically emitted code but I have had no previous experience with emitting MSIL so I am kinda stuck from that point on.

I could refactor the interface under normal circumstances but it is presented by a 3rd party component and so out of my control.

Thanks.
asked by c0d3-m0nk3y (8.7k points)

8 Answers

0 votes
There is a problem with the dynamic mocking when attempting to mock an interface

public interface IFoo
{
double[,] Foo();
}


Hi,
Thanks for pointing this out, we will try to solve this for the coming release
answered by scott (32k points)
0 votes
Any indication when the next release is planned?
answered by c0d3-m0nk3y (8.7k points)
0 votes
:arrow: It should be sometime next month
answered by scott (32k points)
0 votes
Hi,
I am sorry to say that a fix for this bug has not been delivered in version 3.0.
We will try to fix it soon.


:arrow: Following is a technical explaination of the bug :twisted:
--------------------------------------------------------------

The problem with rectangular arrays lies with the way that Reflection.Emit works.

When a method is defined as double[,] it signiture is actually:
double[0..., 0...] this means that the array indexes are 0 based,
You can see this clearly when you use the ildasm.exe of the method.

The actual MSIL signiture is: 20 00 14 0d 02 00 02 00 00

Here is the explaination
20 calling convention
00 number of args
14 return type = Array
0d of type double
02 number of rank (dimensions)
00 following number of known index sizes (0 as both index sizes are unknown)
02 following number of known index low bounds
00 the first rank has a low bound of 0
00 the 2nd rank has a low bound of 0

But when using Reflection.Emit.TypeBuilder.DefineMethod() the signiture will be
20 00 14 0d 02 00 00 meaning that their are no lower bounds to the array indexes

as the signitures don't match the CLR will issue a "Method ... does not have an implementation." error.

The actual BUG is in the internal method SignatureHelper.AddArrayOrPointer(Type) that doesn't check for bounds of the array
answered by richard (3.9k points)
0 votes
Any further progress with this issue since 3.0?

This is really causing a pain in the rect (drumroll please!) for my client as they are consuming a financial analysis library which returns large, complex rect arrays.

Thanks.
answered by c0d3-m0nk3y (8.7k points)
0 votes
Hi,
This item is very high on our list. We are still trying to come up with a standard solution. I hope that we can give you a patch soon.
answered by scott (32k points)
0 votes
Hi,
We are still working on this issue (it seems quite complicated), in the meantime here is a workaround.

Create a Mock Class of the problematic interface.

public class MockIFoo : IFoo 
{
    public double[,] Foo()
    {
        throw new Exception("The method or operation is not implemented.");
    }
}


Now in your tests use MockIFoo instead of IFoo.
// Mock our interface - use Concrete Class instead
MockObject mock = MockManager.MockObject(typeof(MockIFoo));
mock.ExpectAndReturn("Foo", new double[5,4]);
// Get our concrete mocked Object
IFoo foo = (IFoo)mock.Object;
answered by scott (32k points)
0 votes
Hi,

Me to :oops:
As you can see from Richard answer there's a problem in SignatureHelper.AddArrayOrPointer(Type) API method. Does the suggested workaround in Richard answer works for you?
answered by ohad (35.4k points)
...