public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Michael D Kinney" <michael.d.kinney@intel.com>
To: devel@edk2.groups.io
Cc: Liming Gao <liming.gao@intel.com>,
	Sean Brogan <sean.brogan@microsoft.com>,
	Bret Barkelew <Bret.Barkelew@microsoft.com>,
	Jiewen Yao <jiewen.yao@intel.com>
Subject: [Patch v2 14/16] MdePkg/Include: Add UT_EXPECT_ASSERT_FAILURE() to UnitTestLib
Date: Wed,  8 Jul 2020 21:05:19 -0700	[thread overview]
Message-ID: <20200709040521.3748-15-michael.d.kinney@intel.com> (raw)
In-Reply-To: <20200709040521.3748-1-michael.d.kinney@intel.com>

REF: 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.

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.

Add UnitTestExpectAssertFailure() to the UnitTestLib class.
The UnitTestExpectAssertFailure() is called from the new
UT_EXPECT_ASSERT_FAILURE() macro after the status of this
macro check is known.

Add 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.

Cc: Liming Gao <liming.gao@intel.com>
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>
---
 MdePkg/Include/Library/UnitTestLib.h | 90 ++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/MdePkg/Include/Library/UnitTestLib.h b/MdePkg/Include/Library/UnitTestLib.h
index a4374580a8..99175496c8 100644
--- a/MdePkg/Include/Library/UnitTestLib.h
+++ b/MdePkg/Include/Library/UnitTestLib.h
@@ -441,6 +441,56 @@ 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)
+  #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;
+
+  #define UT_EXPECT_ASSERT_FAILURE(FunctionCall, Status)               \
+    do {                                                               \
+      UNIT_TEST_STATUS          UnitTestJumpStatus;                    \
+      BASE_LIBRARY_JUMP_BUFFER  UnitTestJumpBuffer;                    \
+      UnitTestJumpStatus = UNIT_TEST_SKIPPED;                          \
+      if (DebugAssertEnabled ()) {                                     \
+        gUnitTestExpectAssertFailureJumpBuffer = &UnitTestJumpBuffer;  \
+        if (SetJump (gUnitTestExpectAssertFailureJumpBuffer) == 0) {   \
+          FunctionCall;                                                \
+          UnitTestJumpStatus = UNIT_TEST_ERROR_TEST_FAILED;            \
+        } else {                                                       \
+          UnitTestJumpStatus = UNIT_TEST_PASSED;                       \
+        }                                                              \
+        gUnitTestExpectAssertFailureJumpBuffer = NULL;                 \
+      }                                                                \
+      if (!UnitTestExpectAssertFailure (                               \
+             UnitTestJumpStatus,                                       \
+             __FUNCTION__, __LINE__, __FILE__,                         \
+             #FunctionCall, Status)) {                                 \
+        return UNIT_TEST_ERROR_TEST_FAILED;                            \
+      }                                                                \
+    } while (FALSE)
+#else
+  #define UT_EXPECT_ASSERT_FAILURE(FunctionCall, Status)  FunctionCall;
+#endif
+
 /**
   If Expression is TRUE, then TRUE is returned.
   If Expression is FALSE, then an assert is triggered and the location of the
@@ -690,6 +740,46 @@ UnitTestAssertNotNull (
   IN CONST CHAR8  *PointerName
   );
 
+/**
+  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
+  );
+
 /**
   Test logging macro that records an ERROR message in the test framework log.
   Record is associated with the currently executing test case.
-- 
2.21.0.windows.1


  parent reply	other threads:[~2020-07-09  4:05 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-07-09  4:05 [Patch v2 00/16] UnitTestFrameworkPkg: Enhancements and bug fixes Michael D Kinney
2020-07-09  4:05 ` [Patch v2 01/16] BaseTools/Python: Allow HOST_APPLICATION to use NULL libraries Michael D Kinney
2020-07-09 11:44   ` Bob Feng
2020-07-09 23:50   ` [edk2-devel] " Sean
2020-07-09  4:05 ` [Patch v2 02/16] MdePkg/BaseCpuLibNull: Add Null version of CpuLib for host testing Michael D Kinney
2020-07-09 23:51   ` [edk2-devel] " Sean
2020-07-09  4:05 ` [Patch v2 03/16] MdePkg/BaseCacheMaintenanceLibNull: Add Null instance " Michael D Kinney
2020-07-09  4:05 ` [Patch v2 04/16] MdePkg/BaseLib: Break out IA32/X64 GCC inline privileged functions Michael D Kinney
2020-07-09  4:05 ` [Patch v2 05/16] MdePkg/Library/BaseLib: Add BaseLib instance for host based unit tests Michael D Kinney
2020-07-09 14:13   ` Liming Gao
2020-07-09 17:05     ` Michael D Kinney
2020-07-10  7:54       ` Liming Gao
2020-07-10 16:38         ` Michael D Kinney
2020-07-09  4:05 ` [Patch v2 06/16] UnitTestFrameworkPkg: Use host libraries from MdePkg Michael D Kinney
2020-07-09  4:05 ` [Patch v2 07/16] UnitTestFrameworkPkg: Enable source level debug for host tests Michael D Kinney
2020-07-09  4:05 ` [Patch v2 08/16] UnitTestFrameworkPkg: Set host application stack size to 256KB Michael D Kinney
2020-07-09  4:05 ` [Patch v2 09/16] UnitTestFrameworkPkg: Change target mode DebugLib mapping Michael D Kinney
2020-07-09  4:05 ` [Patch v2 10/16] UnitTestFrameworkPkg/UnitTestLib: Move print log into cleanup Michael D Kinney
2020-07-09  4:05 ` [Patch v2 11/16] UnitTestFrameworkPkg/UnitTestLib: Fix target mode log messages Michael D Kinney
2020-07-09  4:05 ` [Patch v2 12/16] UnitTestFrameworkPkg/UnitTestLib: Add checks for ASSERT() Michael D Kinney
2020-07-09  4:05 ` [Patch v2 13/16] MdePkg/Include: Hook DebugLib _ASSERT() for unit tests Michael D Kinney
2020-07-09  4:05 ` Michael D Kinney [this message]
2020-07-09  4:05 ` [Patch v2 15/16] MdePkg/Library/BaseStackCheckLib: Fix PCD type in INF Michael D Kinney
2020-07-09 12:45   ` Liming Gao
2020-07-09  4:05 ` [Patch v2 16/16] UnitTestFramewokPkg/SampleUnitTest: Use UT_EXPECT_ASSERT_FAILURE() Michael D Kinney

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200709040521.3748-15-michael.d.kinney@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox