summaryrefslogtreecommitdiffstats
path: root/UnitTestFrameworkPkg/Library/UnitTestLib
diff options
context:
space:
mode:
authorMichael D Kinney <michael.d.kinney@intel.com>2020-06-10 17:57:16 -0700
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2020-07-15 05:25:21 +0000
commit26824851b041d9e81921ec7ef97220d2a2576157 (patch)
tree560b4ed159e4588646cca5bc5563170506fe62ce /UnitTestFrameworkPkg/Library/UnitTestLib
parent425df6923ec00df32bb6f20d1440a2e920f0e1e7 (diff)
downloadedk2-26824851b041d9e81921ec7ef97220d2a2576157.tar.gz
edk2-26824851b041d9e81921ec7ef97220d2a2576157.tar.bz2
edk2-26824851b041d9e81921ec7ef97220d2a2576157.zip
UnitTestFrameworkPkg/UnitTestLib: Add checks for ASSERT()
REF: REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2801 Add UnitTestDebugAssertLib that provides the UnitTestDebugAssert() service and the gUnitTestExpectAssertFailureJumpBuffer global variable. This NULL library is linked against all host and target unit test builds. This guarantees that the UnitTestDebugAssert() service is available to link against all libraries and modules that use the DebugLib class. EDKII_UNIT_TEST_FRAMEWORK_ENABLED must always be defined when building unit tests so the behavior of the DebugLib ASSERT() macros can be adjusted to allow the unit test framework to catch an ASSERT() if it is triggered by a function under test. Cc: Sean Brogan <sean.brogan@microsoft.com> Cc: Bret Barkelew <Bret.Barkelew@microsoft.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com> Reviewed-by: Bret Barkelew <Bret.Barkelew@microsoft.com>
Diffstat (limited to 'UnitTestFrameworkPkg/Library/UnitTestLib')
-rw-r--r--UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c157
-rw-r--r--UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c68
-rw-r--r--UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c23
3 files changed, 205 insertions, 43 deletions
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c b/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c
index 8a131fab2b..3669d63701 100644
--- a/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c
+++ b/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c
@@ -13,6 +13,8 @@
#include <Library/DebugLib.h>
#include <Library/PrintLib.h>
+extern BASE_LIBRARY_JUMP_BUFFER gUnitTestJumpBuffer;
+
STATIC
EFI_STATUS
AddUnitTestFailure (
@@ -71,7 +73,7 @@ UnitTestLogFailure (
FailureType
);
- return;
+ LongJump (&gUnitTestJumpBuffer, 1);
}
/**
@@ -103,15 +105,15 @@ UnitTestAssertTrue (
)
{
if (!Expression) {
- UnitTestLogFailure (
- FAILURETYPE_ASSERTTRUE,
- "%a:%d: Expression (%a) is not TRUE!\n",
+ UT_LOG_ERROR (
+ "[ASSERT FAIL] %a:%d: Expression (%a) is not TRUE!\n",
FileName,
LineNumber,
Description
);
- UT_LOG_ERROR (
- "[ASSERT FAIL] %a:%d: Expression (%a) is not TRUE!\n",
+ UnitTestLogFailure (
+ FAILURETYPE_ASSERTTRUE,
+ "%a:%d: Expression (%a) is not TRUE!\n",
FileName,
LineNumber,
Description
@@ -149,15 +151,15 @@ UnitTestAssertFalse (
)
{
if (Expression) {
- UnitTestLogFailure (
- FAILURETYPE_ASSERTFALSE,
- "%a:%d: Expression(%a) is not FALSE!\n",
+ UT_LOG_ERROR (
+ "[ASSERT FAIL] %a:%d: Expression (%a) is not FALSE!\n",
FileName,
LineNumber,
Description
);
- UT_LOG_ERROR (
- "[ASSERT FAIL] %a:%d: Expression (%a) is not FALSE!\n",
+ UnitTestLogFailure (
+ FAILURETYPE_ASSERTFALSE,
+ "%a:%d: Expression(%a) is not FALSE!\n",
FileName,
LineNumber,
Description
@@ -195,16 +197,16 @@ UnitTestAssertNotEfiError (
)
{
if (EFI_ERROR (Status)) {
- UnitTestLogFailure (
- FAILURETYPE_ASSERTNOTEFIERROR,
- "%a:%d: Status '%a' is EFI_ERROR (%r)!\n",
+ UT_LOG_ERROR (
+ "[ASSERT FAIL] %a:%d: Status '%a' is EFI_ERROR (%r)!\n",
FileName,
LineNumber,
Description,
Status
);
- UT_LOG_ERROR (
- "[ASSERT FAIL] %a:%d: Status '%a' is EFI_ERROR (%r)!\n",
+ UnitTestLogFailure (
+ FAILURETYPE_ASSERTNOTEFIERROR,
+ "%a:%d: Status '%a' is EFI_ERROR (%r)!\n",
FileName,
LineNumber,
Description,
@@ -248,9 +250,8 @@ UnitTestAssertEqual (
)
{
if (ValueA != ValueB) {
- UnitTestLogFailure (
- FAILURETYPE_ASSERTEQUAL,
- "%a:%d: Value %a != %a (%d != %d)!\n",
+ UT_LOG_ERROR (
+ "[ASSERT FAIL] %a:%d: Value %a != %a (%d != %d)!\n",
FileName,
LineNumber,
DescriptionA,
@@ -258,8 +259,9 @@ UnitTestAssertEqual (
ValueA,
ValueB
);
- UT_LOG_ERROR (
- "[ASSERT FAIL] %a:%d: Value %a != %a (%d != %d)!\n",
+ UnitTestLogFailure (
+ FAILURETYPE_ASSERTEQUAL,
+ "%a:%d: Value %a != %a (%d != %d)!\n",
FileName,
LineNumber,
DescriptionA,
@@ -310,17 +312,17 @@ UnitTestAssertMemEqual (
)
{
if (CompareMem(BufferA, BufferB, Length) != 0) {
- UnitTestLogFailure (
- FAILURETYPE_ASSERTEQUAL,
- "%a:%d: Memory at %a != %a for length %d bytes!\n",
+ UT_LOG_ERROR (
+ "[ASSERT FAIL] %a:%d: Value %a != %a for length %d bytes!\n",
FileName,
LineNumber,
DescriptionA,
DescriptionB,
Length
);
- UT_LOG_ERROR (
- "[ASSERT FAIL] %a:%d: Value %a != %a for length %d bytes!\n",
+ UnitTestLogFailure (
+ FAILURETYPE_ASSERTEQUAL,
+ "%a:%d: Memory at %a != %a for length %d bytes!\n",
FileName,
LineNumber,
DescriptionA,
@@ -366,9 +368,8 @@ UnitTestAssertNotEqual (
)
{
if (ValueA == ValueB) {
- UnitTestLogFailure (
- FAILURETYPE_ASSERTNOTEQUAL,
- "%a:%d: Value %a == %a (%d == %d)!\n",
+ UT_LOG_ERROR (
+ "[ASSERT FAIL] %a:%d: Value %a == %a (%d == %d)!\n",
FileName,
LineNumber,
DescriptionA,
@@ -376,8 +377,9 @@ UnitTestAssertNotEqual (
ValueA,
ValueB
);
- UT_LOG_ERROR (
- "[ASSERT FAIL] %a:%d: Value %a == %a (%d == %d)!\n",
+ UnitTestLogFailure (
+ FAILURETYPE_ASSERTNOTEQUAL,
+ "%a:%d: Value %a == %a (%d == %d)!\n",
FileName,
LineNumber,
DescriptionA,
@@ -421,17 +423,17 @@ UnitTestAssertStatusEqual (
)
{
if (Status != Expected) {
- UnitTestLogFailure (
- FAILURETYPE_ASSERTSTATUSEQUAL,
- "%a:%d: Status '%a' is %r, should be %r!\n",
+ UT_LOG_ERROR (
+ "[ASSERT FAIL] %a:%d: Status '%a' is %r, should be %r!\n",
FileName,
LineNumber,
Description,
Status,
Expected
);
- UT_LOG_ERROR (
- "[ASSERT FAIL] %a:%d: Status '%a' is %r, should be %r!\n",
+ UnitTestLogFailure (
+ FAILURETYPE_ASSERTSTATUSEQUAL,
+ "%a:%d: Status '%a' is %r, should be %r!\n",
FileName,
LineNumber,
Description,
@@ -473,6 +475,12 @@ UnitTestAssertNotNull (
)
{
if (Pointer == NULL) {
+ UT_LOG_ERROR (
+ "[ASSERT FAIL] %a:%d: Pointer (%a) is NULL!\n",
+ FileName,
+ LineNumber,
+ PointerName
+ );
UnitTestLogFailure (
FAILURETYPE_ASSERTNOTNULL,
"%a:%d: Pointer (%a) is NULL!\n",
@@ -480,12 +488,83 @@ UnitTestAssertNotNull (
LineNumber,
PointerName
);
+ }
+ return (Pointer != NULL);
+}
+
+/**
+ If UnitTestStatus is UNIT_TEST_PASSED, then log an info message and return
+ TRUE because an ASSERT() was expected when FunctionCall was executed and an
+ ASSERT() was triggered. If UnitTestStatus is UNIT_TEST_SKIPPED, then log a
+ warning message and return TRUE because ASSERT() macros are disabled. If
+ UnitTestStatus is UNIT_TEST_ERROR_TEST_FAILED, then log an error message and
+ return FALSE because an ASSERT() was expected when FunctionCall was executed,
+ but no ASSERT() conditions were triggered. The log messages contain
+ FunctionName, LineNumber, and FileName strings to provide the location of the
+ UT_EXPECT_ASSERT_FAILURE() macro.
+
+ @param[in] UnitTestStatus The status from UT_EXPECT_ASSERT_FAILURE() that
+ is either pass, skipped, or failed.
+ @param[in] FunctionName Null-terminated ASCII string of the function
+ executing the UT_EXPECT_ASSERT_FAILURE() macro.
+ @param[in] LineNumber The source file line number of the the function
+ executing the UT_EXPECT_ASSERT_FAILURE() macro.
+ @param[in] FileName Null-terminated ASCII string of the filename
+ executing the UT_EXPECT_ASSERT_FAILURE() macro.
+ @param[in] FunctionCall Null-terminated ASCII string of the function call
+ executed by the UT_EXPECT_ASSERT_FAILURE() macro.
+ @param[out] ResultStatus Used to return the UnitTestStatus value to the
+ caller of UT_EXPECT_ASSERT_FAILURE(). This is
+ optional parameter that may be NULL.
+
+ @retval TRUE UnitTestStatus is UNIT_TEST_PASSED.
+ @retval TRUE UnitTestStatus is UNIT_TEST_SKIPPED.
+ @retval FALSE UnitTestStatus is UNIT_TEST_ERROR_TEST_FAILED.
+**/
+BOOLEAN
+EFIAPI
+UnitTestExpectAssertFailure (
+ IN UNIT_TEST_STATUS UnitTestStatus,
+ IN CONST CHAR8 *FunctionName,
+ IN UINTN LineNumber,
+ IN CONST CHAR8 *FileName,
+ IN CONST CHAR8 *FunctionCall,
+ OUT UNIT_TEST_STATUS *ResultStatus OPTIONAL
+ )
+{
+ if (ResultStatus != NULL) {
+ *ResultStatus = UnitTestStatus;
+ }
+ if (UnitTestStatus == UNIT_TEST_PASSED) {
+ UT_LOG_INFO (
+ "[ASSERT PASS] %a:%d: UT_EXPECT_ASSERT_FAILURE(%a) detected expected assert\n",
+ FileName,
+ LineNumber,
+ FunctionCall
+ );
+ }
+ if (UnitTestStatus == UNIT_TEST_SKIPPED) {
+ UT_LOG_WARNING (
+ "[ASSERT WARN] %a:%d: UT_EXPECT_ASSERT_FAILURE(%a) disabled\n",
+ FileName,
+ LineNumber,
+ FunctionCall
+ );
+ }
+ if (UnitTestStatus == UNIT_TEST_ERROR_TEST_FAILED) {
UT_LOG_ERROR (
- "[ASSERT FAIL] %a:%d: Pointer (%a) is NULL!\n",
+ "[ASSERT FAIL] %a:%d: Function call (%a) did not ASSERT()!\n",
FileName,
LineNumber,
- PointerName
+ FunctionCall
+ );
+ UnitTestLogFailure (
+ FAILURETYPE_EXPECTASSERT,
+ "%a:%d: Function call (%a) did not ASSERT()!\n",
+ FileName,
+ LineNumber,
+ FunctionCall
);
}
- return (Pointer != NULL);
+ return (UnitTestStatus != UNIT_TEST_ERROR_TEST_FAILED);
}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c b/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c
index e48d614976..687c6243ab 100644
--- a/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c
+++ b/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c
@@ -333,3 +333,71 @@ UnitTestAssertNotNull (
return (Pointer != NULL);
}
+
+/**
+ If UnitTestStatus is UNIT_TEST_PASSED, then log an info message and return
+ TRUE because an ASSERT() was expected when FunctionCall was executed and an
+ ASSERT() was triggered. If UnitTestStatus is UNIT_TEST_SKIPPED, then log a
+ warning message and return TRUE because ASSERT() macros are disabled. If
+ UnitTestStatus is UNIT_TEST_ERROR_TEST_FAILED, then log an error message and
+ return FALSE because an ASSERT() was expected when FunctionCall was executed,
+ but no ASSERT() conditions were triggered. The log messages contain
+ FunctionName, LineNumber, and FileName strings to provide the location of the
+ UT_EXPECT_ASSERT_FAILURE() macro.
+
+ @param[in] UnitTestStatus The status from UT_EXPECT_ASSERT_FAILURE() that
+ is either pass, skipped, or failed.
+ @param[in] FunctionName Null-terminated ASCII string of the function
+ executing the UT_EXPECT_ASSERT_FAILURE() macro.
+ @param[in] LineNumber The source file line number of the the function
+ executing the UT_EXPECT_ASSERT_FAILURE() macro.
+ @param[in] FileName Null-terminated ASCII string of the filename
+ executing the UT_EXPECT_ASSERT_FAILURE() macro.
+ @param[in] FunctionCall Null-terminated ASCII string of the function call
+ executed by the UT_EXPECT_ASSERT_FAILURE() macro.
+ @param[out] ResultStatus Used to return the UnitTestStatus value to the
+ caller of UT_EXPECT_ASSERT_FAILURE(). This is
+ optional parameter that may be NULL.
+
+ @retval TRUE UnitTestStatus is UNIT_TEST_PASSED.
+ @retval TRUE UnitTestStatus is UNIT_TEST_SKIPPED.
+ @retval FALSE UnitTestStatus is UNIT_TEST_ERROR_TEST_FAILED.
+**/
+BOOLEAN
+EFIAPI
+UnitTestExpectAssertFailure (
+ IN UNIT_TEST_STATUS UnitTestStatus,
+ IN CONST CHAR8 *FunctionName,
+ IN UINTN LineNumber,
+ IN CONST CHAR8 *FileName,
+ IN CONST CHAR8 *FunctionCall,
+ OUT UNIT_TEST_STATUS *ResultStatus OPTIONAL
+ )
+{
+ CHAR8 TempStr[MAX_STRING_SIZE];
+
+ if (ResultStatus != NULL) {
+ *ResultStatus = UnitTestStatus;
+ }
+ if (UnitTestStatus == UNIT_TEST_PASSED) {
+ UT_LOG_INFO (
+ "[ASSERT PASS] %a:%d: UT_EXPECT_ASSERT_FAILURE(%a) detected expected assert\n",
+ FileName,
+ LineNumber,
+ FunctionCall
+ );
+ }
+ if (UnitTestStatus == UNIT_TEST_SKIPPED) {
+ UT_LOG_WARNING (
+ "[ASSERT WARN] %a:%d: UT_EXPECT_ASSERT_FAILURE(%a) disabled\n",
+ FileName,
+ LineNumber,
+ FunctionCall
+ );
+ }
+ if (UnitTestStatus == UNIT_TEST_ERROR_TEST_FAILED) {
+ snprintf (TempStr, sizeof(TempStr), "UT_EXPECT_ASSERT_FAILURE(%s) did not trigger ASSERT()", FunctionCall);
+ _assert_true (FALSE, TempStr, FileName, (INT32)LineNumber);
+ }
+ return (UnitTestStatus != UNIT_TEST_ERROR_TEST_FAILED);
+}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c
index 793335fd0f..2dc1d159d5 100644
--- a/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c
+++ b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c
@@ -14,6 +14,8 @@
STATIC UNIT_TEST_FRAMEWORK_HANDLE mFrameworkHandle = NULL;
+BASE_LIBRARY_JUMP_BUFFER gUnitTestJumpBuffer;
+
UNIT_TEST_FRAMEWORK_HANDLE
GetActiveFrameworkHandle (
VOID
@@ -75,7 +77,14 @@ RunTestSuite (
// Next, if we're still running, make sure that our test prerequisites are in place.
if (Test->Result == UNIT_TEST_PENDING && Test->Prerequisite != NULL) {
DEBUG ((DEBUG_VERBOSE, "PREREQ\n"));
- if (Test->Prerequisite (Test->Context) != UNIT_TEST_PASSED) {
+ if (SetJump (&gUnitTestJumpBuffer) == 0) {
+ if (Test->Prerequisite (Test->Context) != UNIT_TEST_PASSED) {
+ DEBUG ((DEBUG_ERROR, "Prerequisite Not Met\n"));
+ Test->Result = UNIT_TEST_ERROR_PREREQUISITE_NOT_MET;
+ ParentFramework->CurrentTest = NULL;
+ continue;
+ }
+ } else {
DEBUG ((DEBUG_ERROR, "Prerequisite Not Met\n"));
Test->Result = UNIT_TEST_ERROR_PREREQUISITE_NOT_MET;
ParentFramework->CurrentTest = NULL;
@@ -88,14 +97,20 @@ RunTestSuite (
// We set the status to UNIT_TEST_RUNNING in case the test needs to reboot
// or quit. The UNIT_TEST_RUNNING state will allow the test to resume
// but will prevent the Prerequisite from being dispatched a second time.
- Test->Result = UNIT_TEST_RUNNING;
- Test->Result = Test->RunTest (Test->Context);
+ if (SetJump (&gUnitTestJumpBuffer) == 0) {
+ Test->Result = UNIT_TEST_RUNNING;
+ Test->Result = Test->RunTest (Test->Context);
+ } else {
+ Test->Result = UNIT_TEST_ERROR_TEST_FAILED;
+ }
//
// Finally, clean everything up, if need be.
if (Test->CleanUp != NULL) {
DEBUG ((DEBUG_VERBOSE, "CLEANUP\n"));
- Test->CleanUp (Test->Context);
+ if (SetJump (&gUnitTestJumpBuffer) == 0) {
+ Test->CleanUp (Test->Context);
+ }
}
//