Могу ли я создать модульный тест для метода, который маршаллизирует значение из IntPtr? - PullRequest
0 голосов
/ 22 октября 2008

Я использую собственную библиотеку, которая возвращает IntPtr в ячейку памяти, которая содержит значение атрибута. Я знаю, что тип атрибута, и у меня есть метод для маршалинга значения (принимая IntPtr и тип атрибута) из памяти, на которую указывает указатель. Этот метод либо вызывает Marshal.ReadInt32, либо читает серию байтов и преобразует их в двойные, либо читает строку с помощью Marshal.PtrToStringUni и т. Д. И т. Д. Я хотел бы написать несколько модульных тестов для этого метода, но не уверен, как мне поступить о создании IntPtr для передачи в метод. Я использую NUnit и не могу использовать фальшивый фреймворк.

Ответы [ 3 ]

1 голос
/ 22 октября 2008

Проверьте различные перегрузки для Marshal.Copy () , которые позволят вам инициализировать значения с помощью вашего IntPtr.

0 голосов
/ 22 октября 2008

Мое чтение вашего вопроса заставляет меня думать, что вы спрашиваете:

Как мне создать функции, которые имитируют собственный вызов, который я делаю, который возвращает IntPtr в строку типа double или unicode, чтобы я мог передать этот IntPtr функциям, которые я хочу протестировать?

Как-то так может помочь:

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();
        }
    }
}

Следует помнить, что вы не сможете вернуть фиктивный IntPtr, созданный из функции. Т.е. вы не можете создать поддельную версию ваших вызовов P / Invoke и ожидать, что все будет работать.

Среда выполнения .Net перемещает управляемые объекты в памяти (часть процесса сбора мусора). Оператор fixed не позволяет этому произойти для члена / объекта, адрес которого вы берете. Но только на всю жизнь блока. Блок заканчивается, если вы возвращаетесь из функции, поэтому значение указателя может быть недействительным после возврата. Т.е. ваш IntPtr может ссылаться на память, которая больше не содержит данных, которые вы хотите упорядочить.

Ознакомьтесь с документацией MSDN по небезопасному коду и фиксированному оператору . Но то, что у меня есть, должно направить вас в правильном направлении для создания теста NUnit для вашего кода маршалинга.

Также обратите внимание, что этот код требует компиляции с параметром / unsafe. Если вам нужно, чтобы ваша сборка работала в среде, которая не поддерживает небезопасные сборки, вам понадобится тестовый код в другой сборке. Но так как вы уже используете P / Invoke, я думаю, что это не так.

0 голосов
/ 22 октября 2008

Если я правильно понял, вы хотите протестировать свою логику десериализации, используя IntPtr.
Если это так, все, что вам нужно сделать, это иметь копии различных комбинаций сериализованного вывода для проверки каждого уникального пути. Для каждого теста получите IntPtr для возможного сериализованного объекта, вызовите свой метод и проверьте ожидаемые результаты.

Что-то вроде получения указателей на область памяти. Удерживайте сериализованный вывод в строке и получите из нее Intptr. GCHandle выглядит как то, что вам нужно здесь. (никогда не пробовал это все же) http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.gchandle.tointptr.aspx

...