Is this an idiomatic way to pass mocks into objects?
- by Billy ONeal
I'm a bit confused about passing in this mock class into an implementation class. It feels wrong to have all this explicitly managed memory flying around. I'd just pass the class by value but that runs into the slicing problem.
Am I missing something here?
Implementation:
namespace detail
{
struct FileApi
{
virtual HANDLE CreateFileW(
__in LPCWSTR lpFileName,
__in DWORD dwDesiredAccess,
__in DWORD dwShareMode,
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__in DWORD dwCreationDisposition,
__in DWORD dwFlagsAndAttributes,
__in_opt HANDLE hTemplateFile
)
{
return ::CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}
virtual void CloseHandle(HANDLE handleToClose)
{
::CloseHandle(handleToClose);
}
};
}
class File : boost::noncopyable
{
HANDLE hWin32;
boost::scoped_ptr<detail::FileApi> fileApi;
public:
File(
__in LPCWSTR lpFileName,
__in DWORD dwDesiredAccess,
__in DWORD dwShareMode,
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__in DWORD dwCreationDisposition,
__in DWORD dwFlagsAndAttributes,
__in_opt HANDLE hTemplateFile,
__in detail::FileApi * method = new detail::FileApi()
)
{
fileApi.reset(method);
hWin32 = fileApi->CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}
}; namespace detail
{
struct FileApi
{
virtual HANDLE CreateFileW(
__in LPCWSTR lpFileName,
__in DWORD dwDesiredAccess,
__in DWORD dwShareMode,
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__in DWORD dwCreationDisposition,
__in DWORD dwFlagsAndAttributes,
__in_opt HANDLE hTemplateFile
)
{
return ::CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}
virtual void CloseHandle(HANDLE handleToClose)
{
::CloseHandle(handleToClose);
}
};
}
class File : boost::noncopyable
{
HANDLE hWin32;
boost::scoped_ptr<detail::FileApi> fileApi;
public:
File(
__in LPCWSTR lpFileName,
__in DWORD dwDesiredAccess,
__in DWORD dwShareMode,
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__in DWORD dwCreationDisposition,
__in DWORD dwFlagsAndAttributes,
__in_opt HANDLE hTemplateFile,
__in detail::FileApi * method = new detail::FileApi()
)
{
fileApi.reset(method);
hWin32 = fileApi->CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}
~File()
{
fileApi->CloseHandle(hWin32);
}
};
Tests:
namespace detail {
struct MockFileApi : public FileApi
{
MOCK_METHOD7(CreateFileW, HANDLE(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE));
MOCK_METHOD1(CloseHandle, void(HANDLE));
};
}
using namespace detail;
using namespace testing;
TEST(Test_File, OpenPassesArguments)
{
MockFileApi * api = new MockFileApi;
EXPECT_CALL(*api, CreateFileW(Eq(L"BozoFile"), Eq(56), Eq(72), Eq(reinterpret_cast<LPSECURITY_ATTRIBUTES>(67)), Eq(98), Eq(102), Eq(reinterpret_cast<HANDLE>(98))))
.Times(1).WillOnce(Return(reinterpret_cast<HANDLE>(42)));
File test(L"BozoFile", 56, 72, reinterpret_cast<LPSECURITY_ATTRIBUTES>(67), 98, 102, reinterpret_cast<HANDLE>(98), api);
}