[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
--- /dev/null
+## @file\r
+# This module provides Cmocka Library implementation.\r
+#\r
+# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = CmockaLib\r
+ MODULE_UNI_FILE = CmockaLib.uni\r
+ FILE_GUID = F1662152-3399-49AC-BE44-CAA97575FACE\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 0.1\r
+ LIBRARY_CLASS = CmockaLib|HOST_APPLICATION\r
+\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64\r
+#\r
+\r
+[Sources]\r
+ cmocka/src/cmocka.c\r
+\r
+[Packages]\r
+ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec\r
+\r
+[BuildOptions]\r
+ MSFT:*_*_*_CC_FLAGS == /c -DHAVE_VSNPRINTF -DHAVE_SNPRINTF\r
+ MSFT:NOOPT_*_*_CC_FLAGS = /Od\r
+\r
+ GCC:*_*_*_CC_FLAGS == -g -DHAVE_SIGNAL_H\r
+ GCC:NOOPT_*_*_CC_FLAGS = -O0\r
+ GCC:*_*_IA32_CC_FLAGS = -m32\r
+ GCC:*_*_X64_CC_FLAGS = -m64\r
--- /dev/null
+// /** @file\r
+// This module provides Cmocka Library implementation.\r
+//\r
+// This module provides Cmocka Library implementation.\r
+//\r
+// Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// SPDX-License-Identifier: BSD-2-Clause-Patent\r
+//\r
+// **/\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "Cmocka Library implementation"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "This module provides Cmocka Library implementation."\r
--- /dev/null
+Subproject commit 1cc9cde3448cdd2e000886a26acf1caac2db7cf1
--- /dev/null
+/** @file\r
+ Instance of Debug Library based on POSIX APIs\r
+\r
+ Uses Print Library to produce formatted output strings sent to printf().\r
+\r
+ Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <stdio.h>\r
+\r
+#include <Base.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+\r
+///\r
+/// Define the maximum debug and assert message length that this library supports\r
+///\r
+#define MAX_DEBUG_MESSAGE_LENGTH 0x100\r
+\r
+/**\r
+ Prints a debug message to the debug output device if the specified error level is enabled.\r
+\r
+ If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function\r
+ GetDebugPrintErrorLevel (), then print the message specified by Format and the\r
+ associated variable argument list to the debug output device.\r
+\r
+ If Format is NULL, then ASSERT().\r
+\r
+ @param ErrorLevel The error level of the debug message.\r
+ @param Format The format string for the debug message to print.\r
+ @param ... The variable argument list whose contents are accessed\r
+ based on the format string specified by Format.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DebugPrint (\r
+ IN UINTN ErrorLevel,\r
+ IN CONST CHAR8 *Format,\r
+ ...\r
+ )\r
+{\r
+ VA_LIST Marker;\r
+\r
+ VA_START (Marker, Format);\r
+ DebugVPrint (ErrorLevel, Format, Marker);\r
+ VA_END (Marker);\r
+}\r
+\r
+/**\r
+ Prints a debug message to the debug output device if the specified\r
+ error level is enabled.\r
+\r
+ If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function\r
+ GetDebugPrintErrorLevel (), then print the message specified by Format and\r
+ the associated variable argument list to the debug output device.\r
+\r
+ If Format is NULL, then ASSERT().\r
+\r
+ @param ErrorLevel The error level of the debug message.\r
+ @param Format Format string for the debug message to print.\r
+ @param VaListMarker VA_LIST marker for the variable argument list.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DebugVPrint (\r
+ IN UINTN ErrorLevel,\r
+ IN CONST CHAR8 *Format,\r
+ IN VA_LIST VaListMarker\r
+ )\r
+{\r
+ CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH];\r
+\r
+ AsciiVSPrint (Buffer, sizeof (Buffer), Format, VaListMarker);\r
+ printf ("%s", Buffer);\r
+}\r
+\r
+/**\r
+ Prints a debug message to the debug output device if the specified\r
+ error level is enabled.\r
+ This function use BASE_LIST which would provide a more compatible\r
+ service than VA_LIST.\r
+\r
+ If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function\r
+ GetDebugPrintErrorLevel (), then print the message specified by Format and\r
+ the associated variable argument list to the debug output device.\r
+\r
+ If Format is NULL, then ASSERT().\r
+\r
+ @param ErrorLevel The error level of the debug message.\r
+ @param Format Format string for the debug message to print.\r
+ @param BaseListMarker BASE_LIST marker for the variable argument list.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DebugBPrint (\r
+ IN UINTN ErrorLevel,\r
+ IN CONST CHAR8 *Format,\r
+ IN BASE_LIST BaseListMarker\r
+ )\r
+{\r
+ CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH];\r
+\r
+ AsciiBSPrint (Buffer, sizeof (Buffer), Format, BaseListMarker);\r
+ printf ("%s", Buffer);\r
+}\r
+\r
+/**\r
+ Prints an assert message containing a filename, line number, and description.\r
+ This may be followed by a breakpoint or a dead loop.\r
+\r
+ Print a message of the form "ASSERT <FileName>(<LineNumber>): <Description>\n"\r
+ to the debug output device. If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of\r
+ PcdDebugPropertyMask is set then CpuBreakpoint() is called. Otherwise, if\r
+ DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugPropertyMask is set then\r
+ CpuDeadLoop() is called. If neither of these bits are set, then this function\r
+ returns immediately after the message is printed to the debug output device.\r
+ DebugAssert() must actively prevent recursion. If DebugAssert() is called while\r
+ processing another DebugAssert(), then DebugAssert() must return immediately.\r
+\r
+ If FileName is NULL, then a <FileName> string of "(NULL) Filename" is printed.\r
+ If Description is NULL, then a <Description> string of "(NULL) Description" is printed.\r
+\r
+ @param FileName The pointer to the name of the source file that generated the assert condition.\r
+ @param LineNumber The line number in the source file that generated the assert condition\r
+ @param Description The pointer to the description of the assert condition.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DebugAssert (\r
+ IN CONST CHAR8 *FileName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *Description\r
+ )\r
+{\r
+ printf ("ASSERT: %s(%d): %s\n", FileName, (INT32)(UINT32)LineNumber, Description);\r
+\r
+ //\r
+ // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings\r
+ //\r
+ if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) {\r
+ CpuBreakpoint ();\r
+ } else if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) {\r
+ CpuDeadLoop ();\r
+ }\r
+}\r
+\r
+/**\r
+ Fills a target buffer with PcdDebugClearMemoryValue, and returns the target buffer.\r
+\r
+ This function fills Length bytes of Buffer with the value specified by\r
+ PcdDebugClearMemoryValue, and returns Buffer.\r
+\r
+ If Buffer is NULL, then ASSERT().\r
+ If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().\r
+\r
+ @param Buffer The pointer to the target buffer to be filled with PcdDebugClearMemoryValue.\r
+ @param Length The number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue.\r
+\r
+ @return Buffer The pointer to the target buffer filled with PcdDebugClearMemoryValue.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+DebugClearMemory (\r
+ OUT VOID *Buffer,\r
+ IN UINTN Length\r
+ )\r
+{\r
+ //\r
+ // If Buffer is NULL, then ASSERT().\r
+ //\r
+ ASSERT (Buffer != NULL);\r
+\r
+ //\r
+ // SetMem() checks for the the ASSERT() condition on Length and returns Buffer\r
+ //\r
+ return SetMem (Buffer, Length, PcdGet8(PcdDebugClearMemoryValue));\r
+}\r
+\r
+/**\r
+ Returns TRUE if ASSERT() macros are enabled.\r
+\r
+ This function returns TRUE if the DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of\r
+ PcdDebugPropertyMask is set. Otherwise FALSE is returned.\r
+\r
+ @retval TRUE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugPropertyMask is set.\r
+ @retval FALSE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugPropertyMask is clear.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+DebugAssertEnabled (\r
+ VOID\r
+ )\r
+{\r
+ return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0);\r
+}\r
+\r
+/**\r
+ Returns TRUE if DEBUG() macros are enabled.\r
+\r
+ This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of\r
+ PcdDebugPropertyMask is set. Otherwise FALSE is returned.\r
+\r
+ @retval TRUE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugPropertyMask is set.\r
+ @retval FALSE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugPropertyMask is clear.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+DebugPrintEnabled (\r
+ VOID\r
+ )\r
+{\r
+ return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);\r
+}\r
+\r
+/**\r
+ Returns TRUE if DEBUG_CODE() macros are enabled.\r
+\r
+ This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of\r
+ PcdDebugPropertyMask is set. Otherwise FALSE is returned.\r
+\r
+ @retval TRUE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugPropertyMask is set.\r
+ @retval FALSE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugPropertyMask is clear.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+DebugCodeEnabled (\r
+ VOID\r
+ )\r
+{\r
+ return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0);\r
+}\r
+\r
+/**\r
+ Returns TRUE if DEBUG_CLEAR_MEMORY() macro is enabled.\r
+\r
+ This function returns TRUE if the DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of\r
+ PcdDebugPropertyMask is set. Otherwise FALSE is returned.\r
+\r
+ @retval TRUE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugPropertyMask is set.\r
+ @retval FALSE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugPropertyMask is clear.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+DebugClearMemoryEnabled (\r
+ VOID\r
+ )\r
+{\r
+ return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0);\r
+}\r
+\r
+/**\r
+ Returns TRUE if any one of the bit is set both in ErrorLevel and PcdFixedDebugPrintErrorLevel.\r
+\r
+ This function compares the bit mask of ErrorLevel and PcdFixedDebugPrintErrorLevel.\r
+\r
+ @retval TRUE Current ErrorLevel is supported.\r
+ @retval FALSE Current ErrorLevel is not supported.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+DebugPrintLevelEnabled (\r
+ IN CONST UINTN ErrorLevel\r
+ )\r
+{\r
+ return (BOOLEAN) ((ErrorLevel & PcdGet32(PcdFixedDebugPrintErrorLevel)) != 0);\r
+}\r
--- /dev/null
+## @file\r
+# Instance of Debug Library based on POSIX APIs\r
+#\r
+# Uses Print Library to produce formatted output strings sent to printf().\r
+#\r
+# Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = DebugLibPosix\r
+ MODULE_UNI_FILE = DebugLibPosix.uni\r
+ FILE_GUID = 6A77CE89-C1B6-4A6B-9561-07D7127514A7\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = DebugLib|HOST_APPLICATION\r
+\r
+[Sources]\r
+ DebugLibPosix.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseMemoryLib\r
+ PcdLib\r
+ PrintLib\r
+ BaseLib\r
+\r
+[Pcd]\r
+ gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue ## SOMETIMES_CONSUMES\r
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask ## CONSUMES\r
+ gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel ## CONSUMES\r
--- /dev/null
+// /** @file\r
+// Instance of Debug Library based on POSIX APIs\r
+//\r
+// Uses Print Library to produce formatted output strings sent to printf().\r
+//\r
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// SPDX-License-Identifier: BSD-2-Clause-Patent\r
+//\r
+// **/\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "Instance of Debug Library based on POSIX APIs"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "Uses Print Library to produce formatted output strings sent to printf()."\r
--- /dev/null
+/** @file\r
+ Instance of Memory Allocation Library based on POSIX APIs\r
+\r
+ Uses POSIX APIs malloc() and free() to allocate and free memory.\r
+\r
+ Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include <Uefi.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DebugLib.h>\r
+\r
+///\r
+/// Signature for PAGE_HEAD structure\r
+/// Used to verify that buffer being freed was allocated by this library.\r
+///\r
+#define PAGE_HEAD_PRIVATE_SIGNATURE SIGNATURE_32 ('P', 'H', 'D', 'R')\r
+\r
+///\r
+/// Structure placed immediately before an aligned allocation to store the\r
+/// information required to free the entire buffer allocated to support then\r
+/// aligned allocation.\r
+///\r
+typedef struct {\r
+ UINT32 Signature;\r
+ VOID *AllocatedBufffer;\r
+ UINTN TotalPages;\r
+ VOID *AlignedBuffer;\r
+ UINTN AlignedPages;\r
+} PAGE_HEAD;\r
+\r
+/**\r
+ Allocates one or more 4KB pages of type EfiBootServicesData.\r
+\r
+ Allocates the number of 4KB pages of type EfiBootServicesData and returns a pointer to the\r
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL\r
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is\r
+ returned.\r
+\r
+ @param Pages The number of 4 KB pages to allocate.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocatePages (\r
+ IN UINTN Pages\r
+ )\r
+{\r
+ return AllocateAlignedPages (Pages, SIZE_4KB);\r
+}\r
+\r
+/**\r
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData.\r
+\r
+ Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the\r
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL\r
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is\r
+ returned.\r
+\r
+ @param Pages The number of 4 KB pages to allocate.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocateRuntimePages (\r
+ IN UINTN Pages\r
+ )\r
+{\r
+ return AllocatePages (Pages);\r
+}\r
+\r
+/**\r
+ Allocates one or more 4KB pages of type EfiReservedMemoryType.\r
+\r
+ Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a pointer to the\r
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL\r
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is\r
+ returned.\r
+\r
+ @param Pages The number of 4 KB pages to allocate.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocateReservedPages (\r
+ IN UINTN Pages\r
+ )\r
+{\r
+ return AllocatePages (Pages);\r
+}\r
+\r
+/**\r
+ Frees one or more 4KB pages that were previously allocated with one of the page allocation\r
+ functions in the Memory Allocation Library.\r
+\r
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer\r
+ must have been allocated on a previous call to the page allocation services of the Memory\r
+ Allocation Library. If it is not possible to free allocated pages, then this function will\r
+ perform no actions.\r
+\r
+ If Buffer was not allocated with a page allocation function in the Memory Allocation Library,\r
+ then ASSERT().\r
+ If Pages is zero, then ASSERT().\r
+\r
+ @param Buffer The pointer to the buffer of pages to free.\r
+ @param Pages The number of 4 KB pages to free.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+FreePages (\r
+ IN VOID *Buffer,\r
+ IN UINTN Pages\r
+ )\r
+{\r
+ FreeAlignedPages (Buffer, Pages);\r
+}\r
+\r
+/**\r
+ Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment.\r
+\r
+ Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an\r
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is\r
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the\r
+ request, then NULL is returned.\r
+\r
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().\r
+\r
+ @param Pages The number of 4 KB pages to allocate.\r
+ @param Alignment The requested alignment of the allocation. Must be a power of two.\r
+ If Alignment is zero, then byte alignment is used.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/VOID *\r
+EFIAPI\r
+AllocateAlignedPages (\r
+ IN UINTN Pages,\r
+ IN UINTN Alignment\r
+ )\r
+{\r
+ PAGE_HEAD PageHead;\r
+ PAGE_HEAD *PageHeadPtr;\r
+ UINTN AlignmentMask;\r
+\r
+ ASSERT ((Alignment & (Alignment - 1)) == 0);\r
+\r
+ if (Alignment < SIZE_4KB) {\r
+ Alignment = SIZE_4KB;\r
+ }\r
+ AlignmentMask = Alignment - 1;\r
+\r
+ //\r
+ // We need reserve Alignment pages for PAGE_HEAD, as meta data.\r
+ //\r
+ PageHead.Signature = PAGE_HEAD_PRIVATE_SIGNATURE;\r
+ PageHead.TotalPages = Pages + EFI_SIZE_TO_PAGES (Alignment) * 2;\r
+ PageHead.AlignedPages = Pages;\r
+ PageHead.AllocatedBufffer = malloc (EFI_PAGES_TO_SIZE (PageHead.TotalPages));\r
+ if (PageHead.AllocatedBufffer == NULL) {\r
+ return NULL;\r
+ }\r
+ PageHead.AlignedBuffer = (VOID *)(((UINTN) PageHead.AllocatedBufffer + AlignmentMask) & ~AlignmentMask);\r
+ if ((UINTN)PageHead.AlignedBuffer - (UINTN)PageHead.AllocatedBufffer < sizeof(PAGE_HEAD)) {\r
+ PageHead.AlignedBuffer = (VOID *)((UINTN)PageHead.AlignedBuffer + Alignment);\r
+ }\r
+\r
+ PageHeadPtr = (VOID *)((UINTN)PageHead.AlignedBuffer - sizeof(PAGE_HEAD));\r
+ memcpy (PageHeadPtr, &PageHead, sizeof(PAGE_HEAD));\r
+\r
+ return PageHead.AlignedBuffer;\r
+}\r
+\r
+/**\r
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment.\r
+\r
+ Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an\r
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is\r
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the\r
+ request, then NULL is returned.\r
+\r
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().\r
+\r
+ @param Pages The number of 4 KB pages to allocate.\r
+ @param Alignment The requested alignment of the allocation. Must be a power of two.\r
+ If Alignment is zero, then byte alignment is used.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocateAlignedRuntimePages (\r
+ IN UINTN Pages,\r
+ IN UINTN Alignment\r
+ )\r
+{\r
+ return AllocateAlignedPages (Pages, Alignment);\r
+}\r
+\r
+/**\r
+ Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment.\r
+\r
+ Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType with an\r
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is\r
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the\r
+ request, then NULL is returned.\r
+\r
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().\r
+\r
+ @param Pages The number of 4 KB pages to allocate.\r
+ @param Alignment The requested alignment of the allocation. Must be a power of two.\r
+ If Alignment is zero, then byte alignment is used.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocateAlignedReservedPages (\r
+ IN UINTN Pages,\r
+ IN UINTN Alignment\r
+ )\r
+{\r
+ return AllocateAlignedPages (Pages, Alignment);\r
+}\r
+\r
+/**\r
+ Frees one or more 4KB pages that were previously allocated with one of the aligned page\r
+ allocation functions in the Memory Allocation Library.\r
+\r
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer\r
+ must have been allocated on a previous call to the aligned page allocation services of the Memory\r
+ Allocation Library. If it is not possible to free allocated pages, then this function will\r
+ perform no actions.\r
+\r
+ If Buffer was not allocated with an aligned page allocation function in the Memory Allocation\r
+ Library, then ASSERT().\r
+ If Pages is zero, then ASSERT().\r
+\r
+ @param Buffer The pointer to the buffer of pages to free.\r
+ @param Pages The number of 4 KB pages to free.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+FreeAlignedPages (\r
+ IN VOID *Buffer,\r
+ IN UINTN Pages\r
+ )\r
+{\r
+ PAGE_HEAD *PageHeadPtr;\r
+\r
+ //\r
+ // NOTE: Partial free is not supported. Just keep it.\r
+ //\r
+ PageHeadPtr = (VOID *)((UINTN)Buffer - sizeof(PAGE_HEAD));\r
+ if (PageHeadPtr->Signature != PAGE_HEAD_PRIVATE_SIGNATURE) {\r
+ return;\r
+ }\r
+ if (PageHeadPtr->AlignedPages != Pages) {\r
+ return;\r
+ }\r
+\r
+ PageHeadPtr->Signature = 0;\r
+ free (PageHeadPtr->AllocatedBufffer);\r
+}\r
+\r
+/**\r
+ Allocates a buffer of type EfiBootServicesData.\r
+\r
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a\r
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is\r
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.\r
+\r
+ @param AllocationSize The number of bytes to allocate.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/VOID *\r
+EFIAPI\r
+AllocatePool (\r
+ IN UINTN AllocationSize\r
+ )\r
+{\r
+ return malloc (AllocationSize);\r
+}\r
+\r
+/**\r
+ Allocates a buffer of type EfiRuntimeServicesData.\r
+\r
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns\r
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is\r
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.\r
+\r
+ @param AllocationSize The number of bytes to allocate.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocateRuntimePool (\r
+ IN UINTN AllocationSize\r
+ )\r
+{\r
+ return AllocatePool (AllocationSize);\r
+}\r
+\r
+/**\r
+ Allocates a buffer of type EfiReservedMemoryType.\r
+\r
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType and returns\r
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is\r
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.\r
+\r
+ @param AllocationSize The number of bytes to allocate.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocateReservedPool (\r
+ IN UINTN AllocationSize\r
+ )\r
+{\r
+ return AllocatePool (AllocationSize);\r
+}\r
+\r
+/**\r
+ Allocates and zeros a buffer of type EfiBootServicesData.\r
+\r
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the\r
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a\r
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the\r
+ request, then NULL is returned.\r
+\r
+ @param AllocationSize The number of bytes to allocate and zero.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocateZeroPool (\r
+ IN UINTN AllocationSize\r
+ )\r
+{\r
+ VOID *Buffer;\r
+\r
+ Buffer = malloc (AllocationSize);\r
+ if (Buffer == NULL) {\r
+ return NULL;\r
+ }\r
+ memset (Buffer, 0, AllocationSize);\r
+ return Buffer;\r
+}\r
+\r
+/**\r
+ Allocates and zeros a buffer of type EfiRuntimeServicesData.\r
+\r
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the\r
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a\r
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the\r
+ request, then NULL is returned.\r
+\r
+ @param AllocationSize The number of bytes to allocate and zero.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocateRuntimeZeroPool (\r
+ IN UINTN AllocationSize\r
+ )\r
+{\r
+ return AllocateZeroPool (AllocationSize);\r
+}\r
+\r
+/**\r
+ Allocates and zeros a buffer of type EfiReservedMemoryType.\r
+\r
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, clears the\r
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a\r
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the\r
+ request, then NULL is returned.\r
+\r
+ @param AllocationSize The number of bytes to allocate and zero.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocateReservedZeroPool (\r
+ IN UINTN AllocationSize\r
+ )\r
+{\r
+ return AllocateZeroPool (AllocationSize);\r
+}\r
+\r
+/**\r
+ Copies a buffer to an allocated buffer of type EfiBootServicesData.\r
+\r
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, copies\r
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the\r
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there\r
+ is not enough memory remaining to satisfy the request, then NULL is returned.\r
+\r
+ If Buffer is NULL, then ASSERT().\r
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().\r
+\r
+ @param AllocationSize The number of bytes to allocate and zero.\r
+ @param Buffer The buffer to copy to the allocated buffer.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocateCopyPool (\r
+ IN UINTN AllocationSize,\r
+ IN CONST VOID *Buffer\r
+ )\r
+{\r
+ VOID *Memory;\r
+\r
+ Memory = malloc (AllocationSize);\r
+ if (Memory == NULL) {\r
+ return NULL;\r
+ }\r
+ memcpy (Memory, Buffer, AllocationSize);\r
+ return Memory;\r
+}\r
+\r
+/**\r
+ Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.\r
+\r
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies\r
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the\r
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there\r
+ is not enough memory remaining to satisfy the request, then NULL is returned.\r
+\r
+ If Buffer is NULL, then ASSERT().\r
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().\r
+\r
+ @param AllocationSize The number of bytes to allocate and zero.\r
+ @param Buffer The buffer to copy to the allocated buffer.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocateRuntimeCopyPool (\r
+ IN UINTN AllocationSize,\r
+ IN CONST VOID *Buffer\r
+ )\r
+{\r
+ return AllocateCopyPool (AllocationSize, Buffer);\r
+}\r
+\r
+/**\r
+ Copies a buffer to an allocated buffer of type EfiReservedMemoryType.\r
+\r
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, copies\r
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the\r
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there\r
+ is not enough memory remaining to satisfy the request, then NULL is returned.\r
+\r
+ If Buffer is NULL, then ASSERT().\r
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().\r
+\r
+ @param AllocationSize The number of bytes to allocate and zero.\r
+ @param Buffer The buffer to copy to the allocated buffer.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocateReservedCopyPool (\r
+ IN UINTN AllocationSize,\r
+ IN CONST VOID *Buffer\r
+ )\r
+{\r
+ return AllocateCopyPool (AllocationSize, Buffer);\r
+}\r
+\r
+/**\r
+ Reallocates a buffer of type EfiBootServicesData.\r
+\r
+ Allocates and zeros the number bytes specified by NewSize from memory of type\r
+ EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldSize and\r
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and\r
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.\r
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not\r
+ enough memory remaining to satisfy the request, then NULL is returned.\r
+\r
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize\r
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().\r
+\r
+ @param OldSize The size, in bytes, of OldBuffer.\r
+ @param NewSize The size, in bytes, of the buffer to reallocate.\r
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional\r
+ parameter that may be NULL.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+ReallocatePool (\r
+ IN UINTN OldSize,\r
+ IN UINTN NewSize,\r
+ IN VOID *OldBuffer OPTIONAL\r
+ )\r
+{\r
+ VOID *NewBuffer;\r
+\r
+ NewBuffer = malloc (NewSize);\r
+ if (NewBuffer != NULL && OldBuffer != NULL) {\r
+ memcpy (NewBuffer, OldBuffer, MIN (OldSize, NewSize));\r
+ }\r
+ if (OldBuffer != NULL) {\r
+ FreePool(OldBuffer);\r
+ }\r
+ return NewBuffer;\r
+}\r
+\r
+/**\r
+ Reallocates a buffer of type EfiRuntimeServicesData.\r
+\r
+ Allocates and zeros the number bytes specified by NewSize from memory of type\r
+ EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and\r
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and\r
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.\r
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not\r
+ enough memory remaining to satisfy the request, then NULL is returned.\r
+\r
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize\r
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().\r
+\r
+ @param OldSize The size, in bytes, of OldBuffer.\r
+ @param NewSize The size, in bytes, of the buffer to reallocate.\r
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional\r
+ parameter that may be NULL.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+ReallocateRuntimePool (\r
+ IN UINTN OldSize,\r
+ IN UINTN NewSize,\r
+ IN VOID *OldBuffer OPTIONAL\r
+ )\r
+{\r
+ return ReallocatePool (OldSize, NewSize, OldBuffer);\r
+}\r
+\r
+/**\r
+ Reallocates a buffer of type EfiReservedMemoryType.\r
+\r
+ Allocates and zeros the number bytes specified by NewSize from memory of type\r
+ EfiReservedMemoryType. If OldBuffer is not NULL, then the smaller of OldSize and\r
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and\r
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.\r
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not\r
+ enough memory remaining to satisfy the request, then NULL is returned.\r
+\r
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize\r
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().\r
+\r
+ @param OldSize The size, in bytes, of OldBuffer.\r
+ @param NewSize The size, in bytes, of the buffer to reallocate.\r
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional\r
+ parameter that may be NULL.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+ReallocateReservedPool (\r
+ IN UINTN OldSize,\r
+ IN UINTN NewSize,\r
+ IN VOID *OldBuffer OPTIONAL\r
+ )\r
+{\r
+ return ReallocatePool (OldSize, NewSize, OldBuffer);\r
+}\r
+\r
+/**\r
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the\r
+ Memory Allocation Library.\r
+\r
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the\r
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool\r
+ resources, then this function will perform no actions.\r
+\r
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,\r
+ then ASSERT().\r
+\r
+ @param Buffer The pointer to the buffer to free.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+FreePool (\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ free (Buffer);\r
+}\r
--- /dev/null
+## @file\r
+# Instance of Memory Allocation Library based on POSIX APIs\r
+#\r
+# Uses POSIX APIs malloc() and free() to allocate and free memory.\r
+#\r
+# Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = MemoryAllocationLibPosix\r
+ MODULE_UNI_FILE = MemoryAllocationLibPosix.uni\r
+ FILE_GUID = A1672454-A3D3-4AAC-A86B-8D63132BBB91\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = MemoryAllocationLib|HOST_APPLICATION\r
+\r
+[Sources]\r
+ MemoryAllocationLibPosix.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
--- /dev/null
+// /** @file\r
+// Instance of Memory Allocation Library based on POSIX APIs\r
+//\r
+// Uses POSIX APIs malloc() and free() to allocate and free memory.\r
+//\r
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// SPDX-License-Identifier: BSD-2-Clause-Patent\r
+//\r
+// **/\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "Instance of Memory Allocation Library based on POSIX APIs"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "Uses POSIX APIs malloc() and free() to allocate and free memory."\r
--- /dev/null
+/**\r
+ NULL implementation for UnitTestBootLib to allow simple compilation\r
+\r
+ Copyright (c) Microsoft Corporation.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <PiDxe.h>\r
+\r
+/**\r
+ Set the boot manager to boot from a specific device on the next boot. This\r
+ should be set only for the next boot and shouldn't require any manual clean up\r
+\r
+ @retval EFI_SUCCESS Boot device for next boot was set.\r
+ @retval EFI_UNSUPPORTED Setting the boot device for the next boot is not\r
+ supportted.\r
+ @retval Other Boot device for next boot can not be set.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetBootNextDevice(\r
+ VOID\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
--- /dev/null
+## @file\r
+# NULL library for UnitTestBootUsb\r
+#\r
+# Copyright (c) Microsoft Corporation.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010017\r
+ BASE_NAME = UnitTestBootLibNull\r
+ MODULE_UNI_FILE = UnitTestBootLibNull.uni\r
+ FILE_GUID = f143e75d-76e1-4040-b134-8f4f0bd5e3bd\r
+ VERSION_STRING = 1.0\r
+ MODULE_TYPE = DXE_DRIVER\r
+ LIBRARY_CLASS = UnitTestBootLib\r
+\r
+[Sources]\r
+ UnitTestBootLibNull.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+\r
--- /dev/null
+// /** @file\r
+// NULL library for UnitTestBootUsb\r
+//\r
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+// SPDX-License-Identifier: BSD-2-Clause-Patent\r
+//\r
+// **/\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "NULL library for UnitTestBootUsb"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "NULL library for UnitTestBootUsb."\r
--- /dev/null
+/**\r
+ Implement UnitTestBootLib using USB Class Boot option. This should be\r
+ industry standard and should work on all platforms\r
+\r
+ Copyright (c) Microsoft Corporation.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiBootManagerLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+/**\r
+ Set the boot manager to boot from a specific device on the next boot. This\r
+ should be set only for the next boot and shouldn't require any manual clean up\r
+\r
+ @retval EFI_SUCCESS Boot device for next boot was set.\r
+ @retval EFI_UNSUPPORTED Setting the boot device for the next boot is not\r
+ supportted.\r
+ @retval Other Boot device for next boot can not be set.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetBootNextDevice (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION NewOption;\r
+ UINT32 Attributes;\r
+ UINT8 *OptionalData;\r
+ UINT32 OptionalDataSize;\r
+ UINT16 BootNextValue;\r
+ USB_CLASS_DEVICE_PATH UsbDp;\r
+ EFI_DEVICE_PATH_PROTOCOL *DpEnd;\r
+ EFI_DEVICE_PATH_PROTOCOL *Dp;\r
+ BOOLEAN NewOptionValid;\r
+\r
+ OptionalData = NULL;\r
+ OptionalDataSize = 0;\r
+ BootNextValue = 0xABCD; // this should be a safe number...\r
+ DpEnd = NULL;\r
+ Dp = NULL;\r
+ NewOptionValid = FALSE;\r
+\r
+ UsbDp.Header.Length[0] = (UINT8)(sizeof(USB_CLASS_DEVICE_PATH) & 0xff);\r
+ UsbDp.Header.Length[1] = (UINT8)(sizeof(USB_CLASS_DEVICE_PATH) >> 8);\r
+ UsbDp.Header.Type = MESSAGING_DEVICE_PATH;\r
+ UsbDp.Header.SubType = MSG_USB_CLASS_DP;\r
+ UsbDp.VendorId = 0xFFFF;\r
+ UsbDp.ProductId = 0xFFFF;\r
+ UsbDp.DeviceClass = 0xFF;\r
+ UsbDp.DeviceSubClass = 0xFF;\r
+ UsbDp.DeviceProtocol = 0xFF;\r
+\r
+ Attributes = LOAD_OPTION_ACTIVE;\r
+\r
+ DpEnd = AppendDevicePathNode (NULL, NULL);\r
+ if (DpEnd == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "%a: Unable to create device path. DpEnd is NULL.\n", __FUNCTION__));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto CLEANUP;\r
+ }\r
+\r
+ //@MRT --- Is this memory leak because we lose the old Dp memory\r
+ Dp = AppendDevicePathNode (\r
+ DpEnd,\r
+ (EFI_DEVICE_PATH_PROTOCOL *)&UsbDp\r
+ );\r
+ if (Dp == NULL) {\r
+ DEBUG((DEBUG_ERROR, "%a: Unable to create device path. Dp is NULL.\n", __FUNCTION__));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto CLEANUP;\r
+ }\r
+\r
+ Status = EfiBootManagerInitializeLoadOption (\r
+ &NewOption,\r
+ (UINTN) BootNextValue,\r
+ LoadOptionTypeBoot,\r
+ Attributes,\r
+ L"Generic USB Class Device",\r
+ Dp,\r
+ OptionalData,\r
+ OptionalDataSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a: Error creating load option. Status = %r\n", __FUNCTION__, Status));\r
+ goto CLEANUP;\r
+ }\r
+\r
+ NewOptionValid = TRUE;\r
+ DEBUG ((DEBUG_VERBOSE, "%a: Generic USB Class Device boot option created.\n", __FUNCTION__));\r
+ Status = EfiBootManagerLoadOptionToVariable (&NewOption);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a: Error Saving boot option NV variable. Status = %r\n", __FUNCTION__, Status));\r
+ goto CLEANUP;\r
+ }\r
+\r
+ //\r
+ // Set Boot Next\r
+ //\r
+ Status = gRT->SetVariable (\r
+ L"BootNext",\r
+ &gEfiGlobalVariableGuid,\r
+ (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE),\r
+ sizeof(BootNextValue),\r
+ &(BootNextValue)\r
+ );\r
+\r
+ DEBUG((DEBUG_VERBOSE, "%a - Set BootNext Status (%r)\n", __FUNCTION__, Status));\r
+\r
+CLEANUP:\r
+ if (Dp != NULL) {\r
+ FreePool (Dp);\r
+ }\r
+ if (DpEnd != NULL) {\r
+ FreePool (DpEnd);\r
+ }\r
+ if (NewOptionValid) {\r
+ EfiBootManagerFreeLoadOption (&NewOption);\r
+ }\r
+ return Status;\r
+}\r
--- /dev/null
+## @file\r
+# Library to support booting to USB on the next boot\r
+# This instance uses the industry standard usb class boot option.\r
+#\r
+# Copyright (c) Microsoft Corporation.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010017\r
+ BASE_NAME = UnitTestBootLibUsbClass\r
+ MODULE_UNI_FILE = UnitTestBootLibUsbClass.uni\r
+ FILE_GUID = DFADE2A2-DB69-47DE-A37A-40FB6D52E844\r
+ VERSION_STRING = 1.0\r
+ MODULE_TYPE = UEFI_APPLICATION\r
+ LIBRARY_CLASS = UnitTestBootLib\r
+\r
+[Sources]\r
+ UnitTestBootLibUsbClass.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec\r
+\r
+[LibraryClasses]\r
+ DebugLib\r
+ UefiRuntimeServicesTableLib\r
+ MemoryAllocationLib\r
+ DevicePathLib\r
+ UefiBootManagerLib\r
+\r
+[Guids]\r
+ gEfiGlobalVariableGuid ## CONSUMES ## Used to probe boot options and set BootNext.\r
--- /dev/null
+// /** @file\r
+// Library to support booting to USB on the next boot\r
+// This instance uses the industry standard usb class boot option.\r
+//\r
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+// SPDX-License-Identifier: BSD-2-Clause-Patent\r
+//\r
+// **/\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "Library to support booting to USB on the next boot"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "This instance uses the industry standard usb class boot option.."\r
--- /dev/null
+/**\r
+ Implement UnitTestLib assert services\r
+\r
+ Copyright (c) Microsoft Corporation.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <UnitTestFrameworkTypes.h>\r
+#include <Library/UnitTestLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PrintLib.h>\r
+\r
+STATIC\r
+EFI_STATUS\r
+AddUnitTestFailure (\r
+ IN OUT UNIT_TEST *UnitTest,\r
+ IN CONST CHAR8 *FailureMessage,\r
+ IN FAILURE_TYPE FailureType\r
+ )\r
+{\r
+ //\r
+ // Make sure that you're cooking with gas.\r
+ //\r
+ if (UnitTest == NULL || FailureMessage == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ UnitTest->FailureType = FailureType;\r
+ AsciiStrCpyS (\r
+ &UnitTest->FailureMessage[0],\r
+ UNIT_TEST_TESTFAILUREMSG_LENGTH,\r
+ FailureMessage\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+VOID\r
+UnitTestLogFailure (\r
+ IN FAILURE_TYPE FailureType,\r
+ IN CONST CHAR8 *Format,\r
+ ...\r
+ )\r
+{\r
+ UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle;\r
+ CHAR8 LogString[UNIT_TEST_TESTFAILUREMSG_LENGTH];\r
+ VA_LIST Marker;\r
+\r
+ //\r
+ // Get active Framework handle\r
+ //\r
+ FrameworkHandle = GetActiveFrameworkHandle ();\r
+\r
+ //\r
+ // Convert the message to an ASCII String\r
+ //\r
+ VA_START (Marker, Format);\r
+ AsciiVSPrint (LogString, sizeof (LogString), Format, Marker);\r
+ VA_END (Marker);\r
+\r
+ //\r
+ // Finally, add the string to the log.\r
+ //\r
+ AddUnitTestFailure (\r
+ ((UNIT_TEST_FRAMEWORK *)FrameworkHandle)->CurrentTest,\r
+ LogString,\r
+ FailureType\r
+ );\r
+\r
+ return;\r
+}\r
+\r
+/**\r
+ If Expression is TRUE, then TRUE is returned.\r
+ If Expression is FALSE, then an assert is triggered and the location of the\r
+ assert provided by FunctionName, LineNumber, FileName, and Description are\r
+ recorded and FALSE is returned.\r
+\r
+ @param[in] Expression The BOOLEAN result of the expression evaluation.\r
+ @param[in] FunctionName Null-terminated ASCII string of the function\r
+ executing the assert macro.\r
+ @param[in] LineNumber The source file line number of the assert macro.\r
+ @param[in] FileName Null-terminated ASCII string of the filename\r
+ executing the assert macro.\r
+ @param[in] Description Null-terminated ASCII string of the expression being\r
+ evaluated.\r
+\r
+ @retval TRUE Expression is TRUE.\r
+ @retval FALSE Expression is FALSE.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnitTestAssertTrue (\r
+ IN BOOLEAN Expression,\r
+ IN CONST CHAR8 *FunctionName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *FileName,\r
+ IN CONST CHAR8 *Description\r
+ )\r
+{\r
+ if (!Expression) {\r
+ UnitTestLogFailure (\r
+ FAILURETYPE_ASSERTTRUE,\r
+ "%a::%d Expression (%a) is not TRUE!\n",\r
+ FunctionName,\r
+ LineNumber,\r
+ Description\r
+ );\r
+ UT_LOG_ERROR (\r
+ "[ASSERT FAIL] %a::%d Expression (%a) is not TRUE!\n",\r
+ FunctionName,\r
+ LineNumber,\r
+ Description\r
+ );\r
+ }\r
+ return Expression;\r
+}\r
+\r
+/**\r
+ If Expression is FALSE, then TRUE is returned.\r
+ If Expression is TRUE, then an assert is triggered and the location of the\r
+ assert provided by FunctionName, LineNumber, FileName, and Description are\r
+ recorded and FALSE is returned.\r
+\r
+ @param[in] Expression The BOOLEAN result of the expression evaluation.\r
+ @param[in] FunctionName Null-terminated ASCII string of the function\r
+ executing the assert macro.\r
+ @param[in] LineNumber The source file line number of the assert macro.\r
+ @param[in] FileName Null-terminated ASCII string of the filename\r
+ executing the assert macro.\r
+ @param[in] Description Null-terminated ASCII string of the expression being\r
+ evaluated.\r
+\r
+ @retval TRUE Expression is FALSE.\r
+ @retval FALSE Expression is TRUE.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnitTestAssertFalse (\r
+ IN BOOLEAN Expression,\r
+ IN CONST CHAR8 *FunctionName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *FileName,\r
+ IN CONST CHAR8 *Description\r
+ )\r
+{\r
+ if (Expression) {\r
+ UnitTestLogFailure (\r
+ FAILURETYPE_ASSERTFALSE,\r
+ "%a::%d Expression(%a) is not FALSE!\n",\r
+ FunctionName,\r
+ LineNumber,\r
+ Description\r
+ );\r
+ UT_LOG_ERROR (\r
+ "[ASSERT FAIL] %a::%d Expression (%a) is not FALSE!\n",\r
+ FunctionName,\r
+ LineNumber,\r
+ Description\r
+ );\r
+ }\r
+ return !Expression;\r
+}\r
+\r
+/**\r
+ If Status is not an EFI_ERROR(), then TRUE is returned.\r
+ If Status is an EFI_ERROR(), then an assert is triggered and the location of\r
+ the assert provided by FunctionName, LineNumber, FileName, and Description are\r
+ recorded and FALSE is returned.\r
+\r
+ @param[in] Status The EFI_STATUS value to evaluate.\r
+ @param[in] FunctionName Null-terminated ASCII string of the function\r
+ executing the assert macro.\r
+ @param[in] LineNumber The source file line number of the assert macro.\r
+ @param[in] FileName Null-terminated ASCII string of the filename\r
+ executing the assert macro.\r
+ @param[in] Description Null-terminated ASCII string of the status\r
+ expression being evaluated.\r
+\r
+ @retval TRUE Status is not an EFI_ERROR().\r
+ @retval FALSE Status is an EFI_ERROR().\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnitTestAssertNotEfiError (\r
+ IN EFI_STATUS Status,\r
+ IN CONST CHAR8 *FunctionName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *FileName,\r
+ IN CONST CHAR8 *Description\r
+ )\r
+{\r
+ if (EFI_ERROR (Status)) {\r
+ UnitTestLogFailure (\r
+ FAILURETYPE_ASSERTNOTEFIERROR,\r
+ "%a::%d Status '%a' is EFI_ERROR (%r)!\n",\r
+ FunctionName,\r
+ LineNumber,\r
+ Description,\r
+ Status\r
+ );\r
+ UT_LOG_ERROR (\r
+ "[ASSERT FAIL] %a::%d Status '%a' is EFI_ERROR (%r)!\n",\r
+ FunctionName,\r
+ LineNumber,\r
+ Description,\r
+ Status\r
+ );\r
+ }\r
+ return !EFI_ERROR( Status );\r
+}\r
+\r
+/**\r
+ If ValueA is equal ValueB, then TRUE is returned.\r
+ If ValueA is not equal to ValueB, then an assert is triggered and the location\r
+ of the assert provided by FunctionName, LineNumber, FileName, DescriptionA,\r
+ and DescriptionB are recorded and FALSE is returned.\r
+\r
+ @param[in] ValueA 64-bit value.\r
+ @param[in] ValueB 64-bit value.\r
+ @param[in] FunctionName Null-terminated ASCII string of the function\r
+ executing the assert macro.\r
+ @param[in] LineNumber The source file line number of the assert macro.\r
+ @param[in] FileName Null-terminated ASCII string of the filename\r
+ executing the assert macro.\r
+ @param[in] DescriptionA Null-terminated ASCII string that is a description\r
+ of ValueA.\r
+ @param[in] DescriptionB Null-terminated ASCII string that is a description\r
+ of ValueB.\r
+\r
+ @retval TRUE ValueA is equal to ValueB.\r
+ @retval FALSE ValueA is not equal to ValueB.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnitTestAssertEqual (\r
+ IN UINT64 ValueA,\r
+ IN UINT64 ValueB,\r
+ IN CONST CHAR8 *FunctionName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *FileName,\r
+ IN CONST CHAR8 *DescriptionA,\r
+ IN CONST CHAR8 *DescriptionB\r
+ )\r
+{\r
+ if ((ValueA != ValueB)) {\r
+ UnitTestLogFailure (\r
+ FAILURETYPE_ASSERTEQUAL,\r
+ "%a::%d Value %a != %a (%d != %d)!\n",\r
+ FunctionName,\r
+ LineNumber,\r
+ DescriptionA,\r
+ DescriptionB,\r
+ ValueA,\r
+ ValueB\r
+ );\r
+ UT_LOG_ERROR (\r
+ "[ASSERT FAIL] %a::%d Value %a != %a (%d != %d)!\n",\r
+ FunctionName,\r
+ LineNumber,\r
+ DescriptionA,\r
+ DescriptionB,\r
+ ValueA,\r
+ ValueB\r
+ );\r
+ }\r
+ return (ValueA == ValueB);\r
+}\r
+\r
+/**\r
+ If the contents of BufferA are identical to the contents of BufferB, then TRUE\r
+ is returned. If the contents of BufferA are not identical to the contents of\r
+ BufferB, then an assert is triggered and the location of the assert provided\r
+ by FunctionName, LineNumber, FileName, DescriptionA, and DescriptionB are\r
+ recorded and FALSE is returned.\r
+\r
+ @param[in] BufferA Pointer to a buffer for comparison.\r
+ @param[in] BufferB Pointer to a buffer for comparison.\r
+ @param[in] Length Number of bytes to compare in BufferA and BufferB.\r
+ @param[in] FunctionName Null-terminated ASCII string of the function\r
+ executing the assert macro.\r
+ @param[in] LineNumber The source file line number of the assert macro.\r
+ @param[in] FileName Null-terminated ASCII string of the filename\r
+ executing the assert macro.\r
+ @param[in] DescriptionA Null-terminated ASCII string that is a description\r
+ of BufferA.\r
+ @param[in] DescriptionB Null-terminated ASCII string that is a description\r
+ of BufferB.\r
+\r
+ @retval TRUE The contents of BufferA are identical to the contents of\r
+ BufferB.\r
+ @retval FALSE The contents of BufferA are not identical to the contents of\r
+ BufferB.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnitTestAssertMemEqual (\r
+ IN VOID *BufferA,\r
+ IN VOID *BufferB,\r
+ IN UINTN Length,\r
+ IN CONST CHAR8 *FunctionName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *FileName,\r
+ IN CONST CHAR8 *DescriptionA,\r
+ IN CONST CHAR8 *DescriptionB\r
+ )\r
+{\r
+ if (CompareMem(BufferA, BufferB, Length) != 0) {\r
+ UnitTestLogFailure (\r
+ FAILURETYPE_ASSERTEQUAL,\r
+ "%a::%d Memory at %a != %a for length %d bytes!\n",\r
+ FunctionName,\r
+ LineNumber,\r
+ DescriptionA,\r
+ DescriptionB,\r
+ Length\r
+ );\r
+ UT_LOG_ERROR (\r
+ "[ASSERT FAIL] %a::%d Value %a != %a for length %d bytes!\n",\r
+ FunctionName,\r
+ LineNumber,\r
+ DescriptionA,\r
+ DescriptionB,\r
+ Length\r
+ );\r
+ return FALSE;\r
+ }\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ If ValueA is not equal ValueB, then TRUE is returned.\r
+ If ValueA is equal to ValueB, then an assert is triggered and the location\r
+ of the assert provided by FunctionName, LineNumber, FileName, DescriptionA\r
+ and DescriptionB are recorded and FALSE is returned.\r
+\r
+ @param[in] ValueA 64-bit value.\r
+ @param[in] ValueB 64-bit value.\r
+ @param[in] FunctionName Null-terminated ASCII string of the function\r
+ executing the assert macro.\r
+ @param[in] LineNumber The source file line number of the assert macro.\r
+ @param[in] FileName Null-terminated ASCII string of the filename\r
+ executing the assert macro.\r
+ @param[in] DescriptionA Null-terminated ASCII string that is a description\r
+ of ValueA.\r
+ @param[in] DescriptionB Null-terminated ASCII string that is a description\r
+ of ValueB.\r
+\r
+ @retval TRUE ValueA is not equal to ValueB.\r
+ @retval FALSE ValueA is equal to ValueB.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnitTestAssertNotEqual (\r
+ IN UINT64 ValueA,\r
+ IN UINT64 ValueB,\r
+ IN CONST CHAR8 *FunctionName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *FileName,\r
+ IN CONST CHAR8 *DescriptionA,\r
+ IN CONST CHAR8 *DescriptionB\r
+ )\r
+{\r
+ if ((ValueA == ValueB)) {\r
+ UnitTestLogFailure (\r
+ FAILURETYPE_ASSERTNOTEQUAL,\r
+ "%a::%d Value %a == %a (%d == %d)!\n",\r
+ FunctionName,\r
+ LineNumber,\r
+ DescriptionA,\r
+ DescriptionB,\r
+ ValueA,\r
+ ValueB\r
+ );\r
+ UT_LOG_ERROR (\r
+ "[ASSERT FAIL] %a::%d Value %a == %a (%d == %d)!\n",\r
+ FunctionName,\r
+ LineNumber,\r
+ DescriptionA,\r
+ DescriptionB,\r
+ ValueA,\r
+ ValueB\r
+ );\r
+ }\r
+ return (ValueA != ValueB);\r
+}\r
+\r
+/**\r
+ If Status is equal to Expected, then TRUE is returned.\r
+ If Status is not equal to Expected, then an assert is triggered and the\r
+ location of the assert provided by FunctionName, LineNumber, FileName, and\r
+ Description are recorded and FALSE is returned.\r
+\r
+ @param[in] Status EFI_STATUS value returned from an API under test.\r
+ @param[in] Expected The expected EFI_STATUS return value from an API\r
+ under test.\r
+ @param[in] FunctionName Null-terminated ASCII string of the function\r
+ executing the assert macro.\r
+ @param[in] LineNumber The source file line number of the assert macro.\r
+ @param[in] FileName Null-terminated ASCII string of the filename\r
+ executing the assert macro.\r
+ @param[in] Description Null-terminated ASCII string that is a description\r
+ of Status.\r
+\r
+ @retval TRUE Status is equal to Expected.\r
+ @retval FALSE Status is not equal to Expected.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnitTestAssertStatusEqual (\r
+ IN EFI_STATUS Status,\r
+ IN EFI_STATUS Expected,\r
+ IN CONST CHAR8 *FunctionName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *FileName,\r
+ IN CONST CHAR8 *Description\r
+ )\r
+{\r
+ if ((Status != Expected)) {\r
+ UnitTestLogFailure (\r
+ FAILURETYPE_ASSERTSTATUSEQUAL,\r
+ "%a::%d Status '%a' is %r, should be %r!\n",\r
+ FunctionName,\r
+ LineNumber,\r
+ Description,\r
+ Status,\r
+ Expected\r
+ );\r
+ UT_LOG_ERROR (\r
+ "[ASSERT FAIL] %a::%d Status '%a' is %r, should be %r!\n",\r
+ FunctionName,\r
+ LineNumber,\r
+ Description,\r
+ Status,\r
+ Expected\r
+ );\r
+ }\r
+ return (Status == Expected);\r
+}\r
+\r
+/**\r
+ If Pointer is not equal to NULL, then TRUE is returned.\r
+ If Pointer is equal to NULL, then an assert is triggered and the location of\r
+ the assert provided by FunctionName, LineNumber, FileName, and PointerName\r
+ are recorded and FALSE is returned.\r
+\r
+ @param[in] Pointer Pointer value to be checked against NULL.\r
+ @param[in] Expected The expected EFI_STATUS return value from a function\r
+ under test.\r
+ @param[in] FunctionName Null-terminated ASCII string of the function\r
+ executing the assert macro.\r
+ @param[in] LineNumber The source file line number of the assert macro.\r
+ @param[in] FileName Null-terminated ASCII string of the filename\r
+ executing the assert macro.\r
+ @param[in] PointerName Null-terminated ASCII string that is a description\r
+ of Pointer.\r
+\r
+ @retval TRUE Pointer is not equal to NULL.\r
+ @retval FALSE Pointer is equal to NULL.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnitTestAssertNotNull (\r
+ IN VOID *Pointer,\r
+ IN CONST CHAR8 *FunctionName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *FileName,\r
+ IN CONST CHAR8 *PointerName\r
+ )\r
+{\r
+ if (Pointer == NULL) {\r
+ UnitTestLogFailure (\r
+ FAILURETYPE_ASSERTNOTNULL,\r
+ "%a::%d Pointer (%a) is NULL!\n",\r
+ FunctionName,\r
+ LineNumber,\r
+ PointerName\r
+ );\r
+ UT_LOG_ERROR (\r
+ "[ASSERT FAIL] %a::%d Pointer (%a) is NULL!\n",\r
+ FunctionName,\r
+ LineNumber,\r
+ PointerName\r
+ );\r
+ }\r
+ return (Pointer != NULL);\r
+}\r
--- /dev/null
+/** @file\r
+ Implement UnitTestLib assert services using cmocka services\r
+\r
+ Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdarg.h>\r
+#include <stddef.h>\r
+#include <setjmp.h>\r
+#include <cmocka.h>\r
+\r
+#include <Uefi.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UnitTestLib.h>\r
+\r
+#define MAX_STRING_SIZE 1025\r
+\r
+/**\r
+ If Expression is TRUE, then TRUE is returned.\r
+ If Expression is FALSE, then an assert is triggered and the location of the\r
+ assert provided by FunctionName, LineNumber, FileName, and Description are\r
+ recorded and FALSE is returned.\r
+\r
+ @param[in] Expression The BOOLEAN result of the expression evaluation.\r
+ @param[in] FunctionName Null-terminated ASCII string of the function\r
+ executing the assert macro.\r
+ @param[in] LineNumber The source file line number of the assert macro.\r
+ @param[in] FileName Null-terminated ASCII string of the filename\r
+ executing the assert macro.\r
+ @param[in] Description Null-terminated ASCII string of the expression being\r
+ evaluated.\r
+\r
+ @retval TRUE Expression is TRUE.\r
+ @retval FALSE Expression is FALSE.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnitTestAssertTrue (\r
+ IN BOOLEAN Expression,\r
+ IN CONST CHAR8 *FunctionName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *FileName,\r
+ IN CONST CHAR8 *Description\r
+ )\r
+{\r
+ CHAR8 TempStr[MAX_STRING_SIZE];\r
+\r
+ snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_TRUE(%s:%x)", Description, Expression);\r
+ _assert_true (Expression, TempStr, FileName, (INT32)LineNumber);\r
+\r
+ return Expression;\r
+}\r
+\r
+/**\r
+ If Expression is FALSE, then TRUE is returned.\r
+ If Expression is TRUE, then an assert is triggered and the location of the\r
+ assert provided by FunctionName, LineNumber, FileName, and Description are\r
+ recorded and FALSE is returned.\r
+\r
+ @param[in] Expression The BOOLEAN result of the expression evaluation.\r
+ @param[in] FunctionName Null-terminated ASCII string of the function\r
+ executing the assert macro.\r
+ @param[in] LineNumber The source file line number of the assert macro.\r
+ @param[in] FileName Null-terminated ASCII string of the filename\r
+ executing the assert macro.\r
+ @param[in] Description Null-terminated ASCII string of the expression being\r
+ evaluated.\r
+\r
+ @retval TRUE Expression is FALSE.\r
+ @retval FALSE Expression is TRUE.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnitTestAssertFalse (\r
+ IN BOOLEAN Expression,\r
+ IN CONST CHAR8 *FunctionName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *FileName,\r
+ IN CONST CHAR8 *Description\r
+ )\r
+{\r
+ CHAR8 TempStr[MAX_STRING_SIZE];\r
+\r
+ snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_FALSE(%s:%x)", Description, Expression);\r
+ _assert_true (!Expression, TempStr, FileName, (INT32)LineNumber);\r
+\r
+ return !Expression;\r
+}\r
+\r
+/**\r
+ If Status is not an EFI_ERROR(), then TRUE is returned.\r
+ If Status is an EFI_ERROR(), then an assert is triggered and the location of\r
+ the assert provided by FunctionName, LineNumber, FileName, and Description are\r
+ recorded and FALSE is returned.\r
+\r
+ @param[in] Status The EFI_STATUS value to evaluate.\r
+ @param[in] FunctionName Null-terminated ASCII string of the function\r
+ executing the assert macro.\r
+ @param[in] LineNumber The source file line number of the assert macro.\r
+ @param[in] FileName Null-terminated ASCII string of the filename\r
+ executing the assert macro.\r
+ @param[in] Description Null-terminated ASCII string of the status\r
+ expression being evaluated.\r
+\r
+ @retval TRUE Status is not an EFI_ERROR().\r
+ @retval FALSE Status is an EFI_ERROR().\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnitTestAssertNotEfiError (\r
+ IN EFI_STATUS Status,\r
+ IN CONST CHAR8 *FunctionName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *FileName,\r
+ IN CONST CHAR8 *Description\r
+ )\r
+{\r
+ CHAR8 TempStr[MAX_STRING_SIZE];\r
+\r
+ snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_NOT_EFI_ERROR(%s:%p)", Description, (void *)Status);\r
+ _assert_true (!EFI_ERROR (Status), TempStr, FileName, (INT32)LineNumber);\r
+\r
+ return !EFI_ERROR (Status);\r
+}\r
+\r
+/**\r
+ If ValueA is equal ValueB, then TRUE is returned.\r
+ If ValueA is not equal to ValueB, then an assert is triggered and the location\r
+ of the assert provided by FunctionName, LineNumber, FileName, DescriptionA,\r
+ and DescriptionB are recorded and FALSE is returned.\r
+\r
+ @param[in] ValueA 64-bit value.\r
+ @param[in] ValueB 64-bit value.\r
+ @param[in] FunctionName Null-terminated ASCII string of the function\r
+ executing the assert macro.\r
+ @param[in] LineNumber The source file line number of the assert macro.\r
+ @param[in] FileName Null-terminated ASCII string of the filename\r
+ executing the assert macro.\r
+ @param[in] DescriptionA Null-terminated ASCII string that is a description\r
+ of ValueA.\r
+ @param[in] DescriptionB Null-terminated ASCII string that is a description\r
+ of ValueB.\r
+\r
+ @retval TRUE ValueA is equal to ValueB.\r
+ @retval FALSE ValueA is not equal to ValueB.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnitTestAssertEqual (\r
+ IN UINT64 ValueA,\r
+ IN UINT64 ValueB,\r
+ IN CONST CHAR8 *FunctionName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *FileName,\r
+ IN CONST CHAR8 *DescriptionA,\r
+ IN CONST CHAR8 *DescriptionB\r
+ )\r
+{\r
+ CHAR8 TempStr[MAX_STRING_SIZE];\r
+\r
+ snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_EQUAL(%s:%llx, %s:%llx)", DescriptionA, ValueA, DescriptionB, ValueB);\r
+ _assert_true ((ValueA == ValueB), TempStr, FileName, (INT32)LineNumber);\r
+\r
+ return (ValueA == ValueB);\r
+}\r
+\r
+/**\r
+ If the contents of BufferA are identical to the contents of BufferB, then TRUE\r
+ is returned. If the contents of BufferA are not identical to the contents of\r
+ BufferB, then an assert is triggered and the location of the assert provided\r
+ by FunctionName, LineNumber, FileName, DescriptionA, and DescriptionB are\r
+ recorded and FALSE is returned.\r
+\r
+ @param[in] BufferA Pointer to a buffer for comparison.\r
+ @param[in] BufferB Pointer to a buffer for comparison.\r
+ @param[in] Length Number of bytes to compare in BufferA and BufferB.\r
+ @param[in] FunctionName Null-terminated ASCII string of the function\r
+ executing the assert macro.\r
+ @param[in] LineNumber The source file line number of the assert macro.\r
+ @param[in] FileName Null-terminated ASCII string of the filename\r
+ executing the assert macro.\r
+ @param[in] DescriptionA Null-terminated ASCII string that is a description\r
+ of BufferA.\r
+ @param[in] DescriptionB Null-terminated ASCII string that is a description\r
+ of BufferB.\r
+\r
+ @retval TRUE The contents of BufferA are identical to the contents of\r
+ BufferB.\r
+ @retval FALSE The contents of BufferA are not identical to the contents of\r
+ BufferB.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnitTestAssertMemEqual (\r
+ IN VOID *BufferA,\r
+ IN VOID *BufferB,\r
+ IN UINTN Length,\r
+ IN CONST CHAR8 *FunctionName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *FileName,\r
+ IN CONST CHAR8 *DescriptionA,\r
+ IN CONST CHAR8 *DescriptionB\r
+ )\r
+{\r
+ CHAR8 TempStr[MAX_STRING_SIZE];\r
+ BOOLEAN Result;\r
+\r
+ Result = (CompareMem(BufferA, BufferB, Length) == 0);\r
+\r
+ snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_MEM_EQUAL(%s:%p, %s:%p)", DescriptionA, BufferA, DescriptionB, BufferB);\r
+ _assert_true (Result, TempStr, FileName, (INT32)LineNumber);\r
+\r
+ return Result;\r
+}\r
+\r
+/**\r
+ If ValueA is not equal ValueB, then TRUE is returned.\r
+ If ValueA is equal to ValueB, then an assert is triggered and the location\r
+ of the assert provided by FunctionName, LineNumber, FileName, DescriptionA\r
+ and DescriptionB are recorded and FALSE is returned.\r
+\r
+ @param[in] ValueA 64-bit value.\r
+ @param[in] ValueB 64-bit value.\r
+ @param[in] FunctionName Null-terminated ASCII string of the function\r
+ executing the assert macro.\r
+ @param[in] LineNumber The source file line number of the assert macro.\r
+ @param[in] FileName Null-terminated ASCII string of the filename\r
+ executing the assert macro.\r
+ @param[in] DescriptionA Null-terminated ASCII string that is a description\r
+ of ValueA.\r
+ @param[in] DescriptionB Null-terminated ASCII string that is a description\r
+ of ValueB.\r
+\r
+ @retval TRUE ValueA is not equal to ValueB.\r
+ @retval FALSE ValueA is equal to ValueB.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnitTestAssertNotEqual (\r
+ IN UINT64 ValueA,\r
+ IN UINT64 ValueB,\r
+ IN CONST CHAR8 *FunctionName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *FileName,\r
+ IN CONST CHAR8 *DescriptionA,\r
+ IN CONST CHAR8 *DescriptionB\r
+ )\r
+{\r
+ CHAR8 TempStr[MAX_STRING_SIZE];\r
+\r
+ snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_NOT_EQUAL(%s:%llx, %s:%llx)", DescriptionA, ValueA, DescriptionB, ValueB);\r
+ _assert_true ((ValueA != ValueB), TempStr, FileName, (INT32)LineNumber);\r
+\r
+ return (ValueA != ValueB);\r
+}\r
+\r
+/**\r
+ If Status is equal to Expected, then TRUE is returned.\r
+ If Status is not equal to Expected, then an assert is triggered and the\r
+ location of the assert provided by FunctionName, LineNumber, FileName, and\r
+ Description are recorded and FALSE is returned.\r
+\r
+ @param[in] Status EFI_STATUS value returned from an API under test.\r
+ @param[in] Expected The expected EFI_STATUS return value from an API\r
+ under test.\r
+ @param[in] FunctionName Null-terminated ASCII string of the function\r
+ executing the assert macro.\r
+ @param[in] LineNumber The source file line number of the assert macro.\r
+ @param[in] FileName Null-terminated ASCII string of the filename\r
+ executing the assert macro.\r
+ @param[in] Description Null-terminated ASCII string that is a description\r
+ of Status.\r
+\r
+ @retval TRUE Status is equal to Expected.\r
+ @retval FALSE Status is not equal to Expected.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnitTestAssertStatusEqual (\r
+ IN EFI_STATUS Status,\r
+ IN EFI_STATUS Expected,\r
+ IN CONST CHAR8 *FunctionName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *FileName,\r
+ IN CONST CHAR8 *Description\r
+ )\r
+{\r
+ CHAR8 TempStr[MAX_STRING_SIZE];\r
+\r
+ snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_STATUS_EQUAL(%s:%p)", Description, (VOID *)Status);\r
+ _assert_true ((Status == Expected), TempStr, FileName, (INT32)LineNumber);\r
+\r
+ return (Status == Expected);\r
+}\r
+\r
+/**\r
+ If Pointer is not equal to NULL, then TRUE is returned.\r
+ If Pointer is equal to NULL, then an assert is triggered and the location of\r
+ the assert provided by FunctionName, LineNumber, FileName, and PointerName\r
+ are recorded and FALSE is returned.\r
+\r
+ @param[in] Pointer Pointer value to be checked against NULL.\r
+ @param[in] Expected The expected EFI_STATUS return value from a function\r
+ under test.\r
+ @param[in] FunctionName Null-terminated ASCII string of the function\r
+ executing the assert macro.\r
+ @param[in] LineNumber The source file line number of the assert macro.\r
+ @param[in] FileName Null-terminated ASCII string of the filename\r
+ executing the assert macro.\r
+ @param[in] PointerName Null-terminated ASCII string that is a description\r
+ of Pointer.\r
+\r
+ @retval TRUE Pointer is not equal to NULL.\r
+ @retval FALSE Pointer is equal to NULL.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnitTestAssertNotNull (\r
+ IN VOID *Pointer,\r
+ IN CONST CHAR8 *FunctionName,\r
+ IN UINTN LineNumber,\r
+ IN CONST CHAR8 *FileName,\r
+ IN CONST CHAR8 *PointerName\r
+ )\r
+{\r
+ CHAR8 TempStr[MAX_STRING_SIZE];\r
+\r
+ snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_NOT_NULL(%s:%p)", PointerName, Pointer);\r
+ _assert_true ((Pointer != NULL), TempStr, FileName, (INT32)LineNumber);\r
+\r
+ return (Pointer != NULL);\r
+}\r
--- /dev/null
+/**\r
+ Implemnet UnitTestLib log services\r
+\r
+ Copyright (c) Microsoft Corporation.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <UnitTestFrameworkTypes.h>\r
+#include <Library/UnitTestLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+#define UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH (512)\r
+#define UNIT_TEST_MAX_LOG_BUFFER SIZE_16KB\r
+\r
+struct _UNIT_TEST_LOG_PREFIX_STRING {\r
+ UNIT_TEST_STATUS LogLevel;\r
+ CHAR8 *String;\r
+};\r
+\r
+struct _UNIT_TEST_LOG_PREFIX_STRING mLogPrefixStrings[] = {\r
+ { UNIT_TEST_LOG_LEVEL_ERROR, "[ERROR] " },\r
+ { UNIT_TEST_LOG_LEVEL_WARN, "[WARNING] " },\r
+ { UNIT_TEST_LOG_LEVEL_INFO, "[INFO] " },\r
+ { UNIT_TEST_LOG_LEVEL_VERBOSE, "[VERBOSE] " }\r
+};\r
+\r
+//\r
+// Unit-Test Log helper functions\r
+//\r
+\r
+STATIC\r
+CONST CHAR8*\r
+GetStringForStatusLogPrefix (\r
+ IN UINTN LogLevel\r
+ )\r
+{\r
+ UINTN Index;\r
+ CHAR8 *Result;\r
+\r
+ Result = NULL;\r
+ for (Index = 0; Index < ARRAY_SIZE (mLogPrefixStrings); Index++) {\r
+ if (mLogPrefixStrings[Index].LogLevel == LogLevel) {\r
+ Result = mLogPrefixStrings[Index].String;\r
+ break;\r
+ }\r
+ }\r
+ return Result;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+AddStringToUnitTestLog (\r
+ IN OUT UNIT_TEST *UnitTest,\r
+ IN CONST CHAR8 *String\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Make sure that you're cooking with gas.\r
+ //\r
+ if (UnitTest == NULL || String == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // If this is the first log for the test allocate log space\r
+ if (UnitTest->Log == NULL) {\r
+ UnitTestLogInit (UnitTest, NULL, 0);\r
+ }\r
+\r
+ if (UnitTest->Log == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "Failed to allocate space for unit test log\n"));\r
+ ASSERT (UnitTest->Log != NULL);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = AsciiStrnCatS (\r
+ UnitTest->Log,\r
+ UNIT_TEST_MAX_LOG_BUFFER / sizeof (CHAR8),\r
+ String,\r
+ UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH\r
+ );\r
+ if(EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Failed to add unit test log string. Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is responsible for initializing the log buffer for a single test. It can\r
+ be used internally, but may also be consumed by the test framework to add pre-existing\r
+ data to a log before it's used.\r
+\r
+ @param[in,out] TestHandle A handle to the test being initialized.\r
+ @param[in] Buffer [Optional] A pointer to pre-existing log data that should\r
+ be used to initialize the log. Should include a NULL terminator.\r
+ @param[in] BufferSize [Optional] The size of the pre-existing log data.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+UnitTestLogInit (\r
+ IN OUT UNIT_TEST *Test,\r
+ IN UINT8 *Buffer, OPTIONAL\r
+ IN UINTN BufferSize OPTIONAL\r
+ )\r
+{\r
+ //\r
+ // Make sure that you're cooking with gas.\r
+ //\r
+ if (Test == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "%a called with invalid Test parameter\n", __FUNCTION__));\r
+ return;\r
+ }\r
+\r
+ //\r
+ // If this is the first log for the test allocate log space\r
+ //\r
+ if (Test->Log == NULL) {\r
+ Test->Log = AllocateZeroPool (UNIT_TEST_MAX_LOG_BUFFER);\r
+ }\r
+\r
+ //\r
+ //check again to make sure allocate worked\r
+ //\r
+ if(Test->Log == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "Failed to allocate memory for the log\n"));\r
+ return;\r
+ }\r
+\r
+ if((Buffer != NULL) && (BufferSize > 0) && ((BufferSize <= UNIT_TEST_MAX_LOG_BUFFER))) {\r
+ CopyMem (Test->Log, Buffer, BufferSize);\r
+ }\r
+}\r
+\r
+/**\r
+ Test logging function that records a messages in the test framework log.\r
+ Record is associated with the currently executing test case.\r
+\r
+ @param[in] ErrorLevel The error level of the unit test log message.\r
+ @param[in] Format Formatting string following the format defined in the\r
+ MdePkg/Include/Library/PrintLib.h.\r
+ @param[in] ... Print args.\r
+**/\r
+VOID\r
+EFIAPI\r
+UnitTestLog (\r
+ IN UINTN ErrorLevel,\r
+ IN CONST CHAR8 *Format,\r
+ ...\r
+ )\r
+{\r
+ UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle;\r
+ CHAR8 NewFormatString[UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH];\r
+ CHAR8 LogString[UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH];\r
+ CONST CHAR8 *LogTypePrefix;\r
+ VA_LIST Marker;\r
+\r
+ FrameworkHandle = GetActiveFrameworkHandle ();\r
+\r
+ LogTypePrefix = NULL;\r
+\r
+ //\r
+ // Make sure that this unit test log level is enabled.\r
+ //\r
+ if ((ErrorLevel & (UINTN)PcdGet32 (PcdUnitTestLogLevel)) == 0) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // If we need to define a new format string...\r
+ // well... get to it.\r
+ //\r
+ LogTypePrefix = GetStringForStatusLogPrefix (ErrorLevel);\r
+ if (LogTypePrefix != NULL) {\r
+ AsciiSPrint (NewFormatString, sizeof (NewFormatString), "%a%a", LogTypePrefix, Format);\r
+ } else {\r
+ AsciiStrCpyS (NewFormatString, sizeof (NewFormatString), Format);\r
+ }\r
+\r
+ //\r
+ // Convert the message to an ASCII String\r
+ //\r
+ VA_START (Marker, Format);\r
+ AsciiVSPrint (LogString, sizeof (LogString), NewFormatString, Marker);\r
+ VA_END (Marker);\r
+\r
+ //\r
+ // Finally, add the string to the log.\r
+ //\r
+ AddStringToUnitTestLog (((UNIT_TEST_FRAMEWORK *)FrameworkHandle)->CurrentTest, LogString);\r
+}\r
--- /dev/null
+/**\r
+ UnitTestLib APIs to run unit tests\r
+\r
+ Copyright (c) Microsoft Corporation.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <Library/UnitTestLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UnitTestResultReportLib.h>\r
+\r
+STATIC UNIT_TEST_FRAMEWORK_HANDLE mFrameworkHandle = NULL;\r
+\r
+UNIT_TEST_FRAMEWORK_HANDLE\r
+GetActiveFrameworkHandle (\r
+ VOID\r
+ )\r
+{\r
+ ASSERT (mFrameworkHandle != NULL);\r
+ return mFrameworkHandle;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+RunTestSuite (\r
+ IN UNIT_TEST_SUITE *Suite\r
+ )\r
+{\r
+ UNIT_TEST_LIST_ENTRY *TestEntry;\r
+ UNIT_TEST *Test;\r
+ UNIT_TEST_FRAMEWORK *ParentFramework;\r
+\r
+ TestEntry = NULL;\r
+ ParentFramework = (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework;\r
+\r
+ if (Suite == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "RUNNING TEST SUITE: %a\n", Suite->Title));\r
+ DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));\r
+\r
+ if (Suite->Setup != NULL) {\r
+ Suite->Setup ();\r
+ }\r
+\r
+ //\r
+ // Iterate all tests within the suite\r
+ //\r
+ for (TestEntry = (UNIT_TEST_LIST_ENTRY *)GetFirstNode (&(Suite->TestCaseList));\r
+ (LIST_ENTRY*)TestEntry != &(Suite->TestCaseList);\r
+ TestEntry = (UNIT_TEST_LIST_ENTRY *)GetNextNode (&(Suite->TestCaseList), (LIST_ENTRY *)TestEntry)) {\r
+ Test = &TestEntry->UT;\r
+ ParentFramework->CurrentTest = Test;\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "*********************************************************\n"));\r
+ DEBUG ((DEBUG_VERBOSE, " RUNNING TEST: %a:\n", Test->Description));\r
+ DEBUG ((DEBUG_VERBOSE, "**********************************************************\n"));\r
+\r
+ //\r
+ // First, check to see whether the test has already been run.\r
+ // NOTE: This would generally only be the case if a saved state was detected and loaded.\r
+ //\r
+ if (Test->Result != UNIT_TEST_PENDING && Test->Result != UNIT_TEST_RUNNING) {\r
+ DEBUG ((DEBUG_VERBOSE, "Test was run on a previous pass. Skipping.\n"));\r
+ ParentFramework->CurrentTest = NULL;\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Next, if we're still running, make sure that our test prerequisites are in place.\r
+ if (Test->Result == UNIT_TEST_PENDING && Test->Prerequisite != NULL) {\r
+ DEBUG ((DEBUG_VERBOSE, "PREREQ\n"));\r
+ if (Test->Prerequisite (Test->Context) != UNIT_TEST_PASSED) {\r
+ DEBUG ((DEBUG_ERROR, "Prerequisite Not Met\n"));\r
+ Test->Result = UNIT_TEST_ERROR_PREREQUISITE_NOT_MET;\r
+ ParentFramework->CurrentTest = NULL;\r
+ continue;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Now we should be ready to call the actual test.\r
+ // We set the status to UNIT_TEST_RUNNING in case the test needs to reboot\r
+ // or quit. The UNIT_TEST_RUNNING state will allow the test to resume\r
+ // but will prevent the Prerequisite from being dispatched a second time.\r
+ Test->Result = UNIT_TEST_RUNNING;\r
+ Test->Result = Test->RunTest (Test->Context);\r
+\r
+ //\r
+ // Finally, clean everything up, if need be.\r
+ if (Test->CleanUp != NULL) {\r
+ DEBUG ((DEBUG_VERBOSE, "CLEANUP\n"));\r
+ Test->CleanUp (Test->Context);\r
+ }\r
+\r
+ //\r
+ // End the test.\r
+ //\r
+ ParentFramework->CurrentTest = NULL;\r
+ }\r
+\r
+ if (Suite->Teardown != NULL) {\r
+ Suite->Teardown ();\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Execute all unit test cases in all unit test suites added to a Framework.\r
+\r
+ Once a unit test framework is initialized and all unit test suites and unit\r
+ test cases are registered, this function will cause the unit test framework to\r
+ dispatch all unit test cases in sequence and record the results for reporting.\r
+\r
+ @param[in] FrameworkHandle A handle to the current running framework that\r
+ dispatched the test. Necessary for recording\r
+ certain test events with the framework.\r
+\r
+ @retval EFI_SUCCESS All test cases were dispatched.\r
+ @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RunAllTestSuites (\r
+ IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle\r
+ )\r
+{\r
+ UNIT_TEST_FRAMEWORK *Framework;\r
+ UNIT_TEST_SUITE_LIST_ENTRY *Suite;\r
+ EFI_STATUS Status;\r
+\r
+ Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;\r
+ Suite = NULL;\r
+\r
+ if (Framework == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "------------ RUNNING ALL TEST SUITES --------------\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));\r
+ mFrameworkHandle = FrameworkHandle;\r
+\r
+ //\r
+ // Iterate all suites\r
+ //\r
+ for (Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetFirstNode (&Framework->TestSuiteList);\r
+ (LIST_ENTRY *)Suite != &Framework->TestSuiteList;\r
+ Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetNextNode (&Framework->TestSuiteList, (LIST_ENTRY *)Suite)) {\r
+ Status = RunTestSuite (&(Suite->UTS));\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Test Suite Failed with Error. %r\n", Status));\r
+ }\r
+ }\r
+\r
+ //\r
+ // Save current state so if test is started again it doesn't have to run. It will just report\r
+ //\r
+ SaveFrameworkState (FrameworkHandle, NULL, 0);\r
+ OutputUnitTestFrameworkReport (FrameworkHandle);\r
+\r
+ mFrameworkHandle = NULL;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+ UnitTestLib APIs to run unit tests using cmocka\r
+\r
+ Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdarg.h>\r
+#include <stddef.h>\r
+#include <setjmp.h>\r
+#include <cmocka.h>\r
+\r
+#include <Uefi.h>\r
+#include <UnitTestFrameworkTypes.h>\r
+#include <Library/UnitTestLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DebugLib.h>\r
+\r
+STATIC UNIT_TEST_FRAMEWORK_HANDLE mFrameworkHandle = NULL;\r
+\r
+UNIT_TEST_FRAMEWORK_HANDLE\r
+GetActiveFrameworkHandle (\r
+ VOID\r
+ )\r
+{\r
+ ASSERT (mFrameworkHandle != NULL);\r
+ return mFrameworkHandle;\r
+}\r
+\r
+//\r
+// The currently active test suite\r
+//\r
+UNIT_TEST_SUITE *mActiveUnitTestSuite = NULL;\r
+\r
+void\r
+CmockaUnitTestFunctionRunner (\r
+ void **state\r
+ )\r
+{\r
+ UNIT_TEST *UnitTest;\r
+ UNIT_TEST_SUITE *Suite;\r
+ UNIT_TEST_FRAMEWORK *Framework;\r
+\r
+ UnitTest = (UNIT_TEST *)(*state);\r
+ Suite = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite);\r
+ Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework);\r
+\r
+ if (UnitTest->RunTest == NULL) {\r
+ UnitTest->Result = UNIT_TEST_SKIPPED;\r
+ } else {\r
+ UnitTest->Result = UNIT_TEST_RUNNING;\r
+\r
+ Framework->CurrentTest = UnitTest;\r
+ UnitTest->Result = UnitTest->RunTest (UnitTest->Context);\r
+ Framework->CurrentTest = NULL;\r
+\r
+ // Print out the log messages - This is a partial solution as it\r
+ // does not get the log into the XML. Need cmocka changes to support\r
+ // stdout and stderr in their xml format\r
+ //\r
+ if (UnitTest->Log != NULL) {\r
+ print_message("UnitTest: %s - %s\n", UnitTest->Name, UnitTest->Description);\r
+ print_message("Log Output Start\n");\r
+ print_message("%s", UnitTest->Log);\r
+ print_message("Log Output End\n");\r
+ }\r
+ }\r
+}\r
+\r
+int\r
+CmockaUnitTestSetupFunctionRunner (\r
+ void **state\r
+ )\r
+{\r
+ UNIT_TEST *UnitTest;\r
+ UNIT_TEST_SUITE *Suite;\r
+ UNIT_TEST_FRAMEWORK *Framework;\r
+ UNIT_TEST_STATUS Result;\r
+\r
+ UnitTest = (UNIT_TEST *)(*state);\r
+ Suite = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite);\r
+ Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework);\r
+\r
+ if (UnitTest->Prerequisite == NULL) {\r
+ return 0;\r
+ }\r
+\r
+ Framework->CurrentTest = UnitTest;\r
+ Result = UnitTest->Prerequisite (UnitTest->Context);\r
+ Framework->CurrentTest = NULL;\r
+\r
+ //\r
+ // Return 0 for success. Non-zero for error.\r
+ //\r
+ return (int)Result;\r
+}\r
+\r
+int\r
+CmockaUnitTestTeardownFunctionRunner (\r
+ void **state\r
+ )\r
+{\r
+ UNIT_TEST *UnitTest;\r
+ UNIT_TEST_SUITE *Suite;\r
+ UNIT_TEST_FRAMEWORK *Framework;\r
+\r
+ UnitTest = (UNIT_TEST *)(*state);\r
+ Suite = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite);\r
+ Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework);\r
+\r
+ if (UnitTest->CleanUp == NULL) {\r
+ return 0;\r
+ }\r
+\r
+ Framework->CurrentTest = UnitTest;\r
+ UnitTest->CleanUp (UnitTest->Context);\r
+ Framework->CurrentTest = NULL;\r
+ //\r
+ // Return 0 for success. Non-zero for error.\r
+ //\r
+ return 0;\r
+}\r
+\r
+int\r
+CmockaUnitTestSuiteSetupFunctionRunner (\r
+ void **state\r
+ )\r
+{\r
+ if (mActiveUnitTestSuite == NULL) {\r
+ return -1;\r
+ }\r
+ if (mActiveUnitTestSuite->Setup == NULL) {\r
+ return 0;\r
+ }\r
+\r
+ mActiveUnitTestSuite->Setup ();\r
+ //\r
+ // Always succeed\r
+ //\r
+ return 0;\r
+}\r
+\r
+int\r
+CmockaUnitTestSuiteTeardownFunctionRunner (\r
+ void **state\r
+ )\r
+{\r
+ if (mActiveUnitTestSuite == NULL) {\r
+ return -1;\r
+ }\r
+ if (mActiveUnitTestSuite->Teardown == NULL) {\r
+ return 0;\r
+ }\r
+\r
+ mActiveUnitTestSuite->Teardown ();\r
+ //\r
+ // Always succeed\r
+ //\r
+ return 0;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+RunTestSuite (\r
+ IN UNIT_TEST_SUITE *Suite\r
+ )\r
+{\r
+ UNIT_TEST_LIST_ENTRY *TestEntry;\r
+ UNIT_TEST *UnitTest;\r
+ struct CMUnitTest *Tests;\r
+ UINTN Index;\r
+\r
+ TestEntry = NULL;\r
+\r
+ if (Suite == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "RUNNING TEST SUITE: %a\n", Suite->Title));\r
+ DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));\r
+\r
+ //\r
+ // Allocate buffer of CMUnitTest entries\r
+ //\r
+ Tests = AllocateZeroPool (Suite->NumTests * sizeof (struct CMUnitTest));\r
+ ASSERT (Tests != NULL);\r
+\r
+ //\r
+ // Populate buffer of CMUnitTest entries\r
+ //\r
+ Index = 0;\r
+ for (TestEntry = (UNIT_TEST_LIST_ENTRY *)GetFirstNode (&(Suite->TestCaseList));\r
+ (LIST_ENTRY *)TestEntry != &(Suite->TestCaseList);\r
+ TestEntry = (UNIT_TEST_LIST_ENTRY *)GetNextNode (&(Suite->TestCaseList), (LIST_ENTRY *)TestEntry)) {\r
+ UnitTest = &TestEntry->UT;\r
+ Tests[Index].name = UnitTest->Description;\r
+ Tests[Index].test_func = CmockaUnitTestFunctionRunner;\r
+ Tests[Index].setup_func = CmockaUnitTestSetupFunctionRunner;\r
+ Tests[Index].teardown_func = CmockaUnitTestTeardownFunctionRunner;\r
+ Tests[Index].initial_state = UnitTest;\r
+ Index++;\r
+ }\r
+ ASSERT (Index == Suite->NumTests);\r
+\r
+ //\r
+ // Run all unit tests in a test suite\r
+ //\r
+ mActiveUnitTestSuite = Suite;\r
+ _cmocka_run_group_tests (\r
+ Suite->Title,\r
+ Tests,\r
+ Suite->NumTests,\r
+ CmockaUnitTestSuiteSetupFunctionRunner,\r
+ CmockaUnitTestSuiteTeardownFunctionRunner\r
+ );\r
+ mActiveUnitTestSuite = NULL;\r
+ FreePool (Tests);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Execute all unit test cases in all unit test suites added to a Framework.\r
+\r
+ Once a unit test framework is initialized and all unit test suites and unit\r
+ test cases are registered, this function will cause the unit test framework to\r
+ dispatch all unit test cases in sequence and record the results for reporting.\r
+\r
+ @param[in] FrameworkHandle A handle to the current running framework that\r
+ dispatched the test. Necessary for recording\r
+ certain test events with the framework.\r
+\r
+ @retval EFI_SUCCESS All test cases were dispatched.\r
+ @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RunAllTestSuites (\r
+ IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle\r
+ )\r
+{\r
+ UNIT_TEST_FRAMEWORK *Framework;\r
+ UNIT_TEST_SUITE_LIST_ENTRY *Suite;\r
+ EFI_STATUS Status;\r
+\r
+ Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;\r
+ Suite = NULL;\r
+\r
+ if (Framework == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ DEBUG((DEBUG_VERBOSE, "---------------------------------------------------------\n"));\r
+ DEBUG((DEBUG_VERBOSE, "------------ RUNNING ALL TEST SUITES --------------\n"));\r
+ DEBUG((DEBUG_VERBOSE, "---------------------------------------------------------\n"));\r
+ mFrameworkHandle = FrameworkHandle;\r
+\r
+ //\r
+ // Iterate all suites\r
+ //\r
+ for (Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetFirstNode (&Framework->TestSuiteList);\r
+ (LIST_ENTRY *)Suite != &Framework->TestSuiteList;\r
+ Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetNextNode (&Framework->TestSuiteList, (LIST_ENTRY *)Suite)) {\r
+ Status = RunTestSuite (&(Suite->UTS));\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Test Suite Failed with Error. %r\n", Status));\r
+ }\r
+ }\r
+\r
+ mFrameworkHandle = NULL;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/**\r
+ Implement UnitTestLib\r
+\r
+ Copyright (c) Microsoft Corporation.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <Library/UnitTestLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UnitTestPersistenceLib.h>\r
+#include <Library/UnitTestResultReportLib.h>\r
+\r
+///\r
+/// Forward declaration of prototype\r
+///\r
+STATIC\r
+VOID\r
+UpdateTestFromSave (\r
+ IN OUT UNIT_TEST *Test,\r
+ IN UNIT_TEST_SAVE_HEADER *SavedState\r
+ );\r
+\r
+/**\r
+ This function will determine whether the short name violates any rules that would\r
+ prevent it from being used as a reporting name or as a serialization name.\r
+\r
+ Example: If the name cannot be serialized to a filesystem file name.\r
+\r
+ @param[in] ShortTitleString A pointer to the short title string to be evaluated.\r
+\r
+ @retval TRUE The string is acceptable.\r
+ @retval FALSE The string should not be used.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+IsFrameworkShortNameValid (\r
+ IN CHAR8 *ShortTitleString\r
+ )\r
+{\r
+ // TODO: Finish this function.\r
+ return TRUE;\r
+}\r
+\r
+STATIC\r
+CHAR8*\r
+AllocateAndCopyString (\r
+ IN CHAR8 *StringToCopy\r
+ )\r
+{\r
+ CHAR8 *NewString;\r
+ UINTN NewStringLength;\r
+\r
+ NewString = NULL;\r
+ NewStringLength = AsciiStrnLenS (StringToCopy, UNIT_TEST_MAX_STRING_LENGTH) + 1;\r
+ NewString = AllocatePool (NewStringLength * sizeof( CHAR8 ));\r
+ if (NewString != NULL) {\r
+ AsciiStrCpyS (NewString, NewStringLength, StringToCopy);\r
+ }\r
+ return NewString;\r
+}\r
+\r
+STATIC\r
+VOID\r
+SetFrameworkFingerprint (\r
+ OUT UINT8 *Fingerprint,\r
+ IN UNIT_TEST_FRAMEWORK *Framework\r
+ )\r
+{\r
+ UINT32 NewFingerprint;\r
+\r
+ // For this one we'll just use the title and version as the unique fingerprint.\r
+ NewFingerprint = CalculateCrc32( Framework->Title, (AsciiStrLen( Framework->Title ) * sizeof( CHAR8 )) );\r
+ NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32( Framework->VersionString, (AsciiStrLen( Framework->VersionString ) * sizeof( CHAR8 )) );\r
+\r
+ CopyMem( Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE );\r
+ return;\r
+}\r
+\r
+STATIC\r
+VOID\r
+SetSuiteFingerprint (\r
+ OUT UINT8 *Fingerprint,\r
+ IN UNIT_TEST_FRAMEWORK *Framework,\r
+ IN UNIT_TEST_SUITE *Suite\r
+ )\r
+{\r
+ UINT32 NewFingerprint;\r
+\r
+ // For this one, we'll use the fingerprint from the framework, and the title of the suite.\r
+ NewFingerprint = CalculateCrc32( &Framework->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE );\r
+ NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32( Suite->Title, (AsciiStrLen( Suite->Title ) * sizeof( CHAR8 )) );\r
+ NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32( Suite->Name, (AsciiStrLen(Suite->Name) * sizeof(CHAR8)) );\r
+\r
+ CopyMem( Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE );\r
+ return;\r
+}\r
+\r
+STATIC\r
+VOID\r
+SetTestFingerprint (\r
+ OUT UINT8 *Fingerprint,\r
+ IN UNIT_TEST_SUITE *Suite,\r
+ IN UNIT_TEST *Test\r
+ )\r
+{\r
+ UINT32 NewFingerprint;\r
+\r
+ // For this one, we'll use the fingerprint from the suite, and the description and classname of the test.\r
+ NewFingerprint = CalculateCrc32( &Suite->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE );\r
+ NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32( Test->Description, (AsciiStrLen( Test->Description ) * sizeof( CHAR8 )) );\r
+ NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32( Test->Name, (AsciiStrLen(Test->Name) * sizeof(CHAR8)) );\r
+\r
+ CopyMem( Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE );\r
+ return;\r
+}\r
+\r
+STATIC\r
+BOOLEAN\r
+CompareFingerprints (\r
+ IN UINT8 *FingerprintA,\r
+ IN UINT8 *FingerprintB\r
+ )\r
+{\r
+ return (CompareMem( FingerprintA, FingerprintB, UNIT_TEST_FINGERPRINT_SIZE ) == 0);\r
+}\r
+\r
+/**\r
+ Cleanup a test framework.\r
+\r
+ After tests are run, this will teardown the entire framework and free all\r
+ allocated data within.\r
+\r
+ @param[in] FrameworkHandle A handle to the current running framework that\r
+ dispatched the test. Necessary for recording\r
+ certain test events with the framework.\r
+\r
+ @retval EFI_SUCCESS All resources associated with framework were\r
+ freed.\r
+ @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FreeUnitTestFramework (\r
+ IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle\r
+ )\r
+{\r
+ // TODO: Finish this function.\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FreeUnitTestSuiteEntry (\r
+ IN UNIT_TEST_SUITE_LIST_ENTRY *SuiteEntry\r
+ )\r
+{\r
+ // TODO: Finish this function.\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FreeUnitTestTestEntry (\r
+ IN UNIT_TEST_LIST_ENTRY *TestEntry\r
+ )\r
+{\r
+ // TODO: Finish this function.\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Method to Initialize the Unit Test framework. This function registers the\r
+ test name and also initializes the internal state of the test framework to\r
+ receive any new suites and tests.\r
+\r
+ @param[out] FrameworkHandle Unit test framework to be created.\r
+ @param[in] Title Null-terminated ASCII string that is the user\r
+ friendly name of the framework. String is\r
+ copied.\r
+ @param[in] ShortTitle Null-terminated ASCII short string that is the\r
+ short name of the framework with no spaces.\r
+ String is copied.\r
+ @param[in] VersionString Null-terminated ASCII version string for the\r
+ framework. String is copied.\r
+\r
+ @retval EFI_SUCCESS The unit test framework was initialized.\r
+ @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.\r
+ @retval EFI_INVALID_PARAMETER Title is NULL.\r
+ @retval EFI_INVALID_PARAMETER ShortTitle is NULL.\r
+ @retval EFI_INVALID_PARAMETER VersionString is NULL.\r
+ @retval EFI_INVALID_PARAMETER ShortTitle is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to\r
+ initialize the unit test framework.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitUnitTestFramework (\r
+ OUT UNIT_TEST_FRAMEWORK_HANDLE *FrameworkHandle,\r
+ IN CHAR8 *Title,\r
+ IN CHAR8 *ShortTitle,\r
+ IN CHAR8 *VersionString\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UNIT_TEST_FRAMEWORK_HANDLE NewFrameworkHandle;\r
+ UNIT_TEST_FRAMEWORK *NewFramework;\r
+ UNIT_TEST_SAVE_HEADER *SavedState;\r
+\r
+ Status = EFI_SUCCESS;\r
+ NewFramework = NULL;\r
+\r
+ //\r
+ // First, check all pointers and make sure nothing's broked.\r
+ //\r
+ if (FrameworkHandle == NULL || Title == NULL ||\r
+ ShortTitle == NULL || VersionString == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Next, determine whether all of the strings are good to use.\r
+ //\r
+ if (!IsFrameworkShortNameValid (ShortTitle)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Next, set aside some space to start messing with the framework.\r
+ //\r
+ NewFramework = AllocateZeroPool (sizeof (UNIT_TEST_FRAMEWORK));\r
+ if (NewFramework == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Next, set up all the test data.\r
+ //\r
+ NewFrameworkHandle = (UNIT_TEST_FRAMEWORK_HANDLE)NewFramework;\r
+ NewFramework->Title = AllocateAndCopyString (Title);\r
+ NewFramework->ShortTitle = AllocateAndCopyString (ShortTitle);\r
+ NewFramework->VersionString = AllocateAndCopyString (VersionString);\r
+ NewFramework->Log = NULL;\r
+ NewFramework->CurrentTest = NULL;\r
+ NewFramework->SavedState = NULL;\r
+ if (NewFramework->Title == NULL ||\r
+ NewFramework->ShortTitle == NULL ||\r
+ NewFramework->VersionString == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+ InitializeListHead (&(NewFramework->TestSuiteList));\r
+\r
+ //\r
+ // Create the framework fingerprint.\r
+ //\r
+ SetFrameworkFingerprint (&NewFramework->Fingerprint[0], NewFramework);\r
+\r
+ //\r
+ // If there is a persisted context, load it now.\r
+ //\r
+ if (DoesCacheExist (NewFrameworkHandle)) {\r
+ SavedState = (UNIT_TEST_SAVE_HEADER *)NewFramework->SavedState;\r
+ Status = LoadUnitTestCache (NewFrameworkHandle, &SavedState);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Don't actually report it as an error, but emit a warning.\r
+ //\r
+ DEBUG (( DEBUG_ERROR, "%a - Cache was detected, but failed to load.\n", __FUNCTION__ ));\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+Exit:\r
+ //\r
+ // If we're good, then let's copy the framework.\r
+ //\r
+ if (!EFI_ERROR (Status)) {\r
+ *FrameworkHandle = NewFrameworkHandle;\r
+ } else {\r
+ //\r
+ // Otherwise, we need to undo this horrible thing that we've done.\r
+ //\r
+ FreeUnitTestFramework (NewFrameworkHandle);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Registers a Unit Test Suite in the Unit Test Framework.\r
+ At least one test suite must be registered, because all test cases must be\r
+ within a unit test suite.\r
+\r
+ @param[out] SuiteHandle Unit test suite to create\r
+ @param[in] FrameworkHandle Unit test framework to add unit test suite to\r
+ @param[in] Title Null-terminated ASCII string that is the user\r
+ friendly name of the test suite. String is\r
+ copied.\r
+ @param[in] Name Null-terminated ASCII string that is the short\r
+ name of the test suite with no spaces. String\r
+ is copied.\r
+ @param[in] Setup Setup function, runs before suite. This is an\r
+ optional parameter that may be NULL.\r
+ @param[in] Teardown Teardown function, runs after suite. This is an\r
+ optional parameter that may be NULL.\r
+\r
+ @retval EFI_SUCCESS The unit test suite was created.\r
+ @retval EFI_INVALID_PARAMETER SuiteHandle is NULL.\r
+ @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.\r
+ @retval EFI_INVALID_PARAMETER Title is NULL.\r
+ @retval EFI_INVALID_PARAMETER Name is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to\r
+ initialize the unit test suite.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CreateUnitTestSuite (\r
+ OUT UNIT_TEST_SUITE_HANDLE *SuiteHandle,\r
+ IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,\r
+ IN CHAR8 *Title,\r
+ IN CHAR8 *Name,\r
+ IN UNIT_TEST_SUITE_SETUP Setup OPTIONAL,\r
+ IN UNIT_TEST_SUITE_TEARDOWN Teardown OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UNIT_TEST_SUITE_LIST_ENTRY *NewSuiteEntry;\r
+ UNIT_TEST_FRAMEWORK *Framework;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;\r
+\r
+ //\r
+ // First, let's check to make sure that our parameters look good.\r
+ //\r
+ if ((SuiteHandle == NULL) || (Framework == NULL) || (Title == NULL) || (Name == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Create the new entry.\r
+ //\r
+ NewSuiteEntry = AllocateZeroPool (sizeof (UNIT_TEST_SUITE_LIST_ENTRY));\r
+ if (NewSuiteEntry == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Copy the fields we think we need.\r
+ //\r
+ NewSuiteEntry->UTS.NumTests = 0;\r
+ NewSuiteEntry->UTS.Title = AllocateAndCopyString (Title);\r
+ NewSuiteEntry->UTS.Name = AllocateAndCopyString (Name);\r
+ NewSuiteEntry->UTS.Setup = Setup;\r
+ NewSuiteEntry->UTS.Teardown = Teardown;\r
+ NewSuiteEntry->UTS.ParentFramework = FrameworkHandle;\r
+ InitializeListHead (&(NewSuiteEntry->Entry)); // List entry for sibling suites.\r
+ InitializeListHead (&(NewSuiteEntry->UTS.TestCaseList)); // List entry for child tests.\r
+ if (NewSuiteEntry->UTS.Title == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+\r
+ if (NewSuiteEntry->UTS.Name == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Create the suite fingerprint.\r
+ //\r
+ SetSuiteFingerprint( &NewSuiteEntry->UTS.Fingerprint[0], Framework, &NewSuiteEntry->UTS );\r
+\r
+Exit:\r
+ //\r
+ // If everything is going well, add the new suite to the tail list for the framework.\r
+ //\r
+ if (!EFI_ERROR( Status )) {\r
+ InsertTailList (&(Framework->TestSuiteList), (LIST_ENTRY *)NewSuiteEntry);\r
+ *SuiteHandle = (UNIT_TEST_SUITE_HANDLE)(&NewSuiteEntry->UTS);\r
+ } else {\r
+ //\r
+ // Otherwise, make with the destruction.\r
+ //\r
+ FreeUnitTestSuiteEntry (NewSuiteEntry);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Adds test case to Suite\r
+\r
+ @param[in] SuiteHandle Unit test suite to add test to.\r
+ @param[in] Description Null-terminated ASCII string that is the user\r
+ friendly description of a test. String is copied.\r
+ @param[in] Name Null-terminated ASCII string that is the short name\r
+ of the test with no spaces. String is copied.\r
+ @param[in] Function Unit test function.\r
+ @param[in] Prerequisite Prerequisite function, runs before test. This is\r
+ an optional parameter that may be NULL.\r
+ @param[in] CleanUp Clean up function, runs after test. This is an\r
+ optional parameter that may be NULL.\r
+ @param[in] Context Pointer to context. This is an optional parameter\r
+ that may be NULL.\r
+\r
+ @retval EFI_SUCCESS The unit test case was added to Suite.\r
+ @retval EFI_INVALID_PARAMETER SuiteHandle is NULL.\r
+ @retval EFI_INVALID_PARAMETER Description is NULL.\r
+ @retval EFI_INVALID_PARAMETER Name is NULL.\r
+ @retval EFI_INVALID_PARAMETER Function is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to\r
+ add the unit test case to Suite.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AddTestCase (\r
+ IN UNIT_TEST_SUITE_HANDLE SuiteHandle,\r
+ IN CHAR8 *Description,\r
+ IN CHAR8 *Name,\r
+ IN UNIT_TEST_FUNCTION Function,\r
+ IN UNIT_TEST_PREREQUISITE Prerequisite OPTIONAL,\r
+ IN UNIT_TEST_CLEANUP CleanUp OPTIONAL,\r
+ IN UNIT_TEST_CONTEXT Context OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UNIT_TEST_LIST_ENTRY *NewTestEntry;\r
+ UNIT_TEST_FRAMEWORK *ParentFramework;\r
+ UNIT_TEST_SUITE *Suite;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Suite = (UNIT_TEST_SUITE *)SuiteHandle;\r
+ ParentFramework = (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework;\r
+\r
+ //\r
+ // First, let's check to make sure that our parameters look good.\r
+ //\r
+ if ((Suite == NULL) || (Description == NULL) || (Name == NULL) || (Function == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Create the new entry.\r
+ NewTestEntry = AllocateZeroPool (sizeof( UNIT_TEST_LIST_ENTRY ));\r
+ if (NewTestEntry == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Copy the fields we think we need.\r
+ NewTestEntry->UT.Description = AllocateAndCopyString (Description);\r
+ NewTestEntry->UT.Name = AllocateAndCopyString (Name);\r
+ NewTestEntry->UT.FailureType = FAILURETYPE_NOFAILURE;\r
+ NewTestEntry->UT.FailureMessage[0] = '\0';\r
+ NewTestEntry->UT.Log = NULL;\r
+ NewTestEntry->UT.Prerequisite = Prerequisite;\r
+ NewTestEntry->UT.CleanUp = CleanUp;\r
+ NewTestEntry->UT.RunTest = Function;\r
+ NewTestEntry->UT.Context = Context;\r
+ NewTestEntry->UT.Result = UNIT_TEST_PENDING;\r
+ NewTestEntry->UT.ParentSuite = SuiteHandle;\r
+ InitializeListHead (&(NewTestEntry->Entry)); // List entry for sibling tests.\r
+ if (NewTestEntry->UT.Description == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+ if (NewTestEntry->UT.Name == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Create the test fingerprint.\r
+ //\r
+ SetTestFingerprint (&NewTestEntry->UT.Fingerprint[0], Suite, &NewTestEntry->UT);\r
+\r
+ // TODO: Make sure that duplicate fingerprints cannot be created.\r
+\r
+ //\r
+ // If there is saved test data, update this record.\r
+ //\r
+ if (ParentFramework->SavedState != NULL) {\r
+ UpdateTestFromSave (&NewTestEntry->UT, ParentFramework->SavedState);\r
+ }\r
+\r
+Exit:\r
+ //\r
+ // If everything is going well, add the new suite to the tail list for the framework.\r
+ //\r
+ if (!EFI_ERROR (Status)) {\r
+ InsertTailList (&(Suite->TestCaseList), (LIST_ENTRY*)NewTestEntry);\r
+ Suite->NumTests++;\r
+ } else {\r
+ //\r
+ // Otherwise, make with the destruction.\r
+ //\r
+ FreeUnitTestTestEntry (NewTestEntry);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+STATIC\r
+VOID\r
+UpdateTestFromSave (\r
+ IN OUT UNIT_TEST *Test,\r
+ IN UNIT_TEST_SAVE_HEADER *SavedState\r
+ )\r
+{\r
+ UNIT_TEST_SAVE_TEST *CurrentTest;\r
+ UNIT_TEST_SAVE_TEST *MatchingTest;\r
+ UINT8 *FloatingPointer;\r
+ UNIT_TEST_SAVE_CONTEXT *SavedContext;\r
+ UINTN Index;\r
+\r
+ //\r
+ // First, evaluate the inputs.\r
+ //\r
+ if (Test == NULL || SavedState == NULL) {\r
+ return;\r
+ }\r
+ if (SavedState->TestCount == 0) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Next, determine whether a matching test can be found.\r
+ // Start at the beginning.\r
+ //\r
+ MatchingTest = NULL;\r
+ FloatingPointer = (UINT8 *)SavedState + sizeof (*SavedState);\r
+ for (Index = 0; Index < SavedState->TestCount; Index++) {\r
+ CurrentTest = (UNIT_TEST_SAVE_TEST *)FloatingPointer;\r
+ if (CompareFingerprints (&Test->Fingerprint[0], &CurrentTest->Fingerprint[0])) {\r
+ MatchingTest = CurrentTest;\r
+ //\r
+ // If there's a saved context, it's important that we iterate through the entire list.\r
+ //\r
+ if (!SavedState->HasSavedContext) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If we didn't find it, we have to increment to the next test.\r
+ //\r
+ FloatingPointer = (UINT8 *)CurrentTest + CurrentTest->Size;\r
+ }\r
+\r
+ //\r
+ // If a matching test was found, copy the status.\r
+ //\r
+ if (MatchingTest) {\r
+ //\r
+ // Override the test status with the saved status.\r
+ //\r
+ Test->Result = MatchingTest->Result;\r
+\r
+ Test->FailureType = MatchingTest->FailureType;\r
+ AsciiStrnCpyS (\r
+ &Test->FailureMessage[0],\r
+ UNIT_TEST_TESTFAILUREMSG_LENGTH,\r
+ &MatchingTest->FailureMessage[0],\r
+ UNIT_TEST_TESTFAILUREMSG_LENGTH\r
+ );\r
+\r
+ //\r
+ // If there is a log string associated, grab that.\r
+ // We can tell that there's a log string because the "size" will be larger than\r
+ // the structure size.\r
+ // IMPORTANT NOTE: There are security implications here.\r
+ // This data is user-supplied and we're about to play kinda\r
+ // fast and loose with data buffers.\r
+ //\r
+ if (MatchingTest->Size > sizeof (UNIT_TEST_SAVE_TEST)) {\r
+ UnitTestLogInit (Test, (UINT8 *)MatchingTest->Log, MatchingTest->Size - sizeof (UNIT_TEST_SAVE_TEST));\r
+ }\r
+ }\r
+\r
+ //\r
+ // If the saved context exists and matches this test, grab it, too.\r
+ //\r
+ if (SavedState->HasSavedContext) {\r
+ //\r
+ // If there was a saved context, the "matching test" loop will have placed the FloatingPointer\r
+ // at the beginning of the context structure.\r
+ //\r
+ SavedContext = (UNIT_TEST_SAVE_CONTEXT *)FloatingPointer;\r
+ if ((SavedContext->Size - sizeof (UNIT_TEST_SAVE_CONTEXT)) > 0 &&\r
+ CompareFingerprints (&Test->Fingerprint[0], &SavedContext->Fingerprint[0])) {\r
+ //\r
+ // Override the test context with the saved context.\r
+ //\r
+ Test->Context = (VOID*)SavedContext->Data;\r
+ }\r
+ }\r
+}\r
+\r
+STATIC\r
+UNIT_TEST_SAVE_HEADER*\r
+SerializeState (\r
+ IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,\r
+ IN UNIT_TEST_CONTEXT ContextToSave, OPTIONAL\r
+ IN UINTN ContextToSaveSize\r
+ )\r
+{\r
+ UNIT_TEST_FRAMEWORK *Framework;\r
+ UNIT_TEST_SAVE_HEADER *Header;\r
+ LIST_ENTRY *SuiteListHead;\r
+ LIST_ENTRY *Suite;\r
+ LIST_ENTRY *TestListHead;\r
+ LIST_ENTRY *Test;\r
+ UINT32 TestCount;\r
+ UINT32 TotalSize;\r
+ UINTN LogSize;\r
+ UNIT_TEST_SAVE_TEST *TestSaveData;\r
+ UNIT_TEST_SAVE_CONTEXT *TestSaveContext;\r
+ UNIT_TEST *UnitTest;\r
+ UINT8 *FloatingPointer;\r
+\r
+ Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;\r
+ Header = NULL;\r
+\r
+ //\r
+ // First, let's not make assumptions about the parameters.\r
+ //\r
+ if (Framework == NULL ||\r
+ (ContextToSave != NULL && ContextToSaveSize == 0) ||\r
+ ContextToSaveSize > MAX_UINT32) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Next, we've gotta figure out the resources that will be required to serialize the\r
+ // the framework state so that we can persist it.\r
+ // To start with, we're gonna need a header.\r
+ //\r
+ TotalSize = sizeof (UNIT_TEST_SAVE_HEADER);\r
+ //\r
+ // Now we need to figure out how many tests there are.\r
+ //\r
+ TestCount = 0;\r
+ //\r
+ // Iterate all suites.\r
+ //\r
+ SuiteListHead = &Framework->TestSuiteList;\r
+ for (Suite = GetFirstNode (SuiteListHead); Suite != SuiteListHead; Suite = GetNextNode (SuiteListHead, Suite)) {\r
+ //\r
+ // Iterate all tests within the suite.\r
+ //\r
+ TestListHead = &((UNIT_TEST_SUITE_LIST_ENTRY *)Suite)->UTS.TestCaseList;\r
+ for (Test = GetFirstNode (TestListHead); Test != TestListHead; Test = GetNextNode (TestListHead, Test)) {\r
+ UnitTest = &((UNIT_TEST_LIST_ENTRY *)Test)->UT;\r
+ //\r
+ // Account for the size of a test structure.\r
+ //\r
+ TotalSize += sizeof( UNIT_TEST_SAVE_TEST );\r
+ //\r
+ // If there's a log, make sure to account for the log size.\r
+ //\r
+ if (UnitTest->Log != NULL) {\r
+ //\r
+ // The +1 is for the NULL character. Can't forget the NULL character.\r
+ //\r
+ LogSize = (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8);\r
+ ASSERT (LogSize < MAX_UINT32);\r
+ TotalSize += (UINT32)LogSize;\r
+ }\r
+ //\r
+ // Increment the test count.\r
+ //\r
+ TestCount++;\r
+ }\r
+ }\r
+ //\r
+ // If there are no tests, we're done here.\r
+ //\r
+ if (TestCount == 0) {\r
+ return NULL;\r
+ }\r
+ //\r
+ // Add room for the context, if there is one.\r
+ //\r
+ if (ContextToSave != NULL) {\r
+ TotalSize += sizeof (UNIT_TEST_SAVE_CONTEXT) + (UINT32)ContextToSaveSize;\r
+ }\r
+\r
+ //\r
+ // Now that we know the size, we need to allocate space for the serialized output.\r
+ //\r
+ Header = AllocateZeroPool (TotalSize);\r
+ if (Header == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Alright, let's start setting up some data.\r
+ //\r
+ Header->Version = UNIT_TEST_PERSISTENCE_LIB_VERSION;\r
+ Header->SaveStateSize = TotalSize;\r
+ CopyMem (&Header->Fingerprint[0], &Framework->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);\r
+ CopyMem (&Header->StartTime, &Framework->StartTime, sizeof (EFI_TIME));\r
+ Header->TestCount = TestCount;\r
+ Header->HasSavedContext = FALSE;\r
+\r
+ //\r
+ // Start adding all of the test cases.\r
+ // Set the floating pointer to the start of the current test save buffer.\r
+ //\r
+ FloatingPointer = (UINT8*)Header + sizeof( UNIT_TEST_SAVE_HEADER );\r
+ //\r
+ // Iterate all suites.\r
+ //\r
+ SuiteListHead = &Framework->TestSuiteList;\r
+ for (Suite = GetFirstNode (SuiteListHead); Suite != SuiteListHead; Suite = GetNextNode (SuiteListHead, Suite)) {\r
+ //\r
+ // Iterate all tests within the suite.\r
+ //\r
+ TestListHead = &((UNIT_TEST_SUITE_LIST_ENTRY *)Suite)->UTS.TestCaseList;\r
+ for (Test = GetFirstNode (TestListHead); Test != TestListHead; Test = GetNextNode (TestListHead, Test)) {\r
+ TestSaveData = (UNIT_TEST_SAVE_TEST *)FloatingPointer;\r
+ UnitTest = &((UNIT_TEST_LIST_ENTRY *)Test)->UT;\r
+\r
+ //\r
+ // Save the fingerprint.\r
+ //\r
+ CopyMem (&TestSaveData->Fingerprint[0], &UnitTest->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);\r
+\r
+ //\r
+ // Save the result.\r
+ //\r
+ TestSaveData->Result = UnitTest->Result;\r
+ TestSaveData->FailureType = UnitTest->FailureType;\r
+ AsciiStrnCpyS (&TestSaveData->FailureMessage[0], UNIT_TEST_TESTFAILUREMSG_LENGTH, &UnitTest->FailureMessage[0], UNIT_TEST_TESTFAILUREMSG_LENGTH);\r
+\r
+\r
+ //\r
+ // If there is a log, save the log.\r
+ //\r
+ FloatingPointer += sizeof (UNIT_TEST_SAVE_TEST);\r
+ if (UnitTest->Log != NULL) {\r
+ //\r
+ // The +1 is for the NULL character. Can't forget the NULL character.\r
+ //\r
+ LogSize = (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8);\r
+ CopyMem (FloatingPointer, UnitTest->Log, LogSize);\r
+ FloatingPointer += LogSize;\r
+ }\r
+\r
+ //\r
+ // Update the size once the structure is complete.\r
+ // NOTE: Should this be a straight cast without validation?\r
+ //\r
+ TestSaveData->Size = (UINT32)(FloatingPointer - (UINT8 *)TestSaveData);\r
+ }\r
+ }\r
+\r
+ //\r
+ // If there is a context to save, let's do that now.\r
+ //\r
+ if (ContextToSave != NULL && Framework->CurrentTest != NULL) {\r
+ TestSaveContext = (UNIT_TEST_SAVE_CONTEXT*)FloatingPointer;\r
+ TestSaveContext->Size = (UINT32)ContextToSaveSize + sizeof (UNIT_TEST_SAVE_CONTEXT);\r
+ CopyMem (&TestSaveContext->Fingerprint[0], &Framework->CurrentTest->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);\r
+ CopyMem (((UINT8 *)TestSaveContext + sizeof (UNIT_TEST_SAVE_CONTEXT)), ContextToSave, ContextToSaveSize);\r
+ Header->HasSavedContext = TRUE;\r
+ }\r
+\r
+ return Header;\r
+}\r
+\r
+/**\r
+ Leverages a framework-specific mechanism (see UnitTestPersistenceLib if you're\r
+ a framework author) to save the state of the executing framework along with\r
+ any allocated data so that the test may be resumed upon reentry. A test case\r
+ should pass any needed context (which, to prevent an infinite loop, should be\r
+ at least the current execution count) which will be saved by the framework and\r
+ passed to the test case upon resume.\r
+\r
+ Generally called from within a test case prior to quitting or rebooting.\r
+\r
+ @param[in] FrameworkHandle A handle to the current running framework that\r
+ dispatched the test. Necessary for recording\r
+ certain test events with the framework.\r
+ @param[in] ContextToSave A buffer of test case-specific data to be saved\r
+ along with framework state. Will be passed as\r
+ "Context" to the test case upon resume. This\r
+ is an optional parameter that may be NULL.\r
+ @param[in] ContextToSaveSize Size of the ContextToSave buffer.\r
+\r
+ @retval EFI_SUCCESS The framework state and context were saved.\r
+ @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.\r
+ @retval EFI_INVALID_PARAMETER ContextToSave is not NULL and\r
+ ContextToSaveSize is 0.\r
+ @retval EFI_INVALID_PARAMETER ContextToSave is >= 4GB.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to\r
+ save the framework and context state.\r
+ @retval EFI_DEVICE_ERROR The framework and context state could not be\r
+ saved to a persistent storage device due to a\r
+ device error.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SaveFrameworkState (\r
+ IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,\r
+ IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL,\r
+ IN UINTN ContextToSaveSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UNIT_TEST_SAVE_HEADER *Header;\r
+\r
+ Header = NULL;\r
+\r
+ //\r
+ // First, let's not make assumptions about the parameters.\r
+ //\r
+ if (FrameworkHandle == NULL ||\r
+ (ContextToSave != NULL && ContextToSaveSize == 0) ||\r
+ ContextToSaveSize > MAX_UINT32) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Now, let's package up all the data for saving.\r
+ //\r
+ Header = SerializeState (FrameworkHandle, ContextToSave, ContextToSaveSize);\r
+ if (Header == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // All that should be left to do is save it using the associated persistence lib.\r
+ //\r
+ Status = SaveUnitTestCache (FrameworkHandle, Header);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a - Could not save state! %r\n", __FUNCTION__, Status));\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Free data that was used.\r
+ //\r
+ FreePool (Header);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+## @file\r
+# Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications.\r
+#\r
+# Copyright (c) Microsoft Corporation.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010017\r
+ BASE_NAME = UnitTestLib\r
+ MODULE_UNI_FILE = UnitTestLib.uni\r
+ FILE_GUID = 98CEF9CA-15CE-40A3-ADE8-C299953CD0F6\r
+ VERSION_STRING = 1.0\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ LIBRARY_CLASS = UnitTestLib|PEIM DXE_DRIVER DXE_SMM_DRIVER UEFI_DRIVER UEFI_APPLICATION\r
+\r
+[Sources]\r
+ UnitTestLib.c\r
+ RunTests.c\r
+ Assert.c\r
+ Log.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ BaseMemoryLib\r
+ PcdLib\r
+ DebugLib\r
+ MemoryAllocationLib\r
+ UnitTestPersistenceLib\r
+ UnitTestResultReportLib\r
+\r
+[Pcd]\r
+ gUnitTestFrameworkPkgTokenSpaceGuid.PcdUnitTestLogLevel ## CONSUMES\r
--- /dev/null
+// /** @file\r
+// Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications.\r
+//\r
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+// SPDX-License-Identifier: BSD-2-Clause-Patent\r
+//\r
+// **/\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications."\r
--- /dev/null
+## @file\r
+# Library to support Unit Testing from host environments using Cmocka services.\r
+#\r
+# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010017\r
+ BASE_NAME = UnitTestLibCmocka\r
+ MODULE_UNI_FILE = UnitTestLibCmocka.uni\r
+ FILE_GUID = C800595F-45A3-45A1-8B50-28F01C2A5A4F\r
+ VERSION_STRING = 1.0\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ LIBRARY_CLASS = UnitTestLib|HOST_APPLICATION\r
+\r
+[Sources]\r
+ UnitTestLib.c\r
+ RunTestsCmocka.c\r
+ AssertCmocka.c\r
+ Log.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ BaseMemoryLib\r
+ PcdLib\r
+ DebugLib\r
+ MemoryAllocationLib\r
+ UnitTestPersistenceLib\r
+ UnitTestResultReportLib\r
+ CmockaLib\r
+\r
+[Pcd]\r
+ gUnitTestFrameworkPkgTokenSpaceGuid.PcdUnitTestLogLevel ## CONSUMES\r
--- /dev/null
+// /** @file\r
+// Library to support Unit Testing from host environments using Cmocka services.\r
+//\r
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+// SPDX-License-Identifier: BSD-2-Clause-Patent\r
+//\r
+// **/\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "Library to support Unit Testing from host environments using Cmocka services"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "Library to support Unit Testing from host environments using Cmocka services."\r
--- /dev/null
+/** @file\r
+ This is an instance of the Unit Test Persistence Lib that does nothing.\r
+\r
+ Copyright (c) Microsoft Corporation.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <Library/UnitTestPersistenceLib.h>\r
+\r
+/**\r
+ Determines whether a persistence cache already exists for\r
+ the given framework.\r
+\r
+ @param[in] FrameworkHandle A pointer to the framework that is being persisted.\r
+\r
+ @retval TRUE\r
+ @retval FALSE Cache doesn't exist or an error occurred.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+DoesCacheExist (\r
+ IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle\r
+ )\r
+{\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Will save the data associated with an internal Unit Test Framework\r
+ state in a manner that can persist a Unit Test Application quit or\r
+ even a system reboot.\r
+\r
+ @param[in] FrameworkHandle A pointer to the framework that is being persisted.\r
+ @param[in] SaveData A pointer to the buffer containing the serialized\r
+ framework internal state.\r
+\r
+ @retval EFI_SUCCESS Data is persisted and the test can be safely quit.\r
+ @retval Others Data is not persisted and test cannot be resumed upon exit.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SaveUnitTestCache (\r
+ IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,\r
+ IN UNIT_TEST_SAVE_HEADER *SaveData\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Will retrieve any cached state associated with the given framework.\r
+ Will allocate a buffer to hold the loaded data.\r
+\r
+ @param[in] FrameworkHandle A pointer to the framework that is being persisted.\r
+ @param[in] SaveData A pointer pointer that will be updated with the address\r
+ of the loaded data buffer.\r
+\r
+ @retval EFI_SUCCESS Data has been loaded successfully and SaveData is updated\r
+ with a pointer to the buffer.\r
+ @retval Others An error has occurred and no data has been loaded. SaveData\r
+ is set to NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LoadUnitTestCache (\r
+ IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,\r
+ OUT UNIT_TEST_SAVE_HEADER **SaveData\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
--- /dev/null
+## @file\r
+# This is an instance of the Unit Test Persistence Lib does nothing.\r
+#\r
+# Copyright (c) Microsoft Corporation.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010017\r
+ BASE_NAME = UnitTestPersistenceLibNull\r
+ MODULE_UNI_FILE = UnitTestPersistenceLibNull.uni\r
+ FILE_GUID = B8553C7A-0B0B-4BBD-9DF3-825804BF26AB\r
+ VERSION_STRING = 1.0\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ LIBRARY_CLASS = UnitTestPersistenceLib\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64\r
+#\r
+\r
+[Sources]\r
+ UnitTestPersistenceLibNull.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec\r
--- /dev/null
+// /** @file\r
+// NULL library for Unit Test Persistence Lib.\r
+//\r
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+// SPDX-License-Identifier: BSD-2-Clause-Patent\r
+//\r
+// **/\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "NULL library for Unit Test Persistence Lib"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "NULL library for Unit Test Persistence Lib."\r
--- /dev/null
+/** @file\r
+ This is an instance of the Unit Test Persistence Lib that will utilize\r
+ the filesystem that a test application is running from to save a serialized\r
+ version of the internal test state in case the test needs to quit and restore.\r
+\r
+ Copyright (c) Microsoft Corporation.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Library/UnitTestPersistenceLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/ShellLib.h>\r
+#include <Protocol/LoadedImage.h>\r
+\r
+#define CACHE_FILE_SUFFIX L"_Cache.dat"\r
+\r
+/**\r
+ Generate the device path to the cache file.\r
+\r
+ @param[in] FrameworkHandle A pointer to the framework that is being persisted.\r
+\r
+ @retval !NULL A pointer to the EFI_FILE protocol instance for the filesystem.\r
+ @retval NULL Filesystem could not be found or an error occurred.\r
+\r
+**/\r
+STATIC\r
+EFI_DEVICE_PATH_PROTOCOL*\r
+GetCacheFileDevicePath (\r
+ IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UNIT_TEST_FRAMEWORK *Framework;\r
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
+ CHAR16 *AppPath;\r
+ CHAR16 *CacheFilePath;\r
+ CHAR16 *TestName;\r
+ UINTN DirectorySlashOffset;\r
+ UINTN CacheFilePathLength;\r
+ EFI_DEVICE_PATH_PROTOCOL *CacheFileDevicePath;\r
+\r
+ Framework = (UNIT_TEST_FRAMEWORK*)FrameworkHandle;\r
+ AppPath = NULL;\r
+ CacheFilePath = NULL;\r
+ TestName = NULL;\r
+ CacheFileDevicePath = NULL;\r
+\r
+ //\r
+ // First, we need to get some information from the loaded image.\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ gImageHandle,\r
+ &gEfiLoadedImageProtocolGuid,\r
+ (VOID**)&LoadedImage\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_WARN, "%a - Failed to locate DevicePath for loaded image. %r\n", __FUNCTION__, Status));\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Before we can start, change test name from ASCII to Unicode.\r
+ //\r
+ CacheFilePathLength = AsciiStrLen (Framework->ShortTitle) + 1;\r
+ TestName = AllocatePool (CacheFilePathLength);\r
+ if (!TestName) {\r
+ goto Exit;\r
+ }\r
+ AsciiStrToUnicodeStrS (Framework->ShortTitle, TestName, CacheFilePathLength);\r
+\r
+ //\r
+ // Now we should have the device path of the root device and a file path for the rest.\r
+ // In order to target the directory for the test application, we must process\r
+ // the file path a little.\r
+ //\r
+ // NOTE: This may not be necessary... Path processing functions exist...\r
+ // PathCleanUpDirectories (FileNameCopy);\r
+ // if (PathRemoveLastItem (FileNameCopy)) {\r
+ //\r
+ AppPath = ConvertDevicePathToText (LoadedImage->FilePath, TRUE, TRUE); // NOTE: This must be freed.\r
+ DirectorySlashOffset = StrLen (AppPath);\r
+ //\r
+ // Make sure we didn't get any weird data.\r
+ //\r
+ if (DirectorySlashOffset == 0) {\r
+ DEBUG ((DEBUG_ERROR, "%a - Weird 0-length string when processing app path.\n", __FUNCTION__));\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Now that we know we have a decent string, let's take a deeper look.\r
+ //\r
+ do {\r
+ if (AppPath[DirectorySlashOffset] == L'\\') {\r
+ break;\r
+ }\r
+ DirectorySlashOffset--;\r
+ } while (DirectorySlashOffset > 0);\r
+\r
+ //\r
+ // After that little maneuver, DirectorySlashOffset should be pointing at the last '\' in AppString.\r
+ // That would be the path to the parent directory that the test app is executing from.\r
+ // Let's check and make sure that's right.\r
+ //\r
+ if (AppPath[DirectorySlashOffset] != L'\\') {\r
+ DEBUG ((DEBUG_ERROR, "%a - Could not find a single directory separator in app path.\n", __FUNCTION__));\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Now we know some things, we're ready to produce our output string, I think.\r
+ //\r
+ CacheFilePathLength = DirectorySlashOffset + 1;\r
+ CacheFilePathLength += StrLen (TestName);\r
+ CacheFilePathLength += StrLen (CACHE_FILE_SUFFIX);\r
+ CacheFilePathLength += 1; // Don't forget the NULL terminator.\r
+ CacheFilePath = AllocateZeroPool (CacheFilePathLength * sizeof (CHAR16));\r
+ if (!CacheFilePath) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Let's produce our final path string, shall we?\r
+ //\r
+ StrnCpyS (CacheFilePath, CacheFilePathLength, AppPath, DirectorySlashOffset + 1); // Copy the path for the parent directory.\r
+ StrCatS (CacheFilePath, CacheFilePathLength, TestName); // Copy the base name for the test cache.\r
+ StrCatS (CacheFilePath, CacheFilePathLength, CACHE_FILE_SUFFIX); // Copy the file suffix.\r
+\r
+ //\r
+ // Finally, try to create the device path for the thing thing.\r
+ //\r
+ CacheFileDevicePath = FileDevicePath (LoadedImage->DeviceHandle, CacheFilePath);\r
+\r
+Exit:\r
+ //\r
+ // Free allocated buffers.\r
+ //\r
+ if (AppPath != NULL) {\r
+ FreePool (AppPath);\r
+ }\r
+ if (CacheFilePath != NULL) {\r
+ FreePool (CacheFilePath);\r
+ }\r
+ if (TestName != NULL) {\r
+ FreePool (TestName);\r
+ }\r
+\r
+ return CacheFileDevicePath;\r
+}\r
+\r
+/**\r
+ Determines whether a persistence cache already exists for\r
+ the given framework.\r
+\r
+ @param[in] FrameworkHandle A pointer to the framework that is being persisted.\r
+\r
+ @retval TRUE\r
+ @retval FALSE Cache doesn't exist or an error occurred.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+DoesCacheExist (\r
+ IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;\r
+ EFI_STATUS Status;\r
+ SHELL_FILE_HANDLE FileHandle;\r
+\r
+ //\r
+ // NOTE: This devpath is allocated and must be freed.\r
+ //\r
+ FileDevicePath = GetCacheFileDevicePath (FrameworkHandle);\r
+\r
+ //\r
+ // Check to see whether the file exists. If the file can be opened for\r
+ // reading, it exists. Otherwise, probably not.\r
+ //\r
+ Status = ShellOpenFileByDevicePath (\r
+ &FileDevicePath,\r
+ &FileHandle,\r
+ EFI_FILE_MODE_READ,\r
+ 0\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ ShellCloseFile (&FileHandle);\r
+ }\r
+\r
+ if (FileDevicePath != NULL) {\r
+ FreePool (FileDevicePath);\r
+ }\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "%a - Returning %d\n", __FUNCTION__, !EFI_ERROR (Status)));\r
+\r
+ return (!EFI_ERROR (Status));\r
+}\r
+\r
+/**\r
+ Will save the data associated with an internal Unit Test Framework\r
+ state in a manner that can persist a Unit Test Application quit or\r
+ even a system reboot.\r
+\r
+ @param[in] FrameworkHandle A pointer to the framework that is being persisted.\r
+ @param[in] SaveData A pointer to the buffer containing the serialized\r
+ framework internal state.\r
+\r
+ @retval EFI_SUCCESS Data is persisted and the test can be safely quit.\r
+ @retval Others Data is not persisted and test cannot be resumed upon exit.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SaveUnitTestCache (\r
+ IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,\r
+ IN UNIT_TEST_SAVE_HEADER *SaveData\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;\r
+ EFI_STATUS Status;\r
+ SHELL_FILE_HANDLE FileHandle;\r
+ UINTN WriteCount;\r
+\r
+ //\r
+ // Check the inputs for sanity.\r
+ //\r
+ if (FrameworkHandle == NULL || SaveData == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Determine the path for the cache file.\r
+ // NOTE: This devpath is allocated and must be freed.\r
+ //\r
+ FileDevicePath = GetCacheFileDevicePath (FrameworkHandle);\r
+\r
+ //\r
+ //First lets open the file if it exists so we can delete it...This is the work around for truncation\r
+ //\r
+ Status = ShellOpenFileByDevicePath (\r
+ &FileDevicePath,\r
+ &FileHandle,\r
+ (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE),\r
+ 0\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // If file handle above was opened it will be closed by the delete.\r
+ //\r
+ Status = ShellDeleteFile (&FileHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a failed to delete file %r\n", __FUNCTION__, Status));\r
+ }\r
+ }\r
+\r
+ //\r
+ // Now that we know the path to the file... let's open it for writing.\r
+ //\r
+ Status = ShellOpenFileByDevicePath (\r
+ &FileDevicePath,\r
+ &FileHandle,\r
+ (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE),\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a - Opening file for writing failed! %r\n", __FUNCTION__, Status));\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Write the data to the file.\r
+ //\r
+ WriteCount = SaveData->SaveStateSize;\r
+ DEBUG ((DEBUG_INFO, "%a - Writing %d bytes to file...\n", __FUNCTION__, WriteCount));\r
+ Status = ShellWriteFile (\r
+ FileHandle,\r
+ &WriteCount,\r
+ SaveData\r
+ );\r
+\r
+ if (EFI_ERROR (Status) || WriteCount != SaveData->SaveStateSize) {\r
+ DEBUG ((DEBUG_ERROR, "%a - Writing to file failed! %r\n", __FUNCTION__, Status));\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, "%a - SUCCESS!\n", __FUNCTION__));\r
+ }\r
+\r
+ //\r
+ // No matter what, we should probably close the file.\r
+ //\r
+ ShellCloseFile (&FileHandle);\r
+\r
+Exit:\r
+ if (FileDevicePath != NULL) {\r
+ FreePool (FileDevicePath);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Will retrieve any cached state associated with the given framework.\r
+ Will allocate a buffer to hold the loaded data.\r
+\r
+ @param[in] FrameworkHandle A pointer to the framework that is being persisted.\r
+ @param[in] SaveData A pointer pointer that will be updated with the address\r
+ of the loaded data buffer.\r
+\r
+ @retval EFI_SUCCESS Data has been loaded successfully and SaveData is updated\r
+ with a pointer to the buffer.\r
+ @retval Others An error has occurred and no data has been loaded. SaveData\r
+ is set to NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LoadUnitTestCache (\r
+ IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,\r
+ OUT UNIT_TEST_SAVE_HEADER **SaveData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;\r
+ SHELL_FILE_HANDLE FileHandle;\r
+ BOOLEAN IsFileOpened;\r
+ UINT64 LargeFileSize;\r
+ UINTN FileSize;\r
+ UNIT_TEST_SAVE_HEADER *Buffer;\r
+\r
+ IsFileOpened = FALSE;\r
+ Buffer = NULL;\r
+\r
+ //\r
+ // Check the inputs for sanity.\r
+ //\r
+ if (FrameworkHandle == NULL || SaveData == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Determine the path for the cache file.\r
+ // NOTE: This devpath is allocated and must be freed.\r
+ //\r
+ FileDevicePath = GetCacheFileDevicePath (FrameworkHandle);\r
+\r
+ //\r
+ // Now that we know the path to the file... let's open it for writing.\r
+ //\r
+ Status = ShellOpenFileByDevicePath (\r
+ &FileDevicePath,\r
+ &FileHandle,\r
+ EFI_FILE_MODE_READ,\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a - Opening file for writing failed! %r\n", __FUNCTION__, Status));\r
+ goto Exit;\r
+ } else {\r
+ IsFileOpened = TRUE;\r
+ }\r
+\r
+ //\r
+ // Now that the file is opened, we need to determine how large a buffer we need.\r
+ //\r
+ Status = ShellGetFileSize (FileHandle, &LargeFileSize);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a - Failed to determine file size! %r\n", __FUNCTION__, Status));\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Now that we know the size, let's allocated a buffer to hold the contents.\r
+ //\r
+ FileSize = (UINTN)LargeFileSize; // You know what... if it's too large, this lib don't care.\r
+ Buffer = AllocatePool (FileSize);\r
+ if (Buffer == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "%a - Failed to allocate a pool to hold the file contents! %r\n", __FUNCTION__, Status));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Finally, let's read the data.\r
+ //\r
+ Status = ShellReadFile (FileHandle, &FileSize, Buffer);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a - Failed to read the file contents! %r\n", __FUNCTION__, Status));\r
+ }\r
+\r
+Exit:\r
+ //\r
+ // Free allocated buffers\r
+ //\r
+ if (FileDevicePath != NULL) {\r
+ FreePool (FileDevicePath);\r
+ }\r
+ if (IsFileOpened) {\r
+ ShellCloseFile (&FileHandle);\r
+ }\r
+\r
+ //\r
+ // If we're returning an error, make sure\r
+ // the state is sane.\r
+ if (EFI_ERROR (Status) && Buffer != NULL) {\r
+ FreePool (Buffer);\r
+ Buffer = NULL;\r
+ }\r
+\r
+ *SaveData = Buffer;\r
+ return Status;\r
+}\r
--- /dev/null
+## @file\r
+# UEFI Simple File System based version of the Unit Test Persistence Lib\r
+#\r
+# Instance of the Unit Test Persistence Lib that utilizes the UEFI filesystem\r
+# that a test application is running from to save a serialized version of the\r
+# internal test state in case the test needs to quit and restore.\r
+#\r
+# Copyright (c) Microsoft Corporation.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010017\r
+ BASE_NAME = UnitTestPersistenceLibSimpleFileSystem\r
+ MODULE_UNI_FILE = UnitTestPersistenceLibSimpleFileSystem.uni\r
+ FILE_GUID = 9200844A-CDFD-4368-B4BD-106354702605\r
+ VERSION_STRING = 1.0\r
+ MODULE_TYPE = UEFI_APPLICATION\r
+ LIBRARY_CLASS = UnitTestPersistenceLib\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64\r
+#\r
+\r
+[Sources]\r
+ UnitTestPersistenceLibSimpleFileSystem.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec\r
+ ShellPkg/ShellPkg.dec\r
+\r
+[LibraryClasses]\r
+ DebugLib\r
+ UefiBootServicesTableLib\r
+ BaseLib\r
+ ShellLib\r
+\r
+[Protocols]\r
+ gEfiLoadedImageProtocolGuid\r
+ gEfiSimpleFileSystemProtocolGuid\r
+\r
+[Guids]\r
+ gEfiFileInfoGuid\r
+ gEfiFileSystemInfoGuid\r
--- /dev/null
+// /** @file\r
+// UEFI Simple File System based version of the Unit Test Persistence Lib\r
+//\r
+// Instance of the Unit Test Persistence Lib that utilizes the UEFI filesystem\r
+// that a test application is running from to save a serialized version of the\r
+// internal test state in case the test needs to quit and restore.\r
+//\r
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+// SPDX-License-Identifier: BSD-2-Clause-Patent\r
+//\r
+// **/\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "UEFI Simple File System based version of the Unit Test Persistence Lib"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "UEFI Simple File System based version of the Unit Test Persistence Lib."\r
--- /dev/null
+/** @file\r
+ Implement UnitTestResultReportLib doing plain txt out to console\r
+\r
+ Copyright (c) Microsoft Corporation.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <Library/UnitTestResultReportLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+\r
+VOID\r
+ReportPrint (\r
+ IN CONST CHAR8 *Format,\r
+ ...\r
+ );\r
+\r
+VOID\r
+ReportOutput (\r
+ IN CONST CHAR8 *Output\r
+ );\r
+\r
+struct _UNIT_TEST_STATUS_STRING {\r
+ UNIT_TEST_STATUS Status;\r
+ CHAR8 *String;\r
+};\r
+\r
+struct _UNIT_TEST_FAILURE_TYPE_STRING {\r
+ FAILURE_TYPE Type;\r
+ CHAR8 *String;\r
+};\r
+\r
+struct _UNIT_TEST_STATUS_STRING mStatusStrings[] = {\r
+ { UNIT_TEST_PASSED, "PASSED"},\r
+ { UNIT_TEST_ERROR_PREREQUISITE_NOT_MET, "NOT RUN - PREREQUISITE FAILED"},\r
+ { UNIT_TEST_ERROR_TEST_FAILED, "FAILED"},\r
+ { UNIT_TEST_RUNNING, "RUNNING"},\r
+ { UNIT_TEST_PENDING, "PENDING"},\r
+ { 0, "**UNKNOWN**"}\r
+};\r
+\r
+struct _UNIT_TEST_FAILURE_TYPE_STRING mFailureTypeStrings[] = {\r
+ { FAILURETYPE_NOFAILURE, "NO FAILURE"},\r
+ { FAILURETYPE_OTHER, "OTHER FAILURE"},\r
+ { FAILURETYPE_ASSERTTRUE, "ASSERT_TRUE FAILURE"},\r
+ { FAILURETYPE_ASSERTFALSE, "ASSERT_FALSE FAILURE"},\r
+ { FAILURETYPE_ASSERTEQUAL, "ASSERT_EQUAL FAILURE"},\r
+ { FAILURETYPE_ASSERTNOTEQUAL, "ASSERT_NOTEQUAL FAILURE"},\r
+ { FAILURETYPE_ASSERTNOTEFIERROR, "ASSERT_NOTEFIERROR FAILURE"},\r
+ { FAILURETYPE_ASSERTSTATUSEQUAL, "ASSERT_STATUSEQUAL FAILURE"},\r
+ { FAILURETYPE_ASSERTNOTNULL , "ASSERT_NOTNULL FAILURE"},\r
+ { 0, "*UNKNOWN* Failure"}\r
+};\r
+\r
+//\r
+// TEST REPORTING FUNCTIONS\r
+//\r
+\r
+STATIC\r
+CONST CHAR8*\r
+GetStringForUnitTestStatus (\r
+ IN UNIT_TEST_STATUS Status\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < ARRAY_SIZE (mStatusStrings); Index++) {\r
+ if (mStatusStrings[Index].Status == Status) {\r
+ //\r
+ // Return string from matching entry\r
+ //\r
+ return mStatusStrings[Index].String;\r
+ }\r
+ }\r
+ //\r
+ // Return last entry if no match found.\r
+ //\r
+ return mStatusStrings[Index].String;\r
+}\r
+\r
+STATIC\r
+CONST CHAR8*\r
+GetStringForFailureType (\r
+ IN FAILURE_TYPE Failure\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < ARRAY_SIZE (mFailureTypeStrings); Index++) {\r
+ if (mFailureTypeStrings[Index].Type == Failure) {\r
+ //\r
+ // Return string from matching entry\r
+ //\r
+ return mFailureTypeStrings[Index].String;\r
+ }\r
+ }\r
+ //\r
+ // Return last entry if no match found.\r
+ //\r
+ DEBUG((DEBUG_INFO, "%a Failure Type does not have string defined 0x%X\n", __FUNCTION__, (UINT32)Failure));\r
+ return mFailureTypeStrings[Index].String;\r
+}\r
+\r
+/*\r
+ Method to print the Unit Test run results\r
+\r
+ @retval Success\r
+*/\r
+EFI_STATUS\r
+EFIAPI\r
+OutputUnitTestFrameworkReport (\r
+ IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle\r
+ )\r
+{\r
+ UNIT_TEST_FRAMEWORK *Framework;\r
+ INTN Passed;\r
+ INTN Failed;\r
+ INTN NotRun;\r
+ UNIT_TEST_SUITE_LIST_ENTRY *Suite;\r
+ UNIT_TEST_LIST_ENTRY *Test;\r
+ INTN SPassed;\r
+ INTN SFailed;\r
+ INTN SNotRun;\r
+\r
+ Passed = 0;\r
+ Failed = 0;\r
+ NotRun = 0;\r
+ Suite = NULL;\r
+\r
+ Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;\r
+ if (Framework == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ReportPrint ("---------------------------------------------------------\n");\r
+ ReportPrint ("------------- UNIT TEST FRAMEWORK RESULTS ---------------\n");\r
+ ReportPrint ("---------------------------------------------------------\n");\r
+\r
+ //print the version and time\r
+\r
+ //\r
+ // Iterate all suites\r
+ //\r
+ for (Suite = (UNIT_TEST_SUITE_LIST_ENTRY*)GetFirstNode(&Framework->TestSuiteList);\r
+ (LIST_ENTRY*)Suite != &Framework->TestSuiteList;\r
+ Suite = (UNIT_TEST_SUITE_LIST_ENTRY*)GetNextNode(&Framework->TestSuiteList, (LIST_ENTRY*)Suite)) {\r
+\r
+ Test = NULL;\r
+ SPassed = 0;\r
+ SFailed = 0;\r
+ SNotRun = 0;\r
+\r
+ ReportPrint ("/////////////////////////////////////////////////////////\n");\r
+ ReportPrint (" SUITE: %a\n", Suite->UTS.Title);\r
+ ReportPrint (" PACKAGE: %a\n", Suite->UTS.Name);\r
+ ReportPrint ("/////////////////////////////////////////////////////////\n");\r
+\r
+ //\r
+ // Iterate all tests within the suite\r
+ //\r
+ for (Test = (UNIT_TEST_LIST_ENTRY*)GetFirstNode(&(Suite->UTS.TestCaseList));\r
+ (LIST_ENTRY*)Test != &(Suite->UTS.TestCaseList);\r
+ Test = (UNIT_TEST_LIST_ENTRY*)GetNextNode(&(Suite->UTS.TestCaseList), (LIST_ENTRY*)Test)) {\r
+\r
+ ReportPrint ("*********************************************************\n");\r
+ ReportPrint (" CLASS NAME: %a\n", Test->UT.Name);\r
+ ReportPrint (" TEST: %a\n", Test->UT.Description);\r
+ ReportPrint (" STATUS: %a\n", GetStringForUnitTestStatus (Test->UT.Result));\r
+ ReportPrint (" FAILURE: %a\n", GetStringForFailureType (Test->UT.FailureType));\r
+ ReportPrint (" FAILURE MESSAGE:\n%a\n", Test->UT.FailureMessage);\r
+\r
+ if (Test->UT.Log != NULL) {\r
+ ReportPrint (" LOG:\n");\r
+ ReportOutput (Test->UT.Log);\r
+ }\r
+\r
+ switch (Test->UT.Result) {\r
+ case UNIT_TEST_PASSED:\r
+ SPassed++;\r
+ break;\r
+ case UNIT_TEST_ERROR_TEST_FAILED:\r
+ SFailed++;\r
+ break;\r
+ case UNIT_TEST_PENDING: // Fall through...\r
+ case UNIT_TEST_RUNNING: // Fall through...\r
+ case UNIT_TEST_ERROR_PREREQUISITE_NOT_MET:\r
+ SNotRun++;\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ ReportPrint ("**********************************************************\n");\r
+ } //End Test iteration\r
+\r
+ ReportPrint ("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");\r
+ ReportPrint ("Suite Stats\n");\r
+ ReportPrint (" Passed: %d (%d%%)\n", SPassed, (SPassed * 100)/(SPassed+SFailed+SNotRun));\r
+ ReportPrint (" Failed: %d (%d%%)\n", SFailed, (SFailed * 100) / (SPassed + SFailed + SNotRun));\r
+ ReportPrint (" Not Run: %d (%d%%)\n", SNotRun, (SNotRun * 100) / (SPassed + SFailed + SNotRun));\r
+ ReportPrint ("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n" );\r
+\r
+ Passed += SPassed; //add to global counters\r
+ Failed += SFailed; //add to global counters\r
+ NotRun += SNotRun; //add to global counters\r
+ }//End Suite iteration\r
+\r
+ ReportPrint ("=========================================================\n");\r
+ ReportPrint ("Total Stats\n");\r
+ ReportPrint (" Passed: %d (%d%%)\n", Passed, (Passed * 100) / (Passed + Failed + NotRun));\r
+ ReportPrint (" Failed: %d (%d%%)\n", Failed, (Failed * 100) / (Passed + Failed + NotRun));\r
+ ReportPrint (" Not Run: %d (%d%%)\n", NotRun, (NotRun * 100) / (Passed + Failed + NotRun));\r
+ ReportPrint ("=========================================================\n" );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+ Implement UnitTestResultReportLib doing plain txt out to console\r
+\r
+ Copyright (c) Microsoft Corporation.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DebugLib.h>\r
+\r
+VOID\r
+ReportPrint (\r
+ IN CONST CHAR8 *Format,\r
+ ...\r
+ )\r
+{\r
+ VA_LIST Marker;\r
+ CHAR16 String[256];\r
+ UINTN Length;\r
+\r
+ VA_START (Marker, Format);\r
+ Length = UnicodeVSPrintAsciiFormat (String, sizeof (String), Format, Marker);\r
+ if (Length == 0) {\r
+ DEBUG ((DEBUG_ERROR, "%a formatted string is too long\n", __FUNCTION__));\r
+ } else {\r
+ gST->ConOut->OutputString (gST->ConOut, String);\r
+ }\r
+ VA_END (Marker);\r
+}\r
+\r
+VOID\r
+ReportOutput (\r
+ IN CONST CHAR8 *Output\r
+ )\r
+{\r
+ CHAR8 AsciiString[128];\r
+ UINTN Length;\r
+ UINTN Index;\r
+\r
+ Length = AsciiStrLen (Output);\r
+ for (Index = 0; Index < Length; Index += (sizeof (AsciiString) - 1)) {\r
+ AsciiStrCpyS (AsciiString, sizeof (AsciiString), &Output[Index]);\r
+ ReportPrint ("%a", AsciiString);\r
+ }\r
+}\r
--- /dev/null
+## @file\r
+# Library to support printing out the unit test report to a UEFI console\r
+#\r
+# Copyright (c) Microsoft Corporation.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010017\r
+ BASE_NAME = UnitTestResultReportLibConOut\r
+ MODULE_UNI_FILE = UnitTestResultReportLibConOut.uni\r
+ FILE_GUID = C659641D-BA1F-4B58-946E-B1E1103903F9\r
+ VERSION_STRING = 1.0\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ LIBRARY_CLASS = UnitTestResultReportLib\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ DebugLib\r
+ UefiBootServicesTableLib\r
+ PrintLib\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec\r
+\r
+[Sources]\r
+ UnitTestResultReportLib.c\r
+ UnitTestResultReportLibConOut.c\r
--- /dev/null
+// /** @file\r
+// Library to support printing out the unit test report to a UEFI console\r
+//\r
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+// SPDX-License-Identifier: BSD-2-Clause-Patent\r
+//\r
+// **/\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "Library to support printing out the unit test report to a UEFI console"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "Library to support printing out the unit test report to a UEFI console."\r
--- /dev/null
+/** @file\r
+ Implement UnitTestResultReportLib doing plain txt out to console\r
+\r
+ Copyright (c) Microsoft Corporation.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/DebugLib.h>\r
+\r
+VOID\r
+ReportPrint (\r
+ IN CONST CHAR8 *Format,\r
+ ...\r
+ )\r
+{\r
+ VA_LIST Marker;\r
+ CHAR8 String[256];\r
+ UINTN Length;\r
+\r
+ VA_START (Marker, Format);\r
+ Length = AsciiVSPrint (String, sizeof (String), Format, Marker);\r
+ if (Length == 0) {\r
+ DEBUG ((DEBUG_ERROR, "%a formatted string is too long\n", __FUNCTION__));\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, String));\r
+ }\r
+ VA_END (Marker);\r
+}\r
+\r
+VOID\r
+ReportOutput (\r
+ IN CONST CHAR8 *Output\r
+ )\r
+{\r
+ CHAR8 AsciiString[128];\r
+ UINTN Length;\r
+ UINTN Index;\r
+\r
+ Length = AsciiStrLen (Output);\r
+ for (Index = 0; Index < Length; Index += (sizeof (AsciiString) - 1)) {\r
+ AsciiStrCpyS (AsciiString, sizeof (AsciiString), &Output[Index]);\r
+ DEBUG ((DEBUG_INFO, AsciiString));\r
+ }\r
+}\r
--- /dev/null
+## @file\r
+# Library to support printing out the unit test report using DEBUG() macros.\r
+#\r
+# Copyright (c) Microsoft Corporation.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010017\r
+ BASE_NAME = UnitTestResultReportLibDebugLib\r
+ MODULE_UNI_FILE = UnitTestResultReportLibDebugLib.uni\r
+ FILE_GUID = BED736D4-D197-475F-B7CE-0D828FF2C9A6\r
+ VERSION_STRING = 1.0\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ LIBRARY_CLASS = UnitTestResultReportLib\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ DebugLib\r
+ PrintLib\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec\r
+\r
+[Sources]\r
+ UnitTestResultReportLib.c\r
+ UnitTestResultReportLibDebugLib.c\r
--- /dev/null
+// /** @file\r
+// Library to support printing out the unit test report using DEBUG() macros.\r
+//\r
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+// SPDX-License-Identifier: BSD-2-Clause-Patent\r
+//\r
+// **/\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "Library to support printing out the unit test report using DEBUG() macros"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "Library to support printing out the unit test report using DEBUG() macros."\r