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