summaryrefslogtreecommitdiff
path: root/BaseTools/Plugin/DebugMacroCheck/tests
diff options
context:
space:
mode:
Diffstat (limited to 'BaseTools/Plugin/DebugMacroCheck/tests')
-rw-r--r--BaseTools/Plugin/DebugMacroCheck/tests/DebugMacroDataSet.py1348
-rw-r--r--BaseTools/Plugin/DebugMacroCheck/tests/MacroTest.py262
-rw-r--r--BaseTools/Plugin/DebugMacroCheck/tests/test_DebugMacroCheck.py402
3 files changed, 1006 insertions, 1006 deletions
diff --git a/BaseTools/Plugin/DebugMacroCheck/tests/DebugMacroDataSet.py b/BaseTools/Plugin/DebugMacroCheck/tests/DebugMacroDataSet.py
index 98629bb233..c3ce2faca8 100644
--- a/BaseTools/Plugin/DebugMacroCheck/tests/DebugMacroDataSet.py
+++ b/BaseTools/Plugin/DebugMacroCheck/tests/DebugMacroDataSet.py
@@ -1,674 +1,674 @@
-# @file DebugMacroDataSet.py
-#
-# Contains a debug macro test data set for verifying debug macros are
-# recognized and parsed properly.
-#
-# This data is automatically converted into test cases. Just add the new
-# data object here and run the tests.
-#
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-##
-
-from .MacroTest import (NoSpecifierNoArgumentMacroTest,
- EqualSpecifierEqualArgumentMacroTest,
- MoreSpecifiersThanArgumentsMacroTest,
- LessSpecifiersThanArgumentsMacroTest,
- IgnoredSpecifiersMacroTest,
- SpecialParsingMacroTest,
- CodeSnippetMacroTest)
-
-
-# Ignore flake8 linter errors for lines that are too long (E501)
-# flake8: noqa: E501
-
-# Data Set of DEBUG macros and expected results.
-# macro: A string representing a DEBUG macro.
-# result: A tuple with the following value representations.
-# [0]: Count of total formatting errors
-# [1]: Count of print specifiers found
-# [2]: Count of macro arguments found
-DEBUG_MACROS = [
- #####################################################################
- # Section: No Print Specifiers No Arguments
- #####################################################################
- NoSpecifierNoArgumentMacroTest(
- r'',
- (0, 0, 0)
- ),
- NoSpecifierNoArgumentMacroTest(
- r'DEBUG ((DEBUG_ERROR, "\\"));',
- (0, 0, 0)
- ),
- NoSpecifierNoArgumentMacroTest(
- r'DEBUG ((DEBUG_EVENT, ""));',
- (0, 0, 0)
- ),
- NoSpecifierNoArgumentMacroTest(
- r'DEBUG ((DEBUG_EVENT, "\n"));',
- (0, 0, 0)
- ),
- NoSpecifierNoArgumentMacroTest(
- r'DEBUG ((DEBUG_EVENT, "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"));',
- (0, 0, 0)
- ),
- NoSpecifierNoArgumentMacroTest(
- r'DEBUG ((DEBUG_EVENT, "GCD:Initial GCD Memory Space Map\n"));',
- (0, 0, 0)
- ),
- NoSpecifierNoArgumentMacroTest(
- r'DEBUG ((DEBUG_GCD, "GCD:Initial GCD Memory Space Map\n"));',
- (0, 0, 0)
- ),
- NoSpecifierNoArgumentMacroTest(
- r'DEBUG ((DEBUG_INFO, " Retuning TimerCnt Disabled\n"));',
- (0, 0, 0)
- ),
-
- #####################################################################
- # Section: Equal Print Specifiers to Arguments
- #####################################################################
- EqualSpecifierEqualArgumentMacroTest(
- r'DEBUG ((DEBUG_INFO, "%d", Number));',
- (0, 1, 1)
- ),
- EqualSpecifierEqualArgumentMacroTest(
- r'DEBUG ((DEBUG_BLKIO, "NorFlashBlockIoReset(MediaId=0x%x)\n", This->Media->MediaId));',
- (0, 1, 1)
- ),
- EqualSpecifierEqualArgumentMacroTest(
- r'DEBUG ((DEBUG_INFO, " Retuning TimerCnt %dseconds\n", 2 * (Capability->TimerCount - 1)));',
- (0, 1, 1)
- ),
- EqualSpecifierEqualArgumentMacroTest(
- r'DEBUG ((DEBUG_ERROR, "UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status));',
- (0, 2, 2)
- ),
- EqualSpecifierEqualArgumentMacroTest(
- r'DEBUG ((DEBUG_ERROR, "UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status));',
- (0, 2, 2)
- ),
- EqualSpecifierEqualArgumentMacroTest(
- r'DEBUG ((DEBUG_INFO, "Find GPT Partition [0x%lx", PartitionEntryBuffer[Index].StartingLBA));',
- (0, 1, 1)
- ),
- EqualSpecifierEqualArgumentMacroTest(
- r'DEBUG ((DEBUG_ERROR, "Failed to locate gEdkiiBootLogo2ProtocolGuid Status = %r. No Progress bar support. \n", Status));',
- (0, 1, 1)
- ),
- EqualSpecifierEqualArgumentMacroTest(
- r'DEBUG ((DEBUG_LOAD, " (%s)", Image->ExitData));',
- (0, 1, 1)
- ),
- EqualSpecifierEqualArgumentMacroTest(
- r'DEBUG ((DEBUG_DISPATCH, "%a%r%s%lx%p%c%g", Ascii, Status, Unicode, Hex, Pointer, Character, Guid));',
- (0, 7, 7)
- ),
- EqualSpecifierEqualArgumentMacroTest(
- r'DEBUG ((DEBUG_INFO, "LoadCapsuleOnDisk - LoadRecoveryCapsule (%d) - %r\n", CapsuleInstance, Status));',
- (0, 2, 2)
- ),
- EqualSpecifierEqualArgumentMacroTest(
- r'DEBUG ((DEBUG_DISPATCH, "%a%r%s%lx%p%c%g%a%r%s%lx%p%c%g%a%r%s%lx%p%c%g%a%r%s%lx%p%c%g", Ascii, Status, Unicode, Hex, Pointer, Character, Guid, Ascii, Status, Unicode, Hex, Pointer, Character, Guid, Ascii, Status, Unicode, Hex, Pointer, Character, Guid, Ascii, Status, Unicode, Hex, Pointer, Character, Guid));',
- (0, 28, 28)
- ),
-
- #####################################################################
- # Section: More Print Specifiers Than Arguments
- #####################################################################
- MoreSpecifiersThanArgumentsMacroTest(
- r'DEBUG ((DEBUG_BLKIO, "NorFlashBlockIoReadBlocks(MediaId=0x%x, Lba=%ld, BufferSize=0x%x bytes (%d kB), BufferPtr @ 0x%08x)\n", MediaId, Lba, BufferSizeInBytes, Buffer));',
- (1, 5, 4)
- ),
- MoreSpecifiersThanArgumentsMacroTest(
- r'DEBUG ((DEBUG_INFO, "%a: Request=%s\n", __func__));',
- (1, 2, 1)
- ),
- MoreSpecifiersThanArgumentsMacroTest(
- r'DEBUG ((DEBUG_ERROR, "%a: Invalid request format %d for %d\n", CertFormat, CertRequest));',
- (1, 3, 2)
- ),
-
- #####################################################################
- # Section: Less Print Specifiers Than Arguments
- #####################################################################
- LessSpecifiersThanArgumentsMacroTest(
- r'DEBUG ((DEBUG_INFO, "Find GPT Partition [0x%lx", PartitionEntryBuffer[Index].StartingLBA, BlockDevPtr->LastBlock));',
- (1, 1, 2)
- ),
- LessSpecifiersThanArgumentsMacroTest(
- r'DEBUG ((DEBUG_INFO, " Retuning TimerCnt Disabled\n", 2 * (Capability->TimerCount - 1)));',
- (1, 0, 1)
- ),
- LessSpecifiersThanArgumentsMacroTest(
- r'DEBUG ((DEBUG_ERROR, "Failed to locate gEdkiiBootLogo2ProtocolGuid. No Progress bar support. \n", Status));',
- (1, 0, 1)
- ),
- LessSpecifiersThanArgumentsMacroTest(
- r'DEBUG ((DEBUG_ERROR, "UsbEnumeratePort: Critical Over Current\n", Port));',
- (1, 0, 1)
- ),
- LessSpecifiersThanArgumentsMacroTest(
- r'DEBUG ((DEBUG_ERROR, "[TPM2] Submit PP Request failure! Sync PPRQ/PPRM with PP variable.\n", Status));',
- (1, 0, 1)
- ),
- LessSpecifiersThanArgumentsMacroTest(
- r'DEBUG ((DEBUG_ERROR, ": Failed to update debug log index file: %r !\n", __func__, Status));',
- (1, 1, 2)
- ),
- LessSpecifiersThanArgumentsMacroTest(
- r'DEBUG ((DEBUG_ERROR, "%a - Failed to extract nonce from policy blob with return status %r\n", __func__, gPolicyBlobFieldName[MFCI_POLICY_TARGET_NONCE], Status));',
- (1, 2, 3)
- ),
-
- #####################################################################
- # Section: Macros with Ignored Specifiers
- #####################################################################
- IgnoredSpecifiersMacroTest(
- r'DEBUG ((DEBUG_INIT, "%HEmuOpenBlock: opened %a%N\n", Private->Filename));',
- (0, 1, 1)
- ),
- IgnoredSpecifiersMacroTest(
- r'DEBUG ((DEBUG_LOAD, " (%hs)", Image->ExitData));',
- (0, 1, 1)
- ),
- IgnoredSpecifiersMacroTest(
- r'DEBUG ((DEBUG_LOAD, "%H%s%N: Unknown flag - ''%H%s%N''\r\n", String1, String2));',
- (0, 2, 2)
- ),
-
- #####################################################################
- # Section: Macros with Special Parsing Scenarios
- #####################################################################
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_INFO, " File Name: %a\n", "Document.txt"))',
- (0, 1, 1),
- "Malformatted Macro - Missing Semicolon"
- ),
- SpecialParsingMacroTest(
- r'DEBUG (DEBUG_INFO, " File Name: %a\n", "Document.txt");',
- (0, 0, 0),
- "Malformatted Macro - Missing Two Parentheses"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_INFO, "%a\n", "Removable Slot"));',
- (0, 1, 1),
- "Single String Argument in Quotes"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_INFO, " SDR50 Tuning %a\n", Capability->TuningSDR50 ? "TRUE" : "FALSE"));',
- (0, 1, 1),
- "Ternary Operator Present"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_INFO, " SDR50 Tuning %a\n", Capability->TuningSDR50 ? "TRUE" : "FALSE"));',
- (0, 1, 1),
- "Ternary Operator Present"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((DEBUG_ERROR, "\\"));
- DEBUG ((DEBUG_ERROR, "\\"));
- DEBUG ((DEBUG_ERROR, "\\"));
- DEBUG ((DEBUG_ERROR, "\\"));
- ''',
- (0, 0, 0),
- "Multiple Macros with an Escaped Character"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((
- DEBUG_INFO,
- "UsbEnumerateNewDev: device uses translator (%d, %d)\n",
- Child->Translator.TranslatorHubAddress,
- Child->Translator.TranslatorPortNumber
- ));
- ''',
- (0, 2, 2),
- "Multi-line Macro"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((
- DEBUG_INFO,
- "UsbEnumeratePort: port %d state - %02x, change - %02x on %p\n",
- Port,
- PortState.PortStatus,
- PortState.PortChangeStatus,
- HubIf
- ));
- ''',
- (0, 4, 4),
- "Multi-line Macro"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((
- DEBUG_ERROR,
- "%a:%a: failed to allocate reserved pages: "
- "BufferSize=%Lu LoadFile=\"%s\" FilePath=\"%s\"\n",
- gEfiCallerBaseName,
- __func__,
- (UINT64)BufferSize,
- LoadFileText,
- FileText
- ));
- ''',
- (0, 5, 5),
- "Multi-line Macro with Compiler String Concatenation"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((
- DEBUG_ERROR,
- "ERROR: GTDT: GT Block Frame Info Structures %d and %d have the same " \
- "frame number: 0x%x.\n",
- Index1,
- Index2,
- FrameNumber1
- ));
- ''',
- (0, 3, 3),
- "Multi-line Macro with Backslash String Concatenation"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((
- DEBUG_ERROR,
- "ERROR: PPTT: Too many private resources. Count = %d. " \
- "Maximum supported Processor Node size exceeded. " \
- "Token = %p. Status = %r\n",
- ProcInfoNode->NoOfPrivateResources,
- ProcInfoNode->ParentToken,
- Status
- ));
- ''',
- (0, 3, 3),
- "Multi-line Macro with Backslash String Concatenation"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((
- DEBUG_VERBOSE,
- "% 20a % 20a % 20a % 20a\n",
- "PhysicalStart(0x)",
- "PhysicalSize(0x)",
- "CpuStart(0x)",
- "RegionState(0x)"
- ));
- ''',
- (0, 4, 4),
- "Multi-line Macro with Quoted String Arguments"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((
- DEBUG_ERROR,
- "XenPvBlk: "
- "%a error %d on %a at sector %Lx, num bytes %Lx\n",
- Response->operation == BLKIF_OP_READ ? "read" : "write",
- Status,
- IoData->Dev->NodeName,
- (UINT64)IoData->Sector,
- (UINT64)IoData->Size
- ));
- ''',
- (0, 5, 5),
- "Multi-line Macro with Ternary Operator and Quoted String Arguments"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((
- DEBUG_ERROR,
- "%a: Label=\"%s\" OldParentNodeId=%Lu OldName=\"%a\" "
- "NewParentNodeId=%Lu NewName=\"%a\" Errno=%d\n",
- __func__,
- VirtioFs->Label,
- OldParentNodeId,
- OldName,
- NewParentNodeId,
- NewName,
- CommonResp.Error
- ));
- ''',
- (0, 7, 7),
- "Multi-line Macro with Escaped Quotes and String Concatenation"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((DEBUG_WARN, "Failed to retrieve Variable:\"MebxData\", Status = %r\n", Status));
- ''',
- (0, 1, 1),
- "Escaped Parentheses in Debug Message"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG((DEBUG_INFO, "%0d %s", XbB_ddr4[1][bankBit][xorBit], xorBit == (XaB_NUM_OF_BITS-1) ? "]": ", "));
- ''',
- (0, 2, 2),
- "Parentheses in Ternary Operator Expression"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_INFO | DEBUG_EVENT | DEBUG_WARN, " %u\n", &Structure->Block.Value));',
- (0, 1, 1),
- "Multiple Print Specifier Levels Present"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString()));',
- (0, 1, 1),
- "Function Call Argument No Params"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString(&Param1)));',
- (0, 1, 1),
- "Function Call Argument 1 Param"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString(&Param1, Param2)));',
- (0, 1, 1),
- "Function Call Argument Multiple Params"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString(&Param1, ReturnParam())));',
- (0, 1, 1),
- "Function Call Argument 2-Level Depth No 2nd-Level Param"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString(&Param1, ReturnParam(*Param))));',
- (0, 1, 1),
- "Function Call Argument 2-Level Depth 1 2nd-Level Param"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString(&Param1, ReturnParam(*Param, &ParamNext))));',
- (0, 1, 1),
- "Function Call Argument 2-Level Depth Multiple 2nd-Level Param"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString(&Param1, ReturnParam(*Param, GetParam(1, 2, 3)))));',
- (0, 1, 1),
- "Function Call Argument 3-Level Depth Multiple Params"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString(&Param1, ReturnParam(*Param, GetParam(1, 2, 3), NextParam))));',
- (0, 1, 1),
- "Function Call Argument 3-Level Depth Multiple Params with Param After Function Call"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_WARN, " %s-%a\n", ReturnString(&Param1), ReturnString2(&ParamN)));',
- (0, 2, 2),
- "Multiple Function Call Arguments"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString(&Param1), ReturnString2(&ParamN)));',
- (1, 1, 2),
- "Multiple Function Call Arguments with Imbalance"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_WARN, " %s%s\n", (ReturnString(&Param1)), (ReturnString2(&ParamN))));',
- (0, 2, 2),
- "Multiple Function Call Arguments Surrounded with Parentheses"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_WARN, " %s\n", ((((ReturnString(&Param1)))))));',
- (0, 1, 1),
- "Multiple Function Call Arguments Surrounded with Many Parentheses"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_WARN, ""%B%08X%N: %-48a %V*%a*%N"", HexNumber, ReturnString(Array[Index]), &AsciiString[0]));',
- (0, 3, 3),
- "Complex String Print Specifier 1"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_WARN, "0x%-8x:%H%s%N % -64s(%73-.73s){%g}<%H% -70s%N>\n. Size: 0x%-16x (%-,d) bytes.\n\n", HexNumber, GetUnicodeString (), &UnicodeString[4], UnicodeString2, &Guid, AnotherUnicodeString, Struct.SomeSize, CommaDecimalValue));',
- (0, 8, 8),
- "Multiple Complex Print Specifiers 1"
- ),
- SpecialParsingMacroTest(
- r'DEBUG ((DEBUG_WARN, "0x%-8x:%H%s%N % -64s(%73-.73s){%g}<%H% -70s%N%r>\n. Size: 0x%-16x (%-,d) bytes.\n\n", HexNumber, GetUnicodeString (), &UnicodeString[4], UnicodeString2, &Guid, AnotherUnicodeString, Struct.SomeSize, CommaDecimalValue));',
- (1, 9, 8),
- "Multiple Complex Print Specifiers Imbalance 1"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((
- DEBUG_ERROR,
- ("%a: Label=\"%s\" CanonicalPathname=\"%a\" FileName=\"%s\" "
- "OpenMode=0x%Lx Attributes=0x%Lx: nonsensical request to possibly "
- "create a file marked read-only, for read-write access\n"),
- __func__,
- VirtioFs->Label,
- VirtioFsFile->CanonicalPathname,
- FileName,
- OpenMode,
- Attributes
- ));
- ''',
- (0, 6, 6),
- "Multi-Line with Parentheses Around Debug String Compiler String Concat"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG (
- (DEBUG_INFO,
- " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
- (UINTN)Index,
- (UINTN)LocalBbsTable[Index].BootPriority,
- (UINTN)LocalBbsTable[Index].Bus,
- (UINTN)LocalBbsTable[Index].Device,
- (UINTN)LocalBbsTable[Index].Function,
- (UINTN)LocalBbsTable[Index].Class,
- (UINTN)LocalBbsTable[Index].SubClass,
- (UINTN)LocalBbsTable[Index].DeviceType,
- (UINTN)*(UINT16 *)&LocalBbsTable[Index].StatusFlags,
- (UINTN)LocalBbsTable[Index].BootHandlerSegment,
- (UINTN)LocalBbsTable[Index].BootHandlerOffset,
- (UINTN)((LocalBbsTable[Index].MfgStringSegment << 4) + LocalBbsTable[Index].MfgStringOffset),
- (UINTN)((LocalBbsTable[Index].DescStringSegment << 4) + LocalBbsTable[Index].DescStringOffset))
- );
- ''',
- (1, 11, 13),
- "Multi-line Macro with Many Arguments And Multi-Line Parentheses"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((
- DEBUG_WARN,
- "0x%-8x:%H%s%N % -64s(%73-.73s){%g}<%H% -70s%N>\n. Size: 0x%-16x (%-,d) bytes.\n\n",
- HexNumber,
- GetUnicodeString (InnerFunctionCall(Arg1, &Arg2)),
- &UnicodeString[4],
- UnicodeString2,
- &Guid,
- AnotherUnicodeString,
- Struct.SomeSize,
- CommaDecimalValue
- ));
- ''',
- (0, 8, 8),
- "Multi-line Macro with Multiple Complex Print Specifiers 1 and 2-Depth Function Calls"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG (
- (DEBUG_NET,
- "TcpFastRecover: enter fast retransmission for TCB %p, recover point is %d\n",
- Tcb,
- Tcb->Recover)
- );
- ''',
- (0, 2, 2),
- "Multi-line Macro with Parentheses Separated"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: APIC ID " FMT_APIC_ID " was hot-plugged "
- "before; ignoring it\n",
- __func__,
- NewApicId
- ));
- ''',
- (1, 1, 2),
- "Multi-line Imbalanced Macro with Indented String Concatenation"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: APIC ID was hot-plugged - %a",
- __func__,
- "String with , inside"
- ));
- ''',
- (0, 2, 2),
- "Multi-line with Quoted String Argument Containing Comma"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: APIC ID was hot-plugged - %a",
- __func__,
- "St,ring, with , ins,ide"
- ));
- ''',
- (0, 2, 2),
- "Multi-line with Quoted String Argument Containing Multiple Commas"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((DEBUG_VERBOSE, "%a: APIC ID was hot-plugged, \"%a\"", __func__, "S\"t,\"ring, with , ins,i\"de"));
- ''',
- (0, 2, 2),
- "Quoted String Argument with Escaped Quotes and Multiple Commas"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((
- DEBUG_ERROR,
- "%a: AddProcessor(" FMT_APIC_ID "): %r\n",
- __func__,
- Status
- ));
- ''',
- (0, 2, 2),
- "Quoted Parenthesized String Inside Debug Message String"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((
- DEBUG_INFO,
- "%a: hot-added APIC ID " FMT_APIC_ID ", SMBASE 0x%Lx, "
- "EFI_SMM_CPU_SERVICE_PROTOCOL assigned number %Lu\n",
- __func__,
- (UINT64)mCpuHotPlugData->SmBase[NewSlot],
- (UINT64)NewProcessorNumberByProtocol
- ));
- ''',
- (0, 3, 3),
- "Quoted String with Concatenation Inside Debug Message String"
- ),
- SpecialParsingMacroTest(
- r'''
- DEBUG ((DEBUG_INFO, Index == COLUMN_SIZE/2 ? "0" : " %02x", (UINTN)Data[Index]));
- ''',
- (0, 1, 1),
- "Ternary Operating in Debug Message String"
- ),
-
- #####################################################################
- # Section: Code Snippet Tests
- #####################################################################
- CodeSnippetMacroTest(
- r'''
- /**
- Print the BBS Table.
-
- @param LocalBbsTable The BBS table.
- @param BbsCount The count of entry in BBS table.
- **/
- VOID
- LegacyBmPrintBbsTable (
- IN BBS_TABLE *LocalBbsTable,
- IN UINT16 BbsCount
- )
- {
- UINT16 Index;
-
- DEBUG ((DEBUG_INFO, "\n"));
- DEBUG ((DEBUG_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
- DEBUG ((DEBUG_INFO, "=============================================\n"));
- for (Index = 0; Index < BbsCount; Index++) {
- if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
- continue;
- }
-
- DEBUG (
- (DEBUG_INFO,
- " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
- (UINTN)Index,
- (UINTN)LocalBbsTable[Index].BootPriority,
- (UINTN)LocalBbsTable[Index].Bus,
- (UINTN)LocalBbsTable[Index].Device,
- (UINTN)LocalBbsTable[Index].Function,
- (UINTN)LocalBbsTable[Index].Class,
- (UINTN)LocalBbsTable[Index].SubClass,
- (UINTN)LocalBbsTable[Index].DeviceType,
- (UINTN)*(UINT16 *)&LocalBbsTable[Index].StatusFlags,
- (UINTN)LocalBbsTable[Index].BootHandlerSegment,
- (UINTN)LocalBbsTable[Index].BootHandlerOffset,
- (UINTN)((LocalBbsTable[Index].MfgStringSegment << 4) + LocalBbsTable[Index].MfgStringOffset),
- (UINTN)((LocalBbsTable[Index].DescStringSegment << 4) + LocalBbsTable[Index].DescStringOffset))
- );
- }
-
- DEBUG ((DEBUG_INFO, "\n"));
- ''',
- (1, 0, 0),
- "Code Section with An Imbalanced Macro"
- ),
- CodeSnippetMacroTest(
- r'''
- if (*Buffer == AML_ROOT_CHAR) {
- //
- // RootChar
- //
- Buffer++;
- DEBUG ((DEBUG_ERROR, "\\"));
- } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
- //
- // ParentPrefixChar
- //
- do {
- Buffer++;
- DEBUG ((DEBUG_ERROR, "^"));
- } while (*Buffer == AML_PARENT_PREFIX_CHAR);
- }
- DEBUG ((DEBUG_WARN, "Failed to retrieve Variable:\"MebxData\", Status = %r\n", Status));
- ''',
- (0, 1, 1),
- "Code Section with Escaped Backslash and Escaped Quotes"
- ),
- CodeSnippetMacroTest(
- r'''
- if (EFI_ERROR (Status)) {
- UINTN Offset;
- UINTN Start;
-
- DEBUG ((
- DEBUG_INFO,
- "Variable FV header is not valid. It will be reinitialized.\n"
- ));
-
- //
- // Get FvbInfo to provide in FwhInstance.
- //
- Status = GetFvbInfo (Length, &GoodFwVolHeader);
- ASSERT (!EFI_ERROR (Status));
- }
- ''',
- (0, 0, 0),
- "Code Section with Multi-Line Macro with No Arguments"
- )
-]
+# @file DebugMacroDataSet.py
+#
+# Contains a debug macro test data set for verifying debug macros are
+# recognized and parsed properly.
+#
+# This data is automatically converted into test cases. Just add the new
+# data object here and run the tests.
+#
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+from .MacroTest import (NoSpecifierNoArgumentMacroTest,
+ EqualSpecifierEqualArgumentMacroTest,
+ MoreSpecifiersThanArgumentsMacroTest,
+ LessSpecifiersThanArgumentsMacroTest,
+ IgnoredSpecifiersMacroTest,
+ SpecialParsingMacroTest,
+ CodeSnippetMacroTest)
+
+
+# Ignore flake8 linter errors for lines that are too long (E501)
+# flake8: noqa: E501
+
+# Data Set of DEBUG macros and expected results.
+# macro: A string representing a DEBUG macro.
+# result: A tuple with the following value representations.
+# [0]: Count of total formatting errors
+# [1]: Count of print specifiers found
+# [2]: Count of macro arguments found
+DEBUG_MACROS = [
+ #####################################################################
+ # Section: No Print Specifiers No Arguments
+ #####################################################################
+ NoSpecifierNoArgumentMacroTest(
+ r'',
+ (0, 0, 0)
+ ),
+ NoSpecifierNoArgumentMacroTest(
+ r'DEBUG ((DEBUG_ERROR, "\\"));',
+ (0, 0, 0)
+ ),
+ NoSpecifierNoArgumentMacroTest(
+ r'DEBUG ((DEBUG_EVENT, ""));',
+ (0, 0, 0)
+ ),
+ NoSpecifierNoArgumentMacroTest(
+ r'DEBUG ((DEBUG_EVENT, "\n"));',
+ (0, 0, 0)
+ ),
+ NoSpecifierNoArgumentMacroTest(
+ r'DEBUG ((DEBUG_EVENT, "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"));',
+ (0, 0, 0)
+ ),
+ NoSpecifierNoArgumentMacroTest(
+ r'DEBUG ((DEBUG_EVENT, "GCD:Initial GCD Memory Space Map\n"));',
+ (0, 0, 0)
+ ),
+ NoSpecifierNoArgumentMacroTest(
+ r'DEBUG ((DEBUG_GCD, "GCD:Initial GCD Memory Space Map\n"));',
+ (0, 0, 0)
+ ),
+ NoSpecifierNoArgumentMacroTest(
+ r'DEBUG ((DEBUG_INFO, " Retuning TimerCnt Disabled\n"));',
+ (0, 0, 0)
+ ),
+
+ #####################################################################
+ # Section: Equal Print Specifiers to Arguments
+ #####################################################################
+ EqualSpecifierEqualArgumentMacroTest(
+ r'DEBUG ((DEBUG_INFO, "%d", Number));',
+ (0, 1, 1)
+ ),
+ EqualSpecifierEqualArgumentMacroTest(
+ r'DEBUG ((DEBUG_BLKIO, "NorFlashBlockIoReset(MediaId=0x%x)\n", This->Media->MediaId));',
+ (0, 1, 1)
+ ),
+ EqualSpecifierEqualArgumentMacroTest(
+ r'DEBUG ((DEBUG_INFO, " Retuning TimerCnt %dseconds\n", 2 * (Capability->TimerCount - 1)));',
+ (0, 1, 1)
+ ),
+ EqualSpecifierEqualArgumentMacroTest(
+ r'DEBUG ((DEBUG_ERROR, "UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status));',
+ (0, 2, 2)
+ ),
+ EqualSpecifierEqualArgumentMacroTest(
+ r'DEBUG ((DEBUG_ERROR, "UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status));',
+ (0, 2, 2)
+ ),
+ EqualSpecifierEqualArgumentMacroTest(
+ r'DEBUG ((DEBUG_INFO, "Find GPT Partition [0x%lx", PartitionEntryBuffer[Index].StartingLBA));',
+ (0, 1, 1)
+ ),
+ EqualSpecifierEqualArgumentMacroTest(
+ r'DEBUG ((DEBUG_ERROR, "Failed to locate gEdkiiBootLogo2ProtocolGuid Status = %r. No Progress bar support. \n", Status));',
+ (0, 1, 1)
+ ),
+ EqualSpecifierEqualArgumentMacroTest(
+ r'DEBUG ((DEBUG_LOAD, " (%s)", Image->ExitData));',
+ (0, 1, 1)
+ ),
+ EqualSpecifierEqualArgumentMacroTest(
+ r'DEBUG ((DEBUG_DISPATCH, "%a%r%s%lx%p%c%g", Ascii, Status, Unicode, Hex, Pointer, Character, Guid));',
+ (0, 7, 7)
+ ),
+ EqualSpecifierEqualArgumentMacroTest(
+ r'DEBUG ((DEBUG_INFO, "LoadCapsuleOnDisk - LoadRecoveryCapsule (%d) - %r\n", CapsuleInstance, Status));',
+ (0, 2, 2)
+ ),
+ EqualSpecifierEqualArgumentMacroTest(
+ r'DEBUG ((DEBUG_DISPATCH, "%a%r%s%lx%p%c%g%a%r%s%lx%p%c%g%a%r%s%lx%p%c%g%a%r%s%lx%p%c%g", Ascii, Status, Unicode, Hex, Pointer, Character, Guid, Ascii, Status, Unicode, Hex, Pointer, Character, Guid, Ascii, Status, Unicode, Hex, Pointer, Character, Guid, Ascii, Status, Unicode, Hex, Pointer, Character, Guid));',
+ (0, 28, 28)
+ ),
+
+ #####################################################################
+ # Section: More Print Specifiers Than Arguments
+ #####################################################################
+ MoreSpecifiersThanArgumentsMacroTest(
+ r'DEBUG ((DEBUG_BLKIO, "NorFlashBlockIoReadBlocks(MediaId=0x%x, Lba=%ld, BufferSize=0x%x bytes (%d kB), BufferPtr @ 0x%08x)\n", MediaId, Lba, BufferSizeInBytes, Buffer));',
+ (1, 5, 4)
+ ),
+ MoreSpecifiersThanArgumentsMacroTest(
+ r'DEBUG ((DEBUG_INFO, "%a: Request=%s\n", __func__));',
+ (1, 2, 1)
+ ),
+ MoreSpecifiersThanArgumentsMacroTest(
+ r'DEBUG ((DEBUG_ERROR, "%a: Invalid request format %d for %d\n", CertFormat, CertRequest));',
+ (1, 3, 2)
+ ),
+
+ #####################################################################
+ # Section: Less Print Specifiers Than Arguments
+ #####################################################################
+ LessSpecifiersThanArgumentsMacroTest(
+ r'DEBUG ((DEBUG_INFO, "Find GPT Partition [0x%lx", PartitionEntryBuffer[Index].StartingLBA, BlockDevPtr->LastBlock));',
+ (1, 1, 2)
+ ),
+ LessSpecifiersThanArgumentsMacroTest(
+ r'DEBUG ((DEBUG_INFO, " Retuning TimerCnt Disabled\n", 2 * (Capability->TimerCount - 1)));',
+ (1, 0, 1)
+ ),
+ LessSpecifiersThanArgumentsMacroTest(
+ r'DEBUG ((DEBUG_ERROR, "Failed to locate gEdkiiBootLogo2ProtocolGuid. No Progress bar support. \n", Status));',
+ (1, 0, 1)
+ ),
+ LessSpecifiersThanArgumentsMacroTest(
+ r'DEBUG ((DEBUG_ERROR, "UsbEnumeratePort: Critical Over Current\n", Port));',
+ (1, 0, 1)
+ ),
+ LessSpecifiersThanArgumentsMacroTest(
+ r'DEBUG ((DEBUG_ERROR, "[TPM2] Submit PP Request failure! Sync PPRQ/PPRM with PP variable.\n", Status));',
+ (1, 0, 1)
+ ),
+ LessSpecifiersThanArgumentsMacroTest(
+ r'DEBUG ((DEBUG_ERROR, ": Failed to update debug log index file: %r !\n", __func__, Status));',
+ (1, 1, 2)
+ ),
+ LessSpecifiersThanArgumentsMacroTest(
+ r'DEBUG ((DEBUG_ERROR, "%a - Failed to extract nonce from policy blob with return status %r\n", __func__, gPolicyBlobFieldName[MFCI_POLICY_TARGET_NONCE], Status));',
+ (1, 2, 3)
+ ),
+
+ #####################################################################
+ # Section: Macros with Ignored Specifiers
+ #####################################################################
+ IgnoredSpecifiersMacroTest(
+ r'DEBUG ((DEBUG_INIT, "%HEmuOpenBlock: opened %a%N\n", Private->Filename));',
+ (0, 1, 1)
+ ),
+ IgnoredSpecifiersMacroTest(
+ r'DEBUG ((DEBUG_LOAD, " (%hs)", Image->ExitData));',
+ (0, 1, 1)
+ ),
+ IgnoredSpecifiersMacroTest(
+ r'DEBUG ((DEBUG_LOAD, "%H%s%N: Unknown flag - ''%H%s%N''\r\n", String1, String2));',
+ (0, 2, 2)
+ ),
+
+ #####################################################################
+ # Section: Macros with Special Parsing Scenarios
+ #####################################################################
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_INFO, " File Name: %a\n", "Document.txt"))',
+ (0, 1, 1),
+ "Malformatted Macro - Missing Semicolon"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG (DEBUG_INFO, " File Name: %a\n", "Document.txt");',
+ (0, 0, 0),
+ "Malformatted Macro - Missing Two Parentheses"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_INFO, "%a\n", "Removable Slot"));',
+ (0, 1, 1),
+ "Single String Argument in Quotes"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_INFO, " SDR50 Tuning %a\n", Capability->TuningSDR50 ? "TRUE" : "FALSE"));',
+ (0, 1, 1),
+ "Ternary Operator Present"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_INFO, " SDR50 Tuning %a\n", Capability->TuningSDR50 ? "TRUE" : "FALSE"));',
+ (0, 1, 1),
+ "Ternary Operator Present"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((DEBUG_ERROR, "\\"));
+ DEBUG ((DEBUG_ERROR, "\\"));
+ DEBUG ((DEBUG_ERROR, "\\"));
+ DEBUG ((DEBUG_ERROR, "\\"));
+ ''',
+ (0, 0, 0),
+ "Multiple Macros with an Escaped Character"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((
+ DEBUG_INFO,
+ "UsbEnumerateNewDev: device uses translator (%d, %d)\n",
+ Child->Translator.TranslatorHubAddress,
+ Child->Translator.TranslatorPortNumber
+ ));
+ ''',
+ (0, 2, 2),
+ "Multi-line Macro"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((
+ DEBUG_INFO,
+ "UsbEnumeratePort: port %d state - %02x, change - %02x on %p\n",
+ Port,
+ PortState.PortStatus,
+ PortState.PortChangeStatus,
+ HubIf
+ ));
+ ''',
+ (0, 4, 4),
+ "Multi-line Macro"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a:%a: failed to allocate reserved pages: "
+ "BufferSize=%Lu LoadFile=\"%s\" FilePath=\"%s\"\n",
+ gEfiCallerBaseName,
+ __func__,
+ (UINT64)BufferSize,
+ LoadFileText,
+ FileText
+ ));
+ ''',
+ (0, 5, 5),
+ "Multi-line Macro with Compiler String Concatenation"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: GT Block Frame Info Structures %d and %d have the same " \
+ "frame number: 0x%x.\n",
+ Index1,
+ Index2,
+ FrameNumber1
+ ));
+ ''',
+ (0, 3, 3),
+ "Multi-line Macro with Backslash String Concatenation"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Too many private resources. Count = %d. " \
+ "Maximum supported Processor Node size exceeded. " \
+ "Token = %p. Status = %r\n",
+ ProcInfoNode->NoOfPrivateResources,
+ ProcInfoNode->ParentToken,
+ Status
+ ));
+ ''',
+ (0, 3, 3),
+ "Multi-line Macro with Backslash String Concatenation"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "% 20a % 20a % 20a % 20a\n",
+ "PhysicalStart(0x)",
+ "PhysicalSize(0x)",
+ "CpuStart(0x)",
+ "RegionState(0x)"
+ ));
+ ''',
+ (0, 4, 4),
+ "Multi-line Macro with Quoted String Arguments"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((
+ DEBUG_ERROR,
+ "XenPvBlk: "
+ "%a error %d on %a at sector %Lx, num bytes %Lx\n",
+ Response->operation == BLKIF_OP_READ ? "read" : "write",
+ Status,
+ IoData->Dev->NodeName,
+ (UINT64)IoData->Sector,
+ (UINT64)IoData->Size
+ ));
+ ''',
+ (0, 5, 5),
+ "Multi-line Macro with Ternary Operator and Quoted String Arguments"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Label=\"%s\" OldParentNodeId=%Lu OldName=\"%a\" "
+ "NewParentNodeId=%Lu NewName=\"%a\" Errno=%d\n",
+ __func__,
+ VirtioFs->Label,
+ OldParentNodeId,
+ OldName,
+ NewParentNodeId,
+ NewName,
+ CommonResp.Error
+ ));
+ ''',
+ (0, 7, 7),
+ "Multi-line Macro with Escaped Quotes and String Concatenation"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((DEBUG_WARN, "Failed to retrieve Variable:\"MebxData\", Status = %r\n", Status));
+ ''',
+ (0, 1, 1),
+ "Escaped Parentheses in Debug Message"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG((DEBUG_INFO, "%0d %s", XbB_ddr4[1][bankBit][xorBit], xorBit == (XaB_NUM_OF_BITS-1) ? "]": ", "));
+ ''',
+ (0, 2, 2),
+ "Parentheses in Ternary Operator Expression"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_INFO | DEBUG_EVENT | DEBUG_WARN, " %u\n", &Structure->Block.Value));',
+ (0, 1, 1),
+ "Multiple Print Specifier Levels Present"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString()));',
+ (0, 1, 1),
+ "Function Call Argument No Params"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString(&Param1)));',
+ (0, 1, 1),
+ "Function Call Argument 1 Param"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString(&Param1, Param2)));',
+ (0, 1, 1),
+ "Function Call Argument Multiple Params"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString(&Param1, ReturnParam())));',
+ (0, 1, 1),
+ "Function Call Argument 2-Level Depth No 2nd-Level Param"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString(&Param1, ReturnParam(*Param))));',
+ (0, 1, 1),
+ "Function Call Argument 2-Level Depth 1 2nd-Level Param"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString(&Param1, ReturnParam(*Param, &ParamNext))));',
+ (0, 1, 1),
+ "Function Call Argument 2-Level Depth Multiple 2nd-Level Param"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString(&Param1, ReturnParam(*Param, GetParam(1, 2, 3)))));',
+ (0, 1, 1),
+ "Function Call Argument 3-Level Depth Multiple Params"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString(&Param1, ReturnParam(*Param, GetParam(1, 2, 3), NextParam))));',
+ (0, 1, 1),
+ "Function Call Argument 3-Level Depth Multiple Params with Param After Function Call"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_WARN, " %s-%a\n", ReturnString(&Param1), ReturnString2(&ParamN)));',
+ (0, 2, 2),
+ "Multiple Function Call Arguments"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_WARN, " %s\n", ReturnString(&Param1), ReturnString2(&ParamN)));',
+ (1, 1, 2),
+ "Multiple Function Call Arguments with Imbalance"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_WARN, " %s%s\n", (ReturnString(&Param1)), (ReturnString2(&ParamN))));',
+ (0, 2, 2),
+ "Multiple Function Call Arguments Surrounded with Parentheses"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_WARN, " %s\n", ((((ReturnString(&Param1)))))));',
+ (0, 1, 1),
+ "Multiple Function Call Arguments Surrounded with Many Parentheses"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_WARN, ""%B%08X%N: %-48a %V*%a*%N"", HexNumber, ReturnString(Array[Index]), &AsciiString[0]));',
+ (0, 3, 3),
+ "Complex String Print Specifier 1"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_WARN, "0x%-8x:%H%s%N % -64s(%73-.73s){%g}<%H% -70s%N>\n. Size: 0x%-16x (%-,d) bytes.\n\n", HexNumber, GetUnicodeString (), &UnicodeString[4], UnicodeString2, &Guid, AnotherUnicodeString, Struct.SomeSize, CommaDecimalValue));',
+ (0, 8, 8),
+ "Multiple Complex Print Specifiers 1"
+ ),
+ SpecialParsingMacroTest(
+ r'DEBUG ((DEBUG_WARN, "0x%-8x:%H%s%N % -64s(%73-.73s){%g}<%H% -70s%N%r>\n. Size: 0x%-16x (%-,d) bytes.\n\n", HexNumber, GetUnicodeString (), &UnicodeString[4], UnicodeString2, &Guid, AnotherUnicodeString, Struct.SomeSize, CommaDecimalValue));',
+ (1, 9, 8),
+ "Multiple Complex Print Specifiers Imbalance 1"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((
+ DEBUG_ERROR,
+ ("%a: Label=\"%s\" CanonicalPathname=\"%a\" FileName=\"%s\" "
+ "OpenMode=0x%Lx Attributes=0x%Lx: nonsensical request to possibly "
+ "create a file marked read-only, for read-write access\n"),
+ __func__,
+ VirtioFs->Label,
+ VirtioFsFile->CanonicalPathname,
+ FileName,
+ OpenMode,
+ Attributes
+ ));
+ ''',
+ (0, 6, 6),
+ "Multi-Line with Parentheses Around Debug String Compiler String Concat"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG (
+ (DEBUG_INFO,
+ " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
+ (UINTN)Index,
+ (UINTN)LocalBbsTable[Index].BootPriority,
+ (UINTN)LocalBbsTable[Index].Bus,
+ (UINTN)LocalBbsTable[Index].Device,
+ (UINTN)LocalBbsTable[Index].Function,
+ (UINTN)LocalBbsTable[Index].Class,
+ (UINTN)LocalBbsTable[Index].SubClass,
+ (UINTN)LocalBbsTable[Index].DeviceType,
+ (UINTN)*(UINT16 *)&LocalBbsTable[Index].StatusFlags,
+ (UINTN)LocalBbsTable[Index].BootHandlerSegment,
+ (UINTN)LocalBbsTable[Index].BootHandlerOffset,
+ (UINTN)((LocalBbsTable[Index].MfgStringSegment << 4) + LocalBbsTable[Index].MfgStringOffset),
+ (UINTN)((LocalBbsTable[Index].DescStringSegment << 4) + LocalBbsTable[Index].DescStringOffset))
+ );
+ ''',
+ (1, 11, 13),
+ "Multi-line Macro with Many Arguments And Multi-Line Parentheses"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((
+ DEBUG_WARN,
+ "0x%-8x:%H%s%N % -64s(%73-.73s){%g}<%H% -70s%N>\n. Size: 0x%-16x (%-,d) bytes.\n\n",
+ HexNumber,
+ GetUnicodeString (InnerFunctionCall(Arg1, &Arg2)),
+ &UnicodeString[4],
+ UnicodeString2,
+ &Guid,
+ AnotherUnicodeString,
+ Struct.SomeSize,
+ CommaDecimalValue
+ ));
+ ''',
+ (0, 8, 8),
+ "Multi-line Macro with Multiple Complex Print Specifiers 1 and 2-Depth Function Calls"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG (
+ (DEBUG_NET,
+ "TcpFastRecover: enter fast retransmission for TCB %p, recover point is %d\n",
+ Tcb,
+ Tcb->Recover)
+ );
+ ''',
+ (0, 2, 2),
+ "Multi-line Macro with Parentheses Separated"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: APIC ID " FMT_APIC_ID " was hot-plugged "
+ "before; ignoring it\n",
+ __func__,
+ NewApicId
+ ));
+ ''',
+ (1, 1, 2),
+ "Multi-line Imbalanced Macro with Indented String Concatenation"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: APIC ID was hot-plugged - %a",
+ __func__,
+ "String with , inside"
+ ));
+ ''',
+ (0, 2, 2),
+ "Multi-line with Quoted String Argument Containing Comma"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: APIC ID was hot-plugged - %a",
+ __func__,
+ "St,ring, with , ins,ide"
+ ));
+ ''',
+ (0, 2, 2),
+ "Multi-line with Quoted String Argument Containing Multiple Commas"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((DEBUG_VERBOSE, "%a: APIC ID was hot-plugged, \"%a\"", __func__, "S\"t,\"ring, with , ins,i\"de"));
+ ''',
+ (0, 2, 2),
+ "Quoted String Argument with Escaped Quotes and Multiple Commas"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: AddProcessor(" FMT_APIC_ID "): %r\n",
+ __func__,
+ Status
+ ));
+ ''',
+ (0, 2, 2),
+ "Quoted Parenthesized String Inside Debug Message String"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: hot-added APIC ID " FMT_APIC_ID ", SMBASE 0x%Lx, "
+ "EFI_SMM_CPU_SERVICE_PROTOCOL assigned number %Lu\n",
+ __func__,
+ (UINT64)mCpuHotPlugData->SmBase[NewSlot],
+ (UINT64)NewProcessorNumberByProtocol
+ ));
+ ''',
+ (0, 3, 3),
+ "Quoted String with Concatenation Inside Debug Message String"
+ ),
+ SpecialParsingMacroTest(
+ r'''
+ DEBUG ((DEBUG_INFO, Index == COLUMN_SIZE/2 ? "0" : " %02x", (UINTN)Data[Index]));
+ ''',
+ (0, 1, 1),
+ "Ternary Operating in Debug Message String"
+ ),
+
+ #####################################################################
+ # Section: Code Snippet Tests
+ #####################################################################
+ CodeSnippetMacroTest(
+ r'''
+ /**
+ Print the BBS Table.
+
+ @param LocalBbsTable The BBS table.
+ @param BbsCount The count of entry in BBS table.
+ **/
+ VOID
+ LegacyBmPrintBbsTable (
+ IN BBS_TABLE *LocalBbsTable,
+ IN UINT16 BbsCount
+ )
+ {
+ UINT16 Index;
+
+ DEBUG ((DEBUG_INFO, "\n"));
+ DEBUG ((DEBUG_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
+ DEBUG ((DEBUG_INFO, "=============================================\n"));
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
+ continue;
+ }
+
+ DEBUG (
+ (DEBUG_INFO,
+ " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
+ (UINTN)Index,
+ (UINTN)LocalBbsTable[Index].BootPriority,
+ (UINTN)LocalBbsTable[Index].Bus,
+ (UINTN)LocalBbsTable[Index].Device,
+ (UINTN)LocalBbsTable[Index].Function,
+ (UINTN)LocalBbsTable[Index].Class,
+ (UINTN)LocalBbsTable[Index].SubClass,
+ (UINTN)LocalBbsTable[Index].DeviceType,
+ (UINTN)*(UINT16 *)&LocalBbsTable[Index].StatusFlags,
+ (UINTN)LocalBbsTable[Index].BootHandlerSegment,
+ (UINTN)LocalBbsTable[Index].BootHandlerOffset,
+ (UINTN)((LocalBbsTable[Index].MfgStringSegment << 4) + LocalBbsTable[Index].MfgStringOffset),
+ (UINTN)((LocalBbsTable[Index].DescStringSegment << 4) + LocalBbsTable[Index].DescStringOffset))
+ );
+ }
+
+ DEBUG ((DEBUG_INFO, "\n"));
+ ''',
+ (1, 0, 0),
+ "Code Section with An Imbalanced Macro"
+ ),
+ CodeSnippetMacroTest(
+ r'''
+ if (*Buffer == AML_ROOT_CHAR) {
+ //
+ // RootChar
+ //
+ Buffer++;
+ DEBUG ((DEBUG_ERROR, "\\"));
+ } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
+ //
+ // ParentPrefixChar
+ //
+ do {
+ Buffer++;
+ DEBUG ((DEBUG_ERROR, "^"));
+ } while (*Buffer == AML_PARENT_PREFIX_CHAR);
+ }
+ DEBUG ((DEBUG_WARN, "Failed to retrieve Variable:\"MebxData\", Status = %r\n", Status));
+ ''',
+ (0, 1, 1),
+ "Code Section with Escaped Backslash and Escaped Quotes"
+ ),
+ CodeSnippetMacroTest(
+ r'''
+ if (EFI_ERROR (Status)) {
+ UINTN Offset;
+ UINTN Start;
+
+ DEBUG ((
+ DEBUG_INFO,
+ "Variable FV header is not valid. It will be reinitialized.\n"
+ ));
+
+ //
+ // Get FvbInfo to provide in FwhInstance.
+ //
+ Status = GetFvbInfo (Length, &GoodFwVolHeader);
+ ASSERT (!EFI_ERROR (Status));
+ }
+ ''',
+ (0, 0, 0),
+ "Code Section with Multi-Line Macro with No Arguments"
+ )
+]
diff --git a/BaseTools/Plugin/DebugMacroCheck/tests/MacroTest.py b/BaseTools/Plugin/DebugMacroCheck/tests/MacroTest.py
index 3b966d31ff..4b54a4da18 100644
--- a/BaseTools/Plugin/DebugMacroCheck/tests/MacroTest.py
+++ b/BaseTools/Plugin/DebugMacroCheck/tests/MacroTest.py
@@ -1,131 +1,131 @@
-# @file MacroTest.py
-#
-# Contains the data classes that are used to compose debug macro tests.
-#
-# All data classes inherit from a single abstract base class that expects
-# the subclass to define the category of test it represents.
-#
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-##
-
-from dataclasses import dataclass, field
-from os import linesep
-from typing import Tuple
-
-import abc
-
-
-@dataclass(frozen=True)
-class MacroTest(abc.ABC):
- """Abstract base class for an individual macro test case."""
-
- macro: str
- result: Tuple[int, int, int]
- description: str = field(default='')
-
- @property
- @abc.abstractmethod
- def category(self) -> str:
- """Returns the test class category identifier.
-
- Example: 'equal_specifier_equal_argument_macro_test'
-
- This string is used to bind test objects against this class.
-
- Returns:
- str: Test category identifier string.
- """
- pass
-
- @property
- def category_description(self) -> str:
- """Returns the test class category description.
-
- Example: 'Test case with equal count of print specifiers to arguments.'
-
- This string is a human readable description of the test category.
-
- Returns:
- str: String describing the test category.
- """
- return self.__doc__
-
- def __str__(self):
- """Returns a macro test case description string."""
-
- s = [
- f"{linesep}",
- "=" * 80,
- f"Macro Test Type: {self.category_description}",
- f"{linesep}Macro: {self.macro}",
- f"{linesep}Expected Result: {self.result}"
- ]
-
- if self.description:
- s.insert(3, f"Test Description: {self.description}")
-
- return f'{linesep}'.join(s)
-
-
-@dataclass(frozen=True)
-class NoSpecifierNoArgumentMacroTest(MacroTest):
- """Test case with no print specifier and no arguments."""
-
- @property
- def category(self) -> str:
- return "no_specifier_no_argument_macro_test"
-
-
-@dataclass(frozen=True)
-class EqualSpecifierEqualArgumentMacroTest(MacroTest):
- """Test case with equal count of print specifiers to arguments."""
-
- @property
- def category(self) -> str:
- return "equal_specifier_equal_argument_macro_test"
-
-
-@dataclass(frozen=True)
-class MoreSpecifiersThanArgumentsMacroTest(MacroTest):
- """Test case with more print specifiers than arguments."""
-
- @property
- def category(self) -> str:
- return "more_specifiers_than_arguments_macro_test"
-
-
-@dataclass(frozen=True)
-class LessSpecifiersThanArgumentsMacroTest(MacroTest):
- """Test case with less print specifiers than arguments."""
-
- @property
- def category(self) -> str:
- return "less_specifiers_than_arguments_macro_test"
-
-
-@dataclass(frozen=True)
-class IgnoredSpecifiersMacroTest(MacroTest):
- """Test case to test ignored print specifiers."""
-
- @property
- def category(self) -> str:
- return "ignored_specifiers_macro_test"
-
-
-@dataclass(frozen=True)
-class SpecialParsingMacroTest(MacroTest):
- """Test case with special (complicated) parsing scenarios."""
-
- @property
- def category(self) -> str:
- return "special_parsing_macro_test"
-
-
-@dataclass(frozen=True)
-class CodeSnippetMacroTest(MacroTest):
- """Test case within a larger code snippet."""
-
- @property
- def category(self) -> str:
- return "code_snippet_macro_test"
+# @file MacroTest.py
+#
+# Contains the data classes that are used to compose debug macro tests.
+#
+# All data classes inherit from a single abstract base class that expects
+# the subclass to define the category of test it represents.
+#
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+from dataclasses import dataclass, field
+from os import linesep
+from typing import Tuple
+
+import abc
+
+
+@dataclass(frozen=True)
+class MacroTest(abc.ABC):
+ """Abstract base class for an individual macro test case."""
+
+ macro: str
+ result: Tuple[int, int, int]
+ description: str = field(default='')
+
+ @property
+ @abc.abstractmethod
+ def category(self) -> str:
+ """Returns the test class category identifier.
+
+ Example: 'equal_specifier_equal_argument_macro_test'
+
+ This string is used to bind test objects against this class.
+
+ Returns:
+ str: Test category identifier string.
+ """
+ pass
+
+ @property
+ def category_description(self) -> str:
+ """Returns the test class category description.
+
+ Example: 'Test case with equal count of print specifiers to arguments.'
+
+ This string is a human readable description of the test category.
+
+ Returns:
+ str: String describing the test category.
+ """
+ return self.__doc__
+
+ def __str__(self):
+ """Returns a macro test case description string."""
+
+ s = [
+ f"{linesep}",
+ "=" * 80,
+ f"Macro Test Type: {self.category_description}",
+ f"{linesep}Macro: {self.macro}",
+ f"{linesep}Expected Result: {self.result}"
+ ]
+
+ if self.description:
+ s.insert(3, f"Test Description: {self.description}")
+
+ return f'{linesep}'.join(s)
+
+
+@dataclass(frozen=True)
+class NoSpecifierNoArgumentMacroTest(MacroTest):
+ """Test case with no print specifier and no arguments."""
+
+ @property
+ def category(self) -> str:
+ return "no_specifier_no_argument_macro_test"
+
+
+@dataclass(frozen=True)
+class EqualSpecifierEqualArgumentMacroTest(MacroTest):
+ """Test case with equal count of print specifiers to arguments."""
+
+ @property
+ def category(self) -> str:
+ return "equal_specifier_equal_argument_macro_test"
+
+
+@dataclass(frozen=True)
+class MoreSpecifiersThanArgumentsMacroTest(MacroTest):
+ """Test case with more print specifiers than arguments."""
+
+ @property
+ def category(self) -> str:
+ return "more_specifiers_than_arguments_macro_test"
+
+
+@dataclass(frozen=True)
+class LessSpecifiersThanArgumentsMacroTest(MacroTest):
+ """Test case with less print specifiers than arguments."""
+
+ @property
+ def category(self) -> str:
+ return "less_specifiers_than_arguments_macro_test"
+
+
+@dataclass(frozen=True)
+class IgnoredSpecifiersMacroTest(MacroTest):
+ """Test case to test ignored print specifiers."""
+
+ @property
+ def category(self) -> str:
+ return "ignored_specifiers_macro_test"
+
+
+@dataclass(frozen=True)
+class SpecialParsingMacroTest(MacroTest):
+ """Test case with special (complicated) parsing scenarios."""
+
+ @property
+ def category(self) -> str:
+ return "special_parsing_macro_test"
+
+
+@dataclass(frozen=True)
+class CodeSnippetMacroTest(MacroTest):
+ """Test case within a larger code snippet."""
+
+ @property
+ def category(self) -> str:
+ return "code_snippet_macro_test"
diff --git a/BaseTools/Plugin/DebugMacroCheck/tests/test_DebugMacroCheck.py b/BaseTools/Plugin/DebugMacroCheck/tests/test_DebugMacroCheck.py
index 7abc0d2b87..5e85c1da46 100644
--- a/BaseTools/Plugin/DebugMacroCheck/tests/test_DebugMacroCheck.py
+++ b/BaseTools/Plugin/DebugMacroCheck/tests/test_DebugMacroCheck.py
@@ -1,201 +1,201 @@
-# @file test_DebugMacroCheck.py
-#
-# Contains unit tests for the DebugMacroCheck build plugin.
-#
-# An example of running these tests from the root of the workspace:
-# python -m unittest discover -s ./BaseTools/Plugin/DebugMacroCheck/tests -v
-#
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-##
-
-import inspect
-import pathlib
-import sys
-import unittest
-
-# Import the build plugin
-test_file = pathlib.Path(__file__)
-sys.path.append(str(test_file.parent.parent))
-
-# flake8 (E402): Ignore flake8 module level import not at top of file
-import DebugMacroCheck # noqa: E402
-
-from os import linesep # noqa: E402
-from tests import DebugMacroDataSet # noqa: E402
-from tests import MacroTest # noqa: E402
-from typing import Callable, Tuple # noqa: E402
-
-
-#
-# This metaclass is provided to dynamically produce test case container
-# classes. The main purpose of this approach is to:
-# 1. Allow categories of test cases to be defined (test container classes)
-# 2. Allow test cases to automatically (dynamically) be assigned to their
-# corresponding test container class when new test data is defined.
-#
-# The idea being that infrastructure and test data are separated. Adding
-# / removing / modifying test data does not require an infrastructure
-# change (unless new categories are defined).
-# 3. To work with the unittest discovery algorithm and VS Code Test Explorer.
-#
-# Notes:
-# - (1) can roughly be achieved with unittest test suites. In another
-# implementation approach, this solution was tested with relatively minor
-# modifications to use test suites. However, this became a bit overly
-# complicated with the dynamic test case method generation and did not
-# work as well with VS Code Test Explorer.
-# - For (2) and (3), particularly for VS Code Test Explorer to work, the
-# dynamic population of the container class namespace needed to happen prior
-# to class object creation. That is why the metaclass assigns test methods
-# to the new classes based upon the test category specified in the
-# corresponding data class.
-# - This could have been simplified a bit by either using one test case
-# container class and/or testing data in a single, monolithic test function
-# that iterates over the data set. However, the dynamic hierarchy greatly
-# helps organize test results and reporting. The infrastructure though
-# inheriting some complexity to support it, should not need to change (much)
-# as the data set expands.
-# - Test case categories (container classes) are derived from the overall
-# type of macro conditions under test.
-#
-# - This implementation assumes unittest will discover test cases
-# (classes derived from unittest.TestCase) with the name pattern "Test_*"
-# and test functions with the name pattern "test_x". Individual tests are
-# dynamically numbered monotonically within a category.
-# - The final test case description is also able to return fairly clean
-# context information.
-#
-class Meta_TestDebugMacroCheck(type):
- """
- Metaclass for debug macro test case class factory.
- """
- @classmethod
- def __prepare__(mcls, name, bases, **kwargs):
- """Returns the test case namespace for this class."""
- candidate_macros, cls_ns, cnt = [], {}, 0
-
- if "category" in kwargs.keys():
- candidate_macros = [m for m in DebugMacroDataSet.DEBUG_MACROS if
- m.category == kwargs["category"]]
- else:
- candidate_macros = DebugMacroDataSet.DEBUG_MACROS
-
- for cnt, macro_test in enumerate(candidate_macros):
- f_name = f'test_{macro_test.category}_{cnt}'
- t_desc = f'{macro_test!s}'
- cls_ns[f_name] = mcls.build_macro_test(macro_test, t_desc)
- return cls_ns
-
- def __new__(mcls, name, bases, ns, **kwargs):
- """Defined to prevent variable args from bubbling to the base class."""
- return super().__new__(mcls, name, bases, ns)
-
- def __init__(mcls, name, bases, ns, **kwargs):
- """Defined to prevent variable args from bubbling to the base class."""
- return super().__init__(name, bases, ns)
-
- @classmethod
- def build_macro_test(cls, macro_test: MacroTest.MacroTest,
- test_desc: str) -> Callable[[None], None]:
- """Returns a test function for this macro test data."
-
- Args:
- macro_test (MacroTest.MacroTest): The macro test class.
-
- test_desc (str): A test description string.
-
- Returns:
- Callable[[None], None]: A test case function.
- """
- def test_func(self):
- act_result = cls.check_regex(macro_test.macro)
- self.assertCountEqual(
- act_result,
- macro_test.result,
- test_desc + f'{linesep}'.join(
- ["", f"Actual Result: {act_result}", "=" * 80, ""]))
-
- return test_func
-
- @classmethod
- def check_regex(cls, source_str: str) -> Tuple[int, int, int]:
- """Returns the plugin result for the given macro string.
-
- Args:
- source_str (str): A string containing debug macros.
-
- Returns:
- Tuple[int, int, int]: A tuple of the number of formatting errors,
- number of print specifiers, and number of arguments for the macros
- given.
- """
- return DebugMacroCheck.check_debug_macros(
- DebugMacroCheck.get_debug_macros(source_str),
- cls._get_function_name())
-
- @classmethod
- def _get_function_name(cls) -> str:
- """Returns the function name from one level of call depth.
-
- Returns:
- str: The caller function name.
- """
- return "function: " + inspect.currentframe().f_back.f_code.co_name
-
-
-# Test container classes for dynamically generated macro test cases.
-# A class can be removed below to skip / remove it from testing.
-# Test case functions will be added to the appropriate class as they are
-# created.
-class Test_NoSpecifierNoArgument(
- unittest.TestCase,
- metaclass=Meta_TestDebugMacroCheck,
- category="no_specifier_no_argument_macro_test"):
- pass
-
-
-class Test_EqualSpecifierEqualArgument(
- unittest.TestCase,
- metaclass=Meta_TestDebugMacroCheck,
- category="equal_specifier_equal_argument_macro_test"):
- pass
-
-
-class Test_MoreSpecifiersThanArguments(
- unittest.TestCase,
- metaclass=Meta_TestDebugMacroCheck,
- category="more_specifiers_than_arguments_macro_test"):
- pass
-
-
-class Test_LessSpecifiersThanArguments(
- unittest.TestCase,
- metaclass=Meta_TestDebugMacroCheck,
- category="less_specifiers_than_arguments_macro_test"):
- pass
-
-
-class Test_IgnoredSpecifiers(
- unittest.TestCase,
- metaclass=Meta_TestDebugMacroCheck,
- category="ignored_specifiers_macro_test"):
- pass
-
-
-class Test_SpecialParsingMacroTest(
- unittest.TestCase,
- metaclass=Meta_TestDebugMacroCheck,
- category="special_parsing_macro_test"):
- pass
-
-
-class Test_CodeSnippetMacroTest(
- unittest.TestCase,
- metaclass=Meta_TestDebugMacroCheck,
- category="code_snippet_macro_test"):
- pass
-
-
-if __name__ == '__main__':
- unittest.main()
+# @file test_DebugMacroCheck.py
+#
+# Contains unit tests for the DebugMacroCheck build plugin.
+#
+# An example of running these tests from the root of the workspace:
+# python -m unittest discover -s ./BaseTools/Plugin/DebugMacroCheck/tests -v
+#
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+import inspect
+import pathlib
+import sys
+import unittest
+
+# Import the build plugin
+test_file = pathlib.Path(__file__)
+sys.path.append(str(test_file.parent.parent))
+
+# flake8 (E402): Ignore flake8 module level import not at top of file
+import DebugMacroCheck # noqa: E402
+
+from os import linesep # noqa: E402
+from tests import DebugMacroDataSet # noqa: E402
+from tests import MacroTest # noqa: E402
+from typing import Callable, Tuple # noqa: E402
+
+
+#
+# This metaclass is provided to dynamically produce test case container
+# classes. The main purpose of this approach is to:
+# 1. Allow categories of test cases to be defined (test container classes)
+# 2. Allow test cases to automatically (dynamically) be assigned to their
+# corresponding test container class when new test data is defined.
+#
+# The idea being that infrastructure and test data are separated. Adding
+# / removing / modifying test data does not require an infrastructure
+# change (unless new categories are defined).
+# 3. To work with the unittest discovery algorithm and VS Code Test Explorer.
+#
+# Notes:
+# - (1) can roughly be achieved with unittest test suites. In another
+# implementation approach, this solution was tested with relatively minor
+# modifications to use test suites. However, this became a bit overly
+# complicated with the dynamic test case method generation and did not
+# work as well with VS Code Test Explorer.
+# - For (2) and (3), particularly for VS Code Test Explorer to work, the
+# dynamic population of the container class namespace needed to happen prior
+# to class object creation. That is why the metaclass assigns test methods
+# to the new classes based upon the test category specified in the
+# corresponding data class.
+# - This could have been simplified a bit by either using one test case
+# container class and/or testing data in a single, monolithic test function
+# that iterates over the data set. However, the dynamic hierarchy greatly
+# helps organize test results and reporting. The infrastructure though
+# inheriting some complexity to support it, should not need to change (much)
+# as the data set expands.
+# - Test case categories (container classes) are derived from the overall
+# type of macro conditions under test.
+#
+# - This implementation assumes unittest will discover test cases
+# (classes derived from unittest.TestCase) with the name pattern "Test_*"
+# and test functions with the name pattern "test_x". Individual tests are
+# dynamically numbered monotonically within a category.
+# - The final test case description is also able to return fairly clean
+# context information.
+#
+class Meta_TestDebugMacroCheck(type):
+ """
+ Metaclass for debug macro test case class factory.
+ """
+ @classmethod
+ def __prepare__(mcls, name, bases, **kwargs):
+ """Returns the test case namespace for this class."""
+ candidate_macros, cls_ns, cnt = [], {}, 0
+
+ if "category" in kwargs.keys():
+ candidate_macros = [m for m in DebugMacroDataSet.DEBUG_MACROS if
+ m.category == kwargs["category"]]
+ else:
+ candidate_macros = DebugMacroDataSet.DEBUG_MACROS
+
+ for cnt, macro_test in enumerate(candidate_macros):
+ f_name = f'test_{macro_test.category}_{cnt}'
+ t_desc = f'{macro_test!s}'
+ cls_ns[f_name] = mcls.build_macro_test(macro_test, t_desc)
+ return cls_ns
+
+ def __new__(mcls, name, bases, ns, **kwargs):
+ """Defined to prevent variable args from bubbling to the base class."""
+ return super().__new__(mcls, name, bases, ns)
+
+ def __init__(mcls, name, bases, ns, **kwargs):
+ """Defined to prevent variable args from bubbling to the base class."""
+ return super().__init__(name, bases, ns)
+
+ @classmethod
+ def build_macro_test(cls, macro_test: MacroTest.MacroTest,
+ test_desc: str) -> Callable[[None], None]:
+ """Returns a test function for this macro test data."
+
+ Args:
+ macro_test (MacroTest.MacroTest): The macro test class.
+
+ test_desc (str): A test description string.
+
+ Returns:
+ Callable[[None], None]: A test case function.
+ """
+ def test_func(self):
+ act_result = cls.check_regex(macro_test.macro)
+ self.assertCountEqual(
+ act_result,
+ macro_test.result,
+ test_desc + f'{linesep}'.join(
+ ["", f"Actual Result: {act_result}", "=" * 80, ""]))
+
+ return test_func
+
+ @classmethod
+ def check_regex(cls, source_str: str) -> Tuple[int, int, int]:
+ """Returns the plugin result for the given macro string.
+
+ Args:
+ source_str (str): A string containing debug macros.
+
+ Returns:
+ Tuple[int, int, int]: A tuple of the number of formatting errors,
+ number of print specifiers, and number of arguments for the macros
+ given.
+ """
+ return DebugMacroCheck.check_debug_macros(
+ DebugMacroCheck.get_debug_macros(source_str),
+ cls._get_function_name())
+
+ @classmethod
+ def _get_function_name(cls) -> str:
+ """Returns the function name from one level of call depth.
+
+ Returns:
+ str: The caller function name.
+ """
+ return "function: " + inspect.currentframe().f_back.f_code.co_name
+
+
+# Test container classes for dynamically generated macro test cases.
+# A class can be removed below to skip / remove it from testing.
+# Test case functions will be added to the appropriate class as they are
+# created.
+class Test_NoSpecifierNoArgument(
+ unittest.TestCase,
+ metaclass=Meta_TestDebugMacroCheck,
+ category="no_specifier_no_argument_macro_test"):
+ pass
+
+
+class Test_EqualSpecifierEqualArgument(
+ unittest.TestCase,
+ metaclass=Meta_TestDebugMacroCheck,
+ category="equal_specifier_equal_argument_macro_test"):
+ pass
+
+
+class Test_MoreSpecifiersThanArguments(
+ unittest.TestCase,
+ metaclass=Meta_TestDebugMacroCheck,
+ category="more_specifiers_than_arguments_macro_test"):
+ pass
+
+
+class Test_LessSpecifiersThanArguments(
+ unittest.TestCase,
+ metaclass=Meta_TestDebugMacroCheck,
+ category="less_specifiers_than_arguments_macro_test"):
+ pass
+
+
+class Test_IgnoredSpecifiers(
+ unittest.TestCase,
+ metaclass=Meta_TestDebugMacroCheck,
+ category="ignored_specifiers_macro_test"):
+ pass
+
+
+class Test_SpecialParsingMacroTest(
+ unittest.TestCase,
+ metaclass=Meta_TestDebugMacroCheck,
+ category="special_parsing_macro_test"):
+ pass
+
+
+class Test_CodeSnippetMacroTest(
+ unittest.TestCase,
+ metaclass=Meta_TestDebugMacroCheck,
+ category="code_snippet_macro_test"):
+ pass
+
+
+if __name__ == '__main__':
+ unittest.main()