c++ - 是否有可以轻松记录和重放 API 调用结果的库?

标签 c++ unit-testing

我正在编写各种调用相对复杂的 Win32 API 函数的东西。这是一个例子:

//Encapsulates calling NtQuerySystemInformation buffer management.
WindowsApi::AutoArray NtDll::NtQuerySystemInformation( 
    SystemInformationClass toGet ) const
{
    AutoArray result;
    ULONG allocationSize = 1024;
    ULONG previousSize;
    NTSTATUS errorCheck;
    do 
    {
        previousSize = allocationSize;
        result.Allocate(allocationSize);
        errorCheck = WinQuerySystemInformation(toGet, 
            result.GetAs<void>(), allocationSize, &allocationSize);
        if (allocationSize <= previousSize)
            allocationSize = previousSize * 2;
    } while (errorCheck == 0xC0000004L);
    if (errorCheck != 0)
    {
        THROW_MANUAL_WINDOWS_ERROR(WinRtlNtStatusToDosError(errorCheck));
    }
    return result;
}
//Client of the above.
ProcessSnapshot::ProcessSnapshot()
{
    using Dll::NtDll;
    NtDll ntdll;
    AutoArray systemInfoBuffer = ntdll.NtQuerySystemInformation(
        NtDll::SystemProcessInformation);
    BYTE * currentPtr = systemInfoBuffer.GetAs<BYTE>();
    //Loop through the results, creating Process objects.
    SYSTEM_PROCESSES * asSysInfo;
    do
    {
        // Loop book keeping
        asSysInfo = reinterpret_cast<SYSTEM_PROCESSES *>(currentPtr);
        currentPtr += asSysInfo->NextEntryDelta;

        //Create the process for the current iteration and fill it with data.
        std::auto_ptr<ProcImpl> currentProc(ProcFactory(
            static_cast<unsigned __int32>(asSysInfo->ProcessId), this));
        NormalProcess* nptr = dynamic_cast<NormalProcess*>(currentProc.get());
        if (nptr)
        {
            nptr->SetProcessName(asSysInfo->ProcessName);
        }
        // Populate process threads
        for(ULONG idx = 0; idx < asSysInfo->ThreadCount; ++idx)
        {
            SYSTEM_THREADS& sysThread = asSysInfo->Threads[idx];
            Thread thread(
                currentProc.get(),
                static_cast<unsigned __int32>(sysThread.ClientId.UniqueThread),
                sysThread.StartAddress);
            currentProc->AddThread(thread);
        }
        processes.push_back(currentProc);
    } while(asSysInfo->NextEntryDelta != 0);
}

我的问题是模拟 NtDll::NtQuerySystemInformation 方法——也就是说,返回的数据结构很复杂(好吧,这里它实际上相对简单,但也可能很复杂),然后编写像 API 调用那样构建数据结构的测试所花费的时间是编写使用 API 的代码的 5-6 倍。

我想做的是调用 API,并以某种方式记录它,这样我就可以将记录的值返回给被测代码,而无需实际调用 API。返回的结构不能简单地被 memcpy,因为它们通常包含内部指针(指向同一缓冲区中其他位置的指针)。有问题的库需要检查这些类型的东西,并能够在重放时将指针值恢复到类似的缓冲区。 (即检查每个指针大小的值是否可以解释为缓冲区内的指针,将其更改为偏移量,并记住在重播时将其更改回指针——此处的误报率是可以接受的)

有没有什么东西可以做这样的事情?

最佳答案

手工实现真的那么难吗?

#include <stddef.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>

typedef char BYTE;

//Note: Buffer is MODIFIED after this call (hence why it's not const)! Don't re-use it!
void saveBuffer(FILE* stream, BYTE* buffer, size_t bufferSize)
{
    assert(bufferSize % sizeof(void*) == 0);
    fwrite(&bufferSize, sizeof(bufferSize), 1, stream);
    for (size_t i = 0; i < bufferSize - sizeof(void*) + 1; i += sizeof(void*))
    {
        void** pAsPointer = (void**)&buffer[i];
        if (*pAsPointer >= buffer && *pAsPointer < buffer + bufferSize)
        {
            fwrite(&i, sizeof(i), 1, stream);
            *pAsPointer = pAsPointer;
        }
    }
    void* null = NULL;
    fwrite(&null, sizeof(null), 1, stream); //Null-terminator
    fwrite(buffer, 1, bufferSize, stream);
}


size_t loadBuffer(FILE* stream, BYTE* buffer, size_t bufferCapacity) //Buffer size is in stream
{
    size_t bufferSize;
    fread(&bufferSize, sizeof(bufferSize), 1, stream);
    if (bufferSize >= bufferCapacity)
    {
        memset(buffer, 0, bufferSize);
        for (;;)
        {
            size_t pointerOffset;
            fread(&pointerOffset, sizeof(pointerOffset), 1, stream);
            if (pointerOffset != 0)
            { *(size_t*)&buffer[pointerOffset] = (size_t)buffer + pointerOffset; }
            else { break; }
        }
        for (size_t i = 0; i < bufferSize; i += sizeof(void*))
        {
            if (*(void**)&buffer[i] == NULL)
            { fread(&buffer[i], sizeof(size_t), 1, stream); }
        }
    }
    return bufferSize;
}

(抱歉,我还没有测试它,但它应该非常接近工作。)

唯一的问题是假设所有可能是指针的值实际上都是指针,但除此之外,它看起来很简单。

关于c++ - 是否有可以轻松记录和重放 API 调用结果的库?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4638553/

相关文章:

c++ - 如何在 if 语句中结合否定和声明?

c++ - 当互斥锁/解锁深埋在函数调用中时,我是否需要栅栏或屏障或其他东西?

c++ - 无法为 Typedef 声明好友

c# - 如何使用 FakeItEasy 验证 FindOneAndUpdateAsync 方法针对伪造的 MongoCollection 运行?

c++ - 帮助进行单元测试

python - 是否可以运行所有单元测试?

C++指针简单题

c++ - 在类内创建回调映射时出错

带有用户输入的 Python 3 单元测试

javascript - 异步等待单元测试问题