views:

194

answers:

3

I am using a native library which returns an IntPtr to a memory location, which contains the value of an attribute. I know what the type of the attribute is and I have a method for marshalling a value (taking the IntPtr and the type of the attribute) from the memory pointed at by the pointer. This method either calls Marshal.ReadInt32, or reads a series of bytes and converts them to a double, or reads a string with Marshal.PtrToStringUni etc etc. I would like to write some unit tests for this method but am not sure how I go about creating the IntPtr to pass to the method. I'm using NUnit and cannot use a mocking framework.

A: 

If I understood correctly, you want to unit-test your logic of deserializing, given an IntPtr.
If that is the case, all you have to do is have copies of the different combinations of serialized output to test each unique path. For each test, obtain the IntPtr to a possible serialized entity, call your method and verify expected results.

Something like obtaining pointers to an area in memory. Hold the serialized output in a string and obtain an Intptr from it. GCHandle looks like something you need here. (never tried this though) http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.gchandle.tointptr.aspx

Gishu
+1  A: 

Check out the various overloads for Marshal.Copy() which will let you initialise values using your IntPtr.

Ed Guiness
Thanks, that looks like what I need. I'll be able test this out later on.
A: 

My reading of your question makes me think that what you're asking is:

How do I create functions that mock the native call I'm making that returns an IntPtr to a double or unicode string so I can pass that IntPtr to the functions I want to test?

Something like this might help:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace ConsoleApplication1
{
 class Program
 {
  private static double myDouble = 3.14;
  private static unsafe void TestPtrToDouble()
  {
   fixed(double* pDouble = &myDouble)
   {
    IntPtr intp = new IntPtr(pDouble);
    double[] copy = new double[1];
    Marshal.Copy(intp, copy, 0, 1);

    Debug.Assert(copy[0] == myDouble);
   }           
  }

  private static char[] myString = { 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'm', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g' };

  private static unsafe void TestPtrToUnicodeString()
  {
   fixed (char* pChar = &myString[0])
   {
    IntPtr intp = new IntPtr(pChar);
    string copy = Marshal.PtrToStringUni(intp);

    Debug.Assert(copy == "This is my string");
   }
  }

  static void Main(string[] args)
  {
   TestPtrToUnicodeString();
   TestPtrToDouble();
  }
 }
}

Something to be very mindful of is that you won't be able to return the mock IntPtr's created from a function. Ie, you can't create a mocked version of your P/Invoke calls and expect things to work.

The .Net runtime moves managed objects about in memory (part of the garbage collection process). The fixed statement stops this from happening for the member/object you take the address of. But only for the life of the block. The block ends if you return from a function so the pointer value may be invalid after a return. Ie, your IntPtr may be referencing memory that no longer contains the data you want to marshal.

Check out the MSDN documentation on unsafe code and the fixed statement. But what I've got here should send you in the right direction for constructing an NUnit test for your marshaling code.

Also note that this code requires the /unsafe compiler option to compile. If you need your assembly to run in an environment which doesn't support unsafe assemblies you'll have to have the test code in another assembly. But since you're already using P/Invoke I imagine that isn't the case.

orj