Coder Social home page Coder Social logo

smalti / gmock-win32 Goto Github PK

View Code? Open in Web Editor NEW
4.0 1.0 3.0 95 KB

The library implements gmock functionality for global win32 functions.

Home Page: https://smalti.github.io/gmock-win32/

License: MIT License

C++ 100.00%
gmock mock win32 cpp test win32api library mocking mocking-library cpp-lib

gmock-win32's Introduction

Overview

gmock-win32 lib gmock-win32 license gmock-win32 version cpp-logo WindowsOs-logo tests

Suppose there is a task to test code that relies on certain system functions. Ideally, the code should be tested against different possible results of these functions. However, creating the necessary conditions for the functions to return specific results can be challenging. For instance, simulating a lack of space when writing to a file requires a lot of effort.

To simplify this process, this library allows you to replace imported module functions, including Win32 system functions, with a stub for testing purposes using GMock. Since it is an extension of the GMock library, you can use the same actions and matchers as you normally would with GMock.


Mocking of system functions in general can be a sign of poorly designed code. This means that the code is tightly coupled to the system and relies on a specific implementation with side effects, making it less flexible and difficult to test.

But sometimes it may be impossible (or quite expensive) to rewrite existing code to decouple it from that system API before testing it. Also we must not forget that wrappers over the system API must also be tested (and it's usually not recommended to introduce an extra layer of abstraction solely for testing purposes). In such situations, we can use this GMock-lib extension to test that code (at least tests for system wrappers that many projects have). In any case, try to avoid breaking the contracts by monitoring/checking test design.

Implementation idea

To use the mock technique for Win32 APIs, you need to replace the original global Win32 functions with something else. In C++, this is achieved through dynamic polymorphism with virtual functions via vtable and function overloading.

The Import Address Table (IAT) patching technique is a documented approach that can be used to achieve this goal. The library extends GMock library by using this technique. However, there is still a limitation - we cannot substitute a Win32 function that is used by run-time dynamic linking (LoadLibrary + GetProcAddress). You can find several GMock library extensions on GitHub, each with its own unique approach. The current implementation was inspired by a header-only library called gmock-global.

Basic Concepts

To use the mock behavior for Win32 API (or other DLL) module functions, you'll first need to build the library. Once that's done, you can include the library gmock-win32.h header immediately after the gmock/gmock.h header in your test code. Several macros are then available to help you achieve the desired mock behavior:

1. First, we need to initialize the library by using initialize / uninitialize or init_scope initialization wrapper. Typically, it can be done in main function before initializing GTest:

int main(int argc, char* argv[])
{
    const gmock_win32::init_scope gmockWin32{ };

    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

2. Create function mocks by using MOCK_STDCALL_FUNC / MOCK_CDECL_FUNC macro by defining them in global scope:

Macro syntax: MOCK_*CALLING_CONVENTION*_FUNC(Retval, FunctionName, arg1, arg2...):

MOCK_STDCALL_FUNC(DWORD, GetCurrentProcessId);
MOCK_STDCALL_FUNC(DWORD, GetProcessIdOfThread, HANDLE);

3. Then setup expectations via EXPECT_MODULE_FUNC_CALL / ON_MODULE_FUNC_CALL + use GMock matchers and actions as usual

Macro syntax: *EXPECTATION*_MODULE_FUNC_CALL(FunctionName, matchers...)

EXPECT_MODULE_FUNC_CALL:

EXPECT_MODULE_FUNC_CALL(GetCurrentProcessId).WillOnce(Return(42));
EXPECT_MODULE_FUNC_CALL(GetProcessIdOfThread, _).WillRepeatedly(Return(42));

ON_MODULE_FUNC_CALL:

ON_MODULE_FUNC_CALL(GetCurrentProcessId).WillByDefault(Return(42));
ON_MODULE_FUNC_CALL(GetProcessIdOfThread, Eq(HANDLE(42))).WillByDefault(Return(1));

4. To validate and clear expectations after tests use the VERIFY_AND_CLEAR_MODULE_FUNC or VERIFY_AND_CLEAR_MODULE_FUNC_EXPECTATIONS macro

In GMock the expectations of a mock object are verified upon its destruction. However, since we do not destroy our objects, we must manually verify our expectations after test. In the general case, we should verify expectations after every test case, similar to how a Mock object would be destroyed. This can typically be done in the TearDown method:

// Verifies and removes the expectations
VERIFY_AND_CLEAR_MODULE_FUNC_EXPECTATIONS(GetCurrentProcessId);

// Verifies and removes the expectations and removes the default actions set by ON_CALL
VERIFY_AND_CLEAR_MODULE_FUNC(GetProcessIdOfThread);

5. Use the RESTORE_MODULE_FUNC macro to restore the original module function and remove the IAT patch after all tests finished

RESTORE_MODULE_FUNC(GetCurrentProcessId);

Demonstration of the library API

#include <gmock/gmock.h>
#include <gmock-win32.h>

using ::testing::Eq;
using ::testing::Return;

MOCK_STDCALL_FUNC(DWORD, GetCurrentProcessId);
MOCK_STDCALL_FUNC(DWORD, GetProcessIdOfThread, HANDLE);

void test()
{
    cout << "  GetCurrentProcessId:  " << ::GetCurrentProcessId() << endl;
    cout << "  GetProcessIdOfThread: " << ::GetProcessIdOfThread(HANDLE(42)) << endl;
}

int main()
{
    const gmock_win32::init_scope gmockWin32{ };

    // Initial case: we will make actual Win32 function calls and
    // will see their real results before any GMock expectations
    // are set:

    cout << "Before mock expectations set:" << endl;
    test();

    // Now we proceed to set up expectations (this process also
    // involves patching the real Win32 module functions):

    EXPECT_MODULE_FUNC_CALL(GetCurrentProcessId).WillRepeatedly(Return(42));
    ON_MODULE_FUNC_CALL(GetProcessIdOfThread, Eq(HANDLE(42))).WillByDefault(Return(1));

    // After setting up expectations, we will receive faked results that
    // are based on our expectations:

    cout << endl << "After mock expectations set:" << endl;
    test();

    return 0;
}

Output:

Before mock expectations set:
  GetCurrentProcessId:  23924
  GetProcessIdOfThread: 0

After mock expectations set:
  GetCurrentProcessId:  42
  GetProcessIdOfThread: 1

Here are some additional examples of library usage: gmock-win32-sample

Advanced Topics

1. Delegating calls to a real function

You can use a helper macro INVOKE_REAL_MODULE_FUNC to call the original function:

ON_MODULE_FUNC_CALL(GetProcessIdOfThread, _).WillByDefault(Invoke([&](HANDLE handle) -> DWORD
{
    return ::GetCurrentThread() == handle ?
        INVOKE_REAL_MODULE_FUNC(GetProcessIdOfThread, handle) : 12345UL;
}));

You can also use the REAL_MODULE_FUNC macro to get a reference to the original function without calling it. This can be useful to create a mock that calls through to the real function, but is still instrumented:

ON_MODULE_FUNC_CALL(GetProcessIdOfThread, _).WillByDefault(Invoke(REAL_MODULE_FUNC(GetProcessIdOfThread)));
EXPECT_MODULE_FUNC_CALL(GetProcessIdOfThread, _).Times(1);

2. Mocking APIs that are also used inside GTest

There are several Win32 API functions used within GTest code that may interact with client tests. This interaction can lead to oversaturated results or even deadlocks. API used in GTest:

// Possible list of used APIs in GTest (depends on version of the GTest)
CloseHandle
CreateThread
DeleteCriticalSection
EnterCriticalSection
GetCurrentThreadId
GetCurrentThread
GetLastError
GetTempFileNameA
GetTempPathA
GetThreadPriority
InitializeCriticalSection
InterlockedCompareExchange
LeaveCriticalSection
ResumeThread
SetThreadPriority
Sleep
WaitForSingleObject

To address such issues, we have two options. First, we can utilize the BYPASS_MOCKS macro to suppress mocks during the execution of GMock code. Alternatively, we can create a gmock_win32::bypass_mocks{ } object to apply suppression within a specific scope.

However, it's important to note that you do not need to manually suppress mocks when creating function mocks using the MOCK_STDCALL_FUNC or MOCK_CDECL_FUNC macros, or when setting up expectations with their clauses using the ON_MODULE_FUNC_CALL or EXPECT_MODULE_FUNC_CALL macros - this is done automatically for you. Additionally, there's the option to use RESTORE_MODULE_FUNC to revert the API to its original state, for instance, before calling VERIFY_AND_CLEAR_MODULE_FUNC_EXPECTATIONS.

Mocks bypassing example:

#include <gmock/gmock.h>
#include <gmock-win32.h>

// There's no need to take any action to suppress mocks during
// their creation:

MOCK_STDCALL_FUNC(DWORD, GetCurrentThreadId);
...

TEST(GetCurrentThreadIdTest, BaseTest)
{
    // No action is required to suppress mocks during setup of expectations - it
    // will be handled automatically:

    ON_MODULE_FUNC_CALL(GetCurrentThreadId).WillByDefault(testing::Return(42U));
    EXPECT_MODULE_FUNC_CALL(GetCurrentThreadId).Times(2);

    const auto tid1 = ::GetCurrentThreadId();
    const auto tid2 = ::GetCurrentThreadId();

    // Here we suppress our mocks during the execution of EXPECT_EQ (GTest uses
    // the GetCurrentThreadId function (inside the EXPECT_EQ macro) and therefore
    // we could get wrong results):

    BYPASS_MOCKS(EXPECT_EQ(tid1, 42U));
    BYPASS_MOCKS(EXPECT_EQ(tid2, 42U));

    // Mocks can also be suppressed using a scoped object (during the execution
    // of EXPECT_EQ):
    
    {
        const gmock_win32::bypass_mocks useOrigAPI{ };

        EXPECT_EQ(tid1, 42U);
        EXPECT_EQ(tid2, 42U);
    }

    ...

    // If there is some code that shouldn't be involved during testing
    // we can also suppress it:

    {
        const gmock_win32::bypass_mocks useOrigAPI{ };
        std::cout << std::this_thread::get_id() << std::endl;
    }
    ...
    
    RESTORE_MODULE_FUNC(GetCurrentThreadId);
    VERIFY_AND_CLEAR_MODULE_FUNC_EXPECTATIONS(GetCurrentThreadId);
}

int main(int argc, char* argv[])
{
    const gmock_win32::init_scope gmockWin32{ };

    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

Supported Platforms

  • C++ Version >= 14
  • MSVC >= 2019 (v142)
  • Clang >= 12.0.0
  • Windows Client >= 10

Tested with GTest

  • googletest 1.8.1
  • googletest 1.10.0
  • googletest 1.11.0
  • googletest 1.12.1
  • googletest 1.13.0
  • googletest 1.14.0

Related Open Source Projects

GoogleTest

Version history

Version 1.2.2 (25 January 2024)

  • Added support for Win32 API forwarding
  • Added support for macro expansion across all macro definitions
  • Added VERIFY_AND_CLEAR_MODULE_FUNC macro
  • Fixed a typo related to 12 arguments
  • Fixed C++20 compilation errors and warning 4702

Version 1.2.1 (19 October 2023)

  • Added macro expansion for redefined Win32 functions (e.g. GetWindowLongPtrA)
  • Added initialization / uninitialization of the lib-core
  • Added error codes to std::runtime_error exceptions
  • Unified public header code style

Version 1.2.0 (05 October 2023)

  • Added the possibility to bypass mocked APIs used within GTest
  • Added compatibility with Clang
  • Changed the usage of Win32 APIs in the library core from direct usage to runtime dynamic linking
  • Disabled optimization for sensitive code sections
  • Fixed LNK1169: one or more multiply defined symbols found (for an old function pointer)

Version 1.1.0 (29 August 2023)

  • Added support for functions with 9-13 parameters
  • Added REAL_MODULE_FUNC macro
  • Fixed problem with Windows ApiSet DLL functions redirection (AppCompat via Shimm DLL)
Old versions

Version 1.0.4 (19 March 2023)

  • Added support for googletest v1.11.0 / v1.12.1 / v1.13.0

Version 1.0.3 (14 March 2023)

  • Added VERIFY_AND_CLEAR_MODULE_FUNC_EXPECTATIONS macro
  • Added RESTORE_MODULE_FUNC macro

Version 1.0.2 (12 March 2023)

  • Added support of new MOCK_* macro, which no longer requires you to specify the argument count in the name

Version 1.0.1 (10 March 2023)

  • Added support of delegating calls to a real function via INVOKE_REAL_MODULE_FUNC macro

Version 1.0.0 (08 March 2023)

  • Initial public release

gmock-win32's People

Contributors

alex0vsky avatar gtbx avatar smalti avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar

gmock-win32's Issues

Multiple *.cpp supporting

Often tests are located in several *.cpp files, but are compiled into one *.exe.


Expected Behavior

[==========] Running 2 tests from 2 test suites.
[----------] Global test environment set-up.
[----------] 1 test from Bar
[ RUN      ] Bar.test
[       OK ] Bar.test (2 ms)
[----------] 1 test from Bar (7 ms total)

[----------] 1 test from Foo
[ RUN      ] Foo.test
[       OK ] Foo.test (1 ms)
[----------] 1 test from Foo (2 ms total)

[----------] Global test environment tear-down
[==========] 2 tests from 2 test suites ran. (25 ms total)
[  PASSED  ] 2 tests.

Actual Behavior

Link error issue

Foo.obj : error LNK2005: "public: static void * mock_module_GetACP::oldFn_" (?oldFn_@mock_module_GetACP@@2PEAXEA) already defined in Bar.obj
multiply_defined.exe : fatal error LNK1169: one or more multiply defined symbols found

Steps to Reproduce

  1. Two *.cpp files with tests and main file

Foo.cpp

#include "gtest\gtest.h"
#include "gmock\gmock.h"
#include "gmock-win32.h"
#include <Windows.h>
MOCK_STDCALL_FUNC(UINT, GetACP);
TEST(Foo, test) { 
	EXPECT_MODULE_FUNC_CALL( GetACP );
	GetACP( );
}

Bar.cpp

#include "gtest\gtest.h"
#include "gmock\gmock.h"
#include "gmock-win32.h"
#include <Windows.h>
MOCK_STDCALL_FUNC(UINT, GetACP);
TEST(Bar, test) { 
	EXPECT_MODULE_FUNC_CALL( GetACP );
	GetACP( );
}

multiply_defined.cpp

#include "..\src\gtest\src\gtest_main.cc"
#include "..\src\gtest\gtest-all.cc"
#include "..\src\gmock\gmock-all.cc"
#include "..\..\src\gmock-win32.cpp"
  1. Building in cmd line

Include path to googletest and current project

set googletest=googletest\gmock\include
set gmock-win32=gmock-win32\include

Building launch

cl /c Foo.cpp /EHsc /I"%googletest%" /I"%gmock-win32%"
cl /c Bar.cpp /EHsc /I"%googletest%" /I"%gmock-win32%"
cl /c multiply_defined.cpp /EHsc /I"%googletest%" /I"%gmock-win32%"
link multiply_defined Bar Foo
  1. Run multiply_defined.exe

Specifications

  • Version: latest
  • Platform: Windows
  • Subsystem: Visual Studio Community 2019

Deadlock in the setup of expectations for the mocked `GetCurrentThreadId` function

This issue occurred during the instantiation of a static NiceMock object, which, in turn, invokes the GetCurrentThreadId function (referenced in testing::internal::Mutex::Lock). Environment: GoogleTest 1.14.0, Win10.

Minimal sample to reproduce:

#include <gmock/gmock.h>
#include <gmock-win32.h>

using namespace std;
using namespace testing;
	
MOCK_STDCALL_FUNC(DWORD, GetCurrentThreadId);

int main(int argc, char* argv[])
{
    ON_MODULE_FUNC_CALL(GetCurrentThreadId).WillByDefault(Return(1));
    return 0;
}

Very late report for a missed expectation

Unexpected behavior

  • Unexpected behavior after completing a single test..
  • Double "Reporting" on single API hook.

Description

I’m writing about two at once, because one follows from the other and it’s difficult to separate them.

Unexpected behavior after completing a single test..

Leads to: it is impossible to detect an error/failure after the completion of a particular test, there is no process termination error code to be processed, and there are also no error records in the xml/json output file.

Double "Reporting" on single API hook.

Leads to: additional reporting of false expectations.


Additional context

1

After complete single test

Expected Behavior 1

[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from verifyAndClear_unexpectedBehavior_reportAfterTests
[ RUN      ] verifyAndClear_unexpectedBehavior_reportAfterTests.gmockWin32
C:\Prj\_PullRequest\gmock-win32\_changes\verifyAndClear\expectedButFail.cpp(13): error: Actual function call count doesn't match EXPECT_CALL(mock_module_GetActiveWindow::instance(), GetActiveWindow())...
         Expected: to be called once
           Actual: never called - unsatisfied and active
[  FAILED  ] verifyAndClear_unexpectedBehavior_reportAfterTests.gmockWin32 (2 ms)
[----------] 1 test from verifyAndClear_unexpectedBehavior_reportAfterTests (5 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (11 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] verifyAndClear_unexpectedBehavior_reportAfterTests.gmockWin32

 1 FAILED TEST

C:\Prj\_PullRequest\gmock-win32\_changes\verifyAndClear\bin\x64\Debug\expectedButFail.exe (process 5816) exited with code 1.
Press any key to close this window . . .

Note: (process Xxx) exited with code 1 !

Actual Behavior 1

[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from verifyAndClear_unexpectedBehavior_reportAfterTests
[ RUN      ] verifyAndClear_unexpectedBehavior_reportAfterTests.gmockWin32
[       OK ] verifyAndClear_unexpectedBehavior_reportAfterTests.gmockWin32 (0 ms)
[----------] 1 test from verifyAndClear_unexpectedBehavior_reportAfterTests (1 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (3 ms total)
[  PASSED  ] 1 test.
C:\Prj\_PullRequest\gmock-win32\_changes\verifyAndClear\expectedButFail.cpp(13): error: Actual function call count doesn't match EXPECT_CALL(mock_module_GetActiveWindow::instance(), GetActiveWindow())...
         Expected: to be called once
           Actual: never called - unsatisfied and active

C:\Prj\_PullRequest\gmock-win32\_changes\verifyAndClear\bin\x64\Debug\expectedButFail.exe (process 7920) exited with code 0.
Press any key to close this window . . .

Note: (process Xxx) exited with code 0 !.

Steps to Reproduce the Problem 1

1.1. Source code
expectedButFail.cpp

#pragma comment( lib, "kernel32" )
#pragma comment( lib, "user32" )
#include "..\src\gtest\gtest-all.cc"
#include "..\src\gmock\gmock-all.cc"
#include "..\..\src\gmock-win32.cpp"
#include "..\include\gtest\gtest-spi.h" 
int main(int argc, char **argv) {
	const gmock_win32::init_scope gmockWin32{ };
	return ::testing::InitGoogleTest( &argc, argv ), RUN_ALL_TESTS( );
}
MOCK_CDECL_FUNC( HWND, GetCapture );
TEST(verifyAndClear_unexpectedBehavior_reportAfterTests, gmockWin32) { 
	EXPECT_MODULE_FUNC_CALL( GetCapture );
//	bool result = true;
//	EXPECT_NONFATAL_FAILURE( 
//			VERIFY_AND_CLEAR_MODULE_FUNC( GetCapture )
//			, "Actual function call count doesn't match EXPECT_CALL(mock_module_GetCapture::instance(), GetCapture())..."
//		);
//	ASSERT_TRUE( result );
}

2.1. Building in cmd line

Include path to googletest(NuGet) and current project

set googletest=googletest\gmock\include
set gmock-win32=gmock-win32\include

Building for cl from Msvc 2019

cl expectedButFail.cpp /EHsc /I"%googletest%" /I"%gmock-win32%"

3.1. Run expectedButFail.exe

2

Double report

Expected Behavior 2

[==========] Running 2 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 2 tests from verifyAndClear_unexpectedBehavior_doubleReport
[ RUN      ] verifyAndClear_unexpectedBehavior_doubleReport.addingToInternals
C:\Prj\_PullRequest\gmock-win32\_changes\verifyAndClear\verifyAndClear.cpp(13): error: Actual function call count doesn't match EXPECT_CALL(mock_module_GetACP::instance(), GetACP())...
         Expected: to be called once
           Actual: never called - unsatisfied and active
[  FAILED  ] verifyAndClear_unexpectedBehavior_doubleReport.addingToInternals (1 ms)
[ RUN      ] verifyAndClear_unexpectedBehavior_doubleReport.forCurrentGetACP_and_previousGetACP
C:\Prj\_PullRequest\gmock-win32\_changes\verifyAndClear\verifyAndClear.cpp(17): error: Actual function call count doesn't match EXPECT_CALL(mock_module_GetACP::instance(), GetACP())...
         Expected: to be called once
           Actual: never called - unsatisfied and active
[  FAILED  ] verifyAndClear_unexpectedBehavior_doubleReport.forCurrentGetACP_and_previousGetACP (0 ms)

Actual Behavior 2

[==========] Running 2 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 2 tests from verifyAndClear_unexpectedBehavior_doubleReport
[ RUN      ] verifyAndClear_unexpectedBehavior_doubleReport.addingToInternals
[       OK ] verifyAndClear_unexpectedBehavior_doubleReport.addingToInternals (1 ms)
[ RUN      ] verifyAndClear_unexpectedBehavior_doubleReport.forCurrentGetACP_and_previousGetACP
C:\Prj\_PullRequest\gmock-win32\_changes\verifyAndClear\doubleReport.cpp(13): error: Actual function call count doesn't match EXPECT_CALL(mock_module_GetACP::instance(), GetACP())...
         Expected: to be called once
           Actual: never called - unsatisfied and active
C:\Prj\_PullRequest\gmock-win32\_changes\verifyAndClear\doubleReport.cpp(17): error: Actual function call count doesn't match EXPECT_CALL(mock_module_GetACP::instance(), GetACP())...
         Expected: to be called once
           Actual: never called - unsatisfied and active
[  FAILED  ] verifyAndClear_unexpectedBehavior_doubleReport.forCurrentGetACP_and_previousGetACP (1 ms)

Steps to Reproduce the Problem 2

2.1. Source code
doubleReport.cpp

#pragma comment( lib, "kernel32" )
#pragma comment( lib, "user32" )
#include "..\src\gtest\gtest-all.cc"
#include "..\src\gmock\gmock-all.cc"
#include "..\..\src\gmock-win32.cpp"
#include "..\include\gtest\gtest-spi.h" 
int main(int argc, char **argv) {
	const gmock_win32::init_scope gmockWin32{ };
	return ::testing::InitGoogleTest( &argc, argv ), RUN_ALL_TESTS( );
}
MOCK_MODULE_FUNC( UINT, GetACP );
TEST(verifyAndClear_unexpectedBehavior_doubleReport, addingToInternals) { 
	EXPECT_MODULE_FUNC_CALL( GetACP );
	//VERIFY_AND_CLEAR_MODULE_FUNC( GetACP );
}
TEST(verifyAndClear_unexpectedBehavior_doubleReport, forCurrentGetACP_and_previousGetACP) { 
	EXPECT_MODULE_FUNC_CALL( GetACP );
	VERIFY_AND_CLEAR_MODULE_FUNC( GetACP );
}

2.2. Building in cmd line

Include path to googletest(NuGet) and current project

set googletest=googletest\gmock\include
set gmock-win32=gmock-win32\include

Building for cl from Msvc 2019

cl doubleReport.cpp /EHsc /I"%googletest%" /I"%gmock-win32%"

3.2. Run doubleReport.exe

Specifications

  • Version: latest
  • Platform: Windows
  • Subsystem: Visual Studio Community 2019

Add support for Windows ApiSet DLL redirections

The current approach to IAT patching lacks support for certain system functions, such as the RoInitialize function (see the Windows API set redirection mechanism). We need to fix our IAT patching approach to support functions that have been redirected to other DLLs.

Adding CI from GitHubActions for tests

Conversation from #23:

Can I do checks in CI from GitHubAction? I understand this a little.

Yes, it's a good idea, we require CI for writing and executing tests.

About writing tests, from the top of my head:

  1. EXPECT_MODULE_FUNC_CALL and ON_MODULE_FUNC_CALL
    for the WinApi function starting from zero arguments up to 12 from for example CreateWindowExA().
  2. Handling initialization errors
  3. Handling hook errors, set and unset
  4. GTest conflict workaround/bypass
  5. Others such as RESTORE_MODULE_FUNC and VERIFY_AND_CLEAR_MODULE_FUNC_EXPECTATIONS

It would be enough?

Macro expansion for WinApi, proxied when implementing a 64-bit architecture

Using GetWindowLongPtr to get a stored pointer is quite common.

Additional context

From <WinUser.h> if !UNICODE

WINUSERAPI
LONG
WINAPI
GetWindowLongA(
    _In_ HWND hWnd,
    _In_ int nIndex);
#ifdef _WIN64
WINUSERAPI
LONG_PTR
WINAPI
GetWindowLongPtrA(
    _In_ HWND hWnd,
    _In_ int nIndex);
#    define GetWindowLongPtr  GetWindowLongPtrA
#else  /* _WIN64 */
#    define GetWindowLongPtrA   GetWindowLongA
#endif /* _WIN64 */

Along with this: wrong to use GetWindowLongA() on x64, pointer will be 32bit.


Expected Behavior

[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from expander_x86_64_macro
[ RUN      ] expander_x86_64_macro.test
[       OK ] expander_x86_64_macro.test (10 ms)
[----------] 1 test from expander_x86_64_macro (13 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (16 ms total)
[  PASSED  ] 1 test.

Actual Behavior

Compile error issue

expander_x86_64_macro.cpp(12,2): error C3861: 'patchModuleFunc_GetWindowLongPtrA': identifier not found
expander_x86_64_macro.cpp(12,2): error C2653: 'mock_module_GetWindowLongPtrA': is not a class or namespace name
expander_x86_64_macro.cpp(12,2): error C3861: 'instance': identifier not found
expander_x86_64_macro.cpp(12,2): error C2672: 'gmock_win32::detail::make_proxy': no matching overloaded function found

Steps to Reproduce

  1. Source code

expander_x86_64_macro.cpp

#include "gtest\gtest.h"
#include "gmock\gmock.h"
#include "gmock-win32.h"
#include <Windows.h>

// in x86 to `mock_module_GetWindowLongA`
// in x64 to `mock_module_GetWindowLongPtrA`
MOCK_STDCALL_FUNC( LONG_PTR, GetWindowLongPtrA, HWND hWnd, int nIndex );
TEST(expander_x86_64_macro, test) {
	// in x86 to `patchModuleFunc_GetWindowLongPtrA`
	// in x64 to `patchModuleFunc_GetWindowLongPtrA`
	EXPECT_MODULE_FUNC_CALL( GetWindowLongPtrA, 0, 0 );
	GetWindowLongPtrA( 0, 0 );
}
  1. Building in cmd line

Include path to googletest and current project

set googletest=googletest\gmock\include
set gmock-win32=gmock-win32\include

Building launch for x86

cl expander_x86_64_macro.cpp /EHsc /I"%googletest%" /I"%gmock-win32%"
  1. Run expander_x86_64_macro.exe

Specifications

  • Version: latest
  • Platform: Windows
  • Subsystem: Visual Studio Community 2019

Support from additional windows library

Hi,
I am a big fan of this library and it has saved me heaps of time. However, I am now trying other functions from the WIN32 which are not in the windows.h library. For example: physicalmonitorenumerationapi.h.

Is there already a process to support this type of library?

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.