diff options
Diffstat (limited to 'UnitTestFrameworkPkg/Library/UnitTestLib')
| -rw-r--r-- | UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c | 1174 | ||||
| -rw-r--r-- | UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c | 814 | ||||
| -rw-r--r-- | UnitTestFrameworkPkg/Library/UnitTestLib/Log.c | 410 | ||||
| -rw-r--r-- | UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c | 374 | ||||
| -rw-r--r-- | UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c | 562 | ||||
| -rw-r--r-- | UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.c | 1746 | ||||
| -rw-r--r-- | UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf | 74 | ||||
| -rw-r--r-- | UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.uni | 22 | ||||
| -rw-r--r-- | UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf | 76 | ||||
| -rw-r--r-- | UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.uni | 22 |
10 files changed, 2637 insertions, 2637 deletions
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c b/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c index 53cb71f610..4f36899cd1 100644 --- a/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c @@ -1,587 +1,587 @@ -/**
- Implement UnitTestLib assert services
-
- Copyright (c) Microsoft Corporation.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-**/
-
-#include <Uefi.h>
-#include <UnitTestFrameworkTypes.h>
-#include <Library/UnitTestLib.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/DebugLib.h>
-#include <Library/PrintLib.h>
-
-extern BASE_LIBRARY_JUMP_BUFFER gUnitTestJumpBuffer;
-
-STATIC
-EFI_STATUS
-AddUnitTestFailure (
- IN OUT UNIT_TEST *UnitTest,
- IN CONST CHAR8 *FailureMessage,
- IN FAILURE_TYPE FailureType
- )
-{
- //
- // Make sure that you're cooking with gas.
- //
- if ((UnitTest == NULL) || (FailureMessage == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- UnitTest->FailureType = FailureType;
- AsciiStrCpyS (
- &UnitTest->FailureMessage[0],
- UNIT_TEST_TESTFAILUREMSG_LENGTH,
- FailureMessage
- );
-
- return EFI_SUCCESS;
-}
-
-STATIC
-VOID
-EFIAPI
-UnitTestLogFailure (
- IN FAILURE_TYPE FailureType,
- IN CONST CHAR8 *Format,
- ...
- )
-{
- UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle;
- CHAR8 LogString[UNIT_TEST_TESTFAILUREMSG_LENGTH];
- VA_LIST Marker;
-
- //
- // Get active Framework handle
- //
- FrameworkHandle = GetActiveFrameworkHandle ();
- if (FrameworkHandle == NULL) {
- DEBUG ((DEBUG_ERROR, "%a - FrameworkHandle not initialized\n", __func__));
- return;
- }
-
- //
- // Convert the message to an ASCII String
- //
- VA_START (Marker, Format);
- AsciiVSPrint (LogString, sizeof (LogString), Format, Marker);
- VA_END (Marker);
-
- //
- // Finally, add the string to the log.
- //
- AddUnitTestFailure (
- ((UNIT_TEST_FRAMEWORK *)FrameworkHandle)->CurrentTest,
- LogString,
- FailureType
- );
-
- LongJump (&gUnitTestJumpBuffer, 1);
-}
-
-/**
- If Expression is TRUE, then TRUE is returned.
- If Expression is FALSE, then an assert is triggered and the location of the
- assert provided by FunctionName, LineNumber, FileName, and Description are
- recorded and FALSE is returned.
-
- @param[in] Expression The BOOLEAN result of the expression evaluation.
- @param[in] FunctionName Null-terminated ASCII string of the function
- executing the assert macro.
- @param[in] LineNumber The source file line number of the assert macro.
- @param[in] FileName Null-terminated ASCII string of the filename
- executing the assert macro.
- @param[in] Description Null-terminated ASCII string of the expression being
- evaluated.
-
- @retval TRUE Expression is TRUE.
- @retval FALSE Expression is FALSE.
-**/
-BOOLEAN
-EFIAPI
-UnitTestAssertTrue (
- IN BOOLEAN Expression,
- IN CONST CHAR8 *FunctionName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *FileName,
- IN CONST CHAR8 *Description
- )
-{
- if (!Expression) {
- UT_LOG_ERROR (
- "[ASSERT FAIL] %a:%d: Expression (%a) is not TRUE!\n",
- FileName,
- LineNumber,
- Description
- );
- UnitTestLogFailure (
- FAILURETYPE_ASSERTTRUE,
- "%a:%d: Expression (%a) is not TRUE!\n",
- FileName,
- LineNumber,
- Description
- );
- }
-
- return Expression;
-}
-
-/**
- If Expression is FALSE, then TRUE is returned.
- If Expression is TRUE, then an assert is triggered and the location of the
- assert provided by FunctionName, LineNumber, FileName, and Description are
- recorded and FALSE is returned.
-
- @param[in] Expression The BOOLEAN result of the expression evaluation.
- @param[in] FunctionName Null-terminated ASCII string of the function
- executing the assert macro.
- @param[in] LineNumber The source file line number of the assert macro.
- @param[in] FileName Null-terminated ASCII string of the filename
- executing the assert macro.
- @param[in] Description Null-terminated ASCII string of the expression being
- evaluated.
-
- @retval TRUE Expression is FALSE.
- @retval FALSE Expression is TRUE.
-**/
-BOOLEAN
-EFIAPI
-UnitTestAssertFalse (
- IN BOOLEAN Expression,
- IN CONST CHAR8 *FunctionName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *FileName,
- IN CONST CHAR8 *Description
- )
-{
- if (Expression) {
- UT_LOG_ERROR (
- "[ASSERT FAIL] %a:%d: Expression (%a) is not FALSE!\n",
- FileName,
- LineNumber,
- Description
- );
- UnitTestLogFailure (
- FAILURETYPE_ASSERTFALSE,
- "%a:%d: Expression(%a) is not FALSE!\n",
- FileName,
- LineNumber,
- Description
- );
- }
-
- return !Expression;
-}
-
-/**
- If Status is not an EFI_ERROR(), then TRUE is returned.
- If Status is an EFI_ERROR(), then an assert is triggered and the location of
- the assert provided by FunctionName, LineNumber, FileName, and Description are
- recorded and FALSE is returned.
-
- @param[in] Status The EFI_STATUS value to evaluate.
- @param[in] FunctionName Null-terminated ASCII string of the function
- executing the assert macro.
- @param[in] LineNumber The source file line number of the assert macro.
- @param[in] FileName Null-terminated ASCII string of the filename
- executing the assert macro.
- @param[in] Description Null-terminated ASCII string of the status
- expression being evaluated.
-
- @retval TRUE Status is not an EFI_ERROR().
- @retval FALSE Status is an EFI_ERROR().
-**/
-BOOLEAN
-EFIAPI
-UnitTestAssertNotEfiError (
- IN EFI_STATUS Status,
- IN CONST CHAR8 *FunctionName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *FileName,
- IN CONST CHAR8 *Description
- )
-{
- if (EFI_ERROR (Status)) {
- UT_LOG_ERROR (
- "[ASSERT FAIL] %a:%d: Status '%a' is EFI_ERROR (%r)!\n",
- FileName,
- LineNumber,
- Description,
- Status
- );
- UnitTestLogFailure (
- FAILURETYPE_ASSERTNOTEFIERROR,
- "%a:%d: Status '%a' is EFI_ERROR (%r)!\n",
- FileName,
- LineNumber,
- Description,
- Status
- );
- }
-
- return !EFI_ERROR (Status);
-}
-
-/**
- If ValueA is equal ValueB, then TRUE is returned.
- If ValueA is not equal to ValueB, then an assert is triggered and the location
- of the assert provided by FunctionName, LineNumber, FileName, DescriptionA,
- and DescriptionB are recorded and FALSE is returned.
-
- @param[in] ValueA 64-bit value.
- @param[in] ValueB 64-bit value.
- @param[in] FunctionName Null-terminated ASCII string of the function
- executing the assert macro.
- @param[in] LineNumber The source file line number of the assert macro.
- @param[in] FileName Null-terminated ASCII string of the filename
- executing the assert macro.
- @param[in] DescriptionA Null-terminated ASCII string that is a description
- of ValueA.
- @param[in] DescriptionB Null-terminated ASCII string that is a description
- of ValueB.
-
- @retval TRUE ValueA is equal to ValueB.
- @retval FALSE ValueA is not equal to ValueB.
-**/
-BOOLEAN
-EFIAPI
-UnitTestAssertEqual (
- IN UINT64 ValueA,
- IN UINT64 ValueB,
- IN CONST CHAR8 *FunctionName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *FileName,
- IN CONST CHAR8 *DescriptionA,
- IN CONST CHAR8 *DescriptionB
- )
-{
- if (ValueA != ValueB) {
- UT_LOG_ERROR (
- "[ASSERT FAIL] %a:%d: Value %a != %a (%d != %d)!\n",
- FileName,
- LineNumber,
- DescriptionA,
- DescriptionB,
- ValueA,
- ValueB
- );
- UnitTestLogFailure (
- FAILURETYPE_ASSERTEQUAL,
- "%a:%d: Value %a != %a (%d != %d)!\n",
- FileName,
- LineNumber,
- DescriptionA,
- DescriptionB,
- ValueA,
- ValueB
- );
- }
-
- return (ValueA == ValueB);
-}
-
-/**
- If the contents of BufferA are identical to the contents of BufferB, then TRUE
- is returned. If the contents of BufferA are not identical to the contents of
- BufferB, then an assert is triggered and the location of the assert provided
- by FunctionName, LineNumber, FileName, DescriptionA, and DescriptionB are
- recorded and FALSE is returned.
-
- @param[in] BufferA Pointer to a buffer for comparison.
- @param[in] BufferB Pointer to a buffer for comparison.
- @param[in] Length Number of bytes to compare in BufferA and BufferB.
- @param[in] FunctionName Null-terminated ASCII string of the function
- executing the assert macro.
- @param[in] LineNumber The source file line number of the assert macro.
- @param[in] FileName Null-terminated ASCII string of the filename
- executing the assert macro.
- @param[in] DescriptionA Null-terminated ASCII string that is a description
- of BufferA.
- @param[in] DescriptionB Null-terminated ASCII string that is a description
- of BufferB.
-
- @retval TRUE The contents of BufferA are identical to the contents of
- BufferB.
- @retval FALSE The contents of BufferA are not identical to the contents of
- BufferB.
-**/
-BOOLEAN
-EFIAPI
-UnitTestAssertMemEqual (
- IN VOID *BufferA,
- IN VOID *BufferB,
- IN UINTN Length,
- IN CONST CHAR8 *FunctionName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *FileName,
- IN CONST CHAR8 *DescriptionA,
- IN CONST CHAR8 *DescriptionB
- )
-{
- if (CompareMem (BufferA, BufferB, Length) != 0) {
- UT_LOG_ERROR (
- "[ASSERT FAIL] %a:%d: Value %a != %a for length %d bytes!\n",
- FileName,
- LineNumber,
- DescriptionA,
- DescriptionB,
- Length
- );
- UnitTestLogFailure (
- FAILURETYPE_ASSERTEQUAL,
- "%a:%d: Memory at %a != %a for length %d bytes!\n",
- FileName,
- LineNumber,
- DescriptionA,
- DescriptionB,
- Length
- );
- return FALSE;
- }
-
- return TRUE;
-}
-
-/**
- If ValueA is not equal ValueB, then TRUE is returned.
- If ValueA is equal to ValueB, then an assert is triggered and the location
- of the assert provided by FunctionName, LineNumber, FileName, DescriptionA
- and DescriptionB are recorded and FALSE is returned.
-
- @param[in] ValueA 64-bit value.
- @param[in] ValueB 64-bit value.
- @param[in] FunctionName Null-terminated ASCII string of the function
- executing the assert macro.
- @param[in] LineNumber The source file line number of the assert macro.
- @param[in] FileName Null-terminated ASCII string of the filename
- executing the assert macro.
- @param[in] DescriptionA Null-terminated ASCII string that is a description
- of ValueA.
- @param[in] DescriptionB Null-terminated ASCII string that is a description
- of ValueB.
-
- @retval TRUE ValueA is not equal to ValueB.
- @retval FALSE ValueA is equal to ValueB.
-**/
-BOOLEAN
-EFIAPI
-UnitTestAssertNotEqual (
- IN UINT64 ValueA,
- IN UINT64 ValueB,
- IN CONST CHAR8 *FunctionName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *FileName,
- IN CONST CHAR8 *DescriptionA,
- IN CONST CHAR8 *DescriptionB
- )
-{
- if (ValueA == ValueB) {
- UT_LOG_ERROR (
- "[ASSERT FAIL] %a:%d: Value %a == %a (%d == %d)!\n",
- FileName,
- LineNumber,
- DescriptionA,
- DescriptionB,
- ValueA,
- ValueB
- );
- UnitTestLogFailure (
- FAILURETYPE_ASSERTNOTEQUAL,
- "%a:%d: Value %a == %a (%d == %d)!\n",
- FileName,
- LineNumber,
- DescriptionA,
- DescriptionB,
- ValueA,
- ValueB
- );
- }
-
- return (ValueA != ValueB);
-}
-
-/**
- If Status is equal to Expected, then TRUE is returned.
- If Status is not equal to Expected, then an assert is triggered and the
- location of the assert provided by FunctionName, LineNumber, FileName, and
- Description are recorded and FALSE is returned.
-
- @param[in] Status EFI_STATUS value returned from an API under test.
- @param[in] Expected The expected EFI_STATUS return value from an API
- under test.
- @param[in] FunctionName Null-terminated ASCII string of the function
- executing the assert macro.
- @param[in] LineNumber The source file line number of the assert macro.
- @param[in] FileName Null-terminated ASCII string of the filename
- executing the assert macro.
- @param[in] Description Null-terminated ASCII string that is a description
- of Status.
-
- @retval TRUE Status is equal to Expected.
- @retval FALSE Status is not equal to Expected.
-**/
-BOOLEAN
-EFIAPI
-UnitTestAssertStatusEqual (
- IN EFI_STATUS Status,
- IN EFI_STATUS Expected,
- IN CONST CHAR8 *FunctionName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *FileName,
- IN CONST CHAR8 *Description
- )
-{
- if (Status != Expected) {
- UT_LOG_ERROR (
- "[ASSERT FAIL] %a:%d: Status '%a' is %r, should be %r!\n",
- FileName,
- LineNumber,
- Description,
- Status,
- Expected
- );
- UnitTestLogFailure (
- FAILURETYPE_ASSERTSTATUSEQUAL,
- "%a:%d: Status '%a' is %r, should be %r!\n",
- FileName,
- LineNumber,
- Description,
- Status,
- Expected
- );
- }
-
- return (Status == Expected);
-}
-
-/**
- If Pointer is not equal to NULL, then TRUE is returned.
- If Pointer is equal to NULL, then an assert is triggered and the location of
- the assert provided by FunctionName, LineNumber, FileName, and PointerName
- are recorded and FALSE is returned.
-
- @param[in] Pointer Pointer value to be checked against NULL.
- @param[in] Expected The expected EFI_STATUS return value from a function
- under test.
- @param[in] FunctionName Null-terminated ASCII string of the function
- executing the assert macro.
- @param[in] LineNumber The source file line number of the assert macro.
- @param[in] FileName Null-terminated ASCII string of the filename
- executing the assert macro.
- @param[in] PointerName Null-terminated ASCII string that is a description
- of Pointer.
-
- @retval TRUE Pointer is not equal to NULL.
- @retval FALSE Pointer is equal to NULL.
-**/
-BOOLEAN
-EFIAPI
-UnitTestAssertNotNull (
- IN VOID *Pointer,
- IN CONST CHAR8 *FunctionName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *FileName,
- IN CONST CHAR8 *PointerName
- )
-{
- 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",
- FileName,
- 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: Function call (%a) did not ASSERT()!\n",
- FileName,
- LineNumber,
- FunctionCall
- );
- UnitTestLogFailure (
- FAILURETYPE_EXPECTASSERT,
- "%a:%d: Function call (%a) did not ASSERT()!\n",
- FileName,
- LineNumber,
- FunctionCall
- );
- }
-
- return (UnitTestStatus != UNIT_TEST_ERROR_TEST_FAILED);
-}
+/** + Implement UnitTestLib assert services + + Copyright (c) Microsoft Corporation.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <Uefi.h> +#include <UnitTestFrameworkTypes.h> +#include <Library/UnitTestLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/PrintLib.h> + +extern BASE_LIBRARY_JUMP_BUFFER gUnitTestJumpBuffer; + +STATIC +EFI_STATUS +AddUnitTestFailure ( + IN OUT UNIT_TEST *UnitTest, + IN CONST CHAR8 *FailureMessage, + IN FAILURE_TYPE FailureType + ) +{ + // + // Make sure that you're cooking with gas. + // + if ((UnitTest == NULL) || (FailureMessage == NULL)) { + return EFI_INVALID_PARAMETER; + } + + UnitTest->FailureType = FailureType; + AsciiStrCpyS ( + &UnitTest->FailureMessage[0], + UNIT_TEST_TESTFAILUREMSG_LENGTH, + FailureMessage + ); + + return EFI_SUCCESS; +} + +STATIC +VOID +EFIAPI +UnitTestLogFailure ( + IN FAILURE_TYPE FailureType, + IN CONST CHAR8 *Format, + ... + ) +{ + UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle; + CHAR8 LogString[UNIT_TEST_TESTFAILUREMSG_LENGTH]; + VA_LIST Marker; + + // + // Get active Framework handle + // + FrameworkHandle = GetActiveFrameworkHandle (); + if (FrameworkHandle == NULL) { + DEBUG ((DEBUG_ERROR, "%a - FrameworkHandle not initialized\n", __func__)); + return; + } + + // + // Convert the message to an ASCII String + // + VA_START (Marker, Format); + AsciiVSPrint (LogString, sizeof (LogString), Format, Marker); + VA_END (Marker); + + // + // Finally, add the string to the log. + // + AddUnitTestFailure ( + ((UNIT_TEST_FRAMEWORK *)FrameworkHandle)->CurrentTest, + LogString, + FailureType + ); + + LongJump (&gUnitTestJumpBuffer, 1); +} + +/** + If Expression is TRUE, then TRUE is returned. + If Expression is FALSE, then an assert is triggered and the location of the + assert provided by FunctionName, LineNumber, FileName, and Description are + recorded and FALSE is returned. + + @param[in] Expression The BOOLEAN result of the expression evaluation. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the expression being + evaluated. + + @retval TRUE Expression is TRUE. + @retval FALSE Expression is FALSE. +**/ +BOOLEAN +EFIAPI +UnitTestAssertTrue ( + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + if (!Expression) { + UT_LOG_ERROR ( + "[ASSERT FAIL] %a:%d: Expression (%a) is not TRUE!\n", + FileName, + LineNumber, + Description + ); + UnitTestLogFailure ( + FAILURETYPE_ASSERTTRUE, + "%a:%d: Expression (%a) is not TRUE!\n", + FileName, + LineNumber, + Description + ); + } + + return Expression; +} + +/** + If Expression is FALSE, then TRUE is returned. + If Expression is TRUE, then an assert is triggered and the location of the + assert provided by FunctionName, LineNumber, FileName, and Description are + recorded and FALSE is returned. + + @param[in] Expression The BOOLEAN result of the expression evaluation. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the expression being + evaluated. + + @retval TRUE Expression is FALSE. + @retval FALSE Expression is TRUE. +**/ +BOOLEAN +EFIAPI +UnitTestAssertFalse ( + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + if (Expression) { + UT_LOG_ERROR ( + "[ASSERT FAIL] %a:%d: Expression (%a) is not FALSE!\n", + FileName, + LineNumber, + Description + ); + UnitTestLogFailure ( + FAILURETYPE_ASSERTFALSE, + "%a:%d: Expression(%a) is not FALSE!\n", + FileName, + LineNumber, + Description + ); + } + + return !Expression; +} + +/** + If Status is not an EFI_ERROR(), then TRUE is returned. + If Status is an EFI_ERROR(), then an assert is triggered and the location of + the assert provided by FunctionName, LineNumber, FileName, and Description are + recorded and FALSE is returned. + + @param[in] Status The EFI_STATUS value to evaluate. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the status + expression being evaluated. + + @retval TRUE Status is not an EFI_ERROR(). + @retval FALSE Status is an EFI_ERROR(). +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotEfiError ( + IN EFI_STATUS Status, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + if (EFI_ERROR (Status)) { + UT_LOG_ERROR ( + "[ASSERT FAIL] %a:%d: Status '%a' is EFI_ERROR (%r)!\n", + FileName, + LineNumber, + Description, + Status + ); + UnitTestLogFailure ( + FAILURETYPE_ASSERTNOTEFIERROR, + "%a:%d: Status '%a' is EFI_ERROR (%r)!\n", + FileName, + LineNumber, + Description, + Status + ); + } + + return !EFI_ERROR (Status); +} + +/** + If ValueA is equal ValueB, then TRUE is returned. + If ValueA is not equal to ValueB, then an assert is triggered and the location + of the assert provided by FunctionName, LineNumber, FileName, DescriptionA, + and DescriptionB are recorded and FALSE is returned. + + @param[in] ValueA 64-bit value. + @param[in] ValueB 64-bit value. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a description + of ValueA. + @param[in] DescriptionB Null-terminated ASCII string that is a description + of ValueB. + + @retval TRUE ValueA is equal to ValueB. + @retval FALSE ValueA is not equal to ValueB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertEqual ( + IN UINT64 ValueA, + IN UINT64 ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + if (ValueA != ValueB) { + UT_LOG_ERROR ( + "[ASSERT FAIL] %a:%d: Value %a != %a (%d != %d)!\n", + FileName, + LineNumber, + DescriptionA, + DescriptionB, + ValueA, + ValueB + ); + UnitTestLogFailure ( + FAILURETYPE_ASSERTEQUAL, + "%a:%d: Value %a != %a (%d != %d)!\n", + FileName, + LineNumber, + DescriptionA, + DescriptionB, + ValueA, + ValueB + ); + } + + return (ValueA == ValueB); +} + +/** + If the contents of BufferA are identical to the contents of BufferB, then TRUE + is returned. If the contents of BufferA are not identical to the contents of + BufferB, then an assert is triggered and the location of the assert provided + by FunctionName, LineNumber, FileName, DescriptionA, and DescriptionB are + recorded and FALSE is returned. + + @param[in] BufferA Pointer to a buffer for comparison. + @param[in] BufferB Pointer to a buffer for comparison. + @param[in] Length Number of bytes to compare in BufferA and BufferB. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a description + of BufferA. + @param[in] DescriptionB Null-terminated ASCII string that is a description + of BufferB. + + @retval TRUE The contents of BufferA are identical to the contents of + BufferB. + @retval FALSE The contents of BufferA are not identical to the contents of + BufferB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertMemEqual ( + IN VOID *BufferA, + IN VOID *BufferB, + IN UINTN Length, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + if (CompareMem (BufferA, BufferB, Length) != 0) { + UT_LOG_ERROR ( + "[ASSERT FAIL] %a:%d: Value %a != %a for length %d bytes!\n", + FileName, + LineNumber, + DescriptionA, + DescriptionB, + Length + ); + UnitTestLogFailure ( + FAILURETYPE_ASSERTEQUAL, + "%a:%d: Memory at %a != %a for length %d bytes!\n", + FileName, + LineNumber, + DescriptionA, + DescriptionB, + Length + ); + return FALSE; + } + + return TRUE; +} + +/** + If ValueA is not equal ValueB, then TRUE is returned. + If ValueA is equal to ValueB, then an assert is triggered and the location + of the assert provided by FunctionName, LineNumber, FileName, DescriptionA + and DescriptionB are recorded and FALSE is returned. + + @param[in] ValueA 64-bit value. + @param[in] ValueB 64-bit value. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a description + of ValueA. + @param[in] DescriptionB Null-terminated ASCII string that is a description + of ValueB. + + @retval TRUE ValueA is not equal to ValueB. + @retval FALSE ValueA is equal to ValueB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotEqual ( + IN UINT64 ValueA, + IN UINT64 ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + if (ValueA == ValueB) { + UT_LOG_ERROR ( + "[ASSERT FAIL] %a:%d: Value %a == %a (%d == %d)!\n", + FileName, + LineNumber, + DescriptionA, + DescriptionB, + ValueA, + ValueB + ); + UnitTestLogFailure ( + FAILURETYPE_ASSERTNOTEQUAL, + "%a:%d: Value %a == %a (%d == %d)!\n", + FileName, + LineNumber, + DescriptionA, + DescriptionB, + ValueA, + ValueB + ); + } + + return (ValueA != ValueB); +} + +/** + If Status is equal to Expected, then TRUE is returned. + If Status is not equal to Expected, then an assert is triggered and the + location of the assert provided by FunctionName, LineNumber, FileName, and + Description are recorded and FALSE is returned. + + @param[in] Status EFI_STATUS value returned from an API under test. + @param[in] Expected The expected EFI_STATUS return value from an API + under test. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string that is a description + of Status. + + @retval TRUE Status is equal to Expected. + @retval FALSE Status is not equal to Expected. +**/ +BOOLEAN +EFIAPI +UnitTestAssertStatusEqual ( + IN EFI_STATUS Status, + IN EFI_STATUS Expected, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + if (Status != Expected) { + UT_LOG_ERROR ( + "[ASSERT FAIL] %a:%d: Status '%a' is %r, should be %r!\n", + FileName, + LineNumber, + Description, + Status, + Expected + ); + UnitTestLogFailure ( + FAILURETYPE_ASSERTSTATUSEQUAL, + "%a:%d: Status '%a' is %r, should be %r!\n", + FileName, + LineNumber, + Description, + Status, + Expected + ); + } + + return (Status == Expected); +} + +/** + If Pointer is not equal to NULL, then TRUE is returned. + If Pointer is equal to NULL, then an assert is triggered and the location of + the assert provided by FunctionName, LineNumber, FileName, and PointerName + are recorded and FALSE is returned. + + @param[in] Pointer Pointer value to be checked against NULL. + @param[in] Expected The expected EFI_STATUS return value from a function + under test. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] PointerName Null-terminated ASCII string that is a description + of Pointer. + + @retval TRUE Pointer is not equal to NULL. + @retval FALSE Pointer is equal to NULL. +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotNull ( + IN VOID *Pointer, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *PointerName + ) +{ + 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", + FileName, + 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: Function call (%a) did not ASSERT()!\n", + FileName, + LineNumber, + FunctionCall + ); + UnitTestLogFailure ( + FAILURETYPE_EXPECTASSERT, + "%a:%d: Function call (%a) did not ASSERT()!\n", + FileName, + LineNumber, + FunctionCall + ); + } + + return (UnitTestStatus != UNIT_TEST_ERROR_TEST_FAILED); +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c b/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c index 0d8e36c938..6ba115f468 100644 --- a/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c @@ -1,407 +1,407 @@ -/** @file
- Implement UnitTestLib assert services using cmocka services
-
- Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-**/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <setjmp.h>
-#include <cmocka.h>
-
-#include <Uefi.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/UnitTestLib.h>
-
-#define MAX_STRING_SIZE 1025
-
-/**
- If Expression is TRUE, then TRUE is returned.
- If Expression is FALSE, then an assert is triggered and the location of the
- assert provided by FunctionName, LineNumber, FileName, and Description are
- recorded and FALSE is returned.
-
- @param[in] Expression The BOOLEAN result of the expression evaluation.
- @param[in] FunctionName Null-terminated ASCII string of the function
- executing the assert macro.
- @param[in] LineNumber The source file line number of the assert macro.
- @param[in] FileName Null-terminated ASCII string of the filename
- executing the assert macro.
- @param[in] Description Null-terminated ASCII string of the expression being
- evaluated.
-
- @retval TRUE Expression is TRUE.
- @retval FALSE Expression is FALSE.
-**/
-BOOLEAN
-EFIAPI
-UnitTestAssertTrue (
- IN BOOLEAN Expression,
- IN CONST CHAR8 *FunctionName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *FileName,
- IN CONST CHAR8 *Description
- )
-{
- CHAR8 TempStr[MAX_STRING_SIZE];
-
- snprintf (TempStr, sizeof (TempStr), "UT_ASSERT_TRUE(%s:%x)", Description, Expression);
- _assert_true (Expression, TempStr, FileName, (INT32)LineNumber);
-
- return Expression;
-}
-
-/**
- If Expression is FALSE, then TRUE is returned.
- If Expression is TRUE, then an assert is triggered and the location of the
- assert provided by FunctionName, LineNumber, FileName, and Description are
- recorded and FALSE is returned.
-
- @param[in] Expression The BOOLEAN result of the expression evaluation.
- @param[in] FunctionName Null-terminated ASCII string of the function
- executing the assert macro.
- @param[in] LineNumber The source file line number of the assert macro.
- @param[in] FileName Null-terminated ASCII string of the filename
- executing the assert macro.
- @param[in] Description Null-terminated ASCII string of the expression being
- evaluated.
-
- @retval TRUE Expression is FALSE.
- @retval FALSE Expression is TRUE.
-**/
-BOOLEAN
-EFIAPI
-UnitTestAssertFalse (
- IN BOOLEAN Expression,
- IN CONST CHAR8 *FunctionName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *FileName,
- IN CONST CHAR8 *Description
- )
-{
- CHAR8 TempStr[MAX_STRING_SIZE];
-
- snprintf (TempStr, sizeof (TempStr), "UT_ASSERT_FALSE(%s:%x)", Description, Expression);
- _assert_true (!Expression, TempStr, FileName, (INT32)LineNumber);
-
- return !Expression;
-}
-
-/**
- If Status is not an EFI_ERROR(), then TRUE is returned.
- If Status is an EFI_ERROR(), then an assert is triggered and the location of
- the assert provided by FunctionName, LineNumber, FileName, and Description are
- recorded and FALSE is returned.
-
- @param[in] Status The EFI_STATUS value to evaluate.
- @param[in] FunctionName Null-terminated ASCII string of the function
- executing the assert macro.
- @param[in] LineNumber The source file line number of the assert macro.
- @param[in] FileName Null-terminated ASCII string of the filename
- executing the assert macro.
- @param[in] Description Null-terminated ASCII string of the status
- expression being evaluated.
-
- @retval TRUE Status is not an EFI_ERROR().
- @retval FALSE Status is an EFI_ERROR().
-**/
-BOOLEAN
-EFIAPI
-UnitTestAssertNotEfiError (
- IN EFI_STATUS Status,
- IN CONST CHAR8 *FunctionName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *FileName,
- IN CONST CHAR8 *Description
- )
-{
- CHAR8 TempStr[MAX_STRING_SIZE];
-
- snprintf (TempStr, sizeof (TempStr), "UT_ASSERT_NOT_EFI_ERROR(%s:%p)", Description, (void *)Status);
- _assert_true (!EFI_ERROR (Status), TempStr, FileName, (INT32)LineNumber);
-
- return !EFI_ERROR (Status);
-}
-
-/**
- If ValueA is equal ValueB, then TRUE is returned.
- If ValueA is not equal to ValueB, then an assert is triggered and the location
- of the assert provided by FunctionName, LineNumber, FileName, DescriptionA,
- and DescriptionB are recorded and FALSE is returned.
-
- @param[in] ValueA 64-bit value.
- @param[in] ValueB 64-bit value.
- @param[in] FunctionName Null-terminated ASCII string of the function
- executing the assert macro.
- @param[in] LineNumber The source file line number of the assert macro.
- @param[in] FileName Null-terminated ASCII string of the filename
- executing the assert macro.
- @param[in] DescriptionA Null-terminated ASCII string that is a description
- of ValueA.
- @param[in] DescriptionB Null-terminated ASCII string that is a description
- of ValueB.
-
- @retval TRUE ValueA is equal to ValueB.
- @retval FALSE ValueA is not equal to ValueB.
-**/
-BOOLEAN
-EFIAPI
-UnitTestAssertEqual (
- IN UINT64 ValueA,
- IN UINT64 ValueB,
- IN CONST CHAR8 *FunctionName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *FileName,
- IN CONST CHAR8 *DescriptionA,
- IN CONST CHAR8 *DescriptionB
- )
-{
- CHAR8 TempStr[MAX_STRING_SIZE];
-
- snprintf (TempStr, sizeof (TempStr), "UT_ASSERT_EQUAL(%s:%llx, %s:%llx)", DescriptionA, ValueA, DescriptionB, ValueB);
- _assert_true ((ValueA == ValueB), TempStr, FileName, (INT32)LineNumber);
-
- return (ValueA == ValueB);
-}
-
-/**
- If the contents of BufferA are identical to the contents of BufferB, then TRUE
- is returned. If the contents of BufferA are not identical to the contents of
- BufferB, then an assert is triggered and the location of the assert provided
- by FunctionName, LineNumber, FileName, DescriptionA, and DescriptionB are
- recorded and FALSE is returned.
-
- @param[in] BufferA Pointer to a buffer for comparison.
- @param[in] BufferB Pointer to a buffer for comparison.
- @param[in] Length Number of bytes to compare in BufferA and BufferB.
- @param[in] FunctionName Null-terminated ASCII string of the function
- executing the assert macro.
- @param[in] LineNumber The source file line number of the assert macro.
- @param[in] FileName Null-terminated ASCII string of the filename
- executing the assert macro.
- @param[in] DescriptionA Null-terminated ASCII string that is a description
- of BufferA.
- @param[in] DescriptionB Null-terminated ASCII string that is a description
- of BufferB.
-
- @retval TRUE The contents of BufferA are identical to the contents of
- BufferB.
- @retval FALSE The contents of BufferA are not identical to the contents of
- BufferB.
-**/
-BOOLEAN
-EFIAPI
-UnitTestAssertMemEqual (
- IN VOID *BufferA,
- IN VOID *BufferB,
- IN UINTN Length,
- IN CONST CHAR8 *FunctionName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *FileName,
- IN CONST CHAR8 *DescriptionA,
- IN CONST CHAR8 *DescriptionB
- )
-{
- CHAR8 TempStr[MAX_STRING_SIZE];
- BOOLEAN Result;
-
- Result = (CompareMem (BufferA, BufferB, Length) == 0);
-
- snprintf (TempStr, sizeof (TempStr), "UT_ASSERT_MEM_EQUAL(%s:%p, %s:%p)", DescriptionA, BufferA, DescriptionB, BufferB);
- _assert_true (Result, TempStr, FileName, (INT32)LineNumber);
-
- return Result;
-}
-
-/**
- If ValueA is not equal ValueB, then TRUE is returned.
- If ValueA is equal to ValueB, then an assert is triggered and the location
- of the assert provided by FunctionName, LineNumber, FileName, DescriptionA
- and DescriptionB are recorded and FALSE is returned.
-
- @param[in] ValueA 64-bit value.
- @param[in] ValueB 64-bit value.
- @param[in] FunctionName Null-terminated ASCII string of the function
- executing the assert macro.
- @param[in] LineNumber The source file line number of the assert macro.
- @param[in] FileName Null-terminated ASCII string of the filename
- executing the assert macro.
- @param[in] DescriptionA Null-terminated ASCII string that is a description
- of ValueA.
- @param[in] DescriptionB Null-terminated ASCII string that is a description
- of ValueB.
-
- @retval TRUE ValueA is not equal to ValueB.
- @retval FALSE ValueA is equal to ValueB.
-**/
-BOOLEAN
-EFIAPI
-UnitTestAssertNotEqual (
- IN UINT64 ValueA,
- IN UINT64 ValueB,
- IN CONST CHAR8 *FunctionName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *FileName,
- IN CONST CHAR8 *DescriptionA,
- IN CONST CHAR8 *DescriptionB
- )
-{
- CHAR8 TempStr[MAX_STRING_SIZE];
-
- snprintf (TempStr, sizeof (TempStr), "UT_ASSERT_NOT_EQUAL(%s:%llx, %s:%llx)", DescriptionA, ValueA, DescriptionB, ValueB);
- _assert_true ((ValueA != ValueB), TempStr, FileName, (INT32)LineNumber);
-
- return (ValueA != ValueB);
-}
-
-/**
- If Status is equal to Expected, then TRUE is returned.
- If Status is not equal to Expected, then an assert is triggered and the
- location of the assert provided by FunctionName, LineNumber, FileName, and
- Description are recorded and FALSE is returned.
-
- @param[in] Status EFI_STATUS value returned from an API under test.
- @param[in] Expected The expected EFI_STATUS return value from an API
- under test.
- @param[in] FunctionName Null-terminated ASCII string of the function
- executing the assert macro.
- @param[in] LineNumber The source file line number of the assert macro.
- @param[in] FileName Null-terminated ASCII string of the filename
- executing the assert macro.
- @param[in] Description Null-terminated ASCII string that is a description
- of Status.
-
- @retval TRUE Status is equal to Expected.
- @retval FALSE Status is not equal to Expected.
-**/
-BOOLEAN
-EFIAPI
-UnitTestAssertStatusEqual (
- IN EFI_STATUS Status,
- IN EFI_STATUS Expected,
- IN CONST CHAR8 *FunctionName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *FileName,
- IN CONST CHAR8 *Description
- )
-{
- CHAR8 TempStr[MAX_STRING_SIZE];
-
- snprintf (TempStr, sizeof (TempStr), "UT_ASSERT_STATUS_EQUAL(%s:%p expected:%p)", Description, (VOID *)Status, (VOID *)Expected);
- _assert_true ((Status == Expected), TempStr, FileName, (INT32)LineNumber);
-
- return (Status == Expected);
-}
-
-/**
- If Pointer is not equal to NULL, then TRUE is returned.
- If Pointer is equal to NULL, then an assert is triggered and the location of
- the assert provided by FunctionName, LineNumber, FileName, and PointerName
- are recorded and FALSE is returned.
-
- @param[in] Pointer Pointer value to be checked against NULL.
- @param[in] Expected The expected EFI_STATUS return value from a function
- under test.
- @param[in] FunctionName Null-terminated ASCII string of the function
- executing the assert macro.
- @param[in] LineNumber The source file line number of the assert macro.
- @param[in] FileName Null-terminated ASCII string of the filename
- executing the assert macro.
- @param[in] PointerName Null-terminated ASCII string that is a description
- of Pointer.
-
- @retval TRUE Pointer is not equal to NULL.
- @retval FALSE Pointer is equal to NULL.
-**/
-BOOLEAN
-EFIAPI
-UnitTestAssertNotNull (
- IN VOID *Pointer,
- IN CONST CHAR8 *FunctionName,
- IN UINTN LineNumber,
- IN CONST CHAR8 *FileName,
- IN CONST CHAR8 *PointerName
- )
-{
- CHAR8 TempStr[MAX_STRING_SIZE];
-
- snprintf (TempStr, sizeof (TempStr), "UT_ASSERT_NOT_NULL(%s:%p)", PointerName, Pointer);
- _assert_true ((Pointer != NULL), TempStr, FileName, (INT32)LineNumber);
-
- 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);
-}
+/** @file + Implement UnitTestLib assert services using cmocka services + + Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <cmocka.h> + +#include <Uefi.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UnitTestLib.h> + +#define MAX_STRING_SIZE 1025 + +/** + If Expression is TRUE, then TRUE is returned. + If Expression is FALSE, then an assert is triggered and the location of the + assert provided by FunctionName, LineNumber, FileName, and Description are + recorded and FALSE is returned. + + @param[in] Expression The BOOLEAN result of the expression evaluation. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the expression being + evaluated. + + @retval TRUE Expression is TRUE. + @retval FALSE Expression is FALSE. +**/ +BOOLEAN +EFIAPI +UnitTestAssertTrue ( + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof (TempStr), "UT_ASSERT_TRUE(%s:%x)", Description, Expression); + _assert_true (Expression, TempStr, FileName, (INT32)LineNumber); + + return Expression; +} + +/** + If Expression is FALSE, then TRUE is returned. + If Expression is TRUE, then an assert is triggered and the location of the + assert provided by FunctionName, LineNumber, FileName, and Description are + recorded and FALSE is returned. + + @param[in] Expression The BOOLEAN result of the expression evaluation. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the expression being + evaluated. + + @retval TRUE Expression is FALSE. + @retval FALSE Expression is TRUE. +**/ +BOOLEAN +EFIAPI +UnitTestAssertFalse ( + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof (TempStr), "UT_ASSERT_FALSE(%s:%x)", Description, Expression); + _assert_true (!Expression, TempStr, FileName, (INT32)LineNumber); + + return !Expression; +} + +/** + If Status is not an EFI_ERROR(), then TRUE is returned. + If Status is an EFI_ERROR(), then an assert is triggered and the location of + the assert provided by FunctionName, LineNumber, FileName, and Description are + recorded and FALSE is returned. + + @param[in] Status The EFI_STATUS value to evaluate. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the status + expression being evaluated. + + @retval TRUE Status is not an EFI_ERROR(). + @retval FALSE Status is an EFI_ERROR(). +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotEfiError ( + IN EFI_STATUS Status, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof (TempStr), "UT_ASSERT_NOT_EFI_ERROR(%s:%p)", Description, (void *)Status); + _assert_true (!EFI_ERROR (Status), TempStr, FileName, (INT32)LineNumber); + + return !EFI_ERROR (Status); +} + +/** + If ValueA is equal ValueB, then TRUE is returned. + If ValueA is not equal to ValueB, then an assert is triggered and the location + of the assert provided by FunctionName, LineNumber, FileName, DescriptionA, + and DescriptionB are recorded and FALSE is returned. + + @param[in] ValueA 64-bit value. + @param[in] ValueB 64-bit value. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a description + of ValueA. + @param[in] DescriptionB Null-terminated ASCII string that is a description + of ValueB. + + @retval TRUE ValueA is equal to ValueB. + @retval FALSE ValueA is not equal to ValueB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertEqual ( + IN UINT64 ValueA, + IN UINT64 ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof (TempStr), "UT_ASSERT_EQUAL(%s:%llx, %s:%llx)", DescriptionA, ValueA, DescriptionB, ValueB); + _assert_true ((ValueA == ValueB), TempStr, FileName, (INT32)LineNumber); + + return (ValueA == ValueB); +} + +/** + If the contents of BufferA are identical to the contents of BufferB, then TRUE + is returned. If the contents of BufferA are not identical to the contents of + BufferB, then an assert is triggered and the location of the assert provided + by FunctionName, LineNumber, FileName, DescriptionA, and DescriptionB are + recorded and FALSE is returned. + + @param[in] BufferA Pointer to a buffer for comparison. + @param[in] BufferB Pointer to a buffer for comparison. + @param[in] Length Number of bytes to compare in BufferA and BufferB. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a description + of BufferA. + @param[in] DescriptionB Null-terminated ASCII string that is a description + of BufferB. + + @retval TRUE The contents of BufferA are identical to the contents of + BufferB. + @retval FALSE The contents of BufferA are not identical to the contents of + BufferB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertMemEqual ( + IN VOID *BufferA, + IN VOID *BufferB, + IN UINTN Length, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + BOOLEAN Result; + + Result = (CompareMem (BufferA, BufferB, Length) == 0); + + snprintf (TempStr, sizeof (TempStr), "UT_ASSERT_MEM_EQUAL(%s:%p, %s:%p)", DescriptionA, BufferA, DescriptionB, BufferB); + _assert_true (Result, TempStr, FileName, (INT32)LineNumber); + + return Result; +} + +/** + If ValueA is not equal ValueB, then TRUE is returned. + If ValueA is equal to ValueB, then an assert is triggered and the location + of the assert provided by FunctionName, LineNumber, FileName, DescriptionA + and DescriptionB are recorded and FALSE is returned. + + @param[in] ValueA 64-bit value. + @param[in] ValueB 64-bit value. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a description + of ValueA. + @param[in] DescriptionB Null-terminated ASCII string that is a description + of ValueB. + + @retval TRUE ValueA is not equal to ValueB. + @retval FALSE ValueA is equal to ValueB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotEqual ( + IN UINT64 ValueA, + IN UINT64 ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof (TempStr), "UT_ASSERT_NOT_EQUAL(%s:%llx, %s:%llx)", DescriptionA, ValueA, DescriptionB, ValueB); + _assert_true ((ValueA != ValueB), TempStr, FileName, (INT32)LineNumber); + + return (ValueA != ValueB); +} + +/** + If Status is equal to Expected, then TRUE is returned. + If Status is not equal to Expected, then an assert is triggered and the + location of the assert provided by FunctionName, LineNumber, FileName, and + Description are recorded and FALSE is returned. + + @param[in] Status EFI_STATUS value returned from an API under test. + @param[in] Expected The expected EFI_STATUS return value from an API + under test. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string that is a description + of Status. + + @retval TRUE Status is equal to Expected. + @retval FALSE Status is not equal to Expected. +**/ +BOOLEAN +EFIAPI +UnitTestAssertStatusEqual ( + IN EFI_STATUS Status, + IN EFI_STATUS Expected, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof (TempStr), "UT_ASSERT_STATUS_EQUAL(%s:%p expected:%p)", Description, (VOID *)Status, (VOID *)Expected); + _assert_true ((Status == Expected), TempStr, FileName, (INT32)LineNumber); + + return (Status == Expected); +} + +/** + If Pointer is not equal to NULL, then TRUE is returned. + If Pointer is equal to NULL, then an assert is triggered and the location of + the assert provided by FunctionName, LineNumber, FileName, and PointerName + are recorded and FALSE is returned. + + @param[in] Pointer Pointer value to be checked against NULL. + @param[in] Expected The expected EFI_STATUS return value from a function + under test. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] PointerName Null-terminated ASCII string that is a description + of Pointer. + + @retval TRUE Pointer is not equal to NULL. + @retval FALSE Pointer is equal to NULL. +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotNull ( + IN VOID *Pointer, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *PointerName + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof (TempStr), "UT_ASSERT_NOT_NULL(%s:%p)", PointerName, Pointer); + _assert_true ((Pointer != NULL), TempStr, FileName, (INT32)LineNumber); + + 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/Log.c b/UnitTestFrameworkPkg/Library/UnitTestLib/Log.c index f61b9d57b1..0f0dc1f868 100644 --- a/UnitTestFrameworkPkg/Library/UnitTestLib/Log.c +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/Log.c @@ -1,205 +1,205 @@ -/**
- Implemnet UnitTestLib log services
-
- Copyright (c) Microsoft Corporation.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-**/
-
-#include <PiDxe.h>
-#include <UnitTestFrameworkTypes.h>
-#include <Library/UnitTestLib.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/DebugLib.h>
-#include <Library/PrintLib.h>
-#include <Library/PcdLib.h>
-
-#define UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH (512)
-#define UNIT_TEST_MAX_LOG_BUFFER SIZE_16KB
-
-struct _UNIT_TEST_LOG_PREFIX_STRING {
- UNIT_TEST_STATUS LogLevel;
- CHAR8 *String;
-};
-
-struct _UNIT_TEST_LOG_PREFIX_STRING mLogPrefixStrings[] = {
- { UNIT_TEST_LOG_LEVEL_ERROR, "[ERROR] " },
- { UNIT_TEST_LOG_LEVEL_WARN, "[WARNING] " },
- { UNIT_TEST_LOG_LEVEL_INFO, "[INFO] " },
- { UNIT_TEST_LOG_LEVEL_VERBOSE, "[VERBOSE] " }
-};
-
-//
-// Unit-Test Log helper functions
-//
-
-STATIC
-CONST CHAR8 *
-GetStringForStatusLogPrefix (
- IN UINTN LogLevel
- )
-{
- UINTN Index;
- CHAR8 *Result;
-
- Result = NULL;
- for (Index = 0; Index < ARRAY_SIZE (mLogPrefixStrings); Index++) {
- if (mLogPrefixStrings[Index].LogLevel == LogLevel) {
- Result = mLogPrefixStrings[Index].String;
- break;
- }
- }
-
- return Result;
-}
-
-STATIC
-EFI_STATUS
-AddStringToUnitTestLog (
- IN OUT UNIT_TEST *UnitTest,
- IN CONST CHAR8 *String
- )
-{
- EFI_STATUS Status;
-
- //
- // Make sure that you're cooking with gas.
- //
- if ((UnitTest == NULL) || (String == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- // If this is the first log for the test allocate log space
- if (UnitTest->Log == NULL) {
- UnitTestLogInit (UnitTest, NULL, 0);
- }
-
- if (UnitTest->Log == NULL) {
- DEBUG ((DEBUG_ERROR, "Failed to allocate space for unit test log\n"));
- ASSERT (UnitTest->Log != NULL);
- return EFI_OUT_OF_RESOURCES;
- }
-
- Status = AsciiStrnCatS (
- UnitTest->Log,
- UNIT_TEST_MAX_LOG_BUFFER / sizeof (CHAR8),
- String,
- UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Failed to add unit test log string. Status = %r\n", Status));
- return Status;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- This function is responsible for initializing the log buffer for a single test. It can
- be used internally, but may also be consumed by the test framework to add pre-existing
- data to a log before it's used.
-
- @param[in,out] TestHandle A handle to the test being initialized.
- @param[in] Buffer [Optional] A pointer to pre-existing log data that should
- be used to initialize the log. Should include a NULL terminator.
- @param[in] BufferSize [Optional] The size of the pre-existing log data.
-
-**/
-VOID
-EFIAPI
-UnitTestLogInit (
- IN OUT UNIT_TEST *Test,
- IN UINT8 *Buffer OPTIONAL,
- IN UINTN BufferSize OPTIONAL
- )
-{
- //
- // Make sure that you're cooking with gas.
- //
- if (Test == NULL) {
- DEBUG ((DEBUG_ERROR, "%a called with invalid Test parameter\n", __func__));
- return;
- }
-
- //
- // If this is the first log for the test allocate log space
- //
- if (Test->Log == NULL) {
- Test->Log = AllocateZeroPool (UNIT_TEST_MAX_LOG_BUFFER);
- }
-
- //
- // check again to make sure allocate worked
- //
- if (Test->Log == NULL) {
- DEBUG ((DEBUG_ERROR, "Failed to allocate memory for the log\n"));
- return;
- }
-
- if ((Buffer != NULL) && (BufferSize > 0) && (BufferSize <= UNIT_TEST_MAX_LOG_BUFFER)) {
- CopyMem (Test->Log, Buffer, BufferSize);
- }
-}
-
-/**
- Test logging function that records a messages in the test framework log.
- Record is associated with the currently executing test case.
-
- @param[in] ErrorLevel The error level of the unit test log message.
- @param[in] Format Formatting string following the format defined in the
- MdePkg/Include/Library/PrintLib.h.
- @param[in] ... Print args.
-**/
-VOID
-EFIAPI
-UnitTestLog (
- IN UINTN ErrorLevel,
- IN CONST CHAR8 *Format,
- ...
- )
-{
- UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle;
- CHAR8 NewFormatString[UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH];
- CHAR8 LogString[UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH];
- CONST CHAR8 *LogTypePrefix;
- VA_LIST Marker;
-
- FrameworkHandle = GetActiveFrameworkHandle ();
- if (FrameworkHandle == NULL) {
- DEBUG ((DEBUG_ERROR, "%a - FrameworkHandle not initialized\n", __func__));
- return;
- }
-
- LogTypePrefix = NULL;
-
- //
- // Make sure that this unit test log level is enabled.
- //
- if ((ErrorLevel & (UINTN)PcdGet32 (PcdUnitTestLogLevel)) == 0) {
- return;
- }
-
- //
- // If we need to define a new format string...
- // well... get to it.
- //
- LogTypePrefix = GetStringForStatusLogPrefix (ErrorLevel);
- if (LogTypePrefix != NULL) {
- AsciiSPrint (NewFormatString, sizeof (NewFormatString), "%a%a", LogTypePrefix, Format);
- } else {
- AsciiStrCpyS (NewFormatString, sizeof (NewFormatString), Format);
- }
-
- //
- // Convert the message to an ASCII String
- //
- VA_START (Marker, Format);
- AsciiVSPrint (LogString, sizeof (LogString), NewFormatString, Marker);
- VA_END (Marker);
-
- //
- // Finally, add the string to the log.
- //
- AddStringToUnitTestLog (((UNIT_TEST_FRAMEWORK *)FrameworkHandle)->CurrentTest, LogString);
-}
+/** + Implemnet UnitTestLib log services + + Copyright (c) Microsoft Corporation.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <PiDxe.h> +#include <UnitTestFrameworkTypes.h> +#include <Library/UnitTestLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DebugLib.h> +#include <Library/PrintLib.h> +#include <Library/PcdLib.h> + +#define UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH (512) +#define UNIT_TEST_MAX_LOG_BUFFER SIZE_16KB + +struct _UNIT_TEST_LOG_PREFIX_STRING { + UNIT_TEST_STATUS LogLevel; + CHAR8 *String; +}; + +struct _UNIT_TEST_LOG_PREFIX_STRING mLogPrefixStrings[] = { + { UNIT_TEST_LOG_LEVEL_ERROR, "[ERROR] " }, + { UNIT_TEST_LOG_LEVEL_WARN, "[WARNING] " }, + { UNIT_TEST_LOG_LEVEL_INFO, "[INFO] " }, + { UNIT_TEST_LOG_LEVEL_VERBOSE, "[VERBOSE] " } +}; + +// +// Unit-Test Log helper functions +// + +STATIC +CONST CHAR8 * +GetStringForStatusLogPrefix ( + IN UINTN LogLevel + ) +{ + UINTN Index; + CHAR8 *Result; + + Result = NULL; + for (Index = 0; Index < ARRAY_SIZE (mLogPrefixStrings); Index++) { + if (mLogPrefixStrings[Index].LogLevel == LogLevel) { + Result = mLogPrefixStrings[Index].String; + break; + } + } + + return Result; +} + +STATIC +EFI_STATUS +AddStringToUnitTestLog ( + IN OUT UNIT_TEST *UnitTest, + IN CONST CHAR8 *String + ) +{ + EFI_STATUS Status; + + // + // Make sure that you're cooking with gas. + // + if ((UnitTest == NULL) || (String == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // If this is the first log for the test allocate log space + if (UnitTest->Log == NULL) { + UnitTestLogInit (UnitTest, NULL, 0); + } + + if (UnitTest->Log == NULL) { + DEBUG ((DEBUG_ERROR, "Failed to allocate space for unit test log\n")); + ASSERT (UnitTest->Log != NULL); + return EFI_OUT_OF_RESOURCES; + } + + Status = AsciiStrnCatS ( + UnitTest->Log, + UNIT_TEST_MAX_LOG_BUFFER / sizeof (CHAR8), + String, + UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to add unit test log string. Status = %r\n", Status)); + return Status; + } + + return EFI_SUCCESS; +} + +/** + This function is responsible for initializing the log buffer for a single test. It can + be used internally, but may also be consumed by the test framework to add pre-existing + data to a log before it's used. + + @param[in,out] TestHandle A handle to the test being initialized. + @param[in] Buffer [Optional] A pointer to pre-existing log data that should + be used to initialize the log. Should include a NULL terminator. + @param[in] BufferSize [Optional] The size of the pre-existing log data. + +**/ +VOID +EFIAPI +UnitTestLogInit ( + IN OUT UNIT_TEST *Test, + IN UINT8 *Buffer OPTIONAL, + IN UINTN BufferSize OPTIONAL + ) +{ + // + // Make sure that you're cooking with gas. + // + if (Test == NULL) { + DEBUG ((DEBUG_ERROR, "%a called with invalid Test parameter\n", __func__)); + return; + } + + // + // If this is the first log for the test allocate log space + // + if (Test->Log == NULL) { + Test->Log = AllocateZeroPool (UNIT_TEST_MAX_LOG_BUFFER); + } + + // + // check again to make sure allocate worked + // + if (Test->Log == NULL) { + DEBUG ((DEBUG_ERROR, "Failed to allocate memory for the log\n")); + return; + } + + if ((Buffer != NULL) && (BufferSize > 0) && (BufferSize <= UNIT_TEST_MAX_LOG_BUFFER)) { + CopyMem (Test->Log, Buffer, BufferSize); + } +} + +/** + Test logging function that records a messages in the test framework log. + Record is associated with the currently executing test case. + + @param[in] ErrorLevel The error level of the unit test log message. + @param[in] Format Formatting string following the format defined in the + MdePkg/Include/Library/PrintLib.h. + @param[in] ... Print args. +**/ +VOID +EFIAPI +UnitTestLog ( + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + ... + ) +{ + UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle; + CHAR8 NewFormatString[UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH]; + CHAR8 LogString[UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH]; + CONST CHAR8 *LogTypePrefix; + VA_LIST Marker; + + FrameworkHandle = GetActiveFrameworkHandle (); + if (FrameworkHandle == NULL) { + DEBUG ((DEBUG_ERROR, "%a - FrameworkHandle not initialized\n", __func__)); + return; + } + + LogTypePrefix = NULL; + + // + // Make sure that this unit test log level is enabled. + // + if ((ErrorLevel & (UINTN)PcdGet32 (PcdUnitTestLogLevel)) == 0) { + return; + } + + // + // If we need to define a new format string... + // well... get to it. + // + LogTypePrefix = GetStringForStatusLogPrefix (ErrorLevel); + if (LogTypePrefix != NULL) { + AsciiSPrint (NewFormatString, sizeof (NewFormatString), "%a%a", LogTypePrefix, Format); + } else { + AsciiStrCpyS (NewFormatString, sizeof (NewFormatString), Format); + } + + // + // Convert the message to an ASCII String + // + VA_START (Marker, Format); + AsciiVSPrint (LogString, sizeof (LogString), NewFormatString, Marker); + VA_END (Marker); + + // + // Finally, add the string to the log. + // + AddStringToUnitTestLog (((UNIT_TEST_FRAMEWORK *)FrameworkHandle)->CurrentTest, LogString); +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c index dc1b6147d2..16abc7db00 100644 --- a/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c @@ -1,187 +1,187 @@ -/**
- UnitTestLib APIs to run unit tests
-
- Copyright (c) Microsoft Corporation.
- SPDX-License-Identifier: BSD-2-Clause-Patent
-**/
-
-#include <Uefi.h>
-#include <Library/UnitTestLib.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/DebugLib.h>
-#include <Library/UnitTestResultReportLib.h>
-
-STATIC UNIT_TEST_FRAMEWORK_HANDLE mFrameworkHandle = NULL;
-
-BASE_LIBRARY_JUMP_BUFFER gUnitTestJumpBuffer;
-
-UNIT_TEST_FRAMEWORK_HANDLE
-GetActiveFrameworkHandle (
- VOID
- )
-{
- return mFrameworkHandle;
-}
-
-STATIC
-EFI_STATUS
-RunTestSuite (
- IN UNIT_TEST_SUITE *Suite
- )
-{
- UNIT_TEST_LIST_ENTRY *TestEntry;
- UNIT_TEST *Test;
- UNIT_TEST_FRAMEWORK *ParentFramework;
-
- if (Suite == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- TestEntry = NULL;
- ParentFramework = (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework;
-
- DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));
- DEBUG ((DEBUG_VERBOSE, "RUNNING TEST SUITE: %a\n", Suite->Title));
- DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));
-
- if (Suite->Setup != NULL) {
- Suite->Setup ();
- }
-
- //
- // Iterate all tests within the suite
- //
- for (TestEntry = (UNIT_TEST_LIST_ENTRY *)GetFirstNode (&(Suite->TestCaseList));
- (LIST_ENTRY *)TestEntry != &(Suite->TestCaseList);
- TestEntry = (UNIT_TEST_LIST_ENTRY *)GetNextNode (&(Suite->TestCaseList), (LIST_ENTRY *)TestEntry))
- {
- Test = &TestEntry->UT;
- ParentFramework->CurrentTest = Test;
-
- DEBUG ((DEBUG_VERBOSE, "*********************************************************\n"));
- DEBUG ((DEBUG_VERBOSE, " RUNNING TEST: %a:\n", Test->Description));
- DEBUG ((DEBUG_VERBOSE, "**********************************************************\n"));
-
- //
- // First, check to see whether the test has already been run.
- // NOTE: This would generally only be the case if a saved state was detected and loaded.
- //
- if ((Test->Result != UNIT_TEST_PENDING) && (Test->Result != UNIT_TEST_RUNNING)) {
- DEBUG ((DEBUG_VERBOSE, "Test was run on a previous pass. Skipping.\n"));
- ParentFramework->CurrentTest = NULL;
- continue;
- }
-
- //
- // 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 (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;
- continue;
- }
- }
-
- //
- // Now we should be ready to call the actual test.
- // 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.
- 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"));
- if (SetJump (&gUnitTestJumpBuffer) == 0) {
- Test->CleanUp (Test->Context);
- }
- }
-
- //
- // End the test.
- //
- ParentFramework->CurrentTest = NULL;
- }
-
- if (Suite->Teardown != NULL) {
- Suite->Teardown ();
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Execute all unit test cases in all unit test suites added to a Framework.
-
- Once a unit test framework is initialized and all unit test suites and unit
- test cases are registered, this function will cause the unit test framework to
- dispatch all unit test cases in sequence and record the results for reporting.
-
- @param[in] FrameworkHandle A handle to the current running framework that
- dispatched the test. Necessary for recording
- certain test events with the framework.
-
- @retval EFI_SUCCESS All test cases were dispatched.
- @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.
-**/
-EFI_STATUS
-EFIAPI
-RunAllTestSuites (
- IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
- )
-{
- UNIT_TEST_FRAMEWORK *Framework;
- UNIT_TEST_SUITE_LIST_ENTRY *Suite;
- EFI_STATUS Status;
-
- Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
- Suite = NULL;
-
- if (Framework == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));
- DEBUG ((DEBUG_VERBOSE, "------------ RUNNING ALL TEST SUITES --------------\n"));
- DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));
- mFrameworkHandle = FrameworkHandle;
-
- //
- // Iterate all suites
- //
- for (Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetFirstNode (&Framework->TestSuiteList);
- (LIST_ENTRY *)Suite != &Framework->TestSuiteList;
- Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetNextNode (&Framework->TestSuiteList, (LIST_ENTRY *)Suite))
- {
- Status = RunTestSuite (&(Suite->UTS));
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Test Suite Failed with Error. %r\n", Status));
- }
- }
-
- //
- // Save current state so if test is started again it doesn't have to run. It will just report
- //
- SaveFrameworkState (NULL, 0);
- OutputUnitTestFrameworkReport (FrameworkHandle);
-
- mFrameworkHandle = NULL;
-
- return EFI_SUCCESS;
-}
+/** + UnitTestLib APIs to run unit tests + + Copyright (c) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <Uefi.h> +#include <Library/UnitTestLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/UnitTestResultReportLib.h> + +STATIC UNIT_TEST_FRAMEWORK_HANDLE mFrameworkHandle = NULL; + +BASE_LIBRARY_JUMP_BUFFER gUnitTestJumpBuffer; + +UNIT_TEST_FRAMEWORK_HANDLE +GetActiveFrameworkHandle ( + VOID + ) +{ + return mFrameworkHandle; +} + +STATIC +EFI_STATUS +RunTestSuite ( + IN UNIT_TEST_SUITE *Suite + ) +{ + UNIT_TEST_LIST_ENTRY *TestEntry; + UNIT_TEST *Test; + UNIT_TEST_FRAMEWORK *ParentFramework; + + if (Suite == NULL) { + return EFI_INVALID_PARAMETER; + } + + TestEntry = NULL; + ParentFramework = (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework; + + DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + DEBUG ((DEBUG_VERBOSE, "RUNNING TEST SUITE: %a\n", Suite->Title)); + DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + + if (Suite->Setup != NULL) { + Suite->Setup (); + } + + // + // Iterate all tests within the suite + // + for (TestEntry = (UNIT_TEST_LIST_ENTRY *)GetFirstNode (&(Suite->TestCaseList)); + (LIST_ENTRY *)TestEntry != &(Suite->TestCaseList); + TestEntry = (UNIT_TEST_LIST_ENTRY *)GetNextNode (&(Suite->TestCaseList), (LIST_ENTRY *)TestEntry)) + { + Test = &TestEntry->UT; + ParentFramework->CurrentTest = Test; + + DEBUG ((DEBUG_VERBOSE, "*********************************************************\n")); + DEBUG ((DEBUG_VERBOSE, " RUNNING TEST: %a:\n", Test->Description)); + DEBUG ((DEBUG_VERBOSE, "**********************************************************\n")); + + // + // First, check to see whether the test has already been run. + // NOTE: This would generally only be the case if a saved state was detected and loaded. + // + if ((Test->Result != UNIT_TEST_PENDING) && (Test->Result != UNIT_TEST_RUNNING)) { + DEBUG ((DEBUG_VERBOSE, "Test was run on a previous pass. Skipping.\n")); + ParentFramework->CurrentTest = NULL; + continue; + } + + // + // 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 (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; + continue; + } + } + + // + // Now we should be ready to call the actual test. + // 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. + 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")); + if (SetJump (&gUnitTestJumpBuffer) == 0) { + Test->CleanUp (Test->Context); + } + } + + // + // End the test. + // + ParentFramework->CurrentTest = NULL; + } + + if (Suite->Teardown != NULL) { + Suite->Teardown (); + } + + return EFI_SUCCESS; +} + +/** + Execute all unit test cases in all unit test suites added to a Framework. + + Once a unit test framework is initialized and all unit test suites and unit + test cases are registered, this function will cause the unit test framework to + dispatch all unit test cases in sequence and record the results for reporting. + + @param[in] FrameworkHandle A handle to the current running framework that + dispatched the test. Necessary for recording + certain test events with the framework. + + @retval EFI_SUCCESS All test cases were dispatched. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. +**/ +EFI_STATUS +EFIAPI +RunAllTestSuites ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + UNIT_TEST_FRAMEWORK *Framework; + UNIT_TEST_SUITE_LIST_ENTRY *Suite; + EFI_STATUS Status; + + Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle; + Suite = NULL; + + if (Framework == NULL) { + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + DEBUG ((DEBUG_VERBOSE, "------------ RUNNING ALL TEST SUITES --------------\n")); + DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + mFrameworkHandle = FrameworkHandle; + + // + // Iterate all suites + // + for (Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetFirstNode (&Framework->TestSuiteList); + (LIST_ENTRY *)Suite != &Framework->TestSuiteList; + Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetNextNode (&Framework->TestSuiteList, (LIST_ENTRY *)Suite)) + { + Status = RunTestSuite (&(Suite->UTS)); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Test Suite Failed with Error. %r\n", Status)); + } + } + + // + // Save current state so if test is started again it doesn't have to run. It will just report + // + SaveFrameworkState (NULL, 0); + OutputUnitTestFrameworkReport (FrameworkHandle); + + mFrameworkHandle = NULL; + + return EFI_SUCCESS; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c index f24b65174c..7a9a887f67 100644 --- a/UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c @@ -1,281 +1,281 @@ -/** @file
- UnitTestLib APIs to run unit tests using cmocka
-
- Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-**/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <setjmp.h>
-#include <cmocka.h>
-
-#include <Uefi.h>
-#include <UnitTestFrameworkTypes.h>
-#include <Library/UnitTestLib.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/DebugLib.h>
-
-STATIC UNIT_TEST_FRAMEWORK_HANDLE mFrameworkHandle = NULL;
-
-UNIT_TEST_FRAMEWORK_HANDLE
-GetActiveFrameworkHandle (
- VOID
- )
-{
- return mFrameworkHandle;
-}
-
-//
-// The currently active test suite
-//
-UNIT_TEST_SUITE *mActiveUnitTestSuite = NULL;
-
-void
-CmockaUnitTestFunctionRunner (
- void **state
- )
-{
- UNIT_TEST *UnitTest;
- UNIT_TEST_SUITE *Suite;
- UNIT_TEST_FRAMEWORK *Framework;
-
- UnitTest = (UNIT_TEST *)(*state);
- Suite = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite);
- Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework);
-
- if (UnitTest->RunTest == NULL) {
- UnitTest->Result = UNIT_TEST_SKIPPED;
- } else {
- UnitTest->Result = UNIT_TEST_RUNNING;
- Framework->CurrentTest = UnitTest;
- UnitTest->Result = UnitTest->RunTest (UnitTest->Context);
- Framework->CurrentTest = NULL;
- }
-}
-
-int
-CmockaUnitTestSetupFunctionRunner (
- void **state
- )
-{
- UNIT_TEST *UnitTest;
- UNIT_TEST_SUITE *Suite;
- UNIT_TEST_FRAMEWORK *Framework;
- UNIT_TEST_STATUS Result;
-
- UnitTest = (UNIT_TEST *)(*state);
- Suite = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite);
- Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework);
-
- if (UnitTest->Prerequisite == NULL) {
- return 0;
- }
-
- Framework->CurrentTest = UnitTest;
- Result = UnitTest->Prerequisite (UnitTest->Context);
- Framework->CurrentTest = NULL;
-
- //
- // Return 0 for success. Non-zero for error.
- //
- return (int)Result;
-}
-
-int
-CmockaUnitTestTeardownFunctionRunner (
- void **state
- )
-{
- UNIT_TEST *UnitTest;
- UNIT_TEST_SUITE *Suite;
- UNIT_TEST_FRAMEWORK *Framework;
-
- UnitTest = (UNIT_TEST *)(*state);
- Suite = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite);
- Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework);
-
- if (UnitTest->CleanUp != NULL) {
- Framework->CurrentTest = UnitTest;
- UnitTest->CleanUp (UnitTest->Context);
- Framework->CurrentTest = NULL;
- }
-
- //
- // Print out the log messages - This is a partial solution as it
- // does not get the log into the XML. Need cmocka changes to support
- // stdout and stderr in their xml format
- //
- if (UnitTest->Log != NULL) {
- print_message ("UnitTest: %s - %s\n", UnitTest->Name, UnitTest->Description);
- print_message ("Log Output Start\n");
- print_message ("%s", UnitTest->Log);
- print_message ("Log Output End\n");
- }
-
- //
- // Return 0 for success. Non-zero for error.
- //
- return 0;
-}
-
-int
-CmockaUnitTestSuiteSetupFunctionRunner (
- void **state
- )
-{
- if (mActiveUnitTestSuite == NULL) {
- return -1;
- }
-
- if (mActiveUnitTestSuite->Setup == NULL) {
- return 0;
- }
-
- mActiveUnitTestSuite->Setup ();
- //
- // Always succeed
- //
- return 0;
-}
-
-int
-CmockaUnitTestSuiteTeardownFunctionRunner (
- void **state
- )
-{
- if (mActiveUnitTestSuite == NULL) {
- return -1;
- }
-
- if (mActiveUnitTestSuite->Teardown == NULL) {
- return 0;
- }
-
- mActiveUnitTestSuite->Teardown ();
- //
- // Always succeed
- //
- return 0;
-}
-
-STATIC
-EFI_STATUS
-RunTestSuite (
- IN UNIT_TEST_SUITE *Suite
- )
-{
- UNIT_TEST_LIST_ENTRY *TestEntry;
- UNIT_TEST *UnitTest;
- struct CMUnitTest *Tests;
- UINTN Index;
-
- TestEntry = NULL;
-
- if (Suite == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));
- DEBUG ((DEBUG_VERBOSE, "RUNNING TEST SUITE: %a\n", Suite->Title));
- DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));
-
- //
- // Allocate buffer of CMUnitTest entries
- //
- Tests = AllocateZeroPool (Suite->NumTests * sizeof (struct CMUnitTest));
- ASSERT (Tests != NULL);
-
- //
- // Populate buffer of CMUnitTest entries
- //
- Index = 0;
- for (TestEntry = (UNIT_TEST_LIST_ENTRY *)GetFirstNode (&(Suite->TestCaseList));
- (LIST_ENTRY *)TestEntry != &(Suite->TestCaseList);
- TestEntry = (UNIT_TEST_LIST_ENTRY *)GetNextNode (&(Suite->TestCaseList), (LIST_ENTRY *)TestEntry))
- {
- UnitTest = &TestEntry->UT;
- Tests[Index].name = UnitTest->Description;
- Tests[Index].test_func = CmockaUnitTestFunctionRunner;
- Tests[Index].setup_func = CmockaUnitTestSetupFunctionRunner;
- Tests[Index].teardown_func = CmockaUnitTestTeardownFunctionRunner;
- Tests[Index].initial_state = UnitTest;
- Index++;
- }
-
- ASSERT (Index == Suite->NumTests);
-
- //
- // Run all unit tests in a test suite
- //
- mActiveUnitTestSuite = Suite;
- _cmocka_run_group_tests (
- Suite->Title,
- Tests,
- Suite->NumTests,
- CmockaUnitTestSuiteSetupFunctionRunner,
- CmockaUnitTestSuiteTeardownFunctionRunner
- );
- mActiveUnitTestSuite = NULL;
- FreePool (Tests);
-
- return EFI_SUCCESS;
-}
-
-/**
- Execute all unit test cases in all unit test suites added to a Framework.
-
- Once a unit test framework is initialized and all unit test suites and unit
- test cases are registered, this function will cause the unit test framework to
- dispatch all unit test cases in sequence and record the results for reporting.
-
- @param[in] FrameworkHandle A handle to the current running framework that
- dispatched the test. Necessary for recording
- certain test events with the framework.
-
- @retval EFI_SUCCESS All test cases were dispatched.
- @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.
-**/
-EFI_STATUS
-EFIAPI
-RunAllTestSuites (
- IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
- )
-{
- UNIT_TEST_FRAMEWORK *Framework;
- UNIT_TEST_SUITE_LIST_ENTRY *Suite;
- EFI_STATUS Status;
-
- Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
- Suite = NULL;
-
- if (Framework == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));
- DEBUG ((DEBUG_VERBOSE, "------------ RUNNING ALL TEST SUITES --------------\n"));
- DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));
- mFrameworkHandle = FrameworkHandle;
-
- //
- // Iterate all suites
- //
- for (Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetFirstNode (&Framework->TestSuiteList);
- (LIST_ENTRY *)Suite != &Framework->TestSuiteList;
- Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetNextNode (&Framework->TestSuiteList, (LIST_ENTRY *)Suite))
- {
- Status = RunTestSuite (&(Suite->UTS));
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Test Suite Failed with Error. %r\n", Status));
- }
- }
-
- mFrameworkHandle = NULL;
-
- return EFI_SUCCESS;
-}
+/** @file + UnitTestLib APIs to run unit tests using cmocka + + Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <cmocka.h> + +#include <Uefi.h> +#include <UnitTestFrameworkTypes.h> +#include <Library/UnitTestLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DebugLib.h> + +STATIC UNIT_TEST_FRAMEWORK_HANDLE mFrameworkHandle = NULL; + +UNIT_TEST_FRAMEWORK_HANDLE +GetActiveFrameworkHandle ( + VOID + ) +{ + return mFrameworkHandle; +} + +// +// The currently active test suite +// +UNIT_TEST_SUITE *mActiveUnitTestSuite = NULL; + +void +CmockaUnitTestFunctionRunner ( + void **state + ) +{ + UNIT_TEST *UnitTest; + UNIT_TEST_SUITE *Suite; + UNIT_TEST_FRAMEWORK *Framework; + + UnitTest = (UNIT_TEST *)(*state); + Suite = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite); + Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework); + + if (UnitTest->RunTest == NULL) { + UnitTest->Result = UNIT_TEST_SKIPPED; + } else { + UnitTest->Result = UNIT_TEST_RUNNING; + Framework->CurrentTest = UnitTest; + UnitTest->Result = UnitTest->RunTest (UnitTest->Context); + Framework->CurrentTest = NULL; + } +} + +int +CmockaUnitTestSetupFunctionRunner ( + void **state + ) +{ + UNIT_TEST *UnitTest; + UNIT_TEST_SUITE *Suite; + UNIT_TEST_FRAMEWORK *Framework; + UNIT_TEST_STATUS Result; + + UnitTest = (UNIT_TEST *)(*state); + Suite = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite); + Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework); + + if (UnitTest->Prerequisite == NULL) { + return 0; + } + + Framework->CurrentTest = UnitTest; + Result = UnitTest->Prerequisite (UnitTest->Context); + Framework->CurrentTest = NULL; + + // + // Return 0 for success. Non-zero for error. + // + return (int)Result; +} + +int +CmockaUnitTestTeardownFunctionRunner ( + void **state + ) +{ + UNIT_TEST *UnitTest; + UNIT_TEST_SUITE *Suite; + UNIT_TEST_FRAMEWORK *Framework; + + UnitTest = (UNIT_TEST *)(*state); + Suite = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite); + Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework); + + if (UnitTest->CleanUp != NULL) { + Framework->CurrentTest = UnitTest; + UnitTest->CleanUp (UnitTest->Context); + Framework->CurrentTest = NULL; + } + + // + // Print out the log messages - This is a partial solution as it + // does not get the log into the XML. Need cmocka changes to support + // stdout and stderr in their xml format + // + if (UnitTest->Log != NULL) { + print_message ("UnitTest: %s - %s\n", UnitTest->Name, UnitTest->Description); + print_message ("Log Output Start\n"); + print_message ("%s", UnitTest->Log); + print_message ("Log Output End\n"); + } + + // + // Return 0 for success. Non-zero for error. + // + return 0; +} + +int +CmockaUnitTestSuiteSetupFunctionRunner ( + void **state + ) +{ + if (mActiveUnitTestSuite == NULL) { + return -1; + } + + if (mActiveUnitTestSuite->Setup == NULL) { + return 0; + } + + mActiveUnitTestSuite->Setup (); + // + // Always succeed + // + return 0; +} + +int +CmockaUnitTestSuiteTeardownFunctionRunner ( + void **state + ) +{ + if (mActiveUnitTestSuite == NULL) { + return -1; + } + + if (mActiveUnitTestSuite->Teardown == NULL) { + return 0; + } + + mActiveUnitTestSuite->Teardown (); + // + // Always succeed + // + return 0; +} + +STATIC +EFI_STATUS +RunTestSuite ( + IN UNIT_TEST_SUITE *Suite + ) +{ + UNIT_TEST_LIST_ENTRY *TestEntry; + UNIT_TEST *UnitTest; + struct CMUnitTest *Tests; + UINTN Index; + + TestEntry = NULL; + + if (Suite == NULL) { + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + DEBUG ((DEBUG_VERBOSE, "RUNNING TEST SUITE: %a\n", Suite->Title)); + DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + + // + // Allocate buffer of CMUnitTest entries + // + Tests = AllocateZeroPool (Suite->NumTests * sizeof (struct CMUnitTest)); + ASSERT (Tests != NULL); + + // + // Populate buffer of CMUnitTest entries + // + Index = 0; + for (TestEntry = (UNIT_TEST_LIST_ENTRY *)GetFirstNode (&(Suite->TestCaseList)); + (LIST_ENTRY *)TestEntry != &(Suite->TestCaseList); + TestEntry = (UNIT_TEST_LIST_ENTRY *)GetNextNode (&(Suite->TestCaseList), (LIST_ENTRY *)TestEntry)) + { + UnitTest = &TestEntry->UT; + Tests[Index].name = UnitTest->Description; + Tests[Index].test_func = CmockaUnitTestFunctionRunner; + Tests[Index].setup_func = CmockaUnitTestSetupFunctionRunner; + Tests[Index].teardown_func = CmockaUnitTestTeardownFunctionRunner; + Tests[Index].initial_state = UnitTest; + Index++; + } + + ASSERT (Index == Suite->NumTests); + + // + // Run all unit tests in a test suite + // + mActiveUnitTestSuite = Suite; + _cmocka_run_group_tests ( + Suite->Title, + Tests, + Suite->NumTests, + CmockaUnitTestSuiteSetupFunctionRunner, + CmockaUnitTestSuiteTeardownFunctionRunner + ); + mActiveUnitTestSuite = NULL; + FreePool (Tests); + + return EFI_SUCCESS; +} + +/** + Execute all unit test cases in all unit test suites added to a Framework. + + Once a unit test framework is initialized and all unit test suites and unit + test cases are registered, this function will cause the unit test framework to + dispatch all unit test cases in sequence and record the results for reporting. + + @param[in] FrameworkHandle A handle to the current running framework that + dispatched the test. Necessary for recording + certain test events with the framework. + + @retval EFI_SUCCESS All test cases were dispatched. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. +**/ +EFI_STATUS +EFIAPI +RunAllTestSuites ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + UNIT_TEST_FRAMEWORK *Framework; + UNIT_TEST_SUITE_LIST_ENTRY *Suite; + EFI_STATUS Status; + + Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle; + Suite = NULL; + + if (Framework == NULL) { + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + DEBUG ((DEBUG_VERBOSE, "------------ RUNNING ALL TEST SUITES --------------\n")); + DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + mFrameworkHandle = FrameworkHandle; + + // + // Iterate all suites + // + for (Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetFirstNode (&Framework->TestSuiteList); + (LIST_ENTRY *)Suite != &Framework->TestSuiteList; + Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetNextNode (&Framework->TestSuiteList, (LIST_ENTRY *)Suite)) + { + Status = RunTestSuite (&(Suite->UTS)); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Test Suite Failed with Error. %r\n", Status)); + } + } + + mFrameworkHandle = NULL; + + return EFI_SUCCESS; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.c b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.c index 3e3a850af1..160969f5ef 100644 --- a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.c +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.c @@ -1,873 +1,873 @@ -/**
- Implement UnitTestLib
-
- Copyright (c) Microsoft Corporation.
- Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-**/
-
-#include <Uefi.h>
-#include <Library/UnitTestLib.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/DebugLib.h>
-#include <Library/UnitTestPersistenceLib.h>
-#include <Library/UnitTestResultReportLib.h>
-
-///
-/// Forward declaration of prototype
-///
-STATIC
-VOID
-UpdateTestFromSave (
- IN OUT UNIT_TEST *Test,
- IN UNIT_TEST_SAVE_HEADER *SavedState
- );
-
-/**
- This function will determine whether the short name violates any rules that would
- prevent it from being used as a reporting name or as a serialization name.
-
- Example: If the name cannot be serialized to a filesystem file name.
-
- @param[in] ShortTitleString A pointer to the short title string to be evaluated.
-
- @retval TRUE The string is acceptable.
- @retval FALSE The string should not be used.
-
-**/
-STATIC
-BOOLEAN
-IsFrameworkShortNameValid (
- IN CHAR8 *ShortTitleString
- )
-{
- // TODO: Finish this function.
- return TRUE;
-}
-
-STATIC
-CHAR8 *
-AllocateAndCopyString (
- IN CHAR8 *StringToCopy
- )
-{
- CHAR8 *NewString;
- UINTN NewStringLength;
-
- NewString = NULL;
- NewStringLength = AsciiStrnLenS (StringToCopy, UNIT_TEST_MAX_STRING_LENGTH) + 1;
- NewString = AllocatePool (NewStringLength * sizeof (CHAR8));
- if (NewString != NULL) {
- AsciiStrCpyS (NewString, NewStringLength, StringToCopy);
- }
-
- return NewString;
-}
-
-STATIC
-VOID
-SetFrameworkFingerprint (
- OUT UINT8 *Fingerprint,
- IN UNIT_TEST_FRAMEWORK *Framework
- )
-{
- UINT32 NewFingerprint;
-
- // For this one we'll just use the title and version as the unique fingerprint.
- NewFingerprint = CalculateCrc32 (Framework->Title, (AsciiStrLen (Framework->Title) * sizeof (CHAR8)));
- NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Framework->VersionString, (AsciiStrLen (Framework->VersionString) * sizeof (CHAR8)));
-
- CopyMem (Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE);
- return;
-}
-
-STATIC
-VOID
-SetSuiteFingerprint (
- OUT UINT8 *Fingerprint,
- IN UNIT_TEST_FRAMEWORK *Framework,
- IN UNIT_TEST_SUITE *Suite
- )
-{
- UINT32 NewFingerprint;
-
- // For this one, we'll use the fingerprint from the framework, and the title of the suite.
- NewFingerprint = CalculateCrc32 (&Framework->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
- NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Suite->Title, (AsciiStrLen (Suite->Title) * sizeof (CHAR8)));
- NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Suite->Name, (AsciiStrLen (Suite->Name) * sizeof (CHAR8)));
-
- CopyMem (Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE);
- return;
-}
-
-STATIC
-VOID
-SetTestFingerprint (
- OUT UINT8 *Fingerprint,
- IN UNIT_TEST_SUITE *Suite,
- IN UNIT_TEST *Test
- )
-{
- UINT32 NewFingerprint;
-
- // For this one, we'll use the fingerprint from the suite, and the description and classname of the test.
- NewFingerprint = CalculateCrc32 (&Suite->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
- NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Test->Description, (AsciiStrLen (Test->Description) * sizeof (CHAR8)));
- NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Test->Name, (AsciiStrLen (Test->Name) * sizeof (CHAR8)));
-
- CopyMem (Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE);
- return;
-}
-
-STATIC
-BOOLEAN
-CompareFingerprints (
- IN UINT8 *FingerprintA,
- IN UINT8 *FingerprintB
- )
-{
- return (CompareMem (FingerprintA, FingerprintB, UNIT_TEST_FINGERPRINT_SIZE) == 0);
-}
-
-/**
- Cleanup a test framework.
-
- After tests are run, this will teardown the entire framework and free all
- allocated data within.
-
- @param[in] FrameworkHandle A handle to the current running framework that
- dispatched the test. Necessary for recording
- certain test events with the framework.
-
- @retval EFI_SUCCESS All resources associated with framework were
- freed.
- @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.
-**/
-EFI_STATUS
-EFIAPI
-FreeUnitTestFramework (
- IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
- )
-{
- // TODO: Finish this function.
- return EFI_SUCCESS;
-}
-
-STATIC
-EFI_STATUS
-FreeUnitTestSuiteEntry (
- IN UNIT_TEST_SUITE_LIST_ENTRY *SuiteEntry
- )
-{
- // TODO: Finish this function.
- return EFI_SUCCESS;
-}
-
-STATIC
-EFI_STATUS
-FreeUnitTestTestEntry (
- IN UNIT_TEST_LIST_ENTRY *TestEntry
- )
-{
- // TODO: Finish this function.
- return EFI_SUCCESS;
-}
-
-/**
- Method to Initialize the Unit Test framework. This function registers the
- test name and also initializes the internal state of the test framework to
- receive any new suites and tests.
-
- @param[out] FrameworkHandle Unit test framework to be created.
- @param[in] Title Null-terminated ASCII string that is the user
- friendly name of the framework. String is
- copied.
- @param[in] ShortTitle Null-terminated ASCII short string that is the
- short name of the framework with no spaces.
- String is copied.
- @param[in] VersionString Null-terminated ASCII version string for the
- framework. String is copied.
-
- @retval EFI_SUCCESS The unit test framework was initialized.
- @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.
- @retval EFI_INVALID_PARAMETER Title is NULL.
- @retval EFI_INVALID_PARAMETER ShortTitle is NULL.
- @retval EFI_INVALID_PARAMETER VersionString is NULL.
- @retval EFI_INVALID_PARAMETER ShortTitle is invalid.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
- initialize the unit test framework.
-**/
-EFI_STATUS
-EFIAPI
-InitUnitTestFramework (
- OUT UNIT_TEST_FRAMEWORK_HANDLE *FrameworkHandle,
- IN CHAR8 *Title,
- IN CHAR8 *ShortTitle,
- IN CHAR8 *VersionString
- )
-{
- EFI_STATUS Status;
- UNIT_TEST_FRAMEWORK_HANDLE NewFrameworkHandle;
- UNIT_TEST_FRAMEWORK *NewFramework;
- UINTN SaveStateSize;
-
- Status = EFI_SUCCESS;
- NewFramework = NULL;
-
- //
- // First, check all pointers and make sure nothing's broked.
- //
- if ((FrameworkHandle == NULL) || (Title == NULL) ||
- (ShortTitle == NULL) || (VersionString == NULL))
- {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Next, determine whether all of the strings are good to use.
- //
- if (!IsFrameworkShortNameValid (ShortTitle)) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Next, set aside some space to start messing with the framework.
- //
- NewFramework = AllocateZeroPool (sizeof (UNIT_TEST_FRAMEWORK));
- if (NewFramework == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Next, set up all the test data.
- //
- NewFrameworkHandle = (UNIT_TEST_FRAMEWORK_HANDLE)NewFramework;
- NewFramework->Title = AllocateAndCopyString (Title);
- NewFramework->ShortTitle = AllocateAndCopyString (ShortTitle);
- NewFramework->VersionString = AllocateAndCopyString (VersionString);
- NewFramework->Log = NULL;
- NewFramework->CurrentTest = NULL;
- NewFramework->SavedState = NULL;
- if ((NewFramework->Title == NULL) ||
- (NewFramework->ShortTitle == NULL) ||
- (NewFramework->VersionString == NULL))
- {
- Status = EFI_OUT_OF_RESOURCES;
- goto Exit;
- }
-
- InitializeListHead (&(NewFramework->TestSuiteList));
-
- //
- // Create the framework fingerprint.
- //
- SetFrameworkFingerprint (&NewFramework->Fingerprint[0], NewFramework);
-
- //
- // If there is a persisted context, load it now.
- //
- if (DoesCacheExist (NewFrameworkHandle)) {
- Status = LoadUnitTestCache (NewFrameworkHandle, (VOID **)(&NewFramework->SavedState), &SaveStateSize);
- if (EFI_ERROR (Status)) {
- //
- // Don't actually report it as an error, but emit a warning.
- //
- DEBUG ((DEBUG_ERROR, "%a - Cache was detected, but failed to load.\n", __func__));
- Status = EFI_SUCCESS;
- }
- }
-
-Exit:
- //
- // If we're good, then let's copy the framework.
- //
- if (!EFI_ERROR (Status)) {
- *FrameworkHandle = NewFrameworkHandle;
- } else {
- //
- // Otherwise, we need to undo this horrible thing that we've done.
- //
- FreeUnitTestFramework (NewFrameworkHandle);
- }
-
- return Status;
-}
-
-/**
- Registers a Unit Test Suite in the Unit Test Framework.
- At least one test suite must be registered, because all test cases must be
- within a unit test suite.
-
- @param[out] SuiteHandle Unit test suite to create
- @param[in] FrameworkHandle Unit test framework to add unit test suite to
- @param[in] Title Null-terminated ASCII string that is the user
- friendly name of the test suite. String is
- copied.
- @param[in] Name Null-terminated ASCII string that is the short
- name of the test suite with no spaces. String
- is copied.
- @param[in] Setup Setup function, runs before suite. This is an
- optional parameter that may be NULL.
- @param[in] Teardown Teardown function, runs after suite. This is an
- optional parameter that may be NULL.
-
- @retval EFI_SUCCESS The unit test suite was created.
- @retval EFI_INVALID_PARAMETER SuiteHandle is NULL.
- @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.
- @retval EFI_INVALID_PARAMETER Title is NULL.
- @retval EFI_INVALID_PARAMETER Name is NULL.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
- initialize the unit test suite.
-**/
-EFI_STATUS
-EFIAPI
-CreateUnitTestSuite (
- OUT UNIT_TEST_SUITE_HANDLE *SuiteHandle,
- IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,
- IN CHAR8 *Title,
- IN CHAR8 *Name,
- IN UNIT_TEST_SUITE_SETUP Setup OPTIONAL,
- IN UNIT_TEST_SUITE_TEARDOWN Teardown OPTIONAL
- )
-{
- EFI_STATUS Status;
- UNIT_TEST_SUITE_LIST_ENTRY *NewSuiteEntry;
- UNIT_TEST_FRAMEWORK *Framework;
-
- Status = EFI_SUCCESS;
- Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
-
- //
- // First, let's check to make sure that our parameters look good.
- //
- if ((SuiteHandle == NULL) || (Framework == NULL) || (Title == NULL) || (Name == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Create the new entry.
- //
- NewSuiteEntry = AllocateZeroPool (sizeof (UNIT_TEST_SUITE_LIST_ENTRY));
- if (NewSuiteEntry == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Copy the fields we think we need.
- //
- NewSuiteEntry->UTS.NumTests = 0;
- NewSuiteEntry->UTS.Title = AllocateAndCopyString (Title);
- NewSuiteEntry->UTS.Name = AllocateAndCopyString (Name);
- NewSuiteEntry->UTS.Setup = Setup;
- NewSuiteEntry->UTS.Teardown = Teardown;
- NewSuiteEntry->UTS.ParentFramework = FrameworkHandle;
- InitializeListHead (&(NewSuiteEntry->Entry)); // List entry for sibling suites.
- InitializeListHead (&(NewSuiteEntry->UTS.TestCaseList)); // List entry for child tests.
- if (NewSuiteEntry->UTS.Title == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Exit;
- }
-
- if (NewSuiteEntry->UTS.Name == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Exit;
- }
-
- //
- // Create the suite fingerprint.
- //
- SetSuiteFingerprint (&NewSuiteEntry->UTS.Fingerprint[0], Framework, &NewSuiteEntry->UTS);
-
-Exit:
- //
- // If everything is going well, add the new suite to the tail list for the framework.
- //
- if (!EFI_ERROR (Status)) {
- InsertTailList (&(Framework->TestSuiteList), (LIST_ENTRY *)NewSuiteEntry);
- *SuiteHandle = (UNIT_TEST_SUITE_HANDLE)(&NewSuiteEntry->UTS);
- } else {
- //
- // Otherwise, make with the destruction.
- //
- FreeUnitTestSuiteEntry (NewSuiteEntry);
- }
-
- return Status;
-}
-
-/**
- Adds test case to Suite
-
- @param[in] SuiteHandle Unit test suite to add test to.
- @param[in] Description Null-terminated ASCII string that is the user
- friendly description of a test. String is copied.
- @param[in] Name Null-terminated ASCII string that is the short name
- of the test with no spaces. String is copied.
- @param[in] Function Unit test function.
- @param[in] Prerequisite Prerequisite function, runs before test. This is
- an optional parameter that may be NULL.
- @param[in] CleanUp Clean up function, runs after test. This is an
- optional parameter that may be NULL.
- @param[in] Context Pointer to context. This is an optional parameter
- that may be NULL.
-
- @retval EFI_SUCCESS The unit test case was added to Suite.
- @retval EFI_INVALID_PARAMETER SuiteHandle is NULL.
- @retval EFI_INVALID_PARAMETER Description is NULL.
- @retval EFI_INVALID_PARAMETER Name is NULL.
- @retval EFI_INVALID_PARAMETER Function is NULL.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
- add the unit test case to Suite.
-**/
-EFI_STATUS
-EFIAPI
-AddTestCase (
- IN UNIT_TEST_SUITE_HANDLE SuiteHandle,
- IN CHAR8 *Description,
- IN CHAR8 *Name,
- IN UNIT_TEST_FUNCTION Function,
- IN UNIT_TEST_PREREQUISITE Prerequisite OPTIONAL,
- IN UNIT_TEST_CLEANUP CleanUp OPTIONAL,
- IN UNIT_TEST_CONTEXT Context OPTIONAL
- )
-{
- EFI_STATUS Status;
- UNIT_TEST_LIST_ENTRY *NewTestEntry;
- UNIT_TEST_FRAMEWORK *ParentFramework;
- UNIT_TEST_SUITE *Suite;
-
- Status = EFI_SUCCESS;
- Suite = (UNIT_TEST_SUITE *)SuiteHandle;
-
- //
- // First, let's check to make sure that our parameters look good.
- //
- if ((Suite == NULL) || (Description == NULL) || (Name == NULL) || (Function == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- ParentFramework = (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework;
- //
- // Create the new entry.
- NewTestEntry = AllocateZeroPool (sizeof (UNIT_TEST_LIST_ENTRY));
- if (NewTestEntry == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Copy the fields we think we need.
- NewTestEntry->UT.Description = AllocateAndCopyString (Description);
- NewTestEntry->UT.Name = AllocateAndCopyString (Name);
- NewTestEntry->UT.FailureType = FAILURETYPE_NOFAILURE;
- NewTestEntry->UT.FailureMessage[0] = '\0';
- NewTestEntry->UT.Log = NULL;
- NewTestEntry->UT.Prerequisite = Prerequisite;
- NewTestEntry->UT.CleanUp = CleanUp;
- NewTestEntry->UT.RunTest = Function;
- NewTestEntry->UT.Context = Context;
- NewTestEntry->UT.Result = UNIT_TEST_PENDING;
- NewTestEntry->UT.ParentSuite = SuiteHandle;
- InitializeListHead (&(NewTestEntry->Entry)); // List entry for sibling tests.
- if (NewTestEntry->UT.Description == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Exit;
- }
-
- if (NewTestEntry->UT.Name == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Exit;
- }
-
- //
- // Create the test fingerprint.
- //
- SetTestFingerprint (&NewTestEntry->UT.Fingerprint[0], Suite, &NewTestEntry->UT);
-
- // TODO: Make sure that duplicate fingerprints cannot be created.
-
- //
- // If there is saved test data, update this record.
- //
- if (ParentFramework->SavedState != NULL) {
- UpdateTestFromSave (&NewTestEntry->UT, ParentFramework->SavedState);
- }
-
-Exit:
- //
- // If everything is going well, add the new suite to the tail list for the framework.
- //
- if (!EFI_ERROR (Status)) {
- InsertTailList (&(Suite->TestCaseList), (LIST_ENTRY *)NewTestEntry);
- Suite->NumTests++;
- } else {
- //
- // Otherwise, make with the destruction.
- //
- FreeUnitTestTestEntry (NewTestEntry);
- }
-
- return Status;
-}
-
-STATIC
-VOID
-UpdateTestFromSave (
- IN OUT UNIT_TEST *Test,
- IN UNIT_TEST_SAVE_HEADER *SavedState
- )
-{
- UNIT_TEST_SAVE_TEST *CurrentTest;
- UNIT_TEST_SAVE_TEST *MatchingTest;
- UINT8 *FloatingPointer;
- UNIT_TEST_SAVE_CONTEXT *SavedContext;
- UINTN Index;
-
- //
- // First, evaluate the inputs.
- //
- if ((Test == NULL) || (SavedState == NULL)) {
- return;
- }
-
- if (SavedState->TestCount == 0) {
- return;
- }
-
- //
- // Next, determine whether a matching test can be found.
- // Start at the beginning.
- //
- MatchingTest = NULL;
- FloatingPointer = (UINT8 *)SavedState + sizeof (*SavedState);
- for (Index = 0; Index < SavedState->TestCount; Index++) {
- CurrentTest = (UNIT_TEST_SAVE_TEST *)FloatingPointer;
- if (CompareFingerprints (&Test->Fingerprint[0], &CurrentTest->Fingerprint[0])) {
- MatchingTest = CurrentTest;
- //
- // If there's a saved context, it's important that we iterate through the entire list.
- //
- if (!SavedState->HasSavedContext) {
- break;
- }
- }
-
- //
- // If we didn't find it, we have to increment to the next test.
- //
- FloatingPointer = (UINT8 *)CurrentTest + CurrentTest->Size;
- }
-
- //
- // If a matching test was found, copy the status.
- //
- if (MatchingTest) {
- //
- // Override the test status with the saved status.
- //
- Test->Result = MatchingTest->Result;
-
- Test->FailureType = MatchingTest->FailureType;
- AsciiStrnCpyS (
- &Test->FailureMessage[0],
- UNIT_TEST_TESTFAILUREMSG_LENGTH,
- &MatchingTest->FailureMessage[0],
- UNIT_TEST_TESTFAILUREMSG_LENGTH
- );
-
- //
- // If there is a log string associated, grab that.
- // We can tell that there's a log string because the "size" will be larger than
- // the structure size.
- // IMPORTANT NOTE: There are security implications here.
- // This data is user-supplied and we're about to play kinda
- // fast and loose with data buffers.
- //
- if (MatchingTest->Size > sizeof (UNIT_TEST_SAVE_TEST)) {
- UnitTestLogInit (Test, (UINT8 *)MatchingTest->Log, MatchingTest->Size - sizeof (UNIT_TEST_SAVE_TEST));
- }
- }
-
- //
- // If the saved context exists and matches this test, grab it, too.
- //
- if (SavedState->HasSavedContext) {
- //
- // If there was a saved context, the "matching test" loop will have placed the FloatingPointer
- // at the beginning of the context structure.
- //
- SavedContext = (UNIT_TEST_SAVE_CONTEXT *)FloatingPointer;
- if (((SavedContext->Size - sizeof (UNIT_TEST_SAVE_CONTEXT)) > 0) &&
- CompareFingerprints (&Test->Fingerprint[0], &SavedContext->Fingerprint[0]))
- {
- //
- // Override the test context with the saved context.
- //
- Test->Context = (VOID *)SavedContext->Data;
- }
- }
-}
-
-STATIC
-UNIT_TEST_SAVE_HEADER *
-SerializeState (
- IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,
- IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL,
- IN UINTN ContextToSaveSize
- )
-{
- UNIT_TEST_FRAMEWORK *Framework;
- UNIT_TEST_SAVE_HEADER *Header;
- LIST_ENTRY *SuiteListHead;
- LIST_ENTRY *Suite;
- LIST_ENTRY *TestListHead;
- LIST_ENTRY *Test;
- UINT32 TestCount;
- UINT32 TotalSize;
- UINTN LogSize;
- UNIT_TEST_SAVE_TEST *TestSaveData;
- UNIT_TEST_SAVE_CONTEXT *TestSaveContext;
- UNIT_TEST *UnitTest;
- UINT8 *FloatingPointer;
-
- Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
- Header = NULL;
-
- //
- // First, let's not make assumptions about the parameters.
- //
- if ((Framework == NULL) ||
- ((ContextToSave != NULL) && (ContextToSaveSize == 0)) ||
- (ContextToSaveSize > MAX_UINT32))
- {
- return NULL;
- }
-
- //
- // Next, we've gotta figure out the resources that will be required to serialize the
- // the framework state so that we can persist it.
- // To start with, we're gonna need a header.
- //
- TotalSize = sizeof (UNIT_TEST_SAVE_HEADER);
- //
- // Now we need to figure out how many tests there are.
- //
- TestCount = 0;
- //
- // Iterate all suites.
- //
- SuiteListHead = &Framework->TestSuiteList;
- for (Suite = GetFirstNode (SuiteListHead); Suite != SuiteListHead; Suite = GetNextNode (SuiteListHead, Suite)) {
- //
- // Iterate all tests within the suite.
- //
- TestListHead = &((UNIT_TEST_SUITE_LIST_ENTRY *)Suite)->UTS.TestCaseList;
- for (Test = GetFirstNode (TestListHead); Test != TestListHead; Test = GetNextNode (TestListHead, Test)) {
- UnitTest = &((UNIT_TEST_LIST_ENTRY *)Test)->UT;
- //
- // Account for the size of a test structure.
- //
- TotalSize += sizeof (UNIT_TEST_SAVE_TEST);
- //
- // If there's a log, make sure to account for the log size.
- //
- if (UnitTest->Log != NULL) {
- //
- // The +1 is for the NULL character. Can't forget the NULL character.
- //
- LogSize = (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8);
- ASSERT (LogSize < MAX_UINT32);
- TotalSize += (UINT32)LogSize;
- }
-
- //
- // Increment the test count.
- //
- TestCount++;
- }
- }
-
- //
- // If there are no tests, we're done here.
- //
- if (TestCount == 0) {
- return NULL;
- }
-
- //
- // Add room for the context, if there is one.
- //
- if (ContextToSave != NULL) {
- TotalSize += sizeof (UNIT_TEST_SAVE_CONTEXT) + (UINT32)ContextToSaveSize;
- }
-
- //
- // Now that we know the size, we need to allocate space for the serialized output.
- //
- Header = AllocateZeroPool (TotalSize);
- if (Header == NULL) {
- return NULL;
- }
-
- //
- // Alright, let's start setting up some data.
- //
- Header->Version = UNIT_TEST_PERSISTENCE_LIB_VERSION;
- Header->SaveStateSize = TotalSize;
- CopyMem (&Header->Fingerprint[0], &Framework->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
- CopyMem (&Header->StartTime, &Framework->StartTime, sizeof (EFI_TIME));
- Header->TestCount = TestCount;
- Header->HasSavedContext = FALSE;
-
- //
- // Start adding all of the test cases.
- // Set the floating pointer to the start of the current test save buffer.
- //
- FloatingPointer = (UINT8 *)Header + sizeof (UNIT_TEST_SAVE_HEADER);
- //
- // Iterate all suites.
- //
- SuiteListHead = &Framework->TestSuiteList;
- for (Suite = GetFirstNode (SuiteListHead); Suite != SuiteListHead; Suite = GetNextNode (SuiteListHead, Suite)) {
- //
- // Iterate all tests within the suite.
- //
- TestListHead = &((UNIT_TEST_SUITE_LIST_ENTRY *)Suite)->UTS.TestCaseList;
- for (Test = GetFirstNode (TestListHead); Test != TestListHead; Test = GetNextNode (TestListHead, Test)) {
- TestSaveData = (UNIT_TEST_SAVE_TEST *)FloatingPointer;
- UnitTest = &((UNIT_TEST_LIST_ENTRY *)Test)->UT;
-
- //
- // Save the fingerprint.
- //
- CopyMem (&TestSaveData->Fingerprint[0], &UnitTest->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
-
- //
- // Save the result.
- //
- TestSaveData->Result = UnitTest->Result;
- TestSaveData->FailureType = UnitTest->FailureType;
- AsciiStrnCpyS (&TestSaveData->FailureMessage[0], UNIT_TEST_TESTFAILUREMSG_LENGTH, &UnitTest->FailureMessage[0], UNIT_TEST_TESTFAILUREMSG_LENGTH);
-
- //
- // If there is a log, save the log.
- //
- FloatingPointer += sizeof (UNIT_TEST_SAVE_TEST);
- if (UnitTest->Log != NULL) {
- //
- // The +1 is for the NULL character. Can't forget the NULL character.
- //
- LogSize = (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8);
- CopyMem (FloatingPointer, UnitTest->Log, LogSize);
- FloatingPointer += LogSize;
- }
-
- //
- // Update the size once the structure is complete.
- // NOTE: Should this be a straight cast without validation?
- //
- TestSaveData->Size = (UINT32)(FloatingPointer - (UINT8 *)TestSaveData);
- }
- }
-
- //
- // If there is a context to save, let's do that now.
- //
- if ((ContextToSave != NULL) && (Framework->CurrentTest != NULL)) {
- TestSaveContext = (UNIT_TEST_SAVE_CONTEXT *)FloatingPointer;
- TestSaveContext->Size = (UINT32)ContextToSaveSize + sizeof (UNIT_TEST_SAVE_CONTEXT);
- CopyMem (&TestSaveContext->Fingerprint[0], &Framework->CurrentTest->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
- CopyMem (((UINT8 *)TestSaveContext + sizeof (UNIT_TEST_SAVE_CONTEXT)), ContextToSave, ContextToSaveSize);
- Header->HasSavedContext = TRUE;
- }
-
- return Header;
-}
-
-/**
- Leverages a framework-specific mechanism (see UnitTestPersistenceLib if you're
- a framework author) to save the state of the executing framework along with
- any allocated data so that the test may be resumed upon reentry. A test case
- should pass any needed context (which, to prevent an infinite loop, should be
- at least the current execution count) which will be saved by the framework and
- passed to the test case upon resume.
-
- This should be called while the current test framework is valid and active. It is
- generally called from within a test case prior to quitting or rebooting.
-
- @param[in] ContextToSave A buffer of test case-specific data to be saved
- along with framework state. Will be passed as
- "Context" to the test case upon resume. This
- is an optional parameter that may be NULL.
- @param[in] ContextToSaveSize Size of the ContextToSave buffer.
-
- @retval EFI_SUCCESS The framework state and context were saved.
- @retval EFI_NOT_FOUND An active framework handle was not found.
- @retval EFI_INVALID_PARAMETER ContextToSave is not NULL and
- ContextToSaveSize is 0.
- @retval EFI_INVALID_PARAMETER ContextToSave is >= 4GB.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
- save the framework and context state.
- @retval EFI_DEVICE_ERROR The framework and context state could not be
- saved to a persistent storage device due to a
- device error.
-**/
-EFI_STATUS
-EFIAPI
-SaveFrameworkState (
- IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL,
- IN UINTN ContextToSaveSize
- )
-{
- EFI_STATUS Status;
- UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle;
- UNIT_TEST_SAVE_HEADER *Header;
-
- Header = NULL;
- FrameworkHandle = GetActiveFrameworkHandle ();
- if (FrameworkHandle == NULL) {
- DEBUG ((DEBUG_ERROR, "%a - Could not save state! FrameworkHandle not initialized\n", __func__));
- return EFI_DEVICE_ERROR;
- }
-
- //
- // Return a unique error code if the framework is not set.
- //
- if (FrameworkHandle == NULL) {
- return EFI_NOT_FOUND;
- }
-
- //
- // First, let's not make assumptions about the parameters.
- //
- if (((ContextToSave != NULL) && (ContextToSaveSize == 0)) ||
- (ContextToSaveSize > MAX_UINT32))
- {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Now, let's package up all the data for saving.
- //
- Header = SerializeState (FrameworkHandle, ContextToSave, ContextToSaveSize);
- if (Header == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // All that should be left to do is save it using the associated persistence lib.
- //
- Status = SaveUnitTestCache (FrameworkHandle, Header, Header->SaveStateSize);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "%a - Could not save state! %r\n", __func__, Status));
- Status = EFI_DEVICE_ERROR;
- }
-
- //
- // Free data that was used.
- //
- FreePool (Header);
-
- return Status;
-}
+/** + Implement UnitTestLib + + Copyright (c) Microsoft Corporation. + Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <Uefi.h> +#include <Library/UnitTestLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DebugLib.h> +#include <Library/UnitTestPersistenceLib.h> +#include <Library/UnitTestResultReportLib.h> + +/// +/// Forward declaration of prototype +/// +STATIC +VOID +UpdateTestFromSave ( + IN OUT UNIT_TEST *Test, + IN UNIT_TEST_SAVE_HEADER *SavedState + ); + +/** + This function will determine whether the short name violates any rules that would + prevent it from being used as a reporting name or as a serialization name. + + Example: If the name cannot be serialized to a filesystem file name. + + @param[in] ShortTitleString A pointer to the short title string to be evaluated. + + @retval TRUE The string is acceptable. + @retval FALSE The string should not be used. + +**/ +STATIC +BOOLEAN +IsFrameworkShortNameValid ( + IN CHAR8 *ShortTitleString + ) +{ + // TODO: Finish this function. + return TRUE; +} + +STATIC +CHAR8 * +AllocateAndCopyString ( + IN CHAR8 *StringToCopy + ) +{ + CHAR8 *NewString; + UINTN NewStringLength; + + NewString = NULL; + NewStringLength = AsciiStrnLenS (StringToCopy, UNIT_TEST_MAX_STRING_LENGTH) + 1; + NewString = AllocatePool (NewStringLength * sizeof (CHAR8)); + if (NewString != NULL) { + AsciiStrCpyS (NewString, NewStringLength, StringToCopy); + } + + return NewString; +} + +STATIC +VOID +SetFrameworkFingerprint ( + OUT UINT8 *Fingerprint, + IN UNIT_TEST_FRAMEWORK *Framework + ) +{ + UINT32 NewFingerprint; + + // For this one we'll just use the title and version as the unique fingerprint. + NewFingerprint = CalculateCrc32 (Framework->Title, (AsciiStrLen (Framework->Title) * sizeof (CHAR8))); + NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Framework->VersionString, (AsciiStrLen (Framework->VersionString) * sizeof (CHAR8))); + + CopyMem (Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE); + return; +} + +STATIC +VOID +SetSuiteFingerprint ( + OUT UINT8 *Fingerprint, + IN UNIT_TEST_FRAMEWORK *Framework, + IN UNIT_TEST_SUITE *Suite + ) +{ + UINT32 NewFingerprint; + + // For this one, we'll use the fingerprint from the framework, and the title of the suite. + NewFingerprint = CalculateCrc32 (&Framework->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE); + NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Suite->Title, (AsciiStrLen (Suite->Title) * sizeof (CHAR8))); + NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Suite->Name, (AsciiStrLen (Suite->Name) * sizeof (CHAR8))); + + CopyMem (Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE); + return; +} + +STATIC +VOID +SetTestFingerprint ( + OUT UINT8 *Fingerprint, + IN UNIT_TEST_SUITE *Suite, + IN UNIT_TEST *Test + ) +{ + UINT32 NewFingerprint; + + // For this one, we'll use the fingerprint from the suite, and the description and classname of the test. + NewFingerprint = CalculateCrc32 (&Suite->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE); + NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Test->Description, (AsciiStrLen (Test->Description) * sizeof (CHAR8))); + NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Test->Name, (AsciiStrLen (Test->Name) * sizeof (CHAR8))); + + CopyMem (Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE); + return; +} + +STATIC +BOOLEAN +CompareFingerprints ( + IN UINT8 *FingerprintA, + IN UINT8 *FingerprintB + ) +{ + return (CompareMem (FingerprintA, FingerprintB, UNIT_TEST_FINGERPRINT_SIZE) == 0); +} + +/** + Cleanup a test framework. + + After tests are run, this will teardown the entire framework and free all + allocated data within. + + @param[in] FrameworkHandle A handle to the current running framework that + dispatched the test. Necessary for recording + certain test events with the framework. + + @retval EFI_SUCCESS All resources associated with framework were + freed. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. +**/ +EFI_STATUS +EFIAPI +FreeUnitTestFramework ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + // TODO: Finish this function. + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +FreeUnitTestSuiteEntry ( + IN UNIT_TEST_SUITE_LIST_ENTRY *SuiteEntry + ) +{ + // TODO: Finish this function. + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +FreeUnitTestTestEntry ( + IN UNIT_TEST_LIST_ENTRY *TestEntry + ) +{ + // TODO: Finish this function. + return EFI_SUCCESS; +} + +/** + Method to Initialize the Unit Test framework. This function registers the + test name and also initializes the internal state of the test framework to + receive any new suites and tests. + + @param[out] FrameworkHandle Unit test framework to be created. + @param[in] Title Null-terminated ASCII string that is the user + friendly name of the framework. String is + copied. + @param[in] ShortTitle Null-terminated ASCII short string that is the + short name of the framework with no spaces. + String is copied. + @param[in] VersionString Null-terminated ASCII version string for the + framework. String is copied. + + @retval EFI_SUCCESS The unit test framework was initialized. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. + @retval EFI_INVALID_PARAMETER Title is NULL. + @retval EFI_INVALID_PARAMETER ShortTitle is NULL. + @retval EFI_INVALID_PARAMETER VersionString is NULL. + @retval EFI_INVALID_PARAMETER ShortTitle is invalid. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + initialize the unit test framework. +**/ +EFI_STATUS +EFIAPI +InitUnitTestFramework ( + OUT UNIT_TEST_FRAMEWORK_HANDLE *FrameworkHandle, + IN CHAR8 *Title, + IN CHAR8 *ShortTitle, + IN CHAR8 *VersionString + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK_HANDLE NewFrameworkHandle; + UNIT_TEST_FRAMEWORK *NewFramework; + UINTN SaveStateSize; + + Status = EFI_SUCCESS; + NewFramework = NULL; + + // + // First, check all pointers and make sure nothing's broked. + // + if ((FrameworkHandle == NULL) || (Title == NULL) || + (ShortTitle == NULL) || (VersionString == NULL)) + { + return EFI_INVALID_PARAMETER; + } + + // + // Next, determine whether all of the strings are good to use. + // + if (!IsFrameworkShortNameValid (ShortTitle)) { + return EFI_INVALID_PARAMETER; + } + + // + // Next, set aside some space to start messing with the framework. + // + NewFramework = AllocateZeroPool (sizeof (UNIT_TEST_FRAMEWORK)); + if (NewFramework == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Next, set up all the test data. + // + NewFrameworkHandle = (UNIT_TEST_FRAMEWORK_HANDLE)NewFramework; + NewFramework->Title = AllocateAndCopyString (Title); + NewFramework->ShortTitle = AllocateAndCopyString (ShortTitle); + NewFramework->VersionString = AllocateAndCopyString (VersionString); + NewFramework->Log = NULL; + NewFramework->CurrentTest = NULL; + NewFramework->SavedState = NULL; + if ((NewFramework->Title == NULL) || + (NewFramework->ShortTitle == NULL) || + (NewFramework->VersionString == NULL)) + { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + InitializeListHead (&(NewFramework->TestSuiteList)); + + // + // Create the framework fingerprint. + // + SetFrameworkFingerprint (&NewFramework->Fingerprint[0], NewFramework); + + // + // If there is a persisted context, load it now. + // + if (DoesCacheExist (NewFrameworkHandle)) { + Status = LoadUnitTestCache (NewFrameworkHandle, (VOID **)(&NewFramework->SavedState), &SaveStateSize); + if (EFI_ERROR (Status)) { + // + // Don't actually report it as an error, but emit a warning. + // + DEBUG ((DEBUG_ERROR, "%a - Cache was detected, but failed to load.\n", __func__)); + Status = EFI_SUCCESS; + } + } + +Exit: + // + // If we're good, then let's copy the framework. + // + if (!EFI_ERROR (Status)) { + *FrameworkHandle = NewFrameworkHandle; + } else { + // + // Otherwise, we need to undo this horrible thing that we've done. + // + FreeUnitTestFramework (NewFrameworkHandle); + } + + return Status; +} + +/** + Registers a Unit Test Suite in the Unit Test Framework. + At least one test suite must be registered, because all test cases must be + within a unit test suite. + + @param[out] SuiteHandle Unit test suite to create + @param[in] FrameworkHandle Unit test framework to add unit test suite to + @param[in] Title Null-terminated ASCII string that is the user + friendly name of the test suite. String is + copied. + @param[in] Name Null-terminated ASCII string that is the short + name of the test suite with no spaces. String + is copied. + @param[in] Setup Setup function, runs before suite. This is an + optional parameter that may be NULL. + @param[in] Teardown Teardown function, runs after suite. This is an + optional parameter that may be NULL. + + @retval EFI_SUCCESS The unit test suite was created. + @retval EFI_INVALID_PARAMETER SuiteHandle is NULL. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. + @retval EFI_INVALID_PARAMETER Title is NULL. + @retval EFI_INVALID_PARAMETER Name is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + initialize the unit test suite. +**/ +EFI_STATUS +EFIAPI +CreateUnitTestSuite ( + OUT UNIT_TEST_SUITE_HANDLE *SuiteHandle, + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN CHAR8 *Title, + IN CHAR8 *Name, + IN UNIT_TEST_SUITE_SETUP Setup OPTIONAL, + IN UNIT_TEST_SUITE_TEARDOWN Teardown OPTIONAL + ) +{ + EFI_STATUS Status; + UNIT_TEST_SUITE_LIST_ENTRY *NewSuiteEntry; + UNIT_TEST_FRAMEWORK *Framework; + + Status = EFI_SUCCESS; + Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle; + + // + // First, let's check to make sure that our parameters look good. + // + if ((SuiteHandle == NULL) || (Framework == NULL) || (Title == NULL) || (Name == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Create the new entry. + // + NewSuiteEntry = AllocateZeroPool (sizeof (UNIT_TEST_SUITE_LIST_ENTRY)); + if (NewSuiteEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Copy the fields we think we need. + // + NewSuiteEntry->UTS.NumTests = 0; + NewSuiteEntry->UTS.Title = AllocateAndCopyString (Title); + NewSuiteEntry->UTS.Name = AllocateAndCopyString (Name); + NewSuiteEntry->UTS.Setup = Setup; + NewSuiteEntry->UTS.Teardown = Teardown; + NewSuiteEntry->UTS.ParentFramework = FrameworkHandle; + InitializeListHead (&(NewSuiteEntry->Entry)); // List entry for sibling suites. + InitializeListHead (&(NewSuiteEntry->UTS.TestCaseList)); // List entry for child tests. + if (NewSuiteEntry->UTS.Title == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + if (NewSuiteEntry->UTS.Name == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + // + // Create the suite fingerprint. + // + SetSuiteFingerprint (&NewSuiteEntry->UTS.Fingerprint[0], Framework, &NewSuiteEntry->UTS); + +Exit: + // + // If everything is going well, add the new suite to the tail list for the framework. + // + if (!EFI_ERROR (Status)) { + InsertTailList (&(Framework->TestSuiteList), (LIST_ENTRY *)NewSuiteEntry); + *SuiteHandle = (UNIT_TEST_SUITE_HANDLE)(&NewSuiteEntry->UTS); + } else { + // + // Otherwise, make with the destruction. + // + FreeUnitTestSuiteEntry (NewSuiteEntry); + } + + return Status; +} + +/** + Adds test case to Suite + + @param[in] SuiteHandle Unit test suite to add test to. + @param[in] Description Null-terminated ASCII string that is the user + friendly description of a test. String is copied. + @param[in] Name Null-terminated ASCII string that is the short name + of the test with no spaces. String is copied. + @param[in] Function Unit test function. + @param[in] Prerequisite Prerequisite function, runs before test. This is + an optional parameter that may be NULL. + @param[in] CleanUp Clean up function, runs after test. This is an + optional parameter that may be NULL. + @param[in] Context Pointer to context. This is an optional parameter + that may be NULL. + + @retval EFI_SUCCESS The unit test case was added to Suite. + @retval EFI_INVALID_PARAMETER SuiteHandle is NULL. + @retval EFI_INVALID_PARAMETER Description is NULL. + @retval EFI_INVALID_PARAMETER Name is NULL. + @retval EFI_INVALID_PARAMETER Function is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + add the unit test case to Suite. +**/ +EFI_STATUS +EFIAPI +AddTestCase ( + IN UNIT_TEST_SUITE_HANDLE SuiteHandle, + IN CHAR8 *Description, + IN CHAR8 *Name, + IN UNIT_TEST_FUNCTION Function, + IN UNIT_TEST_PREREQUISITE Prerequisite OPTIONAL, + IN UNIT_TEST_CLEANUP CleanUp OPTIONAL, + IN UNIT_TEST_CONTEXT Context OPTIONAL + ) +{ + EFI_STATUS Status; + UNIT_TEST_LIST_ENTRY *NewTestEntry; + UNIT_TEST_FRAMEWORK *ParentFramework; + UNIT_TEST_SUITE *Suite; + + Status = EFI_SUCCESS; + Suite = (UNIT_TEST_SUITE *)SuiteHandle; + + // + // First, let's check to make sure that our parameters look good. + // + if ((Suite == NULL) || (Description == NULL) || (Name == NULL) || (Function == NULL)) { + return EFI_INVALID_PARAMETER; + } + + ParentFramework = (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework; + // + // Create the new entry. + NewTestEntry = AllocateZeroPool (sizeof (UNIT_TEST_LIST_ENTRY)); + if (NewTestEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Copy the fields we think we need. + NewTestEntry->UT.Description = AllocateAndCopyString (Description); + NewTestEntry->UT.Name = AllocateAndCopyString (Name); + NewTestEntry->UT.FailureType = FAILURETYPE_NOFAILURE; + NewTestEntry->UT.FailureMessage[0] = '\0'; + NewTestEntry->UT.Log = NULL; + NewTestEntry->UT.Prerequisite = Prerequisite; + NewTestEntry->UT.CleanUp = CleanUp; + NewTestEntry->UT.RunTest = Function; + NewTestEntry->UT.Context = Context; + NewTestEntry->UT.Result = UNIT_TEST_PENDING; + NewTestEntry->UT.ParentSuite = SuiteHandle; + InitializeListHead (&(NewTestEntry->Entry)); // List entry for sibling tests. + if (NewTestEntry->UT.Description == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + if (NewTestEntry->UT.Name == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + // + // Create the test fingerprint. + // + SetTestFingerprint (&NewTestEntry->UT.Fingerprint[0], Suite, &NewTestEntry->UT); + + // TODO: Make sure that duplicate fingerprints cannot be created. + + // + // If there is saved test data, update this record. + // + if (ParentFramework->SavedState != NULL) { + UpdateTestFromSave (&NewTestEntry->UT, ParentFramework->SavedState); + } + +Exit: + // + // If everything is going well, add the new suite to the tail list for the framework. + // + if (!EFI_ERROR (Status)) { + InsertTailList (&(Suite->TestCaseList), (LIST_ENTRY *)NewTestEntry); + Suite->NumTests++; + } else { + // + // Otherwise, make with the destruction. + // + FreeUnitTestTestEntry (NewTestEntry); + } + + return Status; +} + +STATIC +VOID +UpdateTestFromSave ( + IN OUT UNIT_TEST *Test, + IN UNIT_TEST_SAVE_HEADER *SavedState + ) +{ + UNIT_TEST_SAVE_TEST *CurrentTest; + UNIT_TEST_SAVE_TEST *MatchingTest; + UINT8 *FloatingPointer; + UNIT_TEST_SAVE_CONTEXT *SavedContext; + UINTN Index; + + // + // First, evaluate the inputs. + // + if ((Test == NULL) || (SavedState == NULL)) { + return; + } + + if (SavedState->TestCount == 0) { + return; + } + + // + // Next, determine whether a matching test can be found. + // Start at the beginning. + // + MatchingTest = NULL; + FloatingPointer = (UINT8 *)SavedState + sizeof (*SavedState); + for (Index = 0; Index < SavedState->TestCount; Index++) { + CurrentTest = (UNIT_TEST_SAVE_TEST *)FloatingPointer; + if (CompareFingerprints (&Test->Fingerprint[0], &CurrentTest->Fingerprint[0])) { + MatchingTest = CurrentTest; + // + // If there's a saved context, it's important that we iterate through the entire list. + // + if (!SavedState->HasSavedContext) { + break; + } + } + + // + // If we didn't find it, we have to increment to the next test. + // + FloatingPointer = (UINT8 *)CurrentTest + CurrentTest->Size; + } + + // + // If a matching test was found, copy the status. + // + if (MatchingTest) { + // + // Override the test status with the saved status. + // + Test->Result = MatchingTest->Result; + + Test->FailureType = MatchingTest->FailureType; + AsciiStrnCpyS ( + &Test->FailureMessage[0], + UNIT_TEST_TESTFAILUREMSG_LENGTH, + &MatchingTest->FailureMessage[0], + UNIT_TEST_TESTFAILUREMSG_LENGTH + ); + + // + // If there is a log string associated, grab that. + // We can tell that there's a log string because the "size" will be larger than + // the structure size. + // IMPORTANT NOTE: There are security implications here. + // This data is user-supplied and we're about to play kinda + // fast and loose with data buffers. + // + if (MatchingTest->Size > sizeof (UNIT_TEST_SAVE_TEST)) { + UnitTestLogInit (Test, (UINT8 *)MatchingTest->Log, MatchingTest->Size - sizeof (UNIT_TEST_SAVE_TEST)); + } + } + + // + // If the saved context exists and matches this test, grab it, too. + // + if (SavedState->HasSavedContext) { + // + // If there was a saved context, the "matching test" loop will have placed the FloatingPointer + // at the beginning of the context structure. + // + SavedContext = (UNIT_TEST_SAVE_CONTEXT *)FloatingPointer; + if (((SavedContext->Size - sizeof (UNIT_TEST_SAVE_CONTEXT)) > 0) && + CompareFingerprints (&Test->Fingerprint[0], &SavedContext->Fingerprint[0])) + { + // + // Override the test context with the saved context. + // + Test->Context = (VOID *)SavedContext->Data; + } + } +} + +STATIC +UNIT_TEST_SAVE_HEADER * +SerializeState ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL, + IN UINTN ContextToSaveSize + ) +{ + UNIT_TEST_FRAMEWORK *Framework; + UNIT_TEST_SAVE_HEADER *Header; + LIST_ENTRY *SuiteListHead; + LIST_ENTRY *Suite; + LIST_ENTRY *TestListHead; + LIST_ENTRY *Test; + UINT32 TestCount; + UINT32 TotalSize; + UINTN LogSize; + UNIT_TEST_SAVE_TEST *TestSaveData; + UNIT_TEST_SAVE_CONTEXT *TestSaveContext; + UNIT_TEST *UnitTest; + UINT8 *FloatingPointer; + + Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle; + Header = NULL; + + // + // First, let's not make assumptions about the parameters. + // + if ((Framework == NULL) || + ((ContextToSave != NULL) && (ContextToSaveSize == 0)) || + (ContextToSaveSize > MAX_UINT32)) + { + return NULL; + } + + // + // Next, we've gotta figure out the resources that will be required to serialize the + // the framework state so that we can persist it. + // To start with, we're gonna need a header. + // + TotalSize = sizeof (UNIT_TEST_SAVE_HEADER); + // + // Now we need to figure out how many tests there are. + // + TestCount = 0; + // + // Iterate all suites. + // + SuiteListHead = &Framework->TestSuiteList; + for (Suite = GetFirstNode (SuiteListHead); Suite != SuiteListHead; Suite = GetNextNode (SuiteListHead, Suite)) { + // + // Iterate all tests within the suite. + // + TestListHead = &((UNIT_TEST_SUITE_LIST_ENTRY *)Suite)->UTS.TestCaseList; + for (Test = GetFirstNode (TestListHead); Test != TestListHead; Test = GetNextNode (TestListHead, Test)) { + UnitTest = &((UNIT_TEST_LIST_ENTRY *)Test)->UT; + // + // Account for the size of a test structure. + // + TotalSize += sizeof (UNIT_TEST_SAVE_TEST); + // + // If there's a log, make sure to account for the log size. + // + if (UnitTest->Log != NULL) { + // + // The +1 is for the NULL character. Can't forget the NULL character. + // + LogSize = (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8); + ASSERT (LogSize < MAX_UINT32); + TotalSize += (UINT32)LogSize; + } + + // + // Increment the test count. + // + TestCount++; + } + } + + // + // If there are no tests, we're done here. + // + if (TestCount == 0) { + return NULL; + } + + // + // Add room for the context, if there is one. + // + if (ContextToSave != NULL) { + TotalSize += sizeof (UNIT_TEST_SAVE_CONTEXT) + (UINT32)ContextToSaveSize; + } + + // + // Now that we know the size, we need to allocate space for the serialized output. + // + Header = AllocateZeroPool (TotalSize); + if (Header == NULL) { + return NULL; + } + + // + // Alright, let's start setting up some data. + // + Header->Version = UNIT_TEST_PERSISTENCE_LIB_VERSION; + Header->SaveStateSize = TotalSize; + CopyMem (&Header->Fingerprint[0], &Framework->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE); + CopyMem (&Header->StartTime, &Framework->StartTime, sizeof (EFI_TIME)); + Header->TestCount = TestCount; + Header->HasSavedContext = FALSE; + + // + // Start adding all of the test cases. + // Set the floating pointer to the start of the current test save buffer. + // + FloatingPointer = (UINT8 *)Header + sizeof (UNIT_TEST_SAVE_HEADER); + // + // Iterate all suites. + // + SuiteListHead = &Framework->TestSuiteList; + for (Suite = GetFirstNode (SuiteListHead); Suite != SuiteListHead; Suite = GetNextNode (SuiteListHead, Suite)) { + // + // Iterate all tests within the suite. + // + TestListHead = &((UNIT_TEST_SUITE_LIST_ENTRY *)Suite)->UTS.TestCaseList; + for (Test = GetFirstNode (TestListHead); Test != TestListHead; Test = GetNextNode (TestListHead, Test)) { + TestSaveData = (UNIT_TEST_SAVE_TEST *)FloatingPointer; + UnitTest = &((UNIT_TEST_LIST_ENTRY *)Test)->UT; + + // + // Save the fingerprint. + // + CopyMem (&TestSaveData->Fingerprint[0], &UnitTest->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE); + + // + // Save the result. + // + TestSaveData->Result = UnitTest->Result; + TestSaveData->FailureType = UnitTest->FailureType; + AsciiStrnCpyS (&TestSaveData->FailureMessage[0], UNIT_TEST_TESTFAILUREMSG_LENGTH, &UnitTest->FailureMessage[0], UNIT_TEST_TESTFAILUREMSG_LENGTH); + + // + // If there is a log, save the log. + // + FloatingPointer += sizeof (UNIT_TEST_SAVE_TEST); + if (UnitTest->Log != NULL) { + // + // The +1 is for the NULL character. Can't forget the NULL character. + // + LogSize = (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8); + CopyMem (FloatingPointer, UnitTest->Log, LogSize); + FloatingPointer += LogSize; + } + + // + // Update the size once the structure is complete. + // NOTE: Should this be a straight cast without validation? + // + TestSaveData->Size = (UINT32)(FloatingPointer - (UINT8 *)TestSaveData); + } + } + + // + // If there is a context to save, let's do that now. + // + if ((ContextToSave != NULL) && (Framework->CurrentTest != NULL)) { + TestSaveContext = (UNIT_TEST_SAVE_CONTEXT *)FloatingPointer; + TestSaveContext->Size = (UINT32)ContextToSaveSize + sizeof (UNIT_TEST_SAVE_CONTEXT); + CopyMem (&TestSaveContext->Fingerprint[0], &Framework->CurrentTest->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE); + CopyMem (((UINT8 *)TestSaveContext + sizeof (UNIT_TEST_SAVE_CONTEXT)), ContextToSave, ContextToSaveSize); + Header->HasSavedContext = TRUE; + } + + return Header; +} + +/** + Leverages a framework-specific mechanism (see UnitTestPersistenceLib if you're + a framework author) to save the state of the executing framework along with + any allocated data so that the test may be resumed upon reentry. A test case + should pass any needed context (which, to prevent an infinite loop, should be + at least the current execution count) which will be saved by the framework and + passed to the test case upon resume. + + This should be called while the current test framework is valid and active. It is + generally called from within a test case prior to quitting or rebooting. + + @param[in] ContextToSave A buffer of test case-specific data to be saved + along with framework state. Will be passed as + "Context" to the test case upon resume. This + is an optional parameter that may be NULL. + @param[in] ContextToSaveSize Size of the ContextToSave buffer. + + @retval EFI_SUCCESS The framework state and context were saved. + @retval EFI_NOT_FOUND An active framework handle was not found. + @retval EFI_INVALID_PARAMETER ContextToSave is not NULL and + ContextToSaveSize is 0. + @retval EFI_INVALID_PARAMETER ContextToSave is >= 4GB. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + save the framework and context state. + @retval EFI_DEVICE_ERROR The framework and context state could not be + saved to a persistent storage device due to a + device error. +**/ +EFI_STATUS +EFIAPI +SaveFrameworkState ( + IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL, + IN UINTN ContextToSaveSize + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle; + UNIT_TEST_SAVE_HEADER *Header; + + Header = NULL; + FrameworkHandle = GetActiveFrameworkHandle (); + if (FrameworkHandle == NULL) { + DEBUG ((DEBUG_ERROR, "%a - Could not save state! FrameworkHandle not initialized\n", __func__)); + return EFI_DEVICE_ERROR; + } + + // + // Return a unique error code if the framework is not set. + // + if (FrameworkHandle == NULL) { + return EFI_NOT_FOUND; + } + + // + // First, let's not make assumptions about the parameters. + // + if (((ContextToSave != NULL) && (ContextToSaveSize == 0)) || + (ContextToSaveSize > MAX_UINT32)) + { + return EFI_INVALID_PARAMETER; + } + + // + // Now, let's package up all the data for saving. + // + Header = SerializeState (FrameworkHandle, ContextToSave, ContextToSaveSize); + if (Header == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // All that should be left to do is save it using the associated persistence lib. + // + Status = SaveUnitTestCache (FrameworkHandle, Header, Header->SaveStateSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Could not save state! %r\n", __func__, Status)); + Status = EFI_DEVICE_ERROR; + } + + // + // Free data that was used. + // + FreePool (Header); + + return Status; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf index 0dabd6a6f3..6c03766d0c 100644 --- a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf @@ -1,37 +1,37 @@ -## @file
-# Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications.
-#
-# Copyright (c) Microsoft Corporation.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-##
-
-[Defines]
- INF_VERSION = 0x00010017
- BASE_NAME = UnitTestLib
- MODULE_UNI_FILE = UnitTestLib.uni
- FILE_GUID = 98CEF9CA-15CE-40A3-ADE8-C299953CD0F6
- VERSION_STRING = 1.0
- MODULE_TYPE = UEFI_DRIVER
- LIBRARY_CLASS = UnitTestLib|PEI_CORE PEIM DXE_CORE MM_STANDALONE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER SMM_CORE UEFI_DRIVER UEFI_APPLICATION
-
-[Sources]
- UnitTestLib.c
- RunTests.c
- Assert.c
- Log.c
-
-[Packages]
- MdePkg/MdePkg.dec
- UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
-
-[LibraryClasses]
- BaseLib
- BaseMemoryLib
- PcdLib
- DebugLib
- MemoryAllocationLib
- UnitTestPersistenceLib
- UnitTestResultReportLib
-
-[Pcd]
- gUnitTestFrameworkPkgTokenSpaceGuid.PcdUnitTestLogLevel ## CONSUMES
+## @file +# Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications. +# +# Copyright (c) Microsoft Corporation.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = UnitTestLib + MODULE_UNI_FILE = UnitTestLib.uni + FILE_GUID = 98CEF9CA-15CE-40A3-ADE8-C299953CD0F6 + VERSION_STRING = 1.0 + MODULE_TYPE = UEFI_DRIVER + LIBRARY_CLASS = UnitTestLib|PEI_CORE PEIM DXE_CORE MM_STANDALONE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER SMM_CORE UEFI_DRIVER UEFI_APPLICATION + +[Sources] + UnitTestLib.c + RunTests.c + Assert.c + Log.c + +[Packages] + MdePkg/MdePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + PcdLib + DebugLib + MemoryAllocationLib + UnitTestPersistenceLib + UnitTestResultReportLib + +[Pcd] + gUnitTestFrameworkPkgTokenSpaceGuid.PcdUnitTestLogLevel ## CONSUMES diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.uni b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.uni index fe7c9c7f71..84f98e85f8 100644 --- a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.uni +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.uni @@ -1,11 +1,11 @@ -// /** @file
-// Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications.
-//
-// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-#string STR_MODULE_ABSTRACT #language en-US "Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications"
-
-#string STR_MODULE_DESCRIPTION #language en-US "Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications."
+// /** @file +// Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR> +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications" + +#string STR_MODULE_DESCRIPTION #language en-US "Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications." diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf index b12af91576..a65916c49a 100644 --- a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf @@ -1,38 +1,38 @@ -## @file
-# Library to support Unit Testing from host environments using Cmocka services.
-#
-# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-##
-
-[Defines]
- INF_VERSION = 0x00010017
- BASE_NAME = UnitTestLibCmocka
- MODULE_UNI_FILE = UnitTestLibCmocka.uni
- FILE_GUID = C800595F-45A3-45A1-8B50-28F01C2A5A4F
- VERSION_STRING = 1.0
- MODULE_TYPE = UEFI_DRIVER
- LIBRARY_CLASS = UnitTestLib|HOST_APPLICATION
-
-[Sources]
- UnitTestLib.c
- RunTestsCmocka.c
- AssertCmocka.c
- Log.c
-
-[Packages]
- MdePkg/MdePkg.dec
- UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
-
-[LibraryClasses]
- BaseLib
- BaseMemoryLib
- PcdLib
- DebugLib
- MemoryAllocationLib
- UnitTestPersistenceLib
- UnitTestResultReportLib
- CmockaLib
-
-[Pcd]
- gUnitTestFrameworkPkgTokenSpaceGuid.PcdUnitTestLogLevel ## CONSUMES
+## @file +# Library to support Unit Testing from host environments using Cmocka services. +# +# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = UnitTestLibCmocka + MODULE_UNI_FILE = UnitTestLibCmocka.uni + FILE_GUID = C800595F-45A3-45A1-8B50-28F01C2A5A4F + VERSION_STRING = 1.0 + MODULE_TYPE = UEFI_DRIVER + LIBRARY_CLASS = UnitTestLib|HOST_APPLICATION + +[Sources] + UnitTestLib.c + RunTestsCmocka.c + AssertCmocka.c + Log.c + +[Packages] + MdePkg/MdePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + PcdLib + DebugLib + MemoryAllocationLib + UnitTestPersistenceLib + UnitTestResultReportLib + CmockaLib + +[Pcd] + gUnitTestFrameworkPkgTokenSpaceGuid.PcdUnitTestLogLevel ## CONSUMES diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.uni b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.uni index aa25a44e35..7627dc0128 100644 --- a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.uni +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.uni @@ -1,11 +1,11 @@ -// /** @file
-// Library to support Unit Testing from host environments using Cmocka services.
-//
-// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-#string STR_MODULE_ABSTRACT #language en-US "Library to support Unit Testing from host environments using Cmocka services"
-
-#string STR_MODULE_DESCRIPTION #language en-US "Library to support Unit Testing from host environments using Cmocka services."
+// /** @file +// Library to support Unit Testing from host environments using Cmocka services. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR> +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Library to support Unit Testing from host environments using Cmocka services" + +#string STR_MODULE_DESCRIPTION #language en-US "Library to support Unit Testing from host environments using Cmocka services." |
