mirror of https://github.com/acidanthera/audk.git
UnitTestFrameworkPkg: Add gmock support to GoogleTestLib
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4389 * Add gmock support to GoogleTestLib * Add FunctionMockLib library class and library instance * Add GoogleTest extension to GoogleTestLib.h for CHAR16 type * Add GoogleTest extension to GoogleTestLib.h for buffer types * HOST_APPLICATION only supports IA32/X64 Cc: Sean Brogan <sean.brogan@microsoft.com> Cc: Michael Kubacki <mikuback@linux.microsoft.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Chris Johnson <chris.n.johnson@intel.com> Reviewed-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Oliver Smith-Denny <osde@linux.microsoft.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
This commit is contained in:
parent
caa389625f
commit
d0252b8fc1
|
@ -0,0 +1,131 @@
|
|||
/** @file
|
||||
This header allows the mocking of free (C style) functions using gmock.
|
||||
|
||||
Copyright (c) 2023, Intel Corporation. All rights reserved.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#ifndef FUNCTION_MOCK_LIB_H_
|
||||
#define FUNCTION_MOCK_LIB_H_
|
||||
|
||||
#include <Library/GoogleTestLib.h>
|
||||
#include <Library/SubhookLib.h>
|
||||
#include <type_traits>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// The below macros are the public function mock interface that are intended
|
||||
// to be used outside this file.
|
||||
|
||||
#define MOCK_INTERFACE_DECLARATION(MOCK) \
|
||||
static MOCK * Instance; \
|
||||
MOCK (); \
|
||||
~MOCK ();
|
||||
|
||||
#define MOCK_INTERFACE_DEFINITION(MOCK) \
|
||||
MOCK_STATIC_INSTANCE_DEFINITION (MOCK) \
|
||||
MOCK_INTERFACE_CONSTRUCTOR (MOCK) \
|
||||
MOCK_INTERFACE_DECONSTRUCTOR (MOCK)
|
||||
|
||||
// Mock function declaration for external functions (i.e. functions to
|
||||
// mock that do not exist in the compilation unit).
|
||||
#define MOCK_FUNCTION_DECLARATION(RET_TYPE, FUNC, ARGS) \
|
||||
MOCK_FUNCTION_TYPE_DEFINITIONS(RET_TYPE, FUNC, ARGS) \
|
||||
MOCK_METHOD (RET_TYPE, FUNC, ARGS);
|
||||
|
||||
// Mock function definition for external functions (i.e. functions to
|
||||
// mock that do not exist in the compilation unit).
|
||||
#define MOCK_FUNCTION_DEFINITION(MOCK, FUNC, NUM_ARGS, CALL_TYPE) \
|
||||
FUNCTION_DEFINITION_TO_CALL_MOCK(MOCK, FUNC, FUNC, NUM_ARGS, CALL_TYPE)
|
||||
|
||||
// Mock function declaration for internal functions (i.e. functions to
|
||||
// mock that already exist in the compilation unit).
|
||||
#define MOCK_FUNCTION_INTERNAL_DECLARATION(RET_TYPE, FUNC, ARGS) \
|
||||
MOCK_FUNCTION_DECLARATION(RET_TYPE, FUNC, ARGS) \
|
||||
MOCK_FUNCTION_HOOK_DECLARATIONS(FUNC)
|
||||
|
||||
// Mock function definition for internal functions (i.e. functions to
|
||||
// mock that already exist in the compilation unit). This definition also
|
||||
// implements MOCK_FUNC() which is later hooked as FUNC().
|
||||
#define MOCK_FUNCTION_INTERNAL_DEFINITION(MOCK, FUNC, NUM_ARGS, CALL_TYPE) \
|
||||
FUNCTION_DEFINITION_TO_CALL_MOCK(MOCK, FUNC, MOCK##_##FUNC, NUM_ARGS, CALL_TYPE) \
|
||||
MOCK_FUNCTION_HOOK_DEFINITIONS(MOCK, FUNC)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// The below macros are private and should not be used outside this file.
|
||||
|
||||
#define MOCK_FUNCTION_HOOK_DECLARATIONS(FUNC) \
|
||||
static subhook::Hook Hook##FUNC; \
|
||||
struct MockContainer_##FUNC { \
|
||||
MockContainer_##FUNC (); \
|
||||
~MockContainer_##FUNC (); \
|
||||
}; \
|
||||
MockContainer_##FUNC MockContainerInst_##FUNC;
|
||||
|
||||
// This definition implements a constructor and destructor inside a nested
|
||||
// class to enable automatic installation of the hooks to the associated
|
||||
// MOCK_FUNC() when the mock object is instantiated in scope and automatic
|
||||
// removal when the instantiated mock object goes out of scope.
|
||||
#define MOCK_FUNCTION_HOOK_DEFINITIONS(MOCK, FUNC) \
|
||||
subhook :: Hook MOCK :: Hook##FUNC; \
|
||||
MOCK :: MockContainer_##FUNC :: MockContainer_##FUNC () { \
|
||||
if (MOCK :: Instance == NULL) \
|
||||
MOCK :: Hook##FUNC .Install( \
|
||||
(FUNC##_ret_type *) ::FUNC, \
|
||||
(FUNC##_ret_type *) MOCK##_##FUNC); \
|
||||
} \
|
||||
MOCK :: MockContainer_##FUNC :: ~MockContainer_##FUNC () { \
|
||||
MOCK :: Hook##FUNC .Remove(); \
|
||||
} \
|
||||
static_assert( \
|
||||
std::is_same<decltype(&::FUNC), decltype(&MOCK##_##FUNC)>::value, \
|
||||
"Function signature from 'MOCK_FUNCTION_INTERNAL_DEFINITION' macro " \
|
||||
"invocation for '" #FUNC "' does not match the function signature " \
|
||||
"of '" #FUNC "' function it is mocking. Mismatch could be due to " \
|
||||
"different return type, arguments, or calling convention. See " \
|
||||
"associated 'MOCK_FUNCTION_INTERNAL_DECLARATION' macro invocation " \
|
||||
"for more details.");
|
||||
|
||||
#define MOCK_FUNCTION_TYPE_DEFINITIONS(RET_TYPE, FUNC, ARGS) \
|
||||
using FUNC##_ret_type = RET_TYPE; \
|
||||
using FUNC##_type = FUNC##_ret_type ARGS;
|
||||
|
||||
// This function definition simply calls MOCK::Instance->FUNC() which is the
|
||||
// mocked counterpart of the original function. This allows using gmock with
|
||||
// C free functions (since by default gmock only works with object methods).
|
||||
#define FUNCTION_DEFINITION_TO_CALL_MOCK(MOCK, FUNC, FUNC_DEF_NAME, NUM_ARGS, CALL_TYPE) \
|
||||
extern "C" { \
|
||||
typename MOCK :: FUNC##_ret_type CALL_TYPE FUNC_DEF_NAME( \
|
||||
GMOCK_PP_REPEAT(GMOCK_INTERNAL_PARAMETER, \
|
||||
(MOCK :: FUNC##_type), \
|
||||
NUM_ARGS)) \
|
||||
{ \
|
||||
EXPECT_TRUE(MOCK :: Instance != NULL) \
|
||||
<< "Called '" #FUNC "' in '" #MOCK "' function mock object before " \
|
||||
<< "an instance of '" #MOCK "' was created in test '" \
|
||||
<< ::testing::UnitTest::GetInstance()->current_test_info()->name() \
|
||||
<< "'."; \
|
||||
return MOCK :: Instance->FUNC( \
|
||||
GMOCK_PP_REPEAT(GMOCK_INTERNAL_FORWARD_ARG, \
|
||||
(MOCK :: FUNC##_type), \
|
||||
NUM_ARGS)); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MOCK_STATIC_INSTANCE_DEFINITION(MOCK) MOCK * MOCK :: Instance = NULL;
|
||||
|
||||
#define MOCK_INTERFACE_CONSTRUCTOR(MOCK) \
|
||||
MOCK :: MOCK () { \
|
||||
EXPECT_TRUE(MOCK :: Instance == NULL) \
|
||||
<< "Multiple instances of '" #MOCK "' function mock object were " \
|
||||
<< "created and only one instance is allowed in test '" \
|
||||
<< ::testing::UnitTest::GetInstance()->current_test_info()->name() \
|
||||
<< "'."; \
|
||||
MOCK :: Instance = this; \
|
||||
}
|
||||
|
||||
#define MOCK_INTERFACE_DECONSTRUCTOR(MOCK) \
|
||||
MOCK :: ~ MOCK () { \
|
||||
MOCK :: Instance = NULL; \
|
||||
}
|
||||
|
||||
#endif // FUNCTION_MOCK_LIB_H_
|
|
@ -10,5 +10,101 @@
|
|||
#define GOOGLE_TEST_LIB_H_
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
#include <Uefi.h>
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Below are the action extensions to GoogleTest and gmock for EDK2 types.
|
||||
// These actions are intended to be used in EXPECT_CALL (and related gmock
|
||||
// macros) to support assignments to output arguments in the expected call.
|
||||
//
|
||||
|
||||
// Action to support pointer types to a buffer (such as UINT8* or VOID*)
|
||||
ACTION_TEMPLATE (
|
||||
SetArgBuffer,
|
||||
HAS_1_TEMPLATE_PARAMS (size_t, ArgNum),
|
||||
AND_2_VALUE_PARAMS (Buffer, ByteSize)
|
||||
) {
|
||||
auto ArgBuffer = std::get<ArgNum>(args);
|
||||
|
||||
std::memcpy (ArgBuffer, Buffer, ByteSize);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Below are the matcher extensions to GoogleTest and gmock for EDK2 types.
|
||||
// These matchers are intended to be used in EXPECT_CALL (and related gmock
|
||||
// macros) to support comparisons to input arguments in the expected call.
|
||||
//
|
||||
// Note that these matchers can also be used in the EXPECT_THAT or ASSERT_THAT
|
||||
// macros to compare whether two values are equal.
|
||||
//
|
||||
|
||||
// Matcher to support pointer types to a buffer (such as UINT8* or VOID* or
|
||||
// any structure pointer)
|
||||
MATCHER_P2 (
|
||||
BufferEq,
|
||||
Buffer,
|
||||
ByteSize,
|
||||
std::string ("buffer data to ") + (negation ? "not " : "") + "be the same"
|
||||
) {
|
||||
UINT8 *Actual = (UINT8 *)arg;
|
||||
UINT8 *Expected = (UINT8 *)Buffer;
|
||||
|
||||
for (size_t i = 0; i < ByteSize; i++) {
|
||||
if (Actual[i] != Expected[i]) {
|
||||
*result_listener << "byte at offset " << i
|
||||
<< " does not match expected. [" << std::hex
|
||||
<< "Actual: 0x" << std::setw (2) << std::setfill ('0')
|
||||
<< (unsigned int)Actual[i] << ", "
|
||||
<< "Expected: 0x" << std::setw (2) << std::setfill ('0')
|
||||
<< (unsigned int)Expected[i] << "]";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*result_listener << "all bytes match";
|
||||
return true;
|
||||
}
|
||||
|
||||
// Matcher to support CHAR16* type
|
||||
MATCHER_P (
|
||||
Char16StrEq,
|
||||
String,
|
||||
std::string ("strings to ") + (negation ? "not " : "") + "be the same"
|
||||
) {
|
||||
CHAR16 *Actual = (CHAR16 *)arg;
|
||||
CHAR16 *Expected = (CHAR16 *)String;
|
||||
|
||||
for (size_t i = 0; Actual[i] != 0; i++) {
|
||||
if (Actual[i] != Expected[i]) {
|
||||
*result_listener << "character at offset " << i
|
||||
<< " does not match expected. [" << std::hex
|
||||
<< "Actual: 0x" << std::setw (4) << std::setfill ('0')
|
||||
<< Actual[i];
|
||||
|
||||
if (std::isprint (Actual[i])) {
|
||||
*result_listener << " ('" << (char)Actual[i] << "')";
|
||||
}
|
||||
|
||||
*result_listener << ", Expected: 0x" << std::setw (4) << std::setfill ('0')
|
||||
<< Expected[i];
|
||||
|
||||
if (std::isprint (Expected[i])) {
|
||||
*result_listener << " ('" << (char)Expected[i] << "')";
|
||||
}
|
||||
|
||||
*result_listener << "]";
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*result_listener << "strings match";
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
LIBRARY_CLASS = CmockaLib|HOST_APPLICATION
|
||||
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64
|
||||
# VALID_ARCHITECTURES = IA32 X64
|
||||
#
|
||||
|
||||
[Sources]
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
/** @file
|
||||
Macro-only FunctionMockLib library instance with no services.
|
||||
|
||||
Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
|
@ -0,0 +1,31 @@
|
|||
## @file
|
||||
# This module provides FunctionMockLib Library implementation.
|
||||
#
|
||||
# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010018
|
||||
BASE_NAME = FunctionMockLib
|
||||
MODULE_UNI_FILE = FunctionMockLib.uni
|
||||
FILE_GUID = DF1CAF2F-D584-4EC1-9ABF-07E8B10AD560
|
||||
MODULE_TYPE = HOST_APPLICATION
|
||||
VERSION_STRING = 0.1
|
||||
LIBRARY_CLASS = FunctionMockLib
|
||||
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64
|
||||
#
|
||||
|
||||
[Sources]
|
||||
FunctionMockLib.c
|
||||
|
||||
[LibraryClasses]
|
||||
GoogleTestLib
|
||||
SubhookLib
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
|
|
@ -0,0 +1,11 @@
|
|||
// /** @file
|
||||
// This module provides FunctionMockLib Library implementation.
|
||||
//
|
||||
// Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "FunctionMockLib Library implementation"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "This module provides FunctionMockLib Library implementation."
|
|
@ -7,30 +7,27 @@
|
|||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
INF_VERSION = 0x00010018
|
||||
BASE_NAME = GoogleTestLib
|
||||
MODULE_UNI_FILE = GoogleTestLib.uni
|
||||
FILE_GUID = A90E4751-AD30-43CC-980B-01E356B49ADF
|
||||
MODULE_TYPE = BASE
|
||||
MODULE_TYPE = HOST_APPLICATION
|
||||
VERSION_STRING = 0.1
|
||||
LIBRARY_CLASS = GoogleTestLib|HOST_APPLICATION
|
||||
LIBRARY_CLASS = GoogleTestLib
|
||||
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64
|
||||
# VALID_ARCHITECTURES = IA32 X64
|
||||
#
|
||||
|
||||
[Sources]
|
||||
googletest/googletest/src/gtest-all.cc
|
||||
googletest/googlemock/src/gmock-all.cc
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
|
||||
|
||||
[BuildOptions]
|
||||
MSFT:*_*_*_CC_FLAGS == /c /EHsc /Zi
|
||||
MSFT:NOOPT_*_*_CC_FLAGS = /Od
|
||||
|
||||
GCC:*_*_*_CC_FLAGS == -g -c
|
||||
|
||||
GCC:NOOPT_*_*_CC_FLAGS = -O0
|
||||
GCC:*_*_IA32_CC_FLAGS = -m32
|
||||
GCC:*_*_X64_CC_FLAGS = -m64
|
||||
MSFT:*_*_*_CC_FLAGS == /c /EHsc /Zi /Od
|
||||
GCC:*_*_IA32_CC_FLAGS == -g -c -fshort-wchar -O0 -m32
|
||||
GCC:*_*_X64_CC_FLAGS == -g -c -fshort-wchar -O0 -m64
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
// /** @file
|
||||
// This module provides GoogleTest Library implementation.
|
||||
//
|
||||
// This module provides GoogleTest Library implementation.
|
||||
//
|
||||
// Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
|
|
@ -32,8 +32,9 @@
|
|||
# Build HOST_APPLICATION Libraries
|
||||
#
|
||||
UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf
|
||||
UnitTestFrameworkPkg/Library/FunctionMockLib/FunctionMockLib.inf
|
||||
UnitTestFrameworkPkg/Library/GoogleTestLib/GoogleTestLib.inf
|
||||
UnitTestFrameworkPkg/Library/SubhookLib/SubhookLib.inf
|
||||
UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf
|
||||
UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf
|
||||
UnitTestFrameworkPkg/Library/SubhookLib/SubhookLib.inf
|
||||
UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf
|
||||
|
|
|
@ -79,9 +79,14 @@
|
|||
"AuditOnly": False, # Fails test but run in AuditOnly mode to collect log
|
||||
"IgnoreFiles": [ # use gitignore syntax to ignore errors in matching files
|
||||
"Library/CmockaLib/cmocka/**/*.*", # not going to spell check a submodule
|
||||
"Library/GoogleTestLib/googletest/**/*.*" # not going to spell check a submodule
|
||||
"Library/GoogleTestLib/googletest/**/*.*", # not going to spell check a submodule
|
||||
"Library/SubhookLib/subhook/**/*.*" # not going to spell check a submodule
|
||||
],
|
||||
"ExtendWords": [ # words to extend to the dictionary for this package
|
||||
"Pointee",
|
||||
"gmock",
|
||||
"GMOCK",
|
||||
"DSUBHOOK",
|
||||
"testcase",
|
||||
"testsuites",
|
||||
"cmocka",
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
PrivateInclude
|
||||
Library/CmockaLib/cmocka/include/cmockery
|
||||
Library/GoogleTestLib/googletest/googletest
|
||||
Library/GoogleTestLib/googletest/googlemock
|
||||
|
||||
[LibraryClasses]
|
||||
## @libraryclass Allows save and restore unit test internal state
|
||||
|
@ -36,6 +37,7 @@
|
|||
#
|
||||
GoogleTestLib|Include/Library/GoogleTestLib.h
|
||||
SubhookLib|Include/Library/SubhookLib.h
|
||||
FunctionMockLib|Include/Library/FunctionMockLib.h
|
||||
|
||||
[LibraryClasses.Common.Private]
|
||||
## @libraryclass Provides a unit test result report
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
CmockaLib|UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf
|
||||
GoogleTestLib|UnitTestFrameworkPkg/Library/GoogleTestLib/GoogleTestLib.inf
|
||||
SubhookLib|UnitTestFrameworkPkg/Library/SubhookLib/SubhookLib.inf
|
||||
FunctionMockLib|UnitTestFrameworkPkg/Library/FunctionMockLib/FunctionMockLib.inf
|
||||
UnitTestLib|UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf
|
||||
DebugLib|UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf
|
||||
MemoryAllocationLib|UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf
|
||||
|
|
Loading…
Reference in New Issue