I'm working on writing various things that call relatively complicated Win32 API functions. Here's an example:
//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);
}
My problem is in mocking out the NtDll::NtQuerySystemInformation method -- namely, that the data structure returned is complicated (Well, here it's actually relatively simple but it can be complicated), and writing a test which builds the data structure like the API call does can take 5-6 times as long as writing the code that uses the API.
What I'd like to do is take a call to the API, and record it somehow, so that I can return that recorded value to the code under test without actually calling the API. The returned structures cannot simply be memcpy'd, because they often contain inner pointers (pointers to other locations in the same buffer). The library in question would need to check for these kinds of things, and be able to restore pointer values to a similar buffer upon replay. (i.e. check each pointer sized value if it could be interpreted as a pointer within the buffer, change that to an offset, and remember to change it back to a pointer on replay -- a false positive rate here is acceptable)
Is there anything out there that does anything like this?