https://bugzilla.tianocore.org/show_bug.cgi?id=2801
Add the UT_EXPECT_ASSERT_FAILURE(FunctionCall, Status) macro to the UnitTestLib that can be used to check if a function under test triggers an ASSERT() condition. If an ASSERT() condition is triggered, then the macro returns. If the ASSERT() condition is not triggered, then the current unit test fails with a status of UNIT_TEST_ERROR_TEST_FAILED. If ASSERT()s are disabled, then this check for ASSERT() behavior is not possible, and the check is skipped. Add the UnitTestDebugAssert() to the UnitTestLib class. The UnitTestDebugAssert() service is the same as the DebugLib DebugAssert() service and is invoked from the DebugLib _ASSERT() macro if unit testing is enabled. This allows the Unit Test Framework to know when code under test triggers an ASSERT() condition. The global variable gUnitTestExpectAssertFailureJumpBuffer is added to the UnitTestLib to save/restore context when the UT_EXPECT_ASSERT_FAILURE(FunctionCall, Status) macro is used. The UT_EXPECT_ASSERT_FAILURE() macro uses the SetJump() service with this global variable. The UnitTestLib service UnitTestDebugAssert() uses the LongJump() service with this global to restore context if an ASSERT() is triggered by the code under test. Cc: Liming Gao <liming....@intel.com> Cc: Sean Brogan <sean.bro...@microsoft.com> Cc: Bret Barkelew <bret.barke...@microsoft.com> Cc: Jiewen Yao <jiewen....@intel.com> Signed-off-by: Michael D Kinney <michael.d.kin...@intel.com> --- MdePkg/Include/Library/UnitTestLib.h | 70 ++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/MdePkg/Include/Library/UnitTestLib.h b/MdePkg/Include/Library/UnitTestLib.h index a4374580a8..1935a14ad1 100644 --- a/MdePkg/Include/Library/UnitTestLib.h +++ b/MdePkg/Include/Library/UnitTestLib.h @@ -10,6 +10,14 @@ #ifndef __UNIT_TEST_LIB_H__ #define __UNIT_TEST_LIB_H__ +#include <Library/BaseLib.h> + +/// +/// Pointer to jump buffer used with SetJump()/LongJump() to test if a function +/// under test generates an expected ASSERT() condition. +/// +extern BASE_LIBRARY_JUMP_BUFFER *gUnitTestExpectAssertFailureJumpBuffer; + /// /// Unit Test Status /// @@ -441,6 +449,68 @@ SaveFrameworkState ( return UNIT_TEST_ERROR_TEST_FAILED; \ } +/** + This macro uses the framework assertion logic to check whether a function call + triggers an ASSERT() condition. The BaseLib SetJump()/LongJump() services + are used to establish a safe return point when an ASSERT() is triggered. + If an ASSERT() is triggered, unit test execution continues and Status is set + to UNIT_TEST_PASSED. Otherwise, a unit test case failure is raised and + Status is set to UNIT_TEST_ERROR_TEST_FAILED. + + If ASSERT() macros are disabled, then the test case is skipped and a warning + message is added to the unit test log. Status is set to UNIT_TEST_SKIPPED. + + @param[in] FunctionCall Function call that is expected to trigger ASSERT(). + @param[out] Status Pointer to a UNIT_TEST_STATUS return value. This + is an optional parameter that may be NULL. +**/ +#if defined (EDKII_UNIT_TEST_FRAMEWORK_ENABLED) + #define UT_EXPECT_ASSERT_FAILURE(FunctionCall, Status) \ + if (DebugAssertEnabled ()) { \ + BASE_LIBRARY_JUMP_BUFFER UnitTestJumpBuffer; \ + gUnitTestExpectAssertFailureJumpBuffer = &UnitTestJumpBuffer; \ + if (SetJump (gUnitTestExpectAssertFailureJumpBuffer) == 0) { \ + FunctionCall; \ + gUnitTestExpectAssertFailureJumpBuffer = NULL; \ + UT_LOG_ERROR ("UT_EXPECT_ASSERT_FAILURE("#FunctionCall") did not ASSERT()\n"); \ + if (Status != NULL) { \ + *((UNIT_TEST_STATUS *)Status) = UNIT_TEST_ERROR_TEST_FAILED; \ + } \ + return UNIT_TEST_ERROR_TEST_FAILED; \ + } \ + gUnitTestExpectAssertFailureJumpBuffer = NULL; \ + if (Status != NULL) { \ + *((UNIT_TEST_STATUS *)Status) = UNIT_TEST_PASSED; \ + } \ + } else { \ + UT_LOG_WARNING ("UT_EXPECT_ASSERT_FAILURE("#FunctionCall") disabled\n"); \ + if (Status != NULL) { \ + *((UNIT_TEST_STATUS *)Status) = UNIT_TEST_SKIPPED; \ + } \ + } +#else + #define UT_EXPECT_ASSERT_FAILURE(FunctionCall, Status) FunctionCall; +#endif + +/** + Unit test library replacement for DebugAssert() in DebugLib. + + If FileName is NULL, then a <FileName> string of "(NULL) Filename" is printed. + If Description is NULL, then a <Description> string of "(NULL) Description" is printed. + + @param FileName The pointer to the name of the source file that generated the assert condition. + @param LineNumber The line number in the source file that generated the assert condition + @param Description The pointer to the description of the assert condition. + +**/ +VOID +EFIAPI +UnitTestDebugAssert ( + IN CONST CHAR8 *FileName, + IN UINTN LineNumber, + IN CONST CHAR8 *Description + ); + /** If Expression is TRUE, then TRUE is returned. If Expression is FALSE, then an assert is triggered and the location of the -- 2.21.0.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#61257): https://edk2.groups.io/g/devel/message/61257 Mute This Topic: https://groups.io/mt/74885927/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-