mirror of https://github.com/acidanthera/audk.git
UnitTestFrameworkPkg/Library: Add library instances
https://bugzilla.tianocore.org/show_bug.cgi?id=2505 Add the following library instances that are used to build unit tests for host and target environments. * CmockaLib with cmocka submodule to: https://git.cryptomilk.org/projects/cmocka.git * DebugLibPosix - Instance of DebugLib based on POSIX APIs (e.g. printf). * MemoryAllocationLibPosix - Instance of MemoryAllocationLib based on POSIX APIs (e.g. malloc/free). * UnitTestBootLibNull - Null instance of the UnitTestBootLib * UnitTestBootLibUsbClass - UnitTestBootLib instances that supports setting boot next to a USB device. * UnitTestLib - UnitTestLib instance that is designed to work with PEI, DXE, SMM, and UEFI Shell target environments. * UnitTestLibCmocka - UintTestLib instance that uses cmocka APIs and can only be use in a host environment. * UnitTestPersistenceLibNull - Null instance of the UnitTestPersistenceLib * UnitTestPersistenceLibSimpleFileSystem - UnitTestPersistenceLib instance that can safe the unit test framework state to a media device that supports the UEFI Simple File System Protocol. * UnitTestResultReportLibConOut - UnitTestResultReportLib instance that sends report results to the UEFI standard output console. * UnitTestResultReportLibDebugLib - UnitTestResultReportLib instance that sends report results to a DebugLib using DEBUG() macros. Cc: Sean Brogan <sean.brogan@microsoft.com> Cc: Bret Barkelew <Bret.Barkelew@microsoft.com> Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Bret Barkelew <Bret.Barkelew@microsoft.com>
This commit is contained in:
parent
0f7fb5c5e5
commit
0eb522987f
|
@ -4,3 +4,6 @@
|
|||
[submodule "SoftFloat"]
|
||||
path = ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3
|
||||
url = https://github.com/ucb-bar/berkeley-softfloat-3.git
|
||||
[submodule "UnitTestFrameworkPkg/Library/CmockaLib/cmocka"]
|
||||
path = UnitTestFrameworkPkg/Library/CmockaLib/cmocka
|
||||
url = https://git.cryptomilk.org/projects/cmocka.git
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
## @file
|
||||
# This module provides Cmocka Library implementation.
|
||||
#
|
||||
# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = CmockaLib
|
||||
MODULE_UNI_FILE = CmockaLib.uni
|
||||
FILE_GUID = F1662152-3399-49AC-BE44-CAA97575FACE
|
||||
MODULE_TYPE = BASE
|
||||
VERSION_STRING = 0.1
|
||||
LIBRARY_CLASS = CmockaLib|HOST_APPLICATION
|
||||
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64
|
||||
#
|
||||
|
||||
[Sources]
|
||||
cmocka/src/cmocka.c
|
||||
|
||||
[Packages]
|
||||
UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
|
||||
|
||||
[BuildOptions]
|
||||
MSFT:*_*_*_CC_FLAGS == /c -DHAVE_VSNPRINTF -DHAVE_SNPRINTF
|
||||
MSFT:NOOPT_*_*_CC_FLAGS = /Od
|
||||
|
||||
GCC:*_*_*_CC_FLAGS == -g -DHAVE_SIGNAL_H
|
||||
GCC:NOOPT_*_*_CC_FLAGS = -O0
|
||||
GCC:*_*_IA32_CC_FLAGS = -m32
|
||||
GCC:*_*_X64_CC_FLAGS = -m64
|
|
@ -0,0 +1,14 @@
|
|||
// /** @file
|
||||
// This module provides Cmocka Library implementation.
|
||||
//
|
||||
// This module provides Cmocka Library implementation.
|
||||
//
|
||||
// Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "Cmocka Library implementation"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "This module provides Cmocka Library implementation."
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 1cc9cde3448cdd2e000886a26acf1caac2db7cf1
|
|
@ -0,0 +1,279 @@
|
|||
/** @file
|
||||
Instance of Debug Library based on POSIX APIs
|
||||
|
||||
Uses Print Library to produce formatted output strings sent to printf().
|
||||
|
||||
Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Base.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
|
||||
///
|
||||
/// Define the maximum debug and assert message length that this library supports
|
||||
///
|
||||
#define MAX_DEBUG_MESSAGE_LENGTH 0x100
|
||||
|
||||
/**
|
||||
Prints a debug message to the debug output device if the specified error level is enabled.
|
||||
|
||||
If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
|
||||
GetDebugPrintErrorLevel (), then print the message specified by Format and the
|
||||
associated variable argument list to the debug output device.
|
||||
|
||||
If Format is NULL, then ASSERT().
|
||||
|
||||
@param ErrorLevel The error level of the debug message.
|
||||
@param Format The format string for the debug message to print.
|
||||
@param ... The variable argument list whose contents are accessed
|
||||
based on the format string specified by Format.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
DebugPrint (
|
||||
IN UINTN ErrorLevel,
|
||||
IN CONST CHAR8 *Format,
|
||||
...
|
||||
)
|
||||
{
|
||||
VA_LIST Marker;
|
||||
|
||||
VA_START (Marker, Format);
|
||||
DebugVPrint (ErrorLevel, Format, Marker);
|
||||
VA_END (Marker);
|
||||
}
|
||||
|
||||
/**
|
||||
Prints a debug message to the debug output device if the specified
|
||||
error level is enabled.
|
||||
|
||||
If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
|
||||
GetDebugPrintErrorLevel (), then print the message specified by Format and
|
||||
the associated variable argument list to the debug output device.
|
||||
|
||||
If Format is NULL, then ASSERT().
|
||||
|
||||
@param ErrorLevel The error level of the debug message.
|
||||
@param Format Format string for the debug message to print.
|
||||
@param VaListMarker VA_LIST marker for the variable argument list.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
DebugVPrint (
|
||||
IN UINTN ErrorLevel,
|
||||
IN CONST CHAR8 *Format,
|
||||
IN VA_LIST VaListMarker
|
||||
)
|
||||
{
|
||||
CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH];
|
||||
|
||||
AsciiVSPrint (Buffer, sizeof (Buffer), Format, VaListMarker);
|
||||
printf ("%s", Buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
Prints a debug message to the debug output device if the specified
|
||||
error level is enabled.
|
||||
This function use BASE_LIST which would provide a more compatible
|
||||
service than VA_LIST.
|
||||
|
||||
If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
|
||||
GetDebugPrintErrorLevel (), then print the message specified by Format and
|
||||
the associated variable argument list to the debug output device.
|
||||
|
||||
If Format is NULL, then ASSERT().
|
||||
|
||||
@param ErrorLevel The error level of the debug message.
|
||||
@param Format Format string for the debug message to print.
|
||||
@param BaseListMarker BASE_LIST marker for the variable argument list.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
DebugBPrint (
|
||||
IN UINTN ErrorLevel,
|
||||
IN CONST CHAR8 *Format,
|
||||
IN BASE_LIST BaseListMarker
|
||||
)
|
||||
{
|
||||
CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH];
|
||||
|
||||
AsciiBSPrint (Buffer, sizeof (Buffer), Format, BaseListMarker);
|
||||
printf ("%s", Buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
Prints an assert message containing a filename, line number, and description.
|
||||
This may be followed by a breakpoint or a dead loop.
|
||||
|
||||
Print a message of the form "ASSERT <FileName>(<LineNumber>): <Description>\n"
|
||||
to the debug output device. If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of
|
||||
PcdDebugPropertyMask is set then CpuBreakpoint() is called. Otherwise, if
|
||||
DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugPropertyMask is set then
|
||||
CpuDeadLoop() is called. If neither of these bits are set, then this function
|
||||
returns immediately after the message is printed to the debug output device.
|
||||
DebugAssert() must actively prevent recursion. If DebugAssert() is called while
|
||||
processing another DebugAssert(), then DebugAssert() must return immediately.
|
||||
|
||||
If FileName is NULL, then a <FileName> string of "(NULL) Filename" is printed.
|
||||
If Description is NULL, then a <Description> string of "(NULL) Description" is printed.
|
||||
|
||||
@param FileName The pointer to the name of the source file that generated the assert condition.
|
||||
@param LineNumber The line number in the source file that generated the assert condition
|
||||
@param Description The pointer to the description of the assert condition.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
DebugAssert (
|
||||
IN CONST CHAR8 *FileName,
|
||||
IN UINTN LineNumber,
|
||||
IN CONST CHAR8 *Description
|
||||
)
|
||||
{
|
||||
printf ("ASSERT: %s(%d): %s\n", FileName, (INT32)(UINT32)LineNumber, Description);
|
||||
|
||||
//
|
||||
// Generate a Breakpoint, DeadLoop, or NOP based on PCD settings
|
||||
//
|
||||
if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) {
|
||||
CpuBreakpoint ();
|
||||
} else if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) {
|
||||
CpuDeadLoop ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Fills a target buffer with PcdDebugClearMemoryValue, and returns the target buffer.
|
||||
|
||||
This function fills Length bytes of Buffer with the value specified by
|
||||
PcdDebugClearMemoryValue, and returns Buffer.
|
||||
|
||||
If Buffer is NULL, then ASSERT().
|
||||
If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
|
||||
|
||||
@param Buffer The pointer to the target buffer to be filled with PcdDebugClearMemoryValue.
|
||||
@param Length The number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue.
|
||||
|
||||
@return Buffer The pointer to the target buffer filled with PcdDebugClearMemoryValue.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
DebugClearMemory (
|
||||
OUT VOID *Buffer,
|
||||
IN UINTN Length
|
||||
)
|
||||
{
|
||||
//
|
||||
// If Buffer is NULL, then ASSERT().
|
||||
//
|
||||
ASSERT (Buffer != NULL);
|
||||
|
||||
//
|
||||
// SetMem() checks for the the ASSERT() condition on Length and returns Buffer
|
||||
//
|
||||
return SetMem (Buffer, Length, PcdGet8(PcdDebugClearMemoryValue));
|
||||
}
|
||||
|
||||
/**
|
||||
Returns TRUE if ASSERT() macros are enabled.
|
||||
|
||||
This function returns TRUE if the DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of
|
||||
PcdDebugPropertyMask is set. Otherwise FALSE is returned.
|
||||
|
||||
@retval TRUE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugPropertyMask is set.
|
||||
@retval FALSE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugPropertyMask is clear.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
DebugAssertEnabled (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns TRUE if DEBUG() macros are enabled.
|
||||
|
||||
This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of
|
||||
PcdDebugPropertyMask is set. Otherwise FALSE is returned.
|
||||
|
||||
@retval TRUE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugPropertyMask is set.
|
||||
@retval FALSE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugPropertyMask is clear.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
DebugPrintEnabled (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns TRUE if DEBUG_CODE() macros are enabled.
|
||||
|
||||
This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of
|
||||
PcdDebugPropertyMask is set. Otherwise FALSE is returned.
|
||||
|
||||
@retval TRUE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugPropertyMask is set.
|
||||
@retval FALSE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugPropertyMask is clear.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
DebugCodeEnabled (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns TRUE if DEBUG_CLEAR_MEMORY() macro is enabled.
|
||||
|
||||
This function returns TRUE if the DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of
|
||||
PcdDebugPropertyMask is set. Otherwise FALSE is returned.
|
||||
|
||||
@retval TRUE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugPropertyMask is set.
|
||||
@retval FALSE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugPropertyMask is clear.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
DebugClearMemoryEnabled (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns TRUE if any one of the bit is set both in ErrorLevel and PcdFixedDebugPrintErrorLevel.
|
||||
|
||||
This function compares the bit mask of ErrorLevel and PcdFixedDebugPrintErrorLevel.
|
||||
|
||||
@retval TRUE Current ErrorLevel is supported.
|
||||
@retval FALSE Current ErrorLevel is not supported.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
DebugPrintLevelEnabled (
|
||||
IN CONST UINTN ErrorLevel
|
||||
)
|
||||
{
|
||||
return (BOOLEAN) ((ErrorLevel & PcdGet32(PcdFixedDebugPrintErrorLevel)) != 0);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
## @file
|
||||
# Instance of Debug Library based on POSIX APIs
|
||||
#
|
||||
# Uses Print Library to produce formatted output strings sent to printf().
|
||||
#
|
||||
# Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = DebugLibPosix
|
||||
MODULE_UNI_FILE = DebugLibPosix.uni
|
||||
FILE_GUID = 6A77CE89-C1B6-4A6B-9561-07D7127514A7
|
||||
MODULE_TYPE = BASE
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = DebugLib|HOST_APPLICATION
|
||||
|
||||
[Sources]
|
||||
DebugLibPosix.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
BaseMemoryLib
|
||||
PcdLib
|
||||
PrintLib
|
||||
BaseLib
|
||||
|
||||
[Pcd]
|
||||
gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue ## SOMETIMES_CONSUMES
|
||||
gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask ## CONSUMES
|
||||
gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel ## CONSUMES
|
|
@ -0,0 +1,14 @@
|
|||
// /** @file
|
||||
// Instance of Debug Library based on POSIX APIs
|
||||
//
|
||||
// Uses Print Library to produce formatted output strings sent to printf().
|
||||
//
|
||||
// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "Instance of Debug Library based on POSIX APIs"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "Uses Print Library to produce formatted output strings sent to printf()."
|
|
@ -0,0 +1,631 @@
|
|||
/** @file
|
||||
Instance of Memory Allocation Library based on POSIX APIs
|
||||
|
||||
Uses POSIX APIs malloc() and free() to allocate and free memory.
|
||||
|
||||
Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
|
||||
///
|
||||
/// Signature for PAGE_HEAD structure
|
||||
/// Used to verify that buffer being freed was allocated by this library.
|
||||
///
|
||||
#define PAGE_HEAD_PRIVATE_SIGNATURE SIGNATURE_32 ('P', 'H', 'D', 'R')
|
||||
|
||||
///
|
||||
/// Structure placed immediately before an aligned allocation to store the
|
||||
/// information required to free the entire buffer allocated to support then
|
||||
/// aligned allocation.
|
||||
///
|
||||
typedef struct {
|
||||
UINT32 Signature;
|
||||
VOID *AllocatedBufffer;
|
||||
UINTN TotalPages;
|
||||
VOID *AlignedBuffer;
|
||||
UINTN AlignedPages;
|
||||
} PAGE_HEAD;
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of type EfiBootServicesData.
|
||||
|
||||
Allocates the number of 4KB pages of type EfiBootServicesData and returns a pointer to the
|
||||
allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
|
||||
is returned. If there is not enough memory remaining to satisfy the request, then NULL is
|
||||
returned.
|
||||
|
||||
@param Pages The number of 4 KB pages to allocate.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocatePages (
|
||||
IN UINTN Pages
|
||||
)
|
||||
{
|
||||
return AllocateAlignedPages (Pages, SIZE_4KB);
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of type EfiRuntimeServicesData.
|
||||
|
||||
Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
|
||||
allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
|
||||
is returned. If there is not enough memory remaining to satisfy the request, then NULL is
|
||||
returned.
|
||||
|
||||
@param Pages The number of 4 KB pages to allocate.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocateRuntimePages (
|
||||
IN UINTN Pages
|
||||
)
|
||||
{
|
||||
return AllocatePages (Pages);
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of type EfiReservedMemoryType.
|
||||
|
||||
Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a pointer to the
|
||||
allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
|
||||
is returned. If there is not enough memory remaining to satisfy the request, then NULL is
|
||||
returned.
|
||||
|
||||
@param Pages The number of 4 KB pages to allocate.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocateReservedPages (
|
||||
IN UINTN Pages
|
||||
)
|
||||
{
|
||||
return AllocatePages (Pages);
|
||||
}
|
||||
|
||||
/**
|
||||
Frees one or more 4KB pages that were previously allocated with one of the page allocation
|
||||
functions in the Memory Allocation Library.
|
||||
|
||||
Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
|
||||
must have been allocated on a previous call to the page allocation services of the Memory
|
||||
Allocation Library. If it is not possible to free allocated pages, then this function will
|
||||
perform no actions.
|
||||
|
||||
If Buffer was not allocated with a page allocation function in the Memory Allocation Library,
|
||||
then ASSERT().
|
||||
If Pages is zero, then ASSERT().
|
||||
|
||||
@param Buffer The pointer to the buffer of pages to free.
|
||||
@param Pages The number of 4 KB pages to free.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
FreePages (
|
||||
IN VOID *Buffer,
|
||||
IN UINTN Pages
|
||||
)
|
||||
{
|
||||
FreeAlignedPages (Buffer, Pages);
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment.
|
||||
|
||||
Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an
|
||||
alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
|
||||
returned. If there is not enough memory at the specified alignment remaining to satisfy the
|
||||
request, then NULL is returned.
|
||||
|
||||
If Alignment is not a power of two and Alignment is not zero, then ASSERT().
|
||||
If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
|
||||
|
||||
@param Pages The number of 4 KB pages to allocate.
|
||||
@param Alignment The requested alignment of the allocation. Must be a power of two.
|
||||
If Alignment is zero, then byte alignment is used.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/VOID *
|
||||
EFIAPI
|
||||
AllocateAlignedPages (
|
||||
IN UINTN Pages,
|
||||
IN UINTN Alignment
|
||||
)
|
||||
{
|
||||
PAGE_HEAD PageHead;
|
||||
PAGE_HEAD *PageHeadPtr;
|
||||
UINTN AlignmentMask;
|
||||
|
||||
ASSERT ((Alignment & (Alignment - 1)) == 0);
|
||||
|
||||
if (Alignment < SIZE_4KB) {
|
||||
Alignment = SIZE_4KB;
|
||||
}
|
||||
AlignmentMask = Alignment - 1;
|
||||
|
||||
//
|
||||
// We need reserve Alignment pages for PAGE_HEAD, as meta data.
|
||||
//
|
||||
PageHead.Signature = PAGE_HEAD_PRIVATE_SIGNATURE;
|
||||
PageHead.TotalPages = Pages + EFI_SIZE_TO_PAGES (Alignment) * 2;
|
||||
PageHead.AlignedPages = Pages;
|
||||
PageHead.AllocatedBufffer = malloc (EFI_PAGES_TO_SIZE (PageHead.TotalPages));
|
||||
if (PageHead.AllocatedBufffer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PageHead.AlignedBuffer = (VOID *)(((UINTN) PageHead.AllocatedBufffer + AlignmentMask) & ~AlignmentMask);
|
||||
if ((UINTN)PageHead.AlignedBuffer - (UINTN)PageHead.AllocatedBufffer < sizeof(PAGE_HEAD)) {
|
||||
PageHead.AlignedBuffer = (VOID *)((UINTN)PageHead.AlignedBuffer + Alignment);
|
||||
}
|
||||
|
||||
PageHeadPtr = (VOID *)((UINTN)PageHead.AlignedBuffer - sizeof(PAGE_HEAD));
|
||||
memcpy (PageHeadPtr, &PageHead, sizeof(PAGE_HEAD));
|
||||
|
||||
return PageHead.AlignedBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment.
|
||||
|
||||
Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an
|
||||
alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
|
||||
returned. If there is not enough memory at the specified alignment remaining to satisfy the
|
||||
request, then NULL is returned.
|
||||
|
||||
If Alignment is not a power of two and Alignment is not zero, then ASSERT().
|
||||
If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
|
||||
|
||||
@param Pages The number of 4 KB pages to allocate.
|
||||
@param Alignment The requested alignment of the allocation. Must be a power of two.
|
||||
If Alignment is zero, then byte alignment is used.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocateAlignedRuntimePages (
|
||||
IN UINTN Pages,
|
||||
IN UINTN Alignment
|
||||
)
|
||||
{
|
||||
return AllocateAlignedPages (Pages, Alignment);
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment.
|
||||
|
||||
Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType with an
|
||||
alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
|
||||
returned. If there is not enough memory at the specified alignment remaining to satisfy the
|
||||
request, then NULL is returned.
|
||||
|
||||
If Alignment is not a power of two and Alignment is not zero, then ASSERT().
|
||||
If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
|
||||
|
||||
@param Pages The number of 4 KB pages to allocate.
|
||||
@param Alignment The requested alignment of the allocation. Must be a power of two.
|
||||
If Alignment is zero, then byte alignment is used.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocateAlignedReservedPages (
|
||||
IN UINTN Pages,
|
||||
IN UINTN Alignment
|
||||
)
|
||||
{
|
||||
return AllocateAlignedPages (Pages, Alignment);
|
||||
}
|
||||
|
||||
/**
|
||||
Frees one or more 4KB pages that were previously allocated with one of the aligned page
|
||||
allocation functions in the Memory Allocation Library.
|
||||
|
||||
Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
|
||||
must have been allocated on a previous call to the aligned page allocation services of the Memory
|
||||
Allocation Library. If it is not possible to free allocated pages, then this function will
|
||||
perform no actions.
|
||||
|
||||
If Buffer was not allocated with an aligned page allocation function in the Memory Allocation
|
||||
Library, then ASSERT().
|
||||
If Pages is zero, then ASSERT().
|
||||
|
||||
@param Buffer The pointer to the buffer of pages to free.
|
||||
@param Pages The number of 4 KB pages to free.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
FreeAlignedPages (
|
||||
IN VOID *Buffer,
|
||||
IN UINTN Pages
|
||||
)
|
||||
{
|
||||
PAGE_HEAD *PageHeadPtr;
|
||||
|
||||
//
|
||||
// NOTE: Partial free is not supported. Just keep it.
|
||||
//
|
||||
PageHeadPtr = (VOID *)((UINTN)Buffer - sizeof(PAGE_HEAD));
|
||||
if (PageHeadPtr->Signature != PAGE_HEAD_PRIVATE_SIGNATURE) {
|
||||
return;
|
||||
}
|
||||
if (PageHeadPtr->AlignedPages != Pages) {
|
||||
return;
|
||||
}
|
||||
|
||||
PageHeadPtr->Signature = 0;
|
||||
free (PageHeadPtr->AllocatedBufffer);
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates a buffer of type EfiBootServicesData.
|
||||
|
||||
Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a
|
||||
pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
|
||||
returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
|
||||
|
||||
@param AllocationSize The number of bytes to allocate.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/VOID *
|
||||
EFIAPI
|
||||
AllocatePool (
|
||||
IN UINTN AllocationSize
|
||||
)
|
||||
{
|
||||
return malloc (AllocationSize);
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates a buffer of type EfiRuntimeServicesData.
|
||||
|
||||
Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns
|
||||
a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
|
||||
returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
|
||||
|
||||
@param AllocationSize The number of bytes to allocate.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocateRuntimePool (
|
||||
IN UINTN AllocationSize
|
||||
)
|
||||
{
|
||||
return AllocatePool (AllocationSize);
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates a buffer of type EfiReservedMemoryType.
|
||||
|
||||
Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType and returns
|
||||
a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
|
||||
returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
|
||||
|
||||
@param AllocationSize The number of bytes to allocate.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocateReservedPool (
|
||||
IN UINTN AllocationSize
|
||||
)
|
||||
{
|
||||
return AllocatePool (AllocationSize);
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates and zeros a buffer of type EfiBootServicesData.
|
||||
|
||||
Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
|
||||
buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
|
||||
valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
|
||||
request, then NULL is returned.
|
||||
|
||||
@param AllocationSize The number of bytes to allocate and zero.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocateZeroPool (
|
||||
IN UINTN AllocationSize
|
||||
)
|
||||
{
|
||||
VOID *Buffer;
|
||||
|
||||
Buffer = malloc (AllocationSize);
|
||||
if (Buffer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memset (Buffer, 0, AllocationSize);
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates and zeros a buffer of type EfiRuntimeServicesData.
|
||||
|
||||
Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the
|
||||
buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
|
||||
valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
|
||||
request, then NULL is returned.
|
||||
|
||||
@param AllocationSize The number of bytes to allocate and zero.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocateRuntimeZeroPool (
|
||||
IN UINTN AllocationSize
|
||||
)
|
||||
{
|
||||
return AllocateZeroPool (AllocationSize);
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates and zeros a buffer of type EfiReservedMemoryType.
|
||||
|
||||
Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, clears the
|
||||
buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
|
||||
valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
|
||||
request, then NULL is returned.
|
||||
|
||||
@param AllocationSize The number of bytes to allocate and zero.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocateReservedZeroPool (
|
||||
IN UINTN AllocationSize
|
||||
)
|
||||
{
|
||||
return AllocateZeroPool (AllocationSize);
|
||||
}
|
||||
|
||||
/**
|
||||
Copies a buffer to an allocated buffer of type EfiBootServicesData.
|
||||
|
||||
Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, copies
|
||||
AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
|
||||
allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
|
||||
is not enough memory remaining to satisfy the request, then NULL is returned.
|
||||
|
||||
If Buffer is NULL, then ASSERT().
|
||||
If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
|
||||
|
||||
@param AllocationSize The number of bytes to allocate and zero.
|
||||
@param Buffer The buffer to copy to the allocated buffer.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocateCopyPool (
|
||||
IN UINTN AllocationSize,
|
||||
IN CONST VOID *Buffer
|
||||
)
|
||||
{
|
||||
VOID *Memory;
|
||||
|
||||
Memory = malloc (AllocationSize);
|
||||
if (Memory == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy (Memory, Buffer, AllocationSize);
|
||||
return Memory;
|
||||
}
|
||||
|
||||
/**
|
||||
Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.
|
||||
|
||||
Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies
|
||||
AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
|
||||
allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
|
||||
is not enough memory remaining to satisfy the request, then NULL is returned.
|
||||
|
||||
If Buffer is NULL, then ASSERT().
|
||||
If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
|
||||
|
||||
@param AllocationSize The number of bytes to allocate and zero.
|
||||
@param Buffer The buffer to copy to the allocated buffer.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocateRuntimeCopyPool (
|
||||
IN UINTN AllocationSize,
|
||||
IN CONST VOID *Buffer
|
||||
)
|
||||
{
|
||||
return AllocateCopyPool (AllocationSize, Buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
Copies a buffer to an allocated buffer of type EfiReservedMemoryType.
|
||||
|
||||
Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, copies
|
||||
AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
|
||||
allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
|
||||
is not enough memory remaining to satisfy the request, then NULL is returned.
|
||||
|
||||
If Buffer is NULL, then ASSERT().
|
||||
If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
|
||||
|
||||
@param AllocationSize The number of bytes to allocate and zero.
|
||||
@param Buffer The buffer to copy to the allocated buffer.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocateReservedCopyPool (
|
||||
IN UINTN AllocationSize,
|
||||
IN CONST VOID *Buffer
|
||||
)
|
||||
{
|
||||
return AllocateCopyPool (AllocationSize, Buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
Reallocates a buffer of type EfiBootServicesData.
|
||||
|
||||
Allocates and zeros the number bytes specified by NewSize from memory of type
|
||||
EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
|
||||
NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
|
||||
OldBuffer is freed. A pointer to the newly allocated buffer is returned.
|
||||
If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
|
||||
enough memory remaining to satisfy the request, then NULL is returned.
|
||||
|
||||
If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
|
||||
is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
|
||||
|
||||
@param OldSize The size, in bytes, of OldBuffer.
|
||||
@param NewSize The size, in bytes, of the buffer to reallocate.
|
||||
@param OldBuffer The buffer to copy to the allocated buffer. This is an optional
|
||||
parameter that may be NULL.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
ReallocatePool (
|
||||
IN UINTN OldSize,
|
||||
IN UINTN NewSize,
|
||||
IN VOID *OldBuffer OPTIONAL
|
||||
)
|
||||
{
|
||||
VOID *NewBuffer;
|
||||
|
||||
NewBuffer = malloc (NewSize);
|
||||
if (NewBuffer != NULL && OldBuffer != NULL) {
|
||||
memcpy (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
|
||||
}
|
||||
if (OldBuffer != NULL) {
|
||||
FreePool(OldBuffer);
|
||||
}
|
||||
return NewBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
Reallocates a buffer of type EfiRuntimeServicesData.
|
||||
|
||||
Allocates and zeros the number bytes specified by NewSize from memory of type
|
||||
EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
|
||||
NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
|
||||
OldBuffer is freed. A pointer to the newly allocated buffer is returned.
|
||||
If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
|
||||
enough memory remaining to satisfy the request, then NULL is returned.
|
||||
|
||||
If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
|
||||
is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
|
||||
|
||||
@param OldSize The size, in bytes, of OldBuffer.
|
||||
@param NewSize The size, in bytes, of the buffer to reallocate.
|
||||
@param OldBuffer The buffer to copy to the allocated buffer. This is an optional
|
||||
parameter that may be NULL.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
ReallocateRuntimePool (
|
||||
IN UINTN OldSize,
|
||||
IN UINTN NewSize,
|
||||
IN VOID *OldBuffer OPTIONAL
|
||||
)
|
||||
{
|
||||
return ReallocatePool (OldSize, NewSize, OldBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
Reallocates a buffer of type EfiReservedMemoryType.
|
||||
|
||||
Allocates and zeros the number bytes specified by NewSize from memory of type
|
||||
EfiReservedMemoryType. If OldBuffer is not NULL, then the smaller of OldSize and
|
||||
NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
|
||||
OldBuffer is freed. A pointer to the newly allocated buffer is returned.
|
||||
If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
|
||||
enough memory remaining to satisfy the request, then NULL is returned.
|
||||
|
||||
If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
|
||||
is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
|
||||
|
||||
@param OldSize The size, in bytes, of OldBuffer.
|
||||
@param NewSize The size, in bytes, of the buffer to reallocate.
|
||||
@param OldBuffer The buffer to copy to the allocated buffer. This is an optional
|
||||
parameter that may be NULL.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
ReallocateReservedPool (
|
||||
IN UINTN OldSize,
|
||||
IN UINTN NewSize,
|
||||
IN VOID *OldBuffer OPTIONAL
|
||||
)
|
||||
{
|
||||
return ReallocatePool (OldSize, NewSize, OldBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
Frees a buffer that was previously allocated with one of the pool allocation functions in the
|
||||
Memory Allocation Library.
|
||||
|
||||
Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
|
||||
pool allocation services of the Memory Allocation Library. If it is not possible to free pool
|
||||
resources, then this function will perform no actions.
|
||||
|
||||
If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
|
||||
then ASSERT().
|
||||
|
||||
@param Buffer The pointer to the buffer to free.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
FreePool (
|
||||
IN VOID *Buffer
|
||||
)
|
||||
{
|
||||
free (Buffer);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
## @file
|
||||
# Instance of Memory Allocation Library based on POSIX APIs
|
||||
#
|
||||
# Uses POSIX APIs malloc() and free() to allocate and free memory.
|
||||
#
|
||||
# Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = MemoryAllocationLibPosix
|
||||
MODULE_UNI_FILE = MemoryAllocationLibPosix.uni
|
||||
FILE_GUID = A1672454-A3D3-4AAC-A86B-8D63132BBB91
|
||||
MODULE_TYPE = UEFI_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = MemoryAllocationLib|HOST_APPLICATION
|
||||
|
||||
[Sources]
|
||||
MemoryAllocationLibPosix.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
|
@ -0,0 +1,14 @@
|
|||
// /** @file
|
||||
// Instance of Memory Allocation Library based on POSIX APIs
|
||||
//
|
||||
// Uses POSIX APIs malloc() and free() to allocate and free memory.
|
||||
//
|
||||
// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "Instance of Memory Allocation Library based on POSIX APIs"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "Uses POSIX APIs malloc() and free() to allocate and free memory."
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
NULL implementation for UnitTestBootLib to allow simple compilation
|
||||
|
||||
Copyright (c) Microsoft Corporation.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include <PiDxe.h>
|
||||
|
||||
/**
|
||||
Set the boot manager to boot from a specific device on the next boot. This
|
||||
should be set only for the next boot and shouldn't require any manual clean up
|
||||
|
||||
@retval EFI_SUCCESS Boot device for next boot was set.
|
||||
@retval EFI_UNSUPPORTED Setting the boot device for the next boot is not
|
||||
supportted.
|
||||
@retval Other Boot device for next boot can not be set.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SetBootNextDevice(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
## @file
|
||||
# NULL library for UnitTestBootUsb
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010017
|
||||
BASE_NAME = UnitTestBootLibNull
|
||||
MODULE_UNI_FILE = UnitTestBootLibNull.uni
|
||||
FILE_GUID = f143e75d-76e1-4040-b134-8f4f0bd5e3bd
|
||||
VERSION_STRING = 1.0
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
LIBRARY_CLASS = UnitTestBootLib
|
||||
|
||||
[Sources]
|
||||
UnitTestBootLibNull.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// /** @file
|
||||
// NULL library for UnitTestBootUsb
|
||||
//
|
||||
// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "NULL library for UnitTestBootUsb"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "NULL library for UnitTestBootUsb."
|
|
@ -0,0 +1,127 @@
|
|||
/**
|
||||
Implement UnitTestBootLib using USB Class Boot option. This should be
|
||||
industry standard and should work on all platforms
|
||||
|
||||
Copyright (c) Microsoft Corporation.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include <PiDxe.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
#include <Library/UefiBootManagerLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Protocol/DevicePath.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
|
||||
/**
|
||||
Set the boot manager to boot from a specific device on the next boot. This
|
||||
should be set only for the next boot and shouldn't require any manual clean up
|
||||
|
||||
@retval EFI_SUCCESS Boot device for next boot was set.
|
||||
@retval EFI_UNSUPPORTED Setting the boot device for the next boot is not
|
||||
supportted.
|
||||
@retval Other Boot device for next boot can not be set.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SetBootNextDevice (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
|
||||
UINT32 Attributes;
|
||||
UINT8 *OptionalData;
|
||||
UINT32 OptionalDataSize;
|
||||
UINT16 BootNextValue;
|
||||
USB_CLASS_DEVICE_PATH UsbDp;
|
||||
EFI_DEVICE_PATH_PROTOCOL *DpEnd;
|
||||
EFI_DEVICE_PATH_PROTOCOL *Dp;
|
||||
BOOLEAN NewOptionValid;
|
||||
|
||||
OptionalData = NULL;
|
||||
OptionalDataSize = 0;
|
||||
BootNextValue = 0xABCD; // this should be a safe number...
|
||||
DpEnd = NULL;
|
||||
Dp = NULL;
|
||||
NewOptionValid = FALSE;
|
||||
|
||||
UsbDp.Header.Length[0] = (UINT8)(sizeof(USB_CLASS_DEVICE_PATH) & 0xff);
|
||||
UsbDp.Header.Length[1] = (UINT8)(sizeof(USB_CLASS_DEVICE_PATH) >> 8);
|
||||
UsbDp.Header.Type = MESSAGING_DEVICE_PATH;
|
||||
UsbDp.Header.SubType = MSG_USB_CLASS_DP;
|
||||
UsbDp.VendorId = 0xFFFF;
|
||||
UsbDp.ProductId = 0xFFFF;
|
||||
UsbDp.DeviceClass = 0xFF;
|
||||
UsbDp.DeviceSubClass = 0xFF;
|
||||
UsbDp.DeviceProtocol = 0xFF;
|
||||
|
||||
Attributes = LOAD_OPTION_ACTIVE;
|
||||
|
||||
DpEnd = AppendDevicePathNode (NULL, NULL);
|
||||
if (DpEnd == NULL) {
|
||||
DEBUG ((DEBUG_ERROR, "%a: Unable to create device path. DpEnd is NULL.\n", __FUNCTION__));
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
//@MRT --- Is this memory leak because we lose the old Dp memory
|
||||
Dp = AppendDevicePathNode (
|
||||
DpEnd,
|
||||
(EFI_DEVICE_PATH_PROTOCOL *)&UsbDp
|
||||
);
|
||||
if (Dp == NULL) {
|
||||
DEBUG((DEBUG_ERROR, "%a: Unable to create device path. Dp is NULL.\n", __FUNCTION__));
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
Status = EfiBootManagerInitializeLoadOption (
|
||||
&NewOption,
|
||||
(UINTN) BootNextValue,
|
||||
LoadOptionTypeBoot,
|
||||
Attributes,
|
||||
L"Generic USB Class Device",
|
||||
Dp,
|
||||
OptionalData,
|
||||
OptionalDataSize
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR, "%a: Error creating load option. Status = %r\n", __FUNCTION__, Status));
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
NewOptionValid = TRUE;
|
||||
DEBUG ((DEBUG_VERBOSE, "%a: Generic USB Class Device boot option created.\n", __FUNCTION__));
|
||||
Status = EfiBootManagerLoadOptionToVariable (&NewOption);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR, "%a: Error Saving boot option NV variable. Status = %r\n", __FUNCTION__, Status));
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
//
|
||||
// Set Boot Next
|
||||
//
|
||||
Status = gRT->SetVariable (
|
||||
L"BootNext",
|
||||
&gEfiGlobalVariableGuid,
|
||||
(EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE),
|
||||
sizeof(BootNextValue),
|
||||
&(BootNextValue)
|
||||
);
|
||||
|
||||
DEBUG((DEBUG_VERBOSE, "%a - Set BootNext Status (%r)\n", __FUNCTION__, Status));
|
||||
|
||||
CLEANUP:
|
||||
if (Dp != NULL) {
|
||||
FreePool (Dp);
|
||||
}
|
||||
if (DpEnd != NULL) {
|
||||
FreePool (DpEnd);
|
||||
}
|
||||
if (NewOptionValid) {
|
||||
EfiBootManagerFreeLoadOption (&NewOption);
|
||||
}
|
||||
return Status;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
## @file
|
||||
# Library to support booting to USB on the next boot
|
||||
# This instance uses the industry standard usb class boot option.
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010017
|
||||
BASE_NAME = UnitTestBootLibUsbClass
|
||||
MODULE_UNI_FILE = UnitTestBootLibUsbClass.uni
|
||||
FILE_GUID = DFADE2A2-DB69-47DE-A37A-40FB6D52E844
|
||||
VERSION_STRING = 1.0
|
||||
MODULE_TYPE = UEFI_APPLICATION
|
||||
LIBRARY_CLASS = UnitTestBootLib
|
||||
|
||||
[Sources]
|
||||
UnitTestBootLibUsbClass.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
DebugLib
|
||||
UefiRuntimeServicesTableLib
|
||||
MemoryAllocationLib
|
||||
DevicePathLib
|
||||
UefiBootManagerLib
|
||||
|
||||
[Guids]
|
||||
gEfiGlobalVariableGuid ## CONSUMES ## Used to probe boot options and set BootNext.
|
|
@ -0,0 +1,12 @@
|
|||
// /** @file
|
||||
// Library to support booting to USB on the next boot
|
||||
// This instance uses the industry standard usb class boot option.
|
||||
//
|
||||
// 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 booting to USB on the next boot"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "This instance uses the industry standard usb class boot option.."
|
|
@ -0,0 +1,491 @@
|
|||
/**
|
||||
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>
|
||||
|
||||
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
|
||||
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 ();
|
||||
|
||||
//
|
||||
// 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
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
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) {
|
||||
UnitTestLogFailure (
|
||||
FAILURETYPE_ASSERTTRUE,
|
||||
"%a::%d Expression (%a) is not TRUE!\n",
|
||||
FunctionName,
|
||||
LineNumber,
|
||||
Description
|
||||
);
|
||||
UT_LOG_ERROR (
|
||||
"[ASSERT FAIL] %a::%d Expression (%a) is not TRUE!\n",
|
||||
FunctionName,
|
||||
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) {
|
||||
UnitTestLogFailure (
|
||||
FAILURETYPE_ASSERTFALSE,
|
||||
"%a::%d Expression(%a) is not FALSE!\n",
|
||||
FunctionName,
|
||||
LineNumber,
|
||||
Description
|
||||
);
|
||||
UT_LOG_ERROR (
|
||||
"[ASSERT FAIL] %a::%d Expression (%a) is not FALSE!\n",
|
||||
FunctionName,
|
||||
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)) {
|
||||
UnitTestLogFailure (
|
||||
FAILURETYPE_ASSERTNOTEFIERROR,
|
||||
"%a::%d Status '%a' is EFI_ERROR (%r)!\n",
|
||||
FunctionName,
|
||||
LineNumber,
|
||||
Description,
|
||||
Status
|
||||
);
|
||||
UT_LOG_ERROR (
|
||||
"[ASSERT FAIL] %a::%d Status '%a' is EFI_ERROR (%r)!\n",
|
||||
FunctionName,
|
||||
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)) {
|
||||
UnitTestLogFailure (
|
||||
FAILURETYPE_ASSERTEQUAL,
|
||||
"%a::%d Value %a != %a (%d != %d)!\n",
|
||||
FunctionName,
|
||||
LineNumber,
|
||||
DescriptionA,
|
||||
DescriptionB,
|
||||
ValueA,
|
||||
ValueB
|
||||
);
|
||||
UT_LOG_ERROR (
|
||||
"[ASSERT FAIL] %a::%d Value %a != %a (%d != %d)!\n",
|
||||
FunctionName,
|
||||
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) {
|
||||
UnitTestLogFailure (
|
||||
FAILURETYPE_ASSERTEQUAL,
|
||||
"%a::%d Memory at %a != %a for length %d bytes!\n",
|
||||
FunctionName,
|
||||
LineNumber,
|
||||
DescriptionA,
|
||||
DescriptionB,
|
||||
Length
|
||||
);
|
||||
UT_LOG_ERROR (
|
||||
"[ASSERT FAIL] %a::%d Value %a != %a for length %d bytes!\n",
|
||||
FunctionName,
|
||||
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)) {
|
||||
UnitTestLogFailure (
|
||||
FAILURETYPE_ASSERTNOTEQUAL,
|
||||
"%a::%d Value %a == %a (%d == %d)!\n",
|
||||
FunctionName,
|
||||
LineNumber,
|
||||
DescriptionA,
|
||||
DescriptionB,
|
||||
ValueA,
|
||||
ValueB
|
||||
);
|
||||
UT_LOG_ERROR (
|
||||
"[ASSERT FAIL] %a::%d Value %a == %a (%d == %d)!\n",
|
||||
FunctionName,
|
||||
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)) {
|
||||
UnitTestLogFailure (
|
||||
FAILURETYPE_ASSERTSTATUSEQUAL,
|
||||
"%a::%d Status '%a' is %r, should be %r!\n",
|
||||
FunctionName,
|
||||
LineNumber,
|
||||
Description,
|
||||
Status,
|
||||
Expected
|
||||
);
|
||||
UT_LOG_ERROR (
|
||||
"[ASSERT FAIL] %a::%d Status '%a' is %r, should be %r!\n",
|
||||
FunctionName,
|
||||
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) {
|
||||
UnitTestLogFailure (
|
||||
FAILURETYPE_ASSERTNOTNULL,
|
||||
"%a::%d Pointer (%a) is NULL!\n",
|
||||
FunctionName,
|
||||
LineNumber,
|
||||
PointerName
|
||||
);
|
||||
UT_LOG_ERROR (
|
||||
"[ASSERT FAIL] %a::%d Pointer (%a) is NULL!\n",
|
||||
FunctionName,
|
||||
LineNumber,
|
||||
PointerName
|
||||
);
|
||||
}
|
||||
return (Pointer != NULL);
|
||||
}
|
|
@ -0,0 +1,335 @@
|
|||
/** @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)", Description, (VOID *)Status);
|
||||
_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);
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
/**
|
||||
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", __FUNCTION__));
|
||||
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 ();
|
||||
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
/**
|
||||
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;
|
||||
|
||||
UNIT_TEST_FRAMEWORK_HANDLE
|
||||
GetActiveFrameworkHandle (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
ASSERT (mFrameworkHandle != NULL);
|
||||
return mFrameworkHandle;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
RunTestSuite (
|
||||
IN UNIT_TEST_SUITE *Suite
|
||||
)
|
||||
{
|
||||
UNIT_TEST_LIST_ENTRY *TestEntry;
|
||||
UNIT_TEST *Test;
|
||||
UNIT_TEST_FRAMEWORK *ParentFramework;
|
||||
|
||||
TestEntry = NULL;
|
||||
ParentFramework = (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework;
|
||||
|
||||
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"));
|
||||
|
||||
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 (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;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 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.
|
||||
Test->Result = UNIT_TEST_RUNNING;
|
||||
Test->Result = Test->RunTest (Test->Context);
|
||||
|
||||
//
|
||||
// Finally, clean everything up, if need be.
|
||||
if (Test->CleanUp != NULL) {
|
||||
DEBUG ((DEBUG_VERBOSE, "CLEANUP\n"));
|
||||
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 (FrameworkHandle, NULL, 0);
|
||||
OutputUnitTestFrameworkReport (FrameworkHandle);
|
||||
|
||||
mFrameworkHandle = NULL;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,278 @@
|
|||
/** @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
|
||||
)
|
||||
{
|
||||
ASSERT (mFrameworkHandle != NULL);
|
||||
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;
|
||||
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Framework->CurrentTest = UnitTest;
|
||||
UnitTest->CleanUp (UnitTest->Context);
|
||||
Framework->CurrentTest = NULL;
|
||||
//
|
||||
// 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;
|
||||
}
|
|
@ -0,0 +1,853 @@
|
|||
/**
|
||||
Implement UnitTestLib
|
||||
|
||||
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/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;
|
||||
UNIT_TEST_SAVE_HEADER *SavedState;
|
||||
|
||||
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)) {
|
||||
SavedState = (UNIT_TEST_SAVE_HEADER *)NewFramework->SavedState;
|
||||
Status = LoadUnitTestCache (NewFrameworkHandle, &SavedState);
|
||||
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", __FUNCTION__ ));
|
||||
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;
|
||||
ParentFramework = (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework;
|
||||
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
|
||||
//
|
||||
// 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.
|
||||
|
||||
Generally called from within a test case prior to quitting or rebooting.
|
||||
|
||||
@param[in] FrameworkHandle A handle to the current running framework that
|
||||
dispatched the test. Necessary for recording
|
||||
certain test events with the framework.
|
||||
@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_INVALID_PARAMETER FrameworkHandle is NULL.
|
||||
@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_FRAMEWORK_HANDLE FrameworkHandle,
|
||||
IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL,
|
||||
IN UINTN ContextToSaveSize
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UNIT_TEST_SAVE_HEADER *Header;
|
||||
|
||||
Header = NULL;
|
||||
|
||||
//
|
||||
// First, let's not make assumptions about the parameters.
|
||||
//
|
||||
if (FrameworkHandle == NULL ||
|
||||
(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);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR, "%a - Could not save state! %r\n", __FUNCTION__, Status));
|
||||
Status = EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Free data that was used.
|
||||
//
|
||||
FreePool (Header);
|
||||
|
||||
return Status;
|
||||
}
|
|
@ -0,0 +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|PEIM DXE_DRIVER DXE_SMM_DRIVER 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
|
|
@ -0,0 +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."
|
|
@ -0,0 +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
|
|
@ -0,0 +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."
|
|
@ -0,0 +1,75 @@
|
|||
/** @file
|
||||
This is an instance of the Unit Test Persistence Lib that does nothing.
|
||||
|
||||
Copyright (c) Microsoft Corporation.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/UnitTestPersistenceLib.h>
|
||||
|
||||
/**
|
||||
Determines whether a persistence cache already exists for
|
||||
the given framework.
|
||||
|
||||
@param[in] FrameworkHandle A pointer to the framework that is being persisted.
|
||||
|
||||
@retval TRUE
|
||||
@retval FALSE Cache doesn't exist or an error occurred.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
DoesCacheExist (
|
||||
IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
|
||||
)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
Will save the data associated with an internal Unit Test Framework
|
||||
state in a manner that can persist a Unit Test Application quit or
|
||||
even a system reboot.
|
||||
|
||||
@param[in] FrameworkHandle A pointer to the framework that is being persisted.
|
||||
@param[in] SaveData A pointer to the buffer containing the serialized
|
||||
framework internal state.
|
||||
|
||||
@retval EFI_SUCCESS Data is persisted and the test can be safely quit.
|
||||
@retval Others Data is not persisted and test cannot be resumed upon exit.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SaveUnitTestCache (
|
||||
IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,
|
||||
IN UNIT_TEST_SAVE_HEADER *SaveData
|
||||
)
|
||||
{
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
Will retrieve any cached state associated with the given framework.
|
||||
Will allocate a buffer to hold the loaded data.
|
||||
|
||||
@param[in] FrameworkHandle A pointer to the framework that is being persisted.
|
||||
@param[in] SaveData A pointer pointer that will be updated with the address
|
||||
of the loaded data buffer.
|
||||
|
||||
@retval EFI_SUCCESS Data has been loaded successfully and SaveData is updated
|
||||
with a pointer to the buffer.
|
||||
@retval Others An error has occurred and no data has been loaded. SaveData
|
||||
is set to NULL.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
LoadUnitTestCache (
|
||||
IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,
|
||||
OUT UNIT_TEST_SAVE_HEADER **SaveData
|
||||
)
|
||||
{
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
## @file
|
||||
# This is an instance of the Unit Test Persistence Lib does nothing.
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010017
|
||||
BASE_NAME = UnitTestPersistenceLibNull
|
||||
MODULE_UNI_FILE = UnitTestPersistenceLibNull.uni
|
||||
FILE_GUID = B8553C7A-0B0B-4BBD-9DF3-825804BF26AB
|
||||
VERSION_STRING = 1.0
|
||||
MODULE_TYPE = UEFI_DRIVER
|
||||
LIBRARY_CLASS = UnitTestPersistenceLib
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64
|
||||
#
|
||||
|
||||
[Sources]
|
||||
UnitTestPersistenceLibNull.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
|
|
@ -0,0 +1,11 @@
|
|||
// /** @file
|
||||
// NULL library for Unit Test Persistence Lib.
|
||||
//
|
||||
// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "NULL library for Unit Test Persistence Lib"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "NULL library for Unit Test Persistence Lib."
|
|
@ -0,0 +1,416 @@
|
|||
/** @file
|
||||
This is an instance of the Unit Test Persistence Lib that will utilize
|
||||
the filesystem that a test application is running from to save a serialized
|
||||
version of the internal test state in case the test needs to quit and restore.
|
||||
|
||||
Copyright (c) Microsoft Corporation.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include <PiDxe.h>
|
||||
#include <Library/UnitTestPersistenceLib.h>
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Library/ShellLib.h>
|
||||
#include <Protocol/LoadedImage.h>
|
||||
|
||||
#define CACHE_FILE_SUFFIX L"_Cache.dat"
|
||||
|
||||
/**
|
||||
Generate the device path to the cache file.
|
||||
|
||||
@param[in] FrameworkHandle A pointer to the framework that is being persisted.
|
||||
|
||||
@retval !NULL A pointer to the EFI_FILE protocol instance for the filesystem.
|
||||
@retval NULL Filesystem could not be found or an error occurred.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_DEVICE_PATH_PROTOCOL*
|
||||
GetCacheFileDevicePath (
|
||||
IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UNIT_TEST_FRAMEWORK *Framework;
|
||||
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
|
||||
CHAR16 *AppPath;
|
||||
CHAR16 *CacheFilePath;
|
||||
CHAR16 *TestName;
|
||||
UINTN DirectorySlashOffset;
|
||||
UINTN CacheFilePathLength;
|
||||
EFI_DEVICE_PATH_PROTOCOL *CacheFileDevicePath;
|
||||
|
||||
Framework = (UNIT_TEST_FRAMEWORK*)FrameworkHandle;
|
||||
AppPath = NULL;
|
||||
CacheFilePath = NULL;
|
||||
TestName = NULL;
|
||||
CacheFileDevicePath = NULL;
|
||||
|
||||
//
|
||||
// First, we need to get some information from the loaded image.
|
||||
//
|
||||
Status = gBS->HandleProtocol (
|
||||
gImageHandle,
|
||||
&gEfiLoadedImageProtocolGuid,
|
||||
(VOID**)&LoadedImage
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_WARN, "%a - Failed to locate DevicePath for loaded image. %r\n", __FUNCTION__, Status));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Before we can start, change test name from ASCII to Unicode.
|
||||
//
|
||||
CacheFilePathLength = AsciiStrLen (Framework->ShortTitle) + 1;
|
||||
TestName = AllocatePool (CacheFilePathLength);
|
||||
if (!TestName) {
|
||||
goto Exit;
|
||||
}
|
||||
AsciiStrToUnicodeStrS (Framework->ShortTitle, TestName, CacheFilePathLength);
|
||||
|
||||
//
|
||||
// Now we should have the device path of the root device and a file path for the rest.
|
||||
// In order to target the directory for the test application, we must process
|
||||
// the file path a little.
|
||||
//
|
||||
// NOTE: This may not be necessary... Path processing functions exist...
|
||||
// PathCleanUpDirectories (FileNameCopy);
|
||||
// if (PathRemoveLastItem (FileNameCopy)) {
|
||||
//
|
||||
AppPath = ConvertDevicePathToText (LoadedImage->FilePath, TRUE, TRUE); // NOTE: This must be freed.
|
||||
DirectorySlashOffset = StrLen (AppPath);
|
||||
//
|
||||
// Make sure we didn't get any weird data.
|
||||
//
|
||||
if (DirectorySlashOffset == 0) {
|
||||
DEBUG ((DEBUG_ERROR, "%a - Weird 0-length string when processing app path.\n", __FUNCTION__));
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Now that we know we have a decent string, let's take a deeper look.
|
||||
//
|
||||
do {
|
||||
if (AppPath[DirectorySlashOffset] == L'\\') {
|
||||
break;
|
||||
}
|
||||
DirectorySlashOffset--;
|
||||
} while (DirectorySlashOffset > 0);
|
||||
|
||||
//
|
||||
// After that little maneuver, DirectorySlashOffset should be pointing at the last '\' in AppString.
|
||||
// That would be the path to the parent directory that the test app is executing from.
|
||||
// Let's check and make sure that's right.
|
||||
//
|
||||
if (AppPath[DirectorySlashOffset] != L'\\') {
|
||||
DEBUG ((DEBUG_ERROR, "%a - Could not find a single directory separator in app path.\n", __FUNCTION__));
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Now we know some things, we're ready to produce our output string, I think.
|
||||
//
|
||||
CacheFilePathLength = DirectorySlashOffset + 1;
|
||||
CacheFilePathLength += StrLen (TestName);
|
||||
CacheFilePathLength += StrLen (CACHE_FILE_SUFFIX);
|
||||
CacheFilePathLength += 1; // Don't forget the NULL terminator.
|
||||
CacheFilePath = AllocateZeroPool (CacheFilePathLength * sizeof (CHAR16));
|
||||
if (!CacheFilePath) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Let's produce our final path string, shall we?
|
||||
//
|
||||
StrnCpyS (CacheFilePath, CacheFilePathLength, AppPath, DirectorySlashOffset + 1); // Copy the path for the parent directory.
|
||||
StrCatS (CacheFilePath, CacheFilePathLength, TestName); // Copy the base name for the test cache.
|
||||
StrCatS (CacheFilePath, CacheFilePathLength, CACHE_FILE_SUFFIX); // Copy the file suffix.
|
||||
|
||||
//
|
||||
// Finally, try to create the device path for the thing thing.
|
||||
//
|
||||
CacheFileDevicePath = FileDevicePath (LoadedImage->DeviceHandle, CacheFilePath);
|
||||
|
||||
Exit:
|
||||
//
|
||||
// Free allocated buffers.
|
||||
//
|
||||
if (AppPath != NULL) {
|
||||
FreePool (AppPath);
|
||||
}
|
||||
if (CacheFilePath != NULL) {
|
||||
FreePool (CacheFilePath);
|
||||
}
|
||||
if (TestName != NULL) {
|
||||
FreePool (TestName);
|
||||
}
|
||||
|
||||
return CacheFileDevicePath;
|
||||
}
|
||||
|
||||
/**
|
||||
Determines whether a persistence cache already exists for
|
||||
the given framework.
|
||||
|
||||
@param[in] FrameworkHandle A pointer to the framework that is being persisted.
|
||||
|
||||
@retval TRUE
|
||||
@retval FALSE Cache doesn't exist or an error occurred.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
DoesCacheExist (
|
||||
IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
|
||||
)
|
||||
{
|
||||
EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;
|
||||
EFI_STATUS Status;
|
||||
SHELL_FILE_HANDLE FileHandle;
|
||||
|
||||
//
|
||||
// NOTE: This devpath is allocated and must be freed.
|
||||
//
|
||||
FileDevicePath = GetCacheFileDevicePath (FrameworkHandle);
|
||||
|
||||
//
|
||||
// Check to see whether the file exists. If the file can be opened for
|
||||
// reading, it exists. Otherwise, probably not.
|
||||
//
|
||||
Status = ShellOpenFileByDevicePath (
|
||||
&FileDevicePath,
|
||||
&FileHandle,
|
||||
EFI_FILE_MODE_READ,
|
||||
0
|
||||
);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
ShellCloseFile (&FileHandle);
|
||||
}
|
||||
|
||||
if (FileDevicePath != NULL) {
|
||||
FreePool (FileDevicePath);
|
||||
}
|
||||
|
||||
DEBUG ((DEBUG_VERBOSE, "%a - Returning %d\n", __FUNCTION__, !EFI_ERROR (Status)));
|
||||
|
||||
return (!EFI_ERROR (Status));
|
||||
}
|
||||
|
||||
/**
|
||||
Will save the data associated with an internal Unit Test Framework
|
||||
state in a manner that can persist a Unit Test Application quit or
|
||||
even a system reboot.
|
||||
|
||||
@param[in] FrameworkHandle A pointer to the framework that is being persisted.
|
||||
@param[in] SaveData A pointer to the buffer containing the serialized
|
||||
framework internal state.
|
||||
|
||||
@retval EFI_SUCCESS Data is persisted and the test can be safely quit.
|
||||
@retval Others Data is not persisted and test cannot be resumed upon exit.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SaveUnitTestCache (
|
||||
IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,
|
||||
IN UNIT_TEST_SAVE_HEADER *SaveData
|
||||
)
|
||||
{
|
||||
EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;
|
||||
EFI_STATUS Status;
|
||||
SHELL_FILE_HANDLE FileHandle;
|
||||
UINTN WriteCount;
|
||||
|
||||
//
|
||||
// Check the inputs for sanity.
|
||||
//
|
||||
if (FrameworkHandle == NULL || SaveData == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Determine the path for the cache file.
|
||||
// NOTE: This devpath is allocated and must be freed.
|
||||
//
|
||||
FileDevicePath = GetCacheFileDevicePath (FrameworkHandle);
|
||||
|
||||
//
|
||||
//First lets open the file if it exists so we can delete it...This is the work around for truncation
|
||||
//
|
||||
Status = ShellOpenFileByDevicePath (
|
||||
&FileDevicePath,
|
||||
&FileHandle,
|
||||
(EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE),
|
||||
0
|
||||
);
|
||||
|
||||
if (!EFI_ERROR (Status)) {
|
||||
//
|
||||
// If file handle above was opened it will be closed by the delete.
|
||||
//
|
||||
Status = ShellDeleteFile (&FileHandle);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR, "%a failed to delete file %r\n", __FUNCTION__, Status));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Now that we know the path to the file... let's open it for writing.
|
||||
//
|
||||
Status = ShellOpenFileByDevicePath (
|
||||
&FileDevicePath,
|
||||
&FileHandle,
|
||||
(EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE),
|
||||
0
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR, "%a - Opening file for writing failed! %r\n", __FUNCTION__, Status));
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Write the data to the file.
|
||||
//
|
||||
WriteCount = SaveData->SaveStateSize;
|
||||
DEBUG ((DEBUG_INFO, "%a - Writing %d bytes to file...\n", __FUNCTION__, WriteCount));
|
||||
Status = ShellWriteFile (
|
||||
FileHandle,
|
||||
&WriteCount,
|
||||
SaveData
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status) || WriteCount != SaveData->SaveStateSize) {
|
||||
DEBUG ((DEBUG_ERROR, "%a - Writing to file failed! %r\n", __FUNCTION__, Status));
|
||||
} else {
|
||||
DEBUG ((DEBUG_INFO, "%a - SUCCESS!\n", __FUNCTION__));
|
||||
}
|
||||
|
||||
//
|
||||
// No matter what, we should probably close the file.
|
||||
//
|
||||
ShellCloseFile (&FileHandle);
|
||||
|
||||
Exit:
|
||||
if (FileDevicePath != NULL) {
|
||||
FreePool (FileDevicePath);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Will retrieve any cached state associated with the given framework.
|
||||
Will allocate a buffer to hold the loaded data.
|
||||
|
||||
@param[in] FrameworkHandle A pointer to the framework that is being persisted.
|
||||
@param[in] SaveData A pointer pointer that will be updated with the address
|
||||
of the loaded data buffer.
|
||||
|
||||
@retval EFI_SUCCESS Data has been loaded successfully and SaveData is updated
|
||||
with a pointer to the buffer.
|
||||
@retval Others An error has occurred and no data has been loaded. SaveData
|
||||
is set to NULL.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
LoadUnitTestCache (
|
||||
IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,
|
||||
OUT UNIT_TEST_SAVE_HEADER **SaveData
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;
|
||||
SHELL_FILE_HANDLE FileHandle;
|
||||
BOOLEAN IsFileOpened;
|
||||
UINT64 LargeFileSize;
|
||||
UINTN FileSize;
|
||||
UNIT_TEST_SAVE_HEADER *Buffer;
|
||||
|
||||
IsFileOpened = FALSE;
|
||||
Buffer = NULL;
|
||||
|
||||
//
|
||||
// Check the inputs for sanity.
|
||||
//
|
||||
if (FrameworkHandle == NULL || SaveData == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Determine the path for the cache file.
|
||||
// NOTE: This devpath is allocated and must be freed.
|
||||
//
|
||||
FileDevicePath = GetCacheFileDevicePath (FrameworkHandle);
|
||||
|
||||
//
|
||||
// Now that we know the path to the file... let's open it for writing.
|
||||
//
|
||||
Status = ShellOpenFileByDevicePath (
|
||||
&FileDevicePath,
|
||||
&FileHandle,
|
||||
EFI_FILE_MODE_READ,
|
||||
0
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR, "%a - Opening file for writing failed! %r\n", __FUNCTION__, Status));
|
||||
goto Exit;
|
||||
} else {
|
||||
IsFileOpened = TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Now that the file is opened, we need to determine how large a buffer we need.
|
||||
//
|
||||
Status = ShellGetFileSize (FileHandle, &LargeFileSize);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR, "%a - Failed to determine file size! %r\n", __FUNCTION__, Status));
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Now that we know the size, let's allocated a buffer to hold the contents.
|
||||
//
|
||||
FileSize = (UINTN)LargeFileSize; // You know what... if it's too large, this lib don't care.
|
||||
Buffer = AllocatePool (FileSize);
|
||||
if (Buffer == NULL) {
|
||||
DEBUG ((DEBUG_ERROR, "%a - Failed to allocate a pool to hold the file contents! %r\n", __FUNCTION__, Status));
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Finally, let's read the data.
|
||||
//
|
||||
Status = ShellReadFile (FileHandle, &FileSize, Buffer);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR, "%a - Failed to read the file contents! %r\n", __FUNCTION__, Status));
|
||||
}
|
||||
|
||||
Exit:
|
||||
//
|
||||
// Free allocated buffers
|
||||
//
|
||||
if (FileDevicePath != NULL) {
|
||||
FreePool (FileDevicePath);
|
||||
}
|
||||
if (IsFileOpened) {
|
||||
ShellCloseFile (&FileHandle);
|
||||
}
|
||||
|
||||
//
|
||||
// If we're returning an error, make sure
|
||||
// the state is sane.
|
||||
if (EFI_ERROR (Status) && Buffer != NULL) {
|
||||
FreePool (Buffer);
|
||||
Buffer = NULL;
|
||||
}
|
||||
|
||||
*SaveData = Buffer;
|
||||
return Status;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
## @file
|
||||
# UEFI Simple File System based version of the Unit Test Persistence Lib
|
||||
#
|
||||
# Instance of the Unit Test Persistence Lib that utilizes the UEFI filesystem
|
||||
# that a test application is running from to save a serialized version of the
|
||||
# internal test state in case the test needs to quit and restore.
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010017
|
||||
BASE_NAME = UnitTestPersistenceLibSimpleFileSystem
|
||||
MODULE_UNI_FILE = UnitTestPersistenceLibSimpleFileSystem.uni
|
||||
FILE_GUID = 9200844A-CDFD-4368-B4BD-106354702605
|
||||
VERSION_STRING = 1.0
|
||||
MODULE_TYPE = UEFI_APPLICATION
|
||||
LIBRARY_CLASS = UnitTestPersistenceLib
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64
|
||||
#
|
||||
|
||||
[Sources]
|
||||
UnitTestPersistenceLibSimpleFileSystem.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
|
||||
ShellPkg/ShellPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
DebugLib
|
||||
UefiBootServicesTableLib
|
||||
BaseLib
|
||||
ShellLib
|
||||
|
||||
[Protocols]
|
||||
gEfiLoadedImageProtocolGuid
|
||||
gEfiSimpleFileSystemProtocolGuid
|
||||
|
||||
[Guids]
|
||||
gEfiFileInfoGuid
|
||||
gEfiFileSystemInfoGuid
|
|
@ -0,0 +1,15 @@
|
|||
// /** @file
|
||||
// UEFI Simple File System based version of the Unit Test Persistence Lib
|
||||
//
|
||||
// Instance of the Unit Test Persistence Lib that utilizes the UEFI filesystem
|
||||
// that a test application is running from to save a serialized version of the
|
||||
// internal test state in case the test needs to quit and restore.
|
||||
//
|
||||
// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "UEFI Simple File System based version of the Unit Test Persistence Lib"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "UEFI Simple File System based version of the Unit Test Persistence Lib."
|
|
@ -0,0 +1,216 @@
|
|||
/** @file
|
||||
Implement UnitTestResultReportLib doing plain txt out to console
|
||||
|
||||
Copyright (c) Microsoft Corporation.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/UnitTestResultReportLib.h>
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
|
||||
VOID
|
||||
ReportPrint (
|
||||
IN CONST CHAR8 *Format,
|
||||
...
|
||||
);
|
||||
|
||||
VOID
|
||||
ReportOutput (
|
||||
IN CONST CHAR8 *Output
|
||||
);
|
||||
|
||||
struct _UNIT_TEST_STATUS_STRING {
|
||||
UNIT_TEST_STATUS Status;
|
||||
CHAR8 *String;
|
||||
};
|
||||
|
||||
struct _UNIT_TEST_FAILURE_TYPE_STRING {
|
||||
FAILURE_TYPE Type;
|
||||
CHAR8 *String;
|
||||
};
|
||||
|
||||
struct _UNIT_TEST_STATUS_STRING mStatusStrings[] = {
|
||||
{ UNIT_TEST_PASSED, "PASSED"},
|
||||
{ UNIT_TEST_ERROR_PREREQUISITE_NOT_MET, "NOT RUN - PREREQUISITE FAILED"},
|
||||
{ UNIT_TEST_ERROR_TEST_FAILED, "FAILED"},
|
||||
{ UNIT_TEST_RUNNING, "RUNNING"},
|
||||
{ UNIT_TEST_PENDING, "PENDING"},
|
||||
{ 0, "**UNKNOWN**"}
|
||||
};
|
||||
|
||||
struct _UNIT_TEST_FAILURE_TYPE_STRING mFailureTypeStrings[] = {
|
||||
{ FAILURETYPE_NOFAILURE, "NO FAILURE"},
|
||||
{ FAILURETYPE_OTHER, "OTHER FAILURE"},
|
||||
{ FAILURETYPE_ASSERTTRUE, "ASSERT_TRUE FAILURE"},
|
||||
{ FAILURETYPE_ASSERTFALSE, "ASSERT_FALSE FAILURE"},
|
||||
{ FAILURETYPE_ASSERTEQUAL, "ASSERT_EQUAL FAILURE"},
|
||||
{ FAILURETYPE_ASSERTNOTEQUAL, "ASSERT_NOTEQUAL FAILURE"},
|
||||
{ FAILURETYPE_ASSERTNOTEFIERROR, "ASSERT_NOTEFIERROR FAILURE"},
|
||||
{ FAILURETYPE_ASSERTSTATUSEQUAL, "ASSERT_STATUSEQUAL FAILURE"},
|
||||
{ FAILURETYPE_ASSERTNOTNULL , "ASSERT_NOTNULL FAILURE"},
|
||||
{ 0, "*UNKNOWN* Failure"}
|
||||
};
|
||||
|
||||
//
|
||||
// TEST REPORTING FUNCTIONS
|
||||
//
|
||||
|
||||
STATIC
|
||||
CONST CHAR8*
|
||||
GetStringForUnitTestStatus (
|
||||
IN UNIT_TEST_STATUS Status
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
for (Index = 0; Index < ARRAY_SIZE (mStatusStrings); Index++) {
|
||||
if (mStatusStrings[Index].Status == Status) {
|
||||
//
|
||||
// Return string from matching entry
|
||||
//
|
||||
return mStatusStrings[Index].String;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Return last entry if no match found.
|
||||
//
|
||||
return mStatusStrings[Index].String;
|
||||
}
|
||||
|
||||
STATIC
|
||||
CONST CHAR8*
|
||||
GetStringForFailureType (
|
||||
IN FAILURE_TYPE Failure
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
for (Index = 0; Index < ARRAY_SIZE (mFailureTypeStrings); Index++) {
|
||||
if (mFailureTypeStrings[Index].Type == Failure) {
|
||||
//
|
||||
// Return string from matching entry
|
||||
//
|
||||
return mFailureTypeStrings[Index].String;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Return last entry if no match found.
|
||||
//
|
||||
DEBUG((DEBUG_INFO, "%a Failure Type does not have string defined 0x%X\n", __FUNCTION__, (UINT32)Failure));
|
||||
return mFailureTypeStrings[Index].String;
|
||||
}
|
||||
|
||||
/*
|
||||
Method to print the Unit Test run results
|
||||
|
||||
@retval Success
|
||||
*/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
OutputUnitTestFrameworkReport (
|
||||
IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
|
||||
)
|
||||
{
|
||||
UNIT_TEST_FRAMEWORK *Framework;
|
||||
INTN Passed;
|
||||
INTN Failed;
|
||||
INTN NotRun;
|
||||
UNIT_TEST_SUITE_LIST_ENTRY *Suite;
|
||||
UNIT_TEST_LIST_ENTRY *Test;
|
||||
INTN SPassed;
|
||||
INTN SFailed;
|
||||
INTN SNotRun;
|
||||
|
||||
Passed = 0;
|
||||
Failed = 0;
|
||||
NotRun = 0;
|
||||
Suite = NULL;
|
||||
|
||||
Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
|
||||
if (Framework == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
ReportPrint ("---------------------------------------------------------\n");
|
||||
ReportPrint ("------------- UNIT TEST FRAMEWORK RESULTS ---------------\n");
|
||||
ReportPrint ("---------------------------------------------------------\n");
|
||||
|
||||
//print the version and time
|
||||
|
||||
//
|
||||
// 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)) {
|
||||
|
||||
Test = NULL;
|
||||
SPassed = 0;
|
||||
SFailed = 0;
|
||||
SNotRun = 0;
|
||||
|
||||
ReportPrint ("/////////////////////////////////////////////////////////\n");
|
||||
ReportPrint (" SUITE: %a\n", Suite->UTS.Title);
|
||||
ReportPrint (" PACKAGE: %a\n", Suite->UTS.Name);
|
||||
ReportPrint ("/////////////////////////////////////////////////////////\n");
|
||||
|
||||
//
|
||||
// Iterate all tests within the suite
|
||||
//
|
||||
for (Test = (UNIT_TEST_LIST_ENTRY*)GetFirstNode(&(Suite->UTS.TestCaseList));
|
||||
(LIST_ENTRY*)Test != &(Suite->UTS.TestCaseList);
|
||||
Test = (UNIT_TEST_LIST_ENTRY*)GetNextNode(&(Suite->UTS.TestCaseList), (LIST_ENTRY*)Test)) {
|
||||
|
||||
ReportPrint ("*********************************************************\n");
|
||||
ReportPrint (" CLASS NAME: %a\n", Test->UT.Name);
|
||||
ReportPrint (" TEST: %a\n", Test->UT.Description);
|
||||
ReportPrint (" STATUS: %a\n", GetStringForUnitTestStatus (Test->UT.Result));
|
||||
ReportPrint (" FAILURE: %a\n", GetStringForFailureType (Test->UT.FailureType));
|
||||
ReportPrint (" FAILURE MESSAGE:\n%a\n", Test->UT.FailureMessage);
|
||||
|
||||
if (Test->UT.Log != NULL) {
|
||||
ReportPrint (" LOG:\n");
|
||||
ReportOutput (Test->UT.Log);
|
||||
}
|
||||
|
||||
switch (Test->UT.Result) {
|
||||
case UNIT_TEST_PASSED:
|
||||
SPassed++;
|
||||
break;
|
||||
case UNIT_TEST_ERROR_TEST_FAILED:
|
||||
SFailed++;
|
||||
break;
|
||||
case UNIT_TEST_PENDING: // Fall through...
|
||||
case UNIT_TEST_RUNNING: // Fall through...
|
||||
case UNIT_TEST_ERROR_PREREQUISITE_NOT_MET:
|
||||
SNotRun++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ReportPrint ("**********************************************************\n");
|
||||
} //End Test iteration
|
||||
|
||||
ReportPrint ("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
|
||||
ReportPrint ("Suite Stats\n");
|
||||
ReportPrint (" Passed: %d (%d%%)\n", SPassed, (SPassed * 100)/(SPassed+SFailed+SNotRun));
|
||||
ReportPrint (" Failed: %d (%d%%)\n", SFailed, (SFailed * 100) / (SPassed + SFailed + SNotRun));
|
||||
ReportPrint (" Not Run: %d (%d%%)\n", SNotRun, (SNotRun * 100) / (SPassed + SFailed + SNotRun));
|
||||
ReportPrint ("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n" );
|
||||
|
||||
Passed += SPassed; //add to global counters
|
||||
Failed += SFailed; //add to global counters
|
||||
NotRun += SNotRun; //add to global counters
|
||||
}//End Suite iteration
|
||||
|
||||
ReportPrint ("=========================================================\n");
|
||||
ReportPrint ("Total Stats\n");
|
||||
ReportPrint (" Passed: %d (%d%%)\n", Passed, (Passed * 100) / (Passed + Failed + NotRun));
|
||||
ReportPrint (" Failed: %d (%d%%)\n", Failed, (Failed * 100) / (Passed + Failed + NotRun));
|
||||
ReportPrint (" Not Run: %d (%d%%)\n", NotRun, (NotRun * 100) / (Passed + Failed + NotRun));
|
||||
ReportPrint ("=========================================================\n" );
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/** @file
|
||||
Implement UnitTestResultReportLib doing plain txt out to console
|
||||
|
||||
Copyright (c) Microsoft Corporation.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
|
||||
VOID
|
||||
ReportPrint (
|
||||
IN CONST CHAR8 *Format,
|
||||
...
|
||||
)
|
||||
{
|
||||
VA_LIST Marker;
|
||||
CHAR16 String[256];
|
||||
UINTN Length;
|
||||
|
||||
VA_START (Marker, Format);
|
||||
Length = UnicodeVSPrintAsciiFormat (String, sizeof (String), Format, Marker);
|
||||
if (Length == 0) {
|
||||
DEBUG ((DEBUG_ERROR, "%a formatted string is too long\n", __FUNCTION__));
|
||||
} else {
|
||||
gST->ConOut->OutputString (gST->ConOut, String);
|
||||
}
|
||||
VA_END (Marker);
|
||||
}
|
||||
|
||||
VOID
|
||||
ReportOutput (
|
||||
IN CONST CHAR8 *Output
|
||||
)
|
||||
{
|
||||
CHAR8 AsciiString[128];
|
||||
UINTN Length;
|
||||
UINTN Index;
|
||||
|
||||
Length = AsciiStrLen (Output);
|
||||
for (Index = 0; Index < Length; Index += (sizeof (AsciiString) - 1)) {
|
||||
AsciiStrCpyS (AsciiString, sizeof (AsciiString), &Output[Index]);
|
||||
ReportPrint ("%a", AsciiString);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
## @file
|
||||
# Library to support printing out the unit test report to a UEFI console
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010017
|
||||
BASE_NAME = UnitTestResultReportLibConOut
|
||||
MODULE_UNI_FILE = UnitTestResultReportLibConOut.uni
|
||||
FILE_GUID = C659641D-BA1F-4B58-946E-B1E1103903F9
|
||||
VERSION_STRING = 1.0
|
||||
MODULE_TYPE = UEFI_DRIVER
|
||||
LIBRARY_CLASS = UnitTestResultReportLib
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
DebugLib
|
||||
UefiBootServicesTableLib
|
||||
PrintLib
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
|
||||
|
||||
[Sources]
|
||||
UnitTestResultReportLib.c
|
||||
UnitTestResultReportLibConOut.c
|
|
@ -0,0 +1,11 @@
|
|||
// /** @file
|
||||
// Library to support printing out the unit test report to a UEFI console
|
||||
//
|
||||
// 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 printing out the unit test report to a UEFI console"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "Library to support printing out the unit test report to a UEFI console."
|
|
@ -0,0 +1,47 @@
|
|||
/** @file
|
||||
Implement UnitTestResultReportLib doing plain txt out to console
|
||||
|
||||
Copyright (c) Microsoft Corporation.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
|
||||
VOID
|
||||
ReportPrint (
|
||||
IN CONST CHAR8 *Format,
|
||||
...
|
||||
)
|
||||
{
|
||||
VA_LIST Marker;
|
||||
CHAR8 String[256];
|
||||
UINTN Length;
|
||||
|
||||
VA_START (Marker, Format);
|
||||
Length = AsciiVSPrint (String, sizeof (String), Format, Marker);
|
||||
if (Length == 0) {
|
||||
DEBUG ((DEBUG_ERROR, "%a formatted string is too long\n", __FUNCTION__));
|
||||
} else {
|
||||
DEBUG ((DEBUG_INFO, String));
|
||||
}
|
||||
VA_END (Marker);
|
||||
}
|
||||
|
||||
VOID
|
||||
ReportOutput (
|
||||
IN CONST CHAR8 *Output
|
||||
)
|
||||
{
|
||||
CHAR8 AsciiString[128];
|
||||
UINTN Length;
|
||||
UINTN Index;
|
||||
|
||||
Length = AsciiStrLen (Output);
|
||||
for (Index = 0; Index < Length; Index += (sizeof (AsciiString) - 1)) {
|
||||
AsciiStrCpyS (AsciiString, sizeof (AsciiString), &Output[Index]);
|
||||
DEBUG ((DEBUG_INFO, AsciiString));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
## @file
|
||||
# Library to support printing out the unit test report using DEBUG() macros.
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010017
|
||||
BASE_NAME = UnitTestResultReportLibDebugLib
|
||||
MODULE_UNI_FILE = UnitTestResultReportLibDebugLib.uni
|
||||
FILE_GUID = BED736D4-D197-475F-B7CE-0D828FF2C9A6
|
||||
VERSION_STRING = 1.0
|
||||
MODULE_TYPE = UEFI_DRIVER
|
||||
LIBRARY_CLASS = UnitTestResultReportLib
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
DebugLib
|
||||
PrintLib
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
|
||||
|
||||
[Sources]
|
||||
UnitTestResultReportLib.c
|
||||
UnitTestResultReportLibDebugLib.c
|
|
@ -0,0 +1,11 @@
|
|||
// /** @file
|
||||
// Library to support printing out the unit test report using DEBUG() macros.
|
||||
//
|
||||
// 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 printing out the unit test report using DEBUG() macros"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "Library to support printing out the unit test report using DEBUG() macros."
|
Loading…
Reference in New Issue