我刚刚将我的所有测试从 Google Test 移植到 Visual Studio 2012 的单元测试框架。(长话短说;Google 的断言更好,但 Microsoft 使用开箱即用的 Dev11 单元测试资源管理器,这使得代码覆盖率变得非常容易......)
我把所有东西都移植好了,除了下面的类,它从 Win32 资源中读取一个以换行符分隔的文本文件,然后允许对该资源进行快速查找:
#include "pch.hpp"
#include "resource.h"
#include <functional>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <windows.h>
#include "Win32Exception.hpp"
#include "Whitelist.hpp"
using Instalog::SystemFacades::Win32Exception;
namespace Instalog {
Whitelist::Whitelist( __int32 whitelistId , std::vector<std::pair<std::wstring, std::wstring>> const& replacements )
{
using namespace std::placeholders;
HRSRC resourceHandle = ::FindResource(0, MAKEINTRESOURCEW(whitelistId), L"WHITELIST");
if (resourceHandle == 0)
{
Win32Exception::ThrowFromLastError();
}
HGLOBAL resourceGlobal = ::LoadResource(0, resourceHandle);
if (resourceGlobal == 0)
{
Win32Exception::ThrowFromLastError();
}
void * resourceData = ::LockResource(resourceGlobal);
if (resourceData == 0)
{
Win32Exception::ThrowFromLastError();
}
wchar_t const* resourceDataCasted = static_cast<wchar_t const*>(resourceData);
DWORD resourceLen = ::SizeofResource(0, resourceHandle);
auto sourceRange = boost::make_iterator_range(resourceDataCasted, resourceDataCasted + (resourceLen / sizeof(wchar_t)));
boost::algorithm::split(innards, sourceRange, std::bind1st(std::equal_to<wchar_t>(), L'\n'));
std::for_each(innards.begin(), innards.end(), std::bind(boost::algorithm::to_lower<std::wstring>, _1, std::locale()));
std::for_each(innards.begin(), innards.end(), [&replacements] (std::wstring &a) {
std::for_each(replacements.begin(), replacements.end(), [&a] (std::pair<std::wstring, std::wstring> const&b) {
if (boost::algorithm::starts_with(a, b.first))
{
a.replace(a.begin(), a.begin() + b.first.size(), b.second);
}
});
});
std::sort(innards.begin(), innards.end());
}
bool Whitelist::IsOnWhitelist( std::wstring checked ) const
{
boost::algorithm::to_lower(checked);
return std::binary_search(innards.begin(), innards.end(), checked);
}
void Whitelist::PrintAll( std::wostream & str ) const
{
std::copy(innards.begin(), innards.end(), std::ostream_iterator<std::wstring, wchar_t>(str, L"\n"));
}
}
不幸的是,Dev11 的测试项目生成的是 DLL,而不是 EXE,就像在 Google Test 的系统下一样。因此,在我能够将资源嵌入 EXE 并传递NULL
给FindResource
的第一个参数之前,现在 Visual Studio 在测试期间将 DLL 加载到其进程中。Visual Studio 里面当然没有我的自定义WHITELIST
资源类型,所以这段代码很糟糕。
有什么办法可以吗
- 告诉这段代码以某种方式查看正确的二进制文件,无论是测试 DLL 还是 EXE,取决于上下文?(目前此代码位于与真实 EXE 和测试 DLL 链接的静态库中)或
- 在完全不使用 Win32 资源基础结构的情况下,将相对较大(几 MB)的文本文件干净地嵌入到 C++ 程序中?
应该注意的是,将资源放入附属 DLL(这可能是一个合理的解决方案)不是一种选择;该项目的一个要求是单个 EXE xcopy 部署。