mirror of
https://github.com/reactos/reactos.git
synced 2025-06-01 07:28:19 +00:00
[OLE32_APITEST] Add test for IInitializeSpy. By Mark Jansen. See ROSTESTS-175 for more details.
svn path=/trunk/; revision=68069
This commit is contained in:
parent
820994b29f
commit
66b9b5427f
7 changed files with 392 additions and 35 deletions
|
@ -13,6 +13,7 @@ if(NOT ARCH STREQUAL "amd64")
|
|||
endif()
|
||||
add_subdirectory(msvcrt)
|
||||
add_subdirectory(ntdll)
|
||||
add_subdirectory(ole32)
|
||||
add_subdirectory(powrprof)
|
||||
add_subdirectory(setupapi)
|
||||
add_subdirectory(shell32)
|
||||
|
|
47
rostests/apitests/include/unknownbase.h
Normal file
47
rostests/apitests/include/unknownbase.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#ifndef APITESTS_UNKNOWNBASE_H
|
||||
#define APITESTS_UNKNOWNBASE_H
|
||||
|
||||
template<typename Interface>
|
||||
class CUnknownBase : public Interface
|
||||
{
|
||||
LONG m_lRef;
|
||||
bool m_AutoDelete;
|
||||
protected:
|
||||
virtual const QITAB* GetQITab() = 0;
|
||||
public:
|
||||
|
||||
CUnknownBase(bool autoDelete, LONG initialRef)
|
||||
: m_lRef(initialRef),
|
||||
m_AutoDelete(autoDelete)
|
||||
{
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef ()
|
||||
{
|
||||
return InterlockedIncrement( &m_lRef );
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE Release()
|
||||
{
|
||||
long newref = InterlockedDecrement( &m_lRef );
|
||||
if (m_AutoDelete && newref<=0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
return newref;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv)
|
||||
{
|
||||
return QISearch(this, GetQITab(), riid, ppv);
|
||||
}
|
||||
|
||||
virtual ~CUnknownBase() {}
|
||||
|
||||
LONG GetRef() const
|
||||
{
|
||||
return m_lRef;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // APITESTS_UNKNOWNBASE_H
|
7
rostests/apitests/ole32/CMakeLists.txt
Normal file
7
rostests/apitests/ole32/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
set_cpp(WITH_RUNTIME)
|
||||
add_executable(ole32_apitest initializespy.cpp testlist.c)
|
||||
target_link_libraries(ole32_apitest wine uuid)
|
||||
set_module_type(ole32_apitest win32cui)
|
||||
add_importlibs(ole32_apitest user32 gdi32 shell32 ole32 shlwapi msvcrt kernel32)
|
||||
add_cd_file(TARGET ole32_apitest DESTINATION reactos/bin FOR all)
|
321
rostests/apitests/ole32/initializespy.cpp
Normal file
321
rostests/apitests/ole32/initializespy.cpp
Normal file
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* PROJECT: ReactOS api tests
|
||||
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
||||
* PURPOSE: Tests for IInitializeSpy
|
||||
* PROGRAMMERS: Mark Jansen
|
||||
*/
|
||||
|
||||
#define WIN32_NO_STATUS
|
||||
#define _INC_WINDOWS
|
||||
#define COM_NO_WINDOWS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <wine/test.h>
|
||||
|
||||
#include <winuser.h>
|
||||
#include <winreg.h>
|
||||
|
||||
#include <shlwapi.h>
|
||||
#include <unknownbase.h>
|
||||
|
||||
#define test_S_OK(hres, message) ok((hres) == S_OK, "%s (0x%lx instead of S_OK)\n", (message), (hres))
|
||||
#define test_HRES(hres, hresExpected, message) ok((hres) == (hresExpected), "%s (0x%lx instead of 0x%lx)\n", (message), (hres), (hresExpected))
|
||||
#define test_ref(spy, expectedRef) ok((spy)->GetRef() == (expectedRef), "unexpected refcount, %ld instead of %d\n", (spy)->GetRef(), (expectedRef))
|
||||
|
||||
|
||||
typedef HRESULT (WINAPI *pCoRegisterInitializeSpy_t)(_In_ LPINITIALIZESPY pSpy, _Out_ ULARGE_INTEGER *puliCookie);
|
||||
typedef HRESULT (WINAPI *pCoRevokeInitializeSpy_t)(_In_ ULARGE_INTEGER uliCookie);
|
||||
pCoRegisterInitializeSpy_t pCoRegisterInitializeSpy;
|
||||
pCoRevokeInitializeSpy_t pCoRevokeInitializeSpy;
|
||||
|
||||
|
||||
const DWORD INVALID_VALUE = 0xdeadbeef;
|
||||
|
||||
|
||||
class CTestSpy : public CUnknownBase<IInitializeSpy>
|
||||
{
|
||||
public:
|
||||
HRESULT hr;
|
||||
ULARGE_INTEGER Cookie;
|
||||
|
||||
// expected values to check against
|
||||
HRESULT m_hrCoInit;
|
||||
DWORD m_CoInit;
|
||||
DWORD m_CurAptRefs;
|
||||
|
||||
// keeping count of the times called
|
||||
LONG m_PreInitCalled;
|
||||
LONG m_PostInitCalled;
|
||||
LONG m_PreUninitCalled;
|
||||
LONG m_PostUninitCalled;
|
||||
|
||||
// fake out some
|
||||
bool m_FailQueryInterface;
|
||||
bool m_AlwaysReturnOK;
|
||||
|
||||
CTestSpy()
|
||||
: CUnknownBase( false, 0 ),
|
||||
hr(0),
|
||||
m_hrCoInit(0),
|
||||
m_CoInit(0),
|
||||
m_CurAptRefs(0),
|
||||
m_FailQueryInterface(false),
|
||||
m_AlwaysReturnOK(false)
|
||||
{
|
||||
Cookie.HighPart = Cookie.LowPart = INVALID_VALUE;
|
||||
Clear();
|
||||
}
|
||||
|
||||
~CTestSpy()
|
||||
{
|
||||
// always try to revoke if we succeeded to register.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pCoRevokeInitializeSpy(Cookie);
|
||||
test_S_OK(hr, "CoRevokeInitializeSpy");
|
||||
}
|
||||
// we should be done.
|
||||
ok(GetRef() == 0, "Expected m_lRef to be 0, was: %ld\n", GetRef());
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv)
|
||||
{
|
||||
if (m_FailQueryInterface)
|
||||
{
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
return CUnknownBase::QueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
const QITAB* GetQITab()
|
||||
{
|
||||
static const QITAB tab[] = { { &IID_IInitializeSpy, OFFSETOFCLASS(IInitializeSpy, CTestSpy) }, { 0 } };
|
||||
return tab;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE PreInitialize(DWORD dwCoInit, DWORD dwCurThreadAptRefs)
|
||||
{
|
||||
InterlockedIncrement(&m_PreInitCalled);
|
||||
ok(m_CoInit == dwCoInit, "Unexpected dwCoInit: got %lx, expected %lx\n", dwCoInit, m_CoInit);
|
||||
DWORD expectApt = m_hrCoInit == RPC_E_CHANGED_MODE ? m_CurAptRefs : m_CurAptRefs -1;
|
||||
ok(expectApt == dwCurThreadAptRefs, "Unexpected dwCurThreadAptRefs: got %lx, expected %lx\n", dwCurThreadAptRefs, expectApt);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE PostInitialize(HRESULT hrCoInit, DWORD dwCoInit, DWORD dwNewThreadAptRefs)
|
||||
{
|
||||
InterlockedIncrement(&m_PostInitCalled);
|
||||
ok(m_PreInitCalled == m_PostInitCalled, "Expected balanced pre/post: %ld / %ld\n", m_PreInitCalled, m_PostInitCalled);
|
||||
test_HRES(hrCoInit, m_hrCoInit, "Unexpected hrCoInit in PostInitialize");
|
||||
ok(m_CoInit == dwCoInit, "Unexpected dwCoInit: got %lx, expected %lx\n", dwCoInit, m_CoInit);
|
||||
ok(m_CurAptRefs == dwNewThreadAptRefs, "Unexpected dwNewThreadAptRefs: got %lx, expected %lx\n", dwNewThreadAptRefs, m_CurAptRefs);
|
||||
if (m_AlwaysReturnOK)
|
||||
return S_OK;
|
||||
return hrCoInit;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE PreUninitialize(DWORD dwCurThreadAptRefs)
|
||||
{
|
||||
InterlockedIncrement(&m_PreUninitCalled);
|
||||
ok(m_CurAptRefs == dwCurThreadAptRefs, "Unexpected dwCurThreadAptRefs: got %lx, expected %lx\n", dwCurThreadAptRefs, m_CurAptRefs);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE PostUninitialize(DWORD dwNewThreadAptRefs)
|
||||
{
|
||||
InterlockedIncrement(&m_PostUninitCalled);
|
||||
ok(m_PreUninitCalled == m_PostUninitCalled, "Expected balanced pre/post: %ld / %ld\n", m_PreUninitCalled, m_PostUninitCalled);
|
||||
DWORD apt = m_CurAptRefs ? (m_CurAptRefs-1) : 0;
|
||||
ok(apt == dwNewThreadAptRefs, "Unexpected dwNewThreadAptRefs: got %lx, expected %lx\n", dwNewThreadAptRefs, apt);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
m_PreInitCalled = 0;
|
||||
m_PostInitCalled = 0;
|
||||
m_PreUninitCalled = 0;
|
||||
m_PostUninitCalled = 0;
|
||||
}
|
||||
|
||||
void Expect(HRESULT hrCoInit, DWORD CoInit, DWORD CurAptRefs)
|
||||
{
|
||||
m_hrCoInit = hrCoInit;
|
||||
m_CoInit = CoInit;
|
||||
m_CurAptRefs = CurAptRefs;
|
||||
}
|
||||
|
||||
void Check(LONG PreInit, LONG PostInit, LONG PreUninit, LONG PostUninit)
|
||||
{
|
||||
ok(m_PreInitCalled == PreInit, "Expected PreInit to be %ld, was: %ld\n", PreInit, m_PreInitCalled);
|
||||
ok(m_PostInitCalled == PostInit, "Expected PostInit to be %ld, was: %ld\n", PostInit, m_PostInitCalled);
|
||||
ok(m_PreUninitCalled == PreUninit, "Expected PreUninit to be %ld, was: %ld\n", PreUninit, m_PreUninitCalled);
|
||||
ok(m_PostUninitCalled == PostUninit, "Expected PostUninit to be %ld, was: %ld\n", PostUninit, m_PostUninitCalled);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void test_IInitializeSpy_register2()
|
||||
{
|
||||
CTestSpy spy, spy2;
|
||||
|
||||
// first we register 2 spies
|
||||
spy.hr = pCoRegisterInitializeSpy(&spy, &spy.Cookie);
|
||||
test_S_OK(spy.hr, "CoRegisterInitializeSpy");
|
||||
test_ref(&spy, 1);
|
||||
|
||||
spy2.hr = pCoRegisterInitializeSpy(&spy2, &spy2.Cookie);
|
||||
test_S_OK(spy2.hr, "CoRegisterInitializeSpy");
|
||||
test_ref(&spy, 1);
|
||||
|
||||
// tell them what we expect
|
||||
spy.Expect(S_OK, COINIT_APARTMENTTHREADED, 1);
|
||||
spy2.Expect(S_OK, COINIT_APARTMENTTHREADED, 1);
|
||||
|
||||
// Call CoInitializeEx and validate the results
|
||||
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
test_S_OK(hr, "CoInitializeEx");
|
||||
spy.Check(1, 1, 0, 0);
|
||||
spy2.Check(1, 1, 0, 0);
|
||||
|
||||
// Calling CoInit twice with the same apartment makes it return S_FALSE but still increment count
|
||||
spy.Expect(S_FALSE, COINIT_APARTMENTTHREADED, 2);
|
||||
spy2.Expect(S_FALSE, COINIT_APARTMENTTHREADED, 2);
|
||||
|
||||
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
test_HRES(hr, S_FALSE, "CoInitializeEx");
|
||||
spy.Check(2, 2, 0, 0);
|
||||
spy2.Check(2, 2, 0, 0);
|
||||
|
||||
/* the order we registered the spies in is important here.
|
||||
we have the second one to forcibly return S_OK, which makes the first spy see
|
||||
S_OK instead of S_FALSE.. */
|
||||
spy.Expect(S_OK, COINIT_APARTMENTTHREADED, 3);
|
||||
spy2.m_AlwaysReturnOK = true;
|
||||
spy2.Expect(S_FALSE, COINIT_APARTMENTTHREADED, 3);
|
||||
|
||||
// and the S_OK also influences the returned value from CoInit.
|
||||
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
test_S_OK(hr, "CoInitializeEx");
|
||||
spy.Check(3, 3, 0, 0);
|
||||
spy2.Check(3, 3, 0, 0);
|
||||
|
||||
CoUninitialize();
|
||||
spy.Check(3, 3, 1, 1);
|
||||
spy2.Check(3, 3, 1, 1);
|
||||
|
||||
spy.m_CurAptRefs = spy2.m_CurAptRefs = 2;
|
||||
|
||||
CoUninitialize();
|
||||
spy.Check(3, 3, 2, 2);
|
||||
spy2.Check(3, 3, 2, 2);
|
||||
|
||||
spy.m_CurAptRefs = spy2.m_CurAptRefs = 1;
|
||||
|
||||
CoUninitialize();
|
||||
spy.Check(3, 3, 3, 3);
|
||||
spy2.Check(3, 3, 3, 3);
|
||||
|
||||
spy.m_CurAptRefs = spy2.m_CurAptRefs = 0;
|
||||
|
||||
CoUninitialize();
|
||||
spy.Check(3, 3, 4, 4);
|
||||
spy2.Check(3, 3, 4, 4);
|
||||
}
|
||||
|
||||
void test_IInitializeSpy_switch_apt()
|
||||
{
|
||||
CTestSpy spy;
|
||||
|
||||
spy.hr = pCoRegisterInitializeSpy(&spy, &spy.Cookie);
|
||||
test_S_OK(spy.hr, "CoRegisterInitializeSpy");
|
||||
test_ref(&spy, 1);
|
||||
|
||||
spy.Expect(S_OK, COINIT_APARTMENTTHREADED, 1);
|
||||
|
||||
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
test_S_OK(hr, "CoInitializeEx");
|
||||
spy.Check(1, 1, 0, 0);
|
||||
|
||||
spy.Expect(RPC_E_CHANGED_MODE, COINIT_MULTITHREADED, 1);
|
||||
|
||||
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
test_HRES(hr, RPC_E_CHANGED_MODE, "CoInitializeEx");
|
||||
spy.Check(2, 2, 0, 0);
|
||||
|
||||
|
||||
CoUninitialize();
|
||||
spy.Check(2, 2, 1, 1);
|
||||
|
||||
spy.m_CurAptRefs = 0;
|
||||
|
||||
CoUninitialize();
|
||||
spy.Check(2, 2, 2, 2);
|
||||
|
||||
CoUninitialize();
|
||||
spy.Check(2, 2, 3, 3);
|
||||
}
|
||||
|
||||
void test_IInitializeSpy_fail()
|
||||
{
|
||||
CTestSpy spy;
|
||||
|
||||
spy.m_FailQueryInterface = true;
|
||||
|
||||
spy.hr = pCoRegisterInitializeSpy(&spy, &spy.Cookie);
|
||||
test_HRES(spy.hr, E_NOINTERFACE, "Unexpected hr while registering invalid interface");
|
||||
test_ref(&spy, 0);
|
||||
ok(spy.Cookie.HighPart == 0xffffffff, "Unexpected Cookie.HighPart, expected 0xffffffff got: 0x%08lx\n", spy.Cookie.HighPart);
|
||||
ok(spy.Cookie.LowPart == 0xffffffff, "Unexpected Cookie.HighPart, expected 0xffffffff got: 0x%08lx\n", spy.Cookie.LowPart);
|
||||
|
||||
spy.Cookie.HighPart = spy.Cookie.LowPart = 0xffffffff;
|
||||
HRESULT hr = pCoRevokeInitializeSpy(spy.Cookie);
|
||||
test_HRES(hr, E_INVALIDARG, "Unexpected hr while unregistering invalid interface");
|
||||
test_ref(&spy, 0);
|
||||
|
||||
spy.Cookie.HighPart = spy.Cookie.LowPart = 0;
|
||||
hr = pCoRevokeInitializeSpy(spy.Cookie);
|
||||
test_HRES(hr, E_INVALIDARG, "Unexpected hr while unregistering invalid interface");
|
||||
test_ref(&spy, 0);
|
||||
|
||||
/* we should not crash here, just return E_NOINTERFACE
|
||||
do note the Cookie is not even being touched at all, compared to calling this with an interface
|
||||
that does not respond to IID_IInitializeSpy */
|
||||
spy.Cookie.HighPart = spy.Cookie.LowPart = INVALID_VALUE;
|
||||
hr = pCoRegisterInitializeSpy(NULL, &spy.Cookie);
|
||||
test_HRES(spy.hr, E_NOINTERFACE, "Unexpected hr while registering NULL interface");
|
||||
ok(spy.Cookie.HighPart == INVALID_VALUE, "Unexpected Cookie.HighPart, expected 0xdeadbeef got: %lx\n", spy.Cookie.HighPart);
|
||||
ok(spy.Cookie.LowPart == INVALID_VALUE, "Unexpected Cookie.HighPart, expected 0xdeadbeef got: %lx\n", spy.Cookie.LowPart);
|
||||
}
|
||||
|
||||
void test_IInitializeSpy_twice()
|
||||
{
|
||||
CTestSpy spy;
|
||||
|
||||
spy.hr = pCoRegisterInitializeSpy(&spy, &spy.Cookie);
|
||||
test_S_OK(spy.hr, "CoRegisterInitializeSpy");
|
||||
test_ref(&spy, 1);
|
||||
|
||||
ULARGE_INTEGER Cookie = { { INVALID_VALUE, INVALID_VALUE } };
|
||||
HRESULT hr = pCoRegisterInitializeSpy(&spy, &Cookie);
|
||||
test_S_OK(hr, "CoRegisterInitializeSpy");
|
||||
test_ref(&spy, 2);
|
||||
|
||||
hr = pCoRevokeInitializeSpy(Cookie);
|
||||
test_S_OK(hr, "CoRevokeInitializeSpy");
|
||||
test_ref(&spy, 1);
|
||||
}
|
||||
|
||||
|
||||
START_TEST(initializespy)
|
||||
{
|
||||
HMODULE ole32 = LoadLibraryA("ole32.dll");
|
||||
pCoRegisterInitializeSpy = (pCoRegisterInitializeSpy_t)GetProcAddress(ole32, "CoRegisterInitializeSpy");
|
||||
pCoRevokeInitializeSpy = (pCoRevokeInitializeSpy_t)GetProcAddress(ole32, "CoRevokeInitializeSpy");
|
||||
|
||||
test_IInitializeSpy_register2();
|
||||
test_IInitializeSpy_switch_apt();
|
||||
test_IInitializeSpy_fail();
|
||||
test_IInitializeSpy_twice();
|
||||
}
|
13
rostests/apitests/ole32/testlist.c
Normal file
13
rostests/apitests/ole32/testlist.c
Normal file
|
@ -0,0 +1,13 @@
|
|||
#define __ROS_LONG64__
|
||||
|
||||
#define STANDALONE
|
||||
#include <wine/test.h>
|
||||
|
||||
extern void func_initializespy(void);
|
||||
|
||||
const struct test winetest_testlist[] =
|
||||
{
|
||||
{ "initializespy", func_initializespy },
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
|
@ -34,6 +34,7 @@ protected:
|
|||
|
||||
public:
|
||||
CDummyWindow(HWND hwnd)
|
||||
:CUnknownBase( true, 0 )
|
||||
{
|
||||
m_hwnd = hwnd;
|
||||
}
|
||||
|
@ -220,6 +221,7 @@ protected:
|
|||
|
||||
public:
|
||||
CMenuCallback(struct _test_info *testResults, int testsCount)
|
||||
:CUnknownBase( true, 0 )
|
||||
{
|
||||
m_iTest = 0;
|
||||
m_iCallback = 0;
|
||||
|
|
|
@ -27,38 +27,4 @@
|
|||
|
||||
DEFINE_GUID(CLSID_MenuBandSite, 0xE13EF4E4, 0xD2F2, 0x11D0, 0x98, 0x16, 0x00, 0xC0, 0x4F, 0xD9, 0x19, 0x72);
|
||||
|
||||
template<typename Interface>
|
||||
class CUnknownBase : public Interface
|
||||
{
|
||||
LONG m_lRef;
|
||||
protected:
|
||||
virtual const QITAB* GetQITab() = 0;
|
||||
public:
|
||||
|
||||
CUnknownBase()
|
||||
{
|
||||
m_lRef = 0;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef ()
|
||||
{
|
||||
return InterlockedIncrement( &m_lRef );
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE Release()
|
||||
{
|
||||
long newref = InterlockedDecrement( &m_lRef );
|
||||
if (newref<=0) delete this;
|
||||
return newref;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv)
|
||||
{
|
||||
HRESULT hresult = QISearch(this, GetQITab(), riid, ppv);
|
||||
if(SUCCEEDED(hresult)) AddRef();
|
||||
return hresult;
|
||||
}
|
||||
|
||||
virtual ~CUnknownBase() {}
|
||||
};
|
||||
|
||||
#include "unknownbase.h"
|
||||
|
|
Loading…
Reference in a new issue