Author: akhaldi
Date: Mon Jun 8 11:05:35 2015
New Revision: 68069
URL:
http://svn.reactos.org/svn/reactos?rev=68069&view=rev
Log:
[OLE32_APITEST] Add test for IInitializeSpy. By Mark Jansen. See ROSTESTS-175 for more
details.
Added:
trunk/rostests/apitests/include/unknownbase.h (with props)
trunk/rostests/apitests/ole32/
trunk/rostests/apitests/ole32/CMakeLists.txt (with props)
trunk/rostests/apitests/ole32/initializespy.cpp (with props)
trunk/rostests/apitests/ole32/testlist.c (with props)
Modified:
trunk/rostests/apitests/CMakeLists.txt
trunk/rostests/apitests/shell32/menu.cpp
trunk/rostests/apitests/shell32/shelltest.h
Modified: trunk/rostests/apitests/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/CMakeLists.txt?r…
==============================================================================
--- trunk/rostests/apitests/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/rostests/apitests/CMakeLists.txt [iso-8859-1] Mon Jun 8 11:05:35 2015
@@ -13,6 +13,7 @@
endif()
add_subdirectory(msvcrt)
add_subdirectory(ntdll)
+add_subdirectory(ole32)
add_subdirectory(powrprof)
add_subdirectory(setupapi)
add_subdirectory(shell32)
Added: trunk/rostests/apitests/include/unknownbase.h
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/include/unknownb…
==============================================================================
--- trunk/rostests/apitests/include/unknownbase.h (added)
+++ trunk/rostests/apitests/include/unknownbase.h [iso-8859-1] Mon Jun 8 11:05:35 2015
@@ -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
Propchange: trunk/rostests/apitests/include/unknownbase.h
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/rostests/apitests/ole32/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ole32/CMakeLists…
==============================================================================
--- trunk/rostests/apitests/ole32/CMakeLists.txt (added)
+++ trunk/rostests/apitests/ole32/CMakeLists.txt [iso-8859-1] Mon Jun 8 11:05:35 2015
@@ -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)
Propchange: trunk/rostests/apitests/ole32/CMakeLists.txt
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/rostests/apitests/ole32/initializespy.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ole32/initialize…
==============================================================================
--- trunk/rostests/apitests/ole32/initializespy.cpp (added)
+++ trunk/rostests/apitests/ole32/initializespy.cpp [iso-8859-1] Mon Jun 8 11:05:35 2015
@@ -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();
+}
Propchange: trunk/rostests/apitests/ole32/initializespy.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/rostests/apitests/ole32/testlist.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ole32/testlist.c…
==============================================================================
--- trunk/rostests/apitests/ole32/testlist.c (added)
+++ trunk/rostests/apitests/ole32/testlist.c [iso-8859-1] Mon Jun 8 11:05:35 2015
@@ -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 }
+};
Propchange: trunk/rostests/apitests/ole32/testlist.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: trunk/rostests/apitests/shell32/menu.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/shell32/menu.cpp…
==============================================================================
--- trunk/rostests/apitests/shell32/menu.cpp [iso-8859-1] (original)
+++ trunk/rostests/apitests/shell32/menu.cpp [iso-8859-1] Mon Jun 8 11:05:35 2015
@@ -34,6 +34,7 @@
public:
CDummyWindow(HWND hwnd)
+ :CUnknownBase( true, 0 )
{
m_hwnd = hwnd;
}
@@ -220,6 +221,7 @@
public:
CMenuCallback(struct _test_info *testResults, int testsCount)
+ :CUnknownBase( true, 0 )
{
m_iTest = 0;
m_iCallback = 0;
Modified: trunk/rostests/apitests/shell32/shelltest.h
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/shell32/shelltes…
==============================================================================
--- trunk/rostests/apitests/shell32/shelltest.h [iso-8859-1] (original)
+++ trunk/rostests/apitests/shell32/shelltest.h [iso-8859-1] Mon Jun 8 11:05:35 2015
@@ -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"