blob: f61b9d57b10ae29dbaebeac473e656ce9a44ae4d [file] [log] [blame]
/**
Implemnet UnitTestLib log services
Copyright (c) Microsoft Corporation.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <PiDxe.h>
#include <UnitTestFrameworkTypes.h>
#include <Library/UnitTestLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h>
#include <Library/PrintLib.h>
#include <Library/PcdLib.h>
#define UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH (512)
#define UNIT_TEST_MAX_LOG_BUFFER SIZE_16KB
struct _UNIT_TEST_LOG_PREFIX_STRING {
UNIT_TEST_STATUS LogLevel;
CHAR8 *String;
};
struct _UNIT_TEST_LOG_PREFIX_STRING mLogPrefixStrings[] = {
{ UNIT_TEST_LOG_LEVEL_ERROR, "[ERROR] " },
{ UNIT_TEST_LOG_LEVEL_WARN, "[WARNING] " },
{ UNIT_TEST_LOG_LEVEL_INFO, "[INFO] " },
{ UNIT_TEST_LOG_LEVEL_VERBOSE, "[VERBOSE] " }
};
//
// Unit-Test Log helper functions
//
STATIC
CONST CHAR8 *
GetStringForStatusLogPrefix (
IN UINTN LogLevel
)
{
UINTN Index;
CHAR8 *Result;
Result = NULL;
for (Index = 0; Index < ARRAY_SIZE (mLogPrefixStrings); Index++) {
if (mLogPrefixStrings[Index].LogLevel == LogLevel) {
Result = mLogPrefixStrings[Index].String;
break;
}
}
return Result;
}
STATIC
EFI_STATUS
AddStringToUnitTestLog (
IN OUT UNIT_TEST *UnitTest,
IN CONST CHAR8 *String
)
{
EFI_STATUS Status;
//
// Make sure that you're cooking with gas.
//
if ((UnitTest == NULL) || (String == NULL)) {
return EFI_INVALID_PARAMETER;
}
// If this is the first log for the test allocate log space
if (UnitTest->Log == NULL) {
UnitTestLogInit (UnitTest, NULL, 0);
}
if (UnitTest->Log == NULL) {
DEBUG ((DEBUG_ERROR, "Failed to allocate space for unit test log\n"));
ASSERT (UnitTest->Log != NULL);
return EFI_OUT_OF_RESOURCES;
}
Status = AsciiStrnCatS (
UnitTest->Log,
UNIT_TEST_MAX_LOG_BUFFER / sizeof (CHAR8),
String,
UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Failed to add unit test log string. Status = %r\n", Status));
return Status;
}
return EFI_SUCCESS;
}
/**
This function is responsible for initializing the log buffer for a single test. It can
be used internally, but may also be consumed by the test framework to add pre-existing
data to a log before it's used.
@param[in,out] TestHandle A handle to the test being initialized.
@param[in] Buffer [Optional] A pointer to pre-existing log data that should
be used to initialize the log. Should include a NULL terminator.
@param[in] BufferSize [Optional] The size of the pre-existing log data.
**/
VOID
EFIAPI
UnitTestLogInit (
IN OUT UNIT_TEST *Test,
IN UINT8 *Buffer OPTIONAL,
IN UINTN BufferSize OPTIONAL
)
{
//
// Make sure that you're cooking with gas.
//
if (Test == NULL) {
DEBUG ((DEBUG_ERROR, "%a called with invalid Test parameter\n", __func__));
return;
}
//
// If this is the first log for the test allocate log space
//
if (Test->Log == NULL) {
Test->Log = AllocateZeroPool (UNIT_TEST_MAX_LOG_BUFFER);
}
//
// check again to make sure allocate worked
//
if (Test->Log == NULL) {
DEBUG ((DEBUG_ERROR, "Failed to allocate memory for the log\n"));
return;
}
if ((Buffer != NULL) && (BufferSize > 0) && (BufferSize <= UNIT_TEST_MAX_LOG_BUFFER)) {
CopyMem (Test->Log, Buffer, BufferSize);
}
}
/**
Test logging function that records a messages in the test framework log.
Record is associated with the currently executing test case.
@param[in] ErrorLevel The error level of the unit test log message.
@param[in] Format Formatting string following the format defined in the
MdePkg/Include/Library/PrintLib.h.
@param[in] ... Print args.
**/
VOID
EFIAPI
UnitTestLog (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle;
CHAR8 NewFormatString[UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH];
CHAR8 LogString[UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH];
CONST CHAR8 *LogTypePrefix;
VA_LIST Marker;
FrameworkHandle = GetActiveFrameworkHandle ();
if (FrameworkHandle == NULL) {
DEBUG ((DEBUG_ERROR, "%a - FrameworkHandle not initialized\n", __func__));
return;
}
LogTypePrefix = NULL;
//
// Make sure that this unit test log level is enabled.
//
if ((ErrorLevel & (UINTN)PcdGet32 (PcdUnitTestLogLevel)) == 0) {
return;
}
//
// If we need to define a new format string...
// well... get to it.
//
LogTypePrefix = GetStringForStatusLogPrefix (ErrorLevel);
if (LogTypePrefix != NULL) {
AsciiSPrint (NewFormatString, sizeof (NewFormatString), "%a%a", LogTypePrefix, Format);
} else {
AsciiStrCpyS (NewFormatString, sizeof (NewFormatString), Format);
}
//
// Convert the message to an ASCII String
//
VA_START (Marker, Format);
AsciiVSPrint (LogString, sizeof (LogString), NewFormatString, Marker);
VA_END (Marker);
//
// Finally, add the string to the log.
//
AddStringToUnitTestLog (((UNIT_TEST_FRAMEWORK *)FrameworkHandle)->CurrentTest, LogString);
}