<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:DengXian;
        panose-1:2 1 6 0 3 1 1 1 1 1;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:"\@DengXian";
        panose-1:2 1 6 0 3 1 1 1 1 1;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
.MsoChpDefault
        {mso-style-type:export-only;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
--></style>
</head>
<body lang="EN-US" link="blue" vlink="#954F72">
<div class="WordSection1">
<p class="MsoNormal">Reviewed-by: Bret Barkelew <bret.barkelew@microsoft.com><o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">- Bret</p>
<p class="MsoNormal"><o:p> </o:p></p>
<div style="mso-element:para-border-div;border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal" style="border:none;padding:0in"><b>From: </b><a href="mailto:michael.d.kinney@intel.com">Michael D Kinney</a><br>
<b>Sent: </b>Friday, July 10, 2020 7:09 PM<br>
<b>To: </b><a href="mailto:devel@edk2.groups.io">devel@edk2.groups.io</a><br>
<b>Cc: </b><a href="mailto:sean.brogan@microsoft.com">Sean Brogan</a>; <a href="mailto:Bret.Barkelew@microsoft.com">
Bret Barkelew</a>; <a href="mailto:jiewen.yao@intel.com">Yao, Jiewen</a><br>
<b>Subject: </b>[EXTERNAL] [Patch v3 12/16] UnitTestFrameworkPkg/UnitTestLib: Add checks for ASSERT()</p>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal" style="margin-bottom:12.0pt">REF: REF: <a href="https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D2801&amp;data=02%7C01%7CBret.Barkelew%40microsoft.com%7C5764407d5dc9445fec9808d8253f699c%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637300301574194018&amp;sdata=4UQXMIDPbI9xRP%2BKcPorH1PpbFb1%2BjZR%2BlpsnCP5lAM%3D&amp;reserved=0">
https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D2801&amp;data=02%7C01%7CBret.Barkelew%40microsoft.com%7C5764407d5dc9445fec9808d8253f699c%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637300301574194018&amp;sdata=4UQXMIDPbI9xRP%2BKcPorH1PpbFb1%2BjZR%2BlpsnCP5lAM%3D&amp;reserved=0</a><br>
<br>
Add UnitTestDebugAssertLib that provides the UnitTestDebugAssert()<br>
service and the gUnitTestExpectAssertFailureJumpBuffer global<br>
variable.  This NULL library is linked against all host and target<br>
unit test builds.  This guarantees that the UnitTestDebugAssert()<br>
service is available to link against all libraries and modules that<br>
use the DebugLib class.<br>
<br>
EDKII_UNIT_TEST_FRAMEWORK_ENABLED must always be defined when<br>
building unit tests so the behavior of the DebugLib ASSERT()<br>
macros can be adjusted to allow the unit test framework to<br>
catch an ASSERT() if it is triggered by a function under test.<br>
<br>
Cc: Sean Brogan <sean.brogan@microsoft.com><br>
Cc: Bret Barkelew <Bret.Barkelew@microsoft.com><br>
Cc: Jiewen Yao <jiewen.yao@intel.com><br>
Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com><br>
---<br>
 .../UnitTestDebugAssertLib.c                  |  49 +++++<br>
 .../UnitTestDebugAssertLib.inf                |  31 +++<br>
 .../UnitTestDebugAssertLib.uni                |  11 +<br>
 .../Library/UnitTestLib/Assert.c              | 203 ++++++++++++------<br>
 .../Library/UnitTestLib/AssertCmocka.c        |  68 ++++++<br>
 .../Library/UnitTestLib/RunTests.c            |  23 +-<br>
 .../UnitTestResultReportLib.c                 |   3 +-<br>
 .../PrivateInclude/UnitTestFrameworkTypes.h   |   1 +<br>
 .../Test/UnitTestFrameworkPkgHostTest.dsc     |   2 +-<br>
 UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc |   1 +<br>
 .../UnitTestFrameworkPkgTarget.dsc.inc        |   6 +-<br>
 11 files changed, 328 insertions(+), 70 deletions(-)<br>
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLib.c<br>
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLib.inf<br>
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLib.uni<br>
<br>
diff --git a/UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLib.c b/UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLib.c<br>
new file mode 100644<br>
index 0000000000..0a4001e182<br>
--- /dev/null<br>
+++ b/UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLib.c<br>
@@ -0,0 +1,49 @@<br>
+/** @file<br>
+  Unit Test Debug Assert Library<br>
+<br>
+  Copyright (c) 2020, Intel Corporation. All rights reserved.<BR><br>
+  SPDX-License-Identifier: BSD-2-Clause-Patent<br>
+<br>
+**/<br>
+<br>
+#include <Uefi.h><br>
+#include <Library/BaseLib.h><br>
+#include <Library/UnitTestLib.h><br>
+<br>
+///<br>
+/// Point to jump buffer used with SetJump()/LongJump() to test if a function<br>
+/// under test generates an expected ASSERT() condition.<br>
+///<br>
+BASE_LIBRARY_JUMP_BUFFER  *gUnitTestExpectAssertFailureJumpBuffer = NULL;<br>
+<br>
+/**<br>
+  Unit test library replacement for DebugAssert() in DebugLib.<br>
+<br>
+  If FileName is NULL, then a <FileName> string of "(NULL) Filename" is printed.<br>
+  If Description is NULL, then a <Description> string of "(NULL) Description" is printed.<br>
+<br>
+  @param  FileName     The pointer to the name of the source file that generated the assert condition.<br>
+  @param  LineNumber   The line number in the source file that generated the assert condition<br>
+  @param  Description  The pointer to the description of the assert condition.<br>
+<br>
+**/<br>
+VOID<br>
+EFIAPI<br>
+UnitTestDebugAssert (<br>
+  IN CONST CHAR8  *FileName,<br>
+  IN UINTN        LineNumber,<br>
+  IN CONST CHAR8  *Description<br>
+  )<br>
+{<br>
+  CHAR8  Message[256];<br>
+<br>
+  if (gUnitTestExpectAssertFailureJumpBuffer != NULL) {<br>
+    UT_LOG_INFO ("Detected expected ASSERT: %a(%d): %a\n", FileName, LineNumber, Description);<br>
+    LongJump (gUnitTestExpectAssertFailureJumpBuffer, 1);<br>
+  } else {<br>
+    AsciiStrCpyS (Message, sizeof(Message), "Detected unexpected ASSERT(");<br>
+    AsciiStrCatS (Message, sizeof(Message), Description);<br>
+    AsciiStrCatS (Message, sizeof(Message), ")");<br>
+    UnitTestAssertTrue (FALSE, "", LineNumber, FileName, Message);<br>
+  }<br>
+}<br>
diff --git a/UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLib.inf b/UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLib.inf<br>
new file mode 100644<br>
index 0000000000..e6ccab0dd9<br>
--- /dev/null<br>
+++ b/UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLib.inf<br>
@@ -0,0 +1,31 @@<br>
+## @file<br>
+#  Unit Test Debug Assert Library<br>
+#<br>
+#  Copyright (c) 2020, Intel Corporation. All rights reserved.<BR><br>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent<br>
+#<br>
+##<br>
+<br>
+[Defines]<br>
+  INF_VERSION                    = 0x00010005<br>
+  BASE_NAME                      = UnitTestDebugAssertLib<br>
+  MODULE_UNI_FILE                = UnitTestDebugAssertLib.uni<br>
+  FILE_GUID                      = 9D53AD0D-5416-451F-A5BF-E5420051A99B<br>
+  MODULE_TYPE                    = BASE<br>
+  VERSION_STRING                 = 1.0<br>
+  LIBRARY_CLASS                  = NULL<br>
+<br>
+#<br>
+#  VALID_ARCHITECTURES           = ARM AARCH64<br>
+#<br>
+<br>
+[Sources]<br>
+  UnitTestDebugAssertLib.c<br>
+<br>
+[Packages]<br>
+  MdePkg/MdePkg.dec<br>
+  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec<br>
+<br>
+[LibraryClasses]<br>
+  BaseLib<br>
+  UnitTestLib<br>
diff --git a/UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLib.uni b/UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLib.uni<br>
new file mode 100644<br>
index 0000000000..9b794aa205<br>
--- /dev/null<br>
+++ b/UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLib.uni<br>
@@ -0,0 +1,11 @@<br>
+// /** @file<br>
+// Unit Test Debug Assert Library<br>
+//<br>
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR><br>
+// SPDX-License-Identifier: BSD-2-Clause-Patent<br>
+//<br>
+// **/<br>
+<br>
+#string STR_MODULE_ABSTRACT             #language en-US "Unit Test Debug Assert Library"<br>
+<br>
+#string STR_MODULE_DESCRIPTION          #language en-US "Unit Test Debug Assert Library"<br>
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c b/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c<br>
index 8a131fab2b..3669d63701 100644<br>
--- a/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c<br>
+++ b/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c<br>
@@ -13,6 +13,8 @@<br>
 #include <Library/DebugLib.h><br>
 #include <Library/PrintLib.h><br>
 <br>
+extern BASE_LIBRARY_JUMP_BUFFER  gUnitTestJumpBuffer;<br>
+<br>
 STATIC<br>
 EFI_STATUS<br>
 AddUnitTestFailure (<br>
@@ -71,7 +73,7 @@ UnitTestLogFailure (<br>
     FailureType<br>
     );<br>
 <br>
-  return;<br>
+  LongJump (&gUnitTestJumpBuffer, 1);<br>
 }<br>
 <br>
 /**<br>
@@ -103,6 +105,12 @@ UnitTestAssertTrue (<br>
   )<br>
 {<br>
   if (!Expression) {<br>
+    UT_LOG_ERROR (<br>
+      "[ASSERT FAIL] %a:%d: Expression (%a) is not TRUE!\n",<br>
+      FileName,<br>
+      LineNumber,<br>
+      Description<br>
+      );<br>
     UnitTestLogFailure (<br>
       FAILURETYPE_ASSERTTRUE,<br>
       "%a:%d: Expression (%a) is not TRUE!\n",<br>
@@ -110,12 +118,6 @@ UnitTestAssertTrue (<br>
       LineNumber,<br>
       Description<br>
       );<br>
-    UT_LOG_ERROR (<br>
-      "[ASSERT FAIL] %a:%d: Expression (%a) is not TRUE!\n",<br>
-      FileName,<br>
-      LineNumber,<br>
-      Description<br>
-      );<br>
   }<br>
   return Expression;<br>
 }<br>
@@ -149,6 +151,12 @@ UnitTestAssertFalse (<br>
   )<br>
 {<br>
   if (Expression) {<br>
+    UT_LOG_ERROR (<br>
+      "[ASSERT FAIL] %a:%d: Expression (%a) is not FALSE!\n",<br>
+      FileName,<br>
+      LineNumber,<br>
+      Description<br>
+      );<br>
     UnitTestLogFailure (<br>
       FAILURETYPE_ASSERTFALSE,<br>
       "%a:%d: Expression(%a) is not FALSE!\n",<br>
@@ -156,12 +164,6 @@ UnitTestAssertFalse (<br>
       LineNumber,<br>
       Description<br>
       );<br>
-    UT_LOG_ERROR (<br>
-      "[ASSERT FAIL] %a:%d: Expression (%a) is not FALSE!\n",<br>
-      FileName,<br>
-      LineNumber,<br>
-      Description<br>
-      );<br>
   }<br>
   return !Expression;<br>
 }<br>
@@ -195,6 +197,13 @@ UnitTestAssertNotEfiError (<br>
   )<br>
 {<br>
   if (EFI_ERROR (Status)) {<br>
+    UT_LOG_ERROR (<br>
+      "[ASSERT FAIL] %a:%d: Status '%a' is EFI_ERROR (%r)!\n",<br>
+      FileName,<br>
+      LineNumber,<br>
+      Description,<br>
+      Status<br>
+      );<br>
     UnitTestLogFailure (<br>
       FAILURETYPE_ASSERTNOTEFIERROR,<br>
       "%a:%d: Status '%a' is EFI_ERROR (%r)!\n",<br>
@@ -203,13 +212,6 @@ UnitTestAssertNotEfiError (<br>
       Description,<br>
       Status<br>
       );<br>
-    UT_LOG_ERROR (<br>
-      "[ASSERT FAIL] %a:%d: Status '%a' is EFI_ERROR (%r)!\n",<br>
-      FileName,<br>
-      LineNumber,<br>
-      Description,<br>
-      Status<br>
-      );<br>
   }<br>
   return !EFI_ERROR( Status );<br>
 }<br>
@@ -248,16 +250,6 @@ UnitTestAssertEqual (<br>
   )<br>
 {<br>
   if (ValueA != ValueB) {<br>
-    UnitTestLogFailure (<br>
-      FAILURETYPE_ASSERTEQUAL,<br>
-      "%a:%d: Value %a != %a (%d != %d)!\n",<br>
-      FileName,<br>
-      LineNumber,<br>
-      DescriptionA,<br>
-      DescriptionB,<br>
-      ValueA,<br>
-      ValueB<br>
-      );<br>
     UT_LOG_ERROR (<br>
       "[ASSERT FAIL] %a:%d: Value %a != %a (%d != %d)!\n",<br>
       FileName,<br>
@@ -267,6 +259,16 @@ UnitTestAssertEqual (<br>
       ValueA,<br>
       ValueB<br>
       );<br>
+    UnitTestLogFailure (<br>
+      FAILURETYPE_ASSERTEQUAL,<br>
+      "%a:%d: Value %a != %a (%d != %d)!\n",<br>
+      FileName,<br>
+      LineNumber,<br>
+      DescriptionA,<br>
+      DescriptionB,<br>
+      ValueA,<br>
+      ValueB<br>
+      );<br>
   }<br>
   return (ValueA == ValueB);<br>
 }<br>
@@ -310,15 +312,6 @@ UnitTestAssertMemEqual (<br>
   )<br>
 {<br>
   if (CompareMem(BufferA, BufferB, Length) != 0) {<br>
-    UnitTestLogFailure (<br>
-      FAILURETYPE_ASSERTEQUAL,<br>
-      "%a:%d: Memory at %a != %a for length %d bytes!\n",<br>
-      FileName,<br>
-      LineNumber,<br>
-      DescriptionA,<br>
-      DescriptionB,<br>
-      Length<br>
-      );<br>
     UT_LOG_ERROR (<br>
       "[ASSERT FAIL] %a:%d: Value %a != %a for length %d bytes!\n",<br>
       FileName,<br>
@@ -327,6 +320,15 @@ UnitTestAssertMemEqual (<br>
       DescriptionB,<br>
       Length<br>
       );<br>
+    UnitTestLogFailure (<br>
+      FAILURETYPE_ASSERTEQUAL,<br>
+      "%a:%d: Memory at %a != %a for length %d bytes!\n",<br>
+      FileName,<br>
+      LineNumber,<br>
+      DescriptionA,<br>
+      DescriptionB,<br>
+      Length<br>
+      );<br>
     return FALSE;<br>
   }<br>
   return TRUE;<br>
@@ -366,6 +368,15 @@ UnitTestAssertNotEqual (<br>
   )<br>
 {<br>
   if (ValueA == ValueB) {<br>
+    UT_LOG_ERROR (<br>
+      "[ASSERT FAIL] %a:%d: Value %a == %a (%d == %d)!\n",<br>
+      FileName,<br>
+      LineNumber,<br>
+      DescriptionA,<br>
+      DescriptionB,<br>
+      ValueA,<br>
+      ValueB<br>
+      );<br>
     UnitTestLogFailure (<br>
       FAILURETYPE_ASSERTNOTEQUAL,<br>
       "%a:%d: Value %a == %a (%d == %d)!\n",<br>
@@ -376,15 +387,6 @@ UnitTestAssertNotEqual (<br>
       ValueA,<br>
       ValueB<br>
       );<br>
-    UT_LOG_ERROR (<br>
-      "[ASSERT FAIL] %a:%d: Value %a == %a (%d == %d)!\n",<br>
-      FileName,<br>
-      LineNumber,<br>
-      DescriptionA,<br>
-      DescriptionB,<br>
-      ValueA,<br>
-      ValueB<br>
-      );<br>
   }<br>
   return (ValueA != ValueB);<br>
 }<br>
@@ -421,6 +423,14 @@ UnitTestAssertStatusEqual (<br>
   )<br>
 {<br>
   if (Status != Expected) {<br>
+    UT_LOG_ERROR (<br>
+      "[ASSERT FAIL] %a:%d: Status '%a' is %r, should be %r!\n",<br>
+      FileName,<br>
+      LineNumber,<br>
+      Description,<br>
+      Status,<br>
+      Expected<br>
+      );<br>
     UnitTestLogFailure (<br>
       FAILURETYPE_ASSERTSTATUSEQUAL,<br>
       "%a:%d: Status '%a' is %r, should be %r!\n",<br>
@@ -430,14 +440,6 @@ UnitTestAssertStatusEqual (<br>
       Status,<br>
       Expected<br>
       );<br>
-    UT_LOG_ERROR (<br>
-      "[ASSERT FAIL] %a:%d: Status '%a' is %r, should be %r!\n",<br>
-      FileName,<br>
-      LineNumber,<br>
-      Description,<br>
-      Status,<br>
-      Expected<br>
-      );<br>
   }<br>
   return (Status == Expected);<br>
 }<br>
@@ -473,6 +475,12 @@ UnitTestAssertNotNull (<br>
   )<br>
 {<br>
   if (Pointer == NULL) {<br>
+    UT_LOG_ERROR (<br>
+      "[ASSERT FAIL] %a:%d: Pointer (%a) is NULL!\n",<br>
+      FileName,<br>
+      LineNumber,<br>
+      PointerName<br>
+      );<br>
     UnitTestLogFailure (<br>
       FAILURETYPE_ASSERTNOTNULL,<br>
       "%a:%d: Pointer (%a) is NULL!\n",<br>
@@ -480,12 +488,83 @@ UnitTestAssertNotNull (<br>
       LineNumber,<br>
       PointerName<br>
       );<br>
-    UT_LOG_ERROR (<br>
-      "[ASSERT FAIL] %a:%d: Pointer (%a) is NULL!\n",<br>
-      FileName,<br>
-      LineNumber,<br>
-      PointerName<br>
-      );<br>
   }<br>
   return (Pointer != NULL);<br>
 }<br>
+<br>
+/**<br>
+  If UnitTestStatus is UNIT_TEST_PASSED, then log an info message and return<br>
+  TRUE because an ASSERT() was expected when FunctionCall was executed and an<br>
+  ASSERT() was triggered. If UnitTestStatus is UNIT_TEST_SKIPPED, then log a<br>
+  warning message and return TRUE because ASSERT() macros are disabled.  If<br>
+  UnitTestStatus is UNIT_TEST_ERROR_TEST_FAILED, then log an error message and<br>
+  return FALSE because an ASSERT() was expected when FunctionCall was executed,<br>
+  but no ASSERT() conditions were triggered.  The log messages contain<br>
+  FunctionName, LineNumber, and FileName strings to provide the location of the<br>
+  UT_EXPECT_ASSERT_FAILURE() macro.<br>
+<br>
+  @param[in]  UnitTestStatus  The status from UT_EXPECT_ASSERT_FAILURE() that<br>
+                              is either pass, skipped, or failed.<br>
+  @param[in]  FunctionName    Null-terminated ASCII string of the function<br>
+                              executing the UT_EXPECT_ASSERT_FAILURE() macro.<br>
+  @param[in]  LineNumber      The source file line number of the the function<br>
+                              executing the UT_EXPECT_ASSERT_FAILURE() macro.<br>
+  @param[in]  FileName        Null-terminated ASCII string of the filename<br>
+                              executing the UT_EXPECT_ASSERT_FAILURE() macro.<br>
+  @param[in]  FunctionCall    Null-terminated ASCII string of the function call<br>
+                              executed by the UT_EXPECT_ASSERT_FAILURE() macro.<br>
+  @param[out] ResultStatus    Used to return the UnitTestStatus value to the<br>
+                              caller of UT_EXPECT_ASSERT_FAILURE().  This is<br>
+                              optional parameter that may be NULL.<br>
+<br>
+  @retval  TRUE   UnitTestStatus is UNIT_TEST_PASSED.<br>
+  @retval  TRUE   UnitTestStatus is UNIT_TEST_SKIPPED.<br>
+  @retval  FALSE  UnitTestStatus is UNIT_TEST_ERROR_TEST_FAILED.<br>
+**/<br>
+BOOLEAN<br>
+EFIAPI<br>
+UnitTestExpectAssertFailure (<br>
+  IN  UNIT_TEST_STATUS  UnitTestStatus,<br>
+  IN  CONST CHAR8       *FunctionName,<br>
+  IN  UINTN             LineNumber,<br>
+  IN  CONST CHAR8       *FileName,<br>
+  IN  CONST CHAR8       *FunctionCall,<br>
+  OUT UNIT_TEST_STATUS  *ResultStatus  OPTIONAL<br>
+  )<br>
+{<br>
+  if (ResultStatus != NULL) {<br>
+    *ResultStatus = UnitTestStatus;<br>
+  }<br>
+  if (UnitTestStatus == UNIT_TEST_PASSED) {<br>
+    UT_LOG_INFO (<br>
+      "[ASSERT PASS] %a:%d: UT_EXPECT_ASSERT_FAILURE(%a) detected expected assert\n",<br>
+      FileName,<br>
+      LineNumber,<br>
+      FunctionCall<br>
+      );<br>
+  }<br>
+  if (UnitTestStatus == UNIT_TEST_SKIPPED) {<br>
+    UT_LOG_WARNING (<br>
+      "[ASSERT WARN] %a:%d: UT_EXPECT_ASSERT_FAILURE(%a) disabled\n",<br>
+      FileName,<br>
+      LineNumber,<br>
+      FunctionCall<br>
+      );<br>
+  }<br>
+  if (UnitTestStatus == UNIT_TEST_ERROR_TEST_FAILED) {<br>
+    UT_LOG_ERROR (<br>
+      "[ASSERT FAIL] %a:%d: Function call (%a) did not ASSERT()!\n",<br>
+      FileName,<br>
+      LineNumber,<br>
+      FunctionCall<br>
+      );<br>
+    UnitTestLogFailure (<br>
+      FAILURETYPE_EXPECTASSERT,<br>
+      "%a:%d: Function call (%a) did not ASSERT()!\n",<br>
+      FileName,<br>
+      LineNumber,<br>
+      FunctionCall<br>
+      );<br>
+  }<br>
+  return (UnitTestStatus != UNIT_TEST_ERROR_TEST_FAILED);<br>
+}<br>
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c b/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c<br>
index e48d614976..687c6243ab 100644<br>
--- a/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c<br>
+++ b/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c<br>
@@ -333,3 +333,71 @@ UnitTestAssertNotNull (<br>
 <br>
   return (Pointer != NULL);<br>
 }<br>
+<br>
+/**<br>
+  If UnitTestStatus is UNIT_TEST_PASSED, then log an info message and return<br>
+  TRUE because an ASSERT() was expected when FunctionCall was executed and an<br>
+  ASSERT() was triggered. If UnitTestStatus is UNIT_TEST_SKIPPED, then log a<br>
+  warning message and return TRUE because ASSERT() macros are disabled.  If<br>
+  UnitTestStatus is UNIT_TEST_ERROR_TEST_FAILED, then log an error message and<br>
+  return FALSE because an ASSERT() was expected when FunctionCall was executed,<br>
+  but no ASSERT() conditions were triggered.  The log messages contain<br>
+  FunctionName, LineNumber, and FileName strings to provide the location of the<br>
+  UT_EXPECT_ASSERT_FAILURE() macro.<br>
+<br>
+  @param[in]  UnitTestStatus  The status from UT_EXPECT_ASSERT_FAILURE() that<br>
+                              is either pass, skipped, or failed.<br>
+  @param[in]  FunctionName    Null-terminated ASCII string of the function<br>
+                              executing the UT_EXPECT_ASSERT_FAILURE() macro.<br>
+  @param[in]  LineNumber      The source file line number of the the function<br>
+                              executing the UT_EXPECT_ASSERT_FAILURE() macro.<br>
+  @param[in]  FileName        Null-terminated ASCII string of the filename<br>
+                              executing the UT_EXPECT_ASSERT_FAILURE() macro.<br>
+  @param[in]  FunctionCall    Null-terminated ASCII string of the function call<br>
+                              executed by the UT_EXPECT_ASSERT_FAILURE() macro.<br>
+  @param[out] ResultStatus    Used to return the UnitTestStatus value to the<br>
+                              caller of UT_EXPECT_ASSERT_FAILURE().  This is<br>
+                              optional parameter that may be NULL.<br>
+<br>
+  @retval  TRUE   UnitTestStatus is UNIT_TEST_PASSED.<br>
+  @retval  TRUE   UnitTestStatus is UNIT_TEST_SKIPPED.<br>
+  @retval  FALSE  UnitTestStatus is UNIT_TEST_ERROR_TEST_FAILED.<br>
+**/<br>
+BOOLEAN<br>
+EFIAPI<br>
+UnitTestExpectAssertFailure (<br>
+  IN  UNIT_TEST_STATUS  UnitTestStatus,<br>
+  IN  CONST CHAR8       *FunctionName,<br>
+  IN  UINTN             LineNumber,<br>
+  IN  CONST CHAR8       *FileName,<br>
+  IN  CONST CHAR8       *FunctionCall,<br>
+  OUT UNIT_TEST_STATUS  *ResultStatus  OPTIONAL<br>
+  )<br>
+{<br>
+  CHAR8  TempStr[MAX_STRING_SIZE];<br>
+<br>
+  if (ResultStatus != NULL) {<br>
+    *ResultStatus = UnitTestStatus;<br>
+  }<br>
+  if (UnitTestStatus == UNIT_TEST_PASSED) {<br>
+    UT_LOG_INFO (<br>
+      "[ASSERT PASS] %a:%d: UT_EXPECT_ASSERT_FAILURE(%a) detected expected assert\n",<br>
+      FileName,<br>
+      LineNumber,<br>
+      FunctionCall<br>
+      );<br>
+  }<br>
+  if (UnitTestStatus == UNIT_TEST_SKIPPED) {<br>
+    UT_LOG_WARNING (<br>
+      "[ASSERT WARN] %a:%d: UT_EXPECT_ASSERT_FAILURE(%a) disabled\n",<br>
+      FileName,<br>
+      LineNumber,<br>
+      FunctionCall<br>
+      );<br>
+  }<br>
+  if (UnitTestStatus == UNIT_TEST_ERROR_TEST_FAILED) {<br>
+    snprintf (TempStr, sizeof(TempStr), "UT_EXPECT_ASSERT_FAILURE(%s) did not trigger ASSERT()", FunctionCall);<br>
+    _assert_true (FALSE, TempStr, FileName, (INT32)LineNumber);<br>
+  }<br>
+  return (UnitTestStatus != UNIT_TEST_ERROR_TEST_FAILED);<br>
+}<br>
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c<br>
index 793335fd0f..2dc1d159d5 100644<br>
--- a/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c<br>
+++ b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c<br>
@@ -14,6 +14,8 @@<br>
 <br>
 STATIC UNIT_TEST_FRAMEWORK_HANDLE  mFrameworkHandle = NULL;<br>
 <br>
+BASE_LIBRARY_JUMP_BUFFER  gUnitTestJumpBuffer;<br>
+<br>
 UNIT_TEST_FRAMEWORK_HANDLE<br>
 GetActiveFrameworkHandle (<br>
   VOID<br>
@@ -75,7 +77,14 @@ RunTestSuite (<br>
     // Next, if we're still running, make sure that our test prerequisites are in place.<br>
     if (Test->Result == UNIT_TEST_PENDING && Test->Prerequisite != NULL) {<br>
       DEBUG ((DEBUG_VERBOSE, "PREREQ\n"));<br>
-      if (Test->Prerequisite (Test->Context) != UNIT_TEST_PASSED) {<br>
+      if (SetJump (&gUnitTestJumpBuffer) == 0) {<br>
+        if (Test->Prerequisite (Test->Context) != UNIT_TEST_PASSED) {<br>
+          DEBUG ((DEBUG_ERROR, "Prerequisite Not Met\n"));<br>
+          Test->Result = UNIT_TEST_ERROR_PREREQUISITE_NOT_MET;<br>
+          ParentFramework->CurrentTest  = NULL;<br>
+          continue;<br>
+        }<br>
+      } else {<br>
         DEBUG ((DEBUG_ERROR, "Prerequisite Not Met\n"));<br>
         Test->Result = UNIT_TEST_ERROR_PREREQUISITE_NOT_MET;<br>
         ParentFramework->CurrentTest  = NULL;<br>
@@ -88,14 +97,20 @@ RunTestSuite (<br>
     // We set the status to UNIT_TEST_RUNNING in case the test needs to reboot<br>
     // or quit. The UNIT_TEST_RUNNING state will allow the test to resume<br>
     // but will prevent the Prerequisite from being dispatched a second time.<br>
-    Test->Result = UNIT_TEST_RUNNING;<br>
-    Test->Result = Test->RunTest (Test->Context);<br>
+    if (SetJump (&gUnitTestJumpBuffer) == 0) {<br>
+      Test->Result = UNIT_TEST_RUNNING;<br>
+      Test->Result = Test->RunTest (Test->Context);<br>
+    } else {<br>
+      Test->Result = UNIT_TEST_ERROR_TEST_FAILED;<br>
+    }<br>
 <br>
     //<br>
     // Finally, clean everything up, if need be.<br>
     if (Test->CleanUp != NULL) {<br>
       DEBUG ((DEBUG_VERBOSE, "CLEANUP\n"));<br>
-      Test->CleanUp (Test->Context);<br>
+      if (SetJump (&gUnitTestJumpBuffer) == 0) {<br>
+        Test->CleanUp (Test->Context);<br>
+      }<br>
     }<br>
 <br>
     //<br>
diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLib.c b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLib.c<br>
index eba68e330c..66c9db457d 100644<br>
--- a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLib.c<br>
+++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLib.c<br>
@@ -49,7 +49,8 @@ struct _UNIT_TEST_FAILURE_TYPE_STRING mFailureTypeStrings[] = {<br>
   { FAILURETYPE_ASSERTNOTEQUAL,    "ASSERT_NOTEQUAL FAILURE"},<br>
   { FAILURETYPE_ASSERTNOTEFIERROR, "ASSERT_NOTEFIERROR FAILURE"},<br>
   { FAILURETYPE_ASSERTSTATUSEQUAL, "ASSERT_STATUSEQUAL FAILURE"},<br>
-  { FAILURETYPE_ASSERTNOTNULL ,    "ASSERT_NOTNULL FAILURE"},<br>
+  { FAILURETYPE_ASSERTNOTNULL,     "ASSERT_NOTNULL FAILURE"},<br>
+  { FAILURETYPE_EXPECTASSERT,      "EXPECT_ASSERT FAILURE"},<br>
   { 0,                             "*UNKNOWN* Failure"}<br>
 };<br>
 <br>
diff --git a/UnitTestFrameworkPkg/PrivateInclude/UnitTestFrameworkTypes.h b/UnitTestFrameworkPkg/PrivateInclude/UnitTestFrameworkTypes.h<br>
index e58b30093e..b0e2f61bbf 100644<br>
--- a/UnitTestFrameworkPkg/PrivateInclude/UnitTestFrameworkTypes.h<br>
+++ b/UnitTestFrameworkPkg/PrivateInclude/UnitTestFrameworkTypes.h<br>
@@ -44,6 +44,7 @@ typedef UINT32 FAILURE_TYPE;<br>
 #define FAILURETYPE_ASSERTNOTEFIERROR    (6)<br>
 #define FAILURETYPE_ASSERTSTATUSEQUAL    (7)<br>
 #define FAILURETYPE_ASSERTNOTNULL        (8)<br>
+#define FAILURETYPE_EXPECTASSERT         (9)<br>
 <br>
 ///<br>
 /// Unit Test context structure tracked by the unit test framework.<br>
diff --git a/UnitTestFrameworkPkg/Test/UnitTestFrameworkPkgHostTest.dsc b/UnitTestFrameworkPkg/Test/UnitTestFrameworkPkgHostTest.dsc<br>
index 701e7299d7..70affddead 100644<br>
--- a/UnitTestFrameworkPkg/Test/UnitTestFrameworkPkgHostTest.dsc<br>
+++ b/UnitTestFrameworkPkg/Test/UnitTestFrameworkPkgHostTest.dsc<br>
@@ -25,7 +25,7 @@ [Components]<br>
   UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestHost.inf<br>
 <br>
   #<br>
-  # Build Libraries<br>
+  # Build HOST_APPLICATION Libraries<br>
   #<br>
   UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf<br>
   UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf<br>
diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc<br>
index 2d84691bf1..0dfd98f2a8 100644<br>
--- a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc<br>
+++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc<br>
@@ -28,6 +28,7 @@ [Components]<br>
   UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.inf<br>
   UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.inf<br>
   UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.inf<br>
+  UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLib.inf<br>
 <br>
   UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestDxe.inf<br>
   UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestPei.inf<br>
diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc b/UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc<br>
index 0881278ab0..8adf690098 100644<br>
--- a/UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc<br>
+++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc<br>
@@ -29,6 +29,7 @@ [LibraryClasses]<br>
   UnitTestLib|UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf<br>
   UnitTestPersistenceLib|UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.inf<br>
   UnitTestResultReportLib|UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.inf<br>
+  NULL|UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLib.inf<br>
 <br>
 [LibraryClasses.ARM, LibraryClasses.AARCH64]<br>
   #<br>
@@ -56,5 +57,6 @@ [PcdsFixedAtBuild]<br>
   gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x17<br>
 <br>
 [BuildOptions]<br>
-  MSFT:*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES<br>
-  GCC:*_*_*_CC_FLAGS  = -D DISABLE_NEW_DEPRECATED_INTERFACES<br>
+  MSFT:*_*_*_CC_FLAGS  = -D DISABLE_NEW_DEPRECATED_INTERFACES -D EDKII_UNIT_TEST_FRAMEWORK_ENABLED<br>
+  GCC:*_*_*_CC_FLAGS   = -D DISABLE_NEW_DEPRECATED_INTERFACES -D EDKII_UNIT_TEST_FRAMEWORK_ENABLED<br>
+  XCODE:*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES -D EDKII_UNIT_TEST_FRAMEWORK_ENABLED<br>
-- <br>
2.21.0.windows.1<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
</body>
</html>

<div width="1" style="color:white;clear:both">_._,_._,_</div>
<hr>
Groups.io Links:<p>


You receive all messages sent to this group.



<p>

<a target="_blank" href="https://edk2.groups.io/g/devel/message/62580">View/Reply Online (#62580)</a> |


  


|


  
    <a target="_blank" href="https://groups.io/mt/75514381/1813853">Mute This Topic</a>
  

| <a href="https://edk2.groups.io/g/devel/post">New Topic</a><br>



<br>

<a href="https://edk2.groups.io/g/devel/editsub/1813853">Your Subscription</a> |
<a href="mailto:devel+owner@edk2.groups.io">Contact Group Owner</a> |

<a href="https://edk2.groups.io/g/devel/unsub">Unsubscribe</a>

 [edk2-devel-archive@redhat.com]<br>
<div width="1" style="color:white;clear:both">_._,_._,_</div>