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
Welcome to Typemock Community! Here you can ask and receive answers from other community members. If you liked or disliked an answer or thread: react with an up- or downvote.
0 votes
the following test fail with:

Test method KryonTests.UnderTestTest.MockGetWindowRect_AAA threw exception: System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index.


The test code:

[TestMethod()]
        p[TestMethod()]
public void MockGetWindowRect_AAA()
{
    Win32API.RECT rect;
    IntPtr ptr = new IntPtr();
    Isolate.WhenCalled(() => Win32API.GetWindowRect(ptr,out rect)).WillReturn(false);

    bool actual = Win32API.GetWindowRect(ptr, out rect);
    Assert.IsFalse(actual);
}


production code:

 public static class Win32API
    {public static class Win32API
{
    [DllImport("user32.dll")]
    public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public struct RECT
    {
        public int left { get; set; }
        public int top { get; set; }
        public int right { get; set; }
        public int bottom { get; set; }
        public int Width() { return right - left; }
        public int Height() { return bottom - top; }
    }
}


:!: I also tried the same in natural and still got an exception

any thoughts on the matter?
asked by error (6.6k points)

3 Answers

0 votes
Unfortunately currently P-Invoke interoperability is not supported by Isolator.

I suggest you wrap the calls around the p-invoke with a managed method and fake it instead.

When we add this feature to Isolator I will let you know.
answered by dhelper (11.9k points)
0 votes
Just curious if anything has changed with Isolator supporting p/invoke.

I've been following the Microsoft naming guidelines for unmanaged code methods found http://msdn.microsoft.com/en-us/library/btadwd4w(vs.80).aspx

The unit tests I have work fine, I'm just worried that once I start controlling the Windows dialer I'm going to run into a huge headache for performance of the tests along with needing the required hardware to be able to effectively test all the different scenarios.

Here's the class that handles wrapping all of the interop calls that I'm testing:
http://dotras.codeplex.com/SourceContro ... 273#241556

Here are the methods I'm trying to fake:
http://dotras.codeplex.com/SourceContro ... 273#241559
http://dotras.codeplex.com/SourceContro ... 273#427986

If this isn't supported in Isolator yet, perhaps this will demonstrate how p/invoke is being done in real world scenarios, rather than arbitrary snippets of code.

I was planning on faking out the p/invoke calls so that when it returns, it simply returns data I know won't change.

Here's a perfect example of what I'm talking about:

[DllImport("rasapi32.dll", CharSet = CharSet.Unicode)]
public static extern int RasEnumConnections(
    [In, Out] IntPtr lpRasConn,
    ref IntPtr lpCb,
    ref IntPtr lpcConnections);

[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static ReadOnlyCollection<RasConnection> GetActiveConnections()
{
    ReadOnlyCollection<RasConnection> retval = null;

    int size = Marshal.SizeOf(typeof(NativeMethods.RASCONN));
    IntPtr lpCb = new IntPtr(size);
    IntPtr lpcConnections = IntPtr.Zero;

    bool retry = false;

    do
    {
        NativeMethods.RASCONN conn = new NativeMethods.RASCONN();
        conn.size = size;

        IntPtr pConnections = IntPtr.Zero;
        try
        {
            pConnections = Marshal.AllocHGlobal(lpCb);
            Marshal.StructureToPtr(conn, pConnections, true);

            int ret = SafeNativeMethods.RasEnumConnections(pConnections, ref lpCb, ref lpcConnections);
            if (ret == NativeMethods.ERROR_BUFFER_TOO_SMALL)
            {
                retry = true;
            }
            else if (ret == NativeMethods.SUCCESS)
            {
                retry = false;

                NativeMethods.RASCONN[] connections = RasHelper.CreateArrayOfType<NativeMethods.RASCONN>(pConnections, size, lpcConnections.ToInt32());
                RasConnection[] tempArray = null;

                if (connections == null || connections.Length == 0)
                {
                    tempArray = new RasConnection[0];
                }
                else
                {
                    tempArray = new RasConnection[connections.Length];

                    for (int index = 0; index < connections.Length; index++)
                    {
                        NativeMethods.RASCONN current = connections[index];

                        RasConnection item = new RasConnection();

                        item.Handle = new RasHandle(current.handle);
                        item.EntryName = current.entryName;
                        item.Device = new RasDevice(current.deviceName, current.deviceType);
                        item.PhoneBook = current.phoneBook;
                        item.SubEntryId = current.subEntryId;
                        item.EntryId = current.entryId;
#if (WINXP || WINXPSP2 || WIN2K8)
                        item.ConnectionOptions = current.connectionOptions;
                        item.SessionId = current.sessionId;
#endif
#if (WIN2K8)
                        item.CorrelationId = current.correlationId;
#endif

                        tempArray[index] = item;
                    }
                }

                retval = new ReadOnlyCollection<RasConnection>(tempArray);
            }
            else
            {
                ThrowHelper.ThrowRasException(ret);
            }
        }
        finally
        {
            if (pConnections != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(pConnections);
            }
        }
    } 
    while (retry);

    return retval;
}
answered by jeff_winn (140 points)
0 votes
Hi Jeff

I looked at DotRas and Indeed it give us a good real world example of P/invoke usage.
Unfortunately faking p/invoke methods directly is not supported yet by the Isolator.
The only way to do it is wrap the calls in managed code.

So if you use this wrapper:
public static int RasEnumConnectionsWrap(IntPtr lpRasConn, ref IntPtr lpCb,ref IntPtr lpcConnections)
{
    int res = RasEnumConnections(lpRasConn, ref lpCb, ref lpcConnections);
    return res;
}

and than fake the call like this:
Isolate.WhenCalled(() => SafeNativeMethods.RasEnumConnectionsWrap(pConnections, ref lpCb, ref pConnections)).WillReturn(NativeMethods.SUCCESS);
answered by ohad (35.5k points)
...