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:
Michael D Kinney 2020-01-22 10:07:17 -08:00 committed by mergify[bot]
parent 0f7fb5c5e5
commit 0eb522987f
39 changed files with 4693 additions and 0 deletions

3
.gitmodules vendored
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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()."

View File

@ -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);
}

View File

@ -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

View File

@ -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."

View File

@ -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;
}

View File

@ -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

View File

@ -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."

View File

@ -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;
}

View File

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

View File

@ -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.."

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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."

View File

@ -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

View File

@ -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."

View File

@ -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;
}

View File

@ -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

View File

@ -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."

View File

@ -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;
}

View File

@ -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

View File

@ -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."

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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."

View File

@ -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));
}
}

View File

@ -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

View File

@ -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."