diff --git a/UnitTestFrameworkPkg/ReadMe.md b/UnitTestFrameworkPkg/ReadMe.md index 6f96ce7072..fef3f5fa30 100644 --- a/UnitTestFrameworkPkg/ReadMe.md +++ b/UnitTestFrameworkPkg/ReadMe.md @@ -38,7 +38,7 @@ that may be used to implement, run, and debug unit tests implemented using Googl is an example of the C++ TestMate JSON configuration to find unit tests and configure the environment for unit test execution. -``` +```json "testMate.cpp.test.advancedExecutables": [ { "pattern": "Build/**/*Test*", @@ -67,24 +67,24 @@ reviewed. The paths to the SecureBootVariableLib unit tests are: ## Framework and GoogleTest Feature Comparison -| Feature | Framework | GoogleTest | -|:----------------------------|:---------:|:----------:| -| Host Based Unit Tests | YES | YES | -| Target Based Unit Tests | YES | NO | -| Unit Test Source Language | C | C++ | -| Register Test Suite | YES | Auto | -| Register Test Case | YES | Auto | -| Expected Assert Tests | YES | YES | -| Setup/Teardown Hooks | YES | YES | -| Value-Parameterized Tests | NO | YES | -| Typed Tests | NO | YES | -| Type-Parameterized Tests | NO | YES | -| Timeout Support | NO | YES | -| Mocking Support | Cmocka | gMock | -| JUNIT XML Reports | YES | YES | -| Execute subset of tests | NO | YES | -| VS Code Extensions | NO | YES | -| Address Sanitizer | Cmocka | YES | +| Feature | Framework | GoogleTest | +| :------------------------ | :-------: | :--------: | +| Host Based Unit Tests | YES | YES | +| Target Based Unit Tests | YES | NO | +| Unit Test Source Language | C | C++ | +| Register Test Suite | YES | Auto | +| Register Test Case | YES | Auto | +| Expected Assert Tests | YES | YES | +| Setup/Teardown Hooks | YES | YES | +| Value-Parameterized Tests | NO | YES | +| Typed Tests | NO | YES | +| Type-Parameterized Tests | NO | YES | +| Timeout Support | NO | YES | +| Mocking Support | Cmocka | gMock | +| JUNIT XML Reports | YES | YES | +| Execute subset of tests | NO | YES | +| VS Code Extensions | NO | YES | +| Address Sanitizer | Cmocka | YES | ## Framework Libraries @@ -140,7 +140,7 @@ you should be good to go. See this example in `SampleUnitTestUefiShell.inf`... -``` +```inf [Packages] MdePkg/MdePkg.dec @@ -155,7 +155,7 @@ See this example in `SampleUnitTestUefiShell.inf`... Also, if you want your test to automatically be picked up by the Test Runner plugin, you will need to make sure that the module `BASE_NAME` contains the word `Test`... -``` +```inf [Defines] BASE_NAME = SampleUnitTestUefiShell ``` @@ -167,7 +167,7 @@ section so that the unit tests will be built. See this example in `UnitTestFrameworkPkg.dsc`... -``` +```inf [Components] UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestUefiShell.inf ``` @@ -176,7 +176,7 @@ Also, based on the type of tests that are being created, the associated DSC incl UnitTestFrameworkPkg for Host or Target based tests should also be included at the top of the DSC file. -``` +```inf !include UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc ``` @@ -186,7 +186,7 @@ they should be added in the \ sub-section for the INF file in t See this example in `SecurityPkgHostTest.dsc`... -``` +```inf [Components] SecurityPkg/Library/SecureBootVariableLib/UnitTest/SecureBootVariableLibUnitTest.inf { @@ -342,7 +342,7 @@ Beyond that, if you're writing host-based tests and want to take a dependency on leverage the `cmocka.h` interface and write tests with all the features of the Cmocka framework. Documentation for Cmocka can be found here: -https://api.cmocka.org/ + ## GoogleTest Libraries @@ -361,16 +361,16 @@ the following tables. #### Custom Actions -| Action Name | Similar gMock Generic Action | Usage | -|:--- |:--- |:--- | -| `SetArgBuffer()` | `SetArgPointee()` | Used to set a buffer output argument (such as UINT8*, VOID*, a structure pointer, etc.) with data in an expect call. Can be used in an `EXPECT_CALL()` | +| Action Name | Similar gMock Generic Action | Usage | +| :--------------- | :--------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- | +| `SetArgBuffer()` | `SetArgPointee()` | Used to set a buffer output argument (such as UINT8*, VOID*, a structure pointer, etc.) with data in an expect call. Can be used in an `EXPECT_CALL()` | #### Custom Matchers -| Matcher Name | Similar gMock Generic Matcher | Usage | -|:--- |:--- |:--- | -| `BufferEq()` | `Pointee(Eq())` | Used to compare two buffer pointer types (such as UINT8*, VOID*, a structure pointer, etc.). Can be used in an `EXPECT_CALL()`, `EXPECT_THAT()`, or anywhere else a matcher to compare two buffers is needed. | -| `Char16StrEq()` | `Pointee(Eq())` | Used to compare two CHAR16* strings. Can be used in an `EXPECT_CALL()`, `EXPECT_THAT()`, or anywhere else a matcher to compare two CHAR16* strings is needed. | +| Matcher Name | Similar gMock Generic Matcher | Usage | +| :-------------- | :---------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `BufferEq()` | `Pointee(Eq())` | Used to compare two buffer pointer types (such as UINT8*, VOID*, a structure pointer, etc.). Can be used in an `EXPECT_CALL()`, `EXPECT_THAT()`, or anywhere else a matcher to compare two buffers is needed. | +| `Char16StrEq()` | `Pointee(Eq())` | Used to compare two CHAR16*strings. Can be used in an `EXPECT_CALL()`, `EXPECT_THAT()`, or anywhere else a matcher to compare two CHAR16* strings is needed. | ### FunctionMockLib @@ -386,6 +386,7 @@ the mock functions, and the other two macros are related to creating an interfac to contain the mock functions and connect them into the gMock framework. The macros used to create the interface are... + 1. `MOCK_INTERFACE_DECLARATION(MOCK)` 2. `MOCK_INTERFACE_DEFINITION(MOCK)` @@ -408,6 +409,7 @@ MOCK_INTERFACE_DEFINITION(MockUefiLib); ``` The macros used to create the mock functions are... + 1. `MOCK_FUNCTION_DECLARATION(RET_TYPE, FUNC, ARGS)` 2. `MOCK_FUNCTION_DEFINITION(MOCK, FUNC, NUM_ARGS, CALL_TYPE)` 3. `MOCK_FUNCTION_INTERNAL_DECLARATION(RET_TYPE, FUNC, ARGS)` @@ -537,9 +539,9 @@ module being tested and use run-time replacement. The below table shows which macros to use in these two use cases. However, note that for the creation of the interface, the same macros are used in both cases. -| Mock Function Use Case | Mock Interface Macros | Mock Function Macros | -|:--- |:--- |:--- | -| External mock functions | `MOCK_INTERFACE_DECLARATION`
`MOCK_INTERFACE_DEFINITION` | `MOCK_FUNCTION_DECLARATION`
`MOCK_FUNCTION_DEFINITION` | +| Mock Function Use Case | Mock Interface Macros | Mock Function Macros | +| :---------------------- | :----------------------------------------------------------- | :--------------------------------------------------------------------------- | +| External mock functions | `MOCK_INTERFACE_DECLARATION`
`MOCK_INTERFACE_DEFINITION` | `MOCK_FUNCTION_DECLARATION`
`MOCK_FUNCTION_DEFINITION` | | Internal mock functions | `MOCK_INTERFACE_DECLARATION`
`MOCK_INTERFACE_DEFINITION` | `MOCK_FUNCTION_INTERNAL_DECLARATION`
`MOCK_FUNCTION_INTERNAL_DEFINITION` | #### FunctionMockLib Mocks - External mock function @@ -580,19 +582,19 @@ in header files. The name of the header file is determined by the interface (such as a library or a protocol) that is being created for the mock functions. The rules for naming the file are shown in the table below. -| Interface Type | Header File Name | -| :--- | :--- | -| Library | Mock\Lib.h | +| Interface Type | Header File Name | +| :--------------------------------- | :---------------------------------- | +| Library | Mock\Lib.h | | Global Table (e.g. gRT, gBS, etc.) | Mock\Lib.h | -| Protocol | Mock\Protocol.h | +| Protocol | Mock\Protocol.h | The below table shows examples for file names with each of the above cases. -| Interface Type | Interface Name | Header File Name | -| :--- | :--- | :--- | -| Library | UefiLib | MockUefiLib.h | +| Interface Type | Interface Name | Header File Name | +| :--------------------------------- | :-------------------------- | :-------------------------------- | +| Library | UefiLib | MockUefiLib.h | | Global Table (e.g. gRT, gBS, etc.) | UefiRuntimeServicesTableLib | MockUefiRuntimeServicesTableLib.h | -| Protocol | EFI_USB_IO_PROTOCOL | MockEfiUsbIoProtocol.h | +| Protocol | EFI_USB_IO_PROTOCOL | MockEfiUsbIoProtocol.h | Once the header file name is known, the file needs to be created in the proper location. For internal mock functions, the location is simply the same @@ -602,19 +604,19 @@ package where the library, global table, or protocol that is being mocked is declared. The exact location depends on the interface type and is shown in the below table. -| Interface Type | Header File Location | -| :--- | :--- | -| Library | \/Test/Mock/Include/GoogleTest/Library | -| Global Table (e.g. gRT, gBS, etc.) | \/Test/Mock/Include/GoogleTest/Library | -| Protocol | \/Test/Mock/Include/GoogleTest/Protocol | +| Interface Type | Header File Location | +| :--------------------------------- | :---------------------------------------------------- | +| Library | \/Test/Mock/Include/GoogleTest/Library | +| Global Table (e.g. gRT, gBS, etc.) | \/Test/Mock/Include/GoogleTest/Library | +| Protocol | \/Test/Mock/Include/GoogleTest/Protocol | The below table shows examples for file locations with each of the above cases. -| Interface Type | Interface Name | Header File Location | -| :--- | :--- | :--- | -| Library | UefiLib | MdePkg/Test/Mock/Include/GoogleTest/Library/MockUefiLib.h | +| Interface Type | Interface Name | Header File Location | +| :--------------------------------- | :-------------------------- | :---------------------------------------------------------------------------- | +| Library | UefiLib | MdePkg/Test/Mock/Include/GoogleTest/Library/MockUefiLib.h | | Global Table (e.g. gRT, gBS, etc.) | UefiRuntimeServicesTableLib | MdePkg/Test/Mock/Include/GoogleTest/Library/MockUefiRuntimeServicesTableLib.h | -| Protocol | EFI_USB_IO_PROTOCOL | MdePkg/Test/Mock/Include/GoogleTest/Protocol/MockEfiUsbIoProtocol.h | +| Protocol | EFI_USB_IO_PROTOCOL | MdePkg/Test/Mock/Include/GoogleTest/Protocol/MockEfiUsbIoProtocol.h | Now that the file location is known, the contents can be added to it. After the standard `#ifndef` for a header file is added at the top of the file, the @@ -677,11 +679,11 @@ case of global tables and protocols, to eliminate possible function name collisions, the names are adjusted slightly in the mock declarations as shown in the below table. -| Mock Function Use Case | Design Function Name | Mock Function Name | -| :--- | :--- | :--- | -| Library | GetVariable2 | GetVariable2 | -| Global Table (e.g. gRT, gBS, etc.) | gRT->GetVariable | gRT_GetVariable | -| Protocol | UsbIoProtocol->UsbPortReset | UsbIoProtocol_UsbPortReset | +| Mock Function Use Case | Design Function Name | Mock Function Name | +| :--------------------------------- | :-------------------------- | :------------------------- | +| Library | GetVariable2 | GetVariable2 | +| Global Table (e.g. gRT, gBS, etc.) | gRT->GetVariable | gRT_GetVariable | +| Protocol | UsbIoProtocol->UsbPortReset | UsbIoProtocol_UsbPortReset | Lastly, when creating mock functions, there are two limitations to be aware of in gMock that extend into FunctionMockLib. @@ -701,19 +703,19 @@ in source files. The name of the source file is determined by the interface The rules for naming the file align with the naming of the file for declarations and are shown in the table below. -| Interface Type | Source File Name | -| :--- | :--- | -| Library | Mock\Lib.cpp | +| Interface Type | Source File Name | +| :--------------------------------- | :------------------------------------ | +| Library | Mock\Lib.cpp | | Global Table (e.g. gRT, gBS, etc.) | Mock\Lib.cpp | -| Protocol | Mock\Protocol.cpp | +| Protocol | Mock\Protocol.cpp | The below table shows examples for file names with each of the above cases. -| Interface Type | Interface Name | Source File Name | -| :--- | :--- | :--- | -| Library | UefiLib | MockUefiLib.cpp | +| Interface Type | Interface Name | Source File Name | +| :--------------------------------- | :-------------------------- | :---------------------------------- | +| Library | UefiLib | MockUefiLib.cpp | | Global Table (e.g. gRT, gBS, etc.) | UefiRuntimeServicesTableLib | MockUefiRuntimeServicesTableLib.cpp | -| Protocol | EFI_USB_IO_PROTOCOL | MockEfiUsbIoProtocol.cpp | +| Protocol | EFI_USB_IO_PROTOCOL | MockEfiUsbIoProtocol.cpp | Once the source file name is known, the file needs to be created in the proper location. The location of the source file is aligned with the location for the @@ -724,19 +726,19 @@ package where the library, global table, or protocol that is being mocked is declared. The exact location depends on the interface type and is shown in the below table. -| Interface Type | Source File Location | -| :--- | :--- | -| Library | \/Test/Mock/Library/GoogleTest/Mock\Lib | +| Interface Type | Source File Location | +| :--------------------------------- | :----------------------------------------------------------------------------- | +| Library | \/Test/Mock/Library/GoogleTest/Mock\Lib | | Global Table (e.g. gRT, gBS, etc.) | \/Test/Mock/Library/GoogleTest/Mock\Lib | -| Protocol | \/Test/Mock/Library/GoogleTest/Mock\Protocol | +| Protocol | \/Test/Mock/Library/GoogleTest/Mock\Protocol | The below table shows examples for file locations with each of the above cases. -| Interface Type | Interface Name | Source File Location | -| :--- | :--- | :--- | -| Library | UefiLib | MdePkg/Test/Mock/Library/GoogleTest/MockUefiLib/MockUefiLib.cpp | +| Interface Type | Interface Name | Source File Location | +| :--------------------------------- | :-------------------------- | :------------------------------------------------------------------------------------------------------ | +| Library | UefiLib | MdePkg/Test/Mock/Library/GoogleTest/MockUefiLib/MockUefiLib.cpp | | Global Table (e.g. gRT, gBS, etc.) | UefiRuntimeServicesTableLib | MdePkg/Test/Mock/Library/GoogleTest/MockUefiRuntimeServicesTableLib/MockUefiRuntimeServicesTableLib.cpp | -| Protocol | EFI_USB_IO_PROTOCOL | MdePkg/Test/Mock/Library/GoogleTest/MockEfiUsbIoProtocol/MockEfiUsbIoProtocol.cpp | +| Protocol | EFI_USB_IO_PROTOCOL | MdePkg/Test/Mock/Library/GoogleTest/MockEfiUsbIoProtocol/MockEfiUsbIoProtocol.cpp | Now that the file location is known, the contents can be added to it. At the top of the file, the header file containing the mock function declarations is always @@ -855,7 +857,7 @@ the `GoogleTestLib`, and the `[BuildOptions]` will need to append the `/EHsc` compilation flag to all MSFT builds to enable proper use of the C++ exception handler. Below is the complete `MockUefiLib.inf` as an example. -``` +```inf [Defines] INF_VERSION = 0x00010005 BASE_NAME = MockUefiLib @@ -890,7 +892,7 @@ if no test uses it yet, this created INF file needs to be added into the which this INF file resides. For example, the above `MockUefiLib.inf` would need to be added to the `MdePkg/Test/MdePkgHostTest.dsc` file as shown below. -``` +```inf [Components] MdePkg/Test/Mock/Library/GoogleTest/MockUefiLib/MockUefiLib.inf ``` @@ -908,7 +910,7 @@ locate the mock function header file. For example, if `MockUefiLib.inf` were the first mock added to the `MdePkg`, then the below snippet would need to be added to the `MdePkg.dec` file. -``` +```inf [Includes] Test/Mock/Include ``` @@ -928,7 +930,7 @@ mock function definitions file be added to the `[Sources]` section, the Below is a minimal contrived example for a `MyModuleGoogleTest.inf` that uses a `MockMyModuleInternalFunctions.cpp` source file for its internal mock functions. -``` +```inf [Defines] INF_VERSION = 0x00010017 BASE_NAME = MyModuleGoogleTest @@ -990,7 +992,7 @@ you should be good to go. See this example in `SampleGoogleTestHost.inf`... -``` +```inf [Packages] MdePkg/MdePkg.dec UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec @@ -1004,7 +1006,7 @@ See this example in `SampleGoogleTestHost.inf`... Also, if you want your test to automatically be picked up by the Test Runner plugin, you will need to make sure that the module `BASE_NAME` contains the word `Test`... -``` +```inf [Defines] BASE_NAME = SampleGoogleTestHost ``` @@ -1016,7 +1018,7 @@ section so that the unit tests will be built. See this example in `UnitTestFrameworkPkgHostTest.dsc`... -``` +```inf [Components] UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/SampleGoogleTestHost.inf ``` @@ -1025,7 +1027,7 @@ Also, based on the type of tests that are being created, the associated DSC incl UnitTestFrameworkPkg for Host or Target based tests should also be included at the top of the DSC file. This provides the default defines and library class mappings requires for unit testing. -``` +```inf !include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc ``` @@ -1040,7 +1042,7 @@ See this example in `SecurityPkgHostTest.dsc` where the `SecureBootVariableLib` being tested using mock versions of `UefiRuntimeServicesTableLib`, `PlatformPKProtectionLib`, and `UefiLib`... -``` +```inf [Components] SecurityPkg/Library/SecureBootVariableLib/GoogleTest/SecureBootVariableLibGoogleTest.inf { @@ -1396,7 +1398,7 @@ stuart_ci_build -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=VS2022 -t NOOPT -p Mde By default, the address sanitizer feature is enabled for all host based unit test builds. It can be disabled for development/debug purposes by setting the DSC define `UNIT_TESTING_ADDRESS_SANITIZER_ENABLE` to `FALSE`. -``` +```bash stuart_ci_build -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=VS2022 -t NOOPT -p MdePkg BLD_*_UNIT_TESTING_ADDRESS_SANITIZER_ENABLE=FALSE ``` @@ -1498,14 +1500,14 @@ shell or using VS Code extensions such as `C++ TestMate`, then the environment m #### Windows Environment Variable Settings -``` +```bash set GTEST_CATCH_EXCEPTIONS=0 set ASAN_OPTIONS=detect_leaks=0 ``` #### Linux Environment Variable Settings -``` +```bash export GTEST_CATCH_EXCEPTIONS=0 export ASAN_OPTIONS=detect_leaks=0 ``` @@ -1516,7 +1518,7 @@ Unit test applications using Framework are built using Cmocka that requires the following environment variables to be set to generate structured XML output rather than text: -``` +```bash CMOCKA_MESSAGE_OUTPUT=xml CMOCKA_XML_FILE= ``` @@ -1524,7 +1526,7 @@ CMOCKA_XML_FILE= Unit test applications using GoogleTest require the following environment variable to be set to generate structured XML output rather than text: -``` +```bash GTEST_OUTPUT=xml: ``` @@ -1537,7 +1539,8 @@ Host based Unit Tests will automatically enable coverage data. For Windows, this is primarily leveraged for pipeline builds, but this can be leveraged locally using the OpenCppCoverage windows tool to parse coverage data to cobertura xml format. -- Windows Prerequisite +* Windows Prerequisite + ```bash Download and install https://github.com/OpenCppCoverage/OpenCppCoverage/releases python -m pip install --upgrade -r ./pip-requirements.txt @@ -1545,32 +1548,34 @@ OpenCppCoverage windows tool to parse coverage data to cobertura xml format. Open Build/coverage.xml ``` - - How to see code coverage data on IDE Visual Studio - ``` + * How to see code coverage data on IDE Visual Studio + + ```bash Open Visual Studio VS2022 or above version Click "Tools" -> "OpenCppCoverage Settings" Fill your execute file into "Program to run:" Click "Tools" -> "Run OpenCppCoverage" ``` - For Linux, this is primarily leveraged for pipeline builds, but this can be leveraged locally using the lcov linux tool, and parsed using the lcov_cobertura python tool to parse it to cobertura xml format. -- Linux Prerequisite +* Linux Prerequisite + ```bash sudo apt-get install -y lcov python -m pip install --upgrade -r ./pip-requirements.txt stuart_ci_build -c .pytool/CISettings.py -t NOOPT TOOL_CHAIN_TAG=GCC -p MdeModulePkg Open Build/coverage.xml ``` - - How to see code coverage data on IDE Visual Studio Code - ``` + + * How to see code coverage data on IDE Visual Studio Code + + ```bash Download plugin "Coverage Gutters" Press Hot Key "Ctrl + Shift + P" and click option "Coverage Gutters: Display Coverage" ``` - ### Important Note This works on both Windows and Linux but is currently limited to x64 architectures. Working on getting others, but we @@ -1599,12 +1604,12 @@ We will continue trying to make these as similar as possible. ## Unit Test Location/Layout Rules -Code/Test | Location ---------- | -------- -Host-Based Unit Tests for a Library/Protocol/PPI/GUID Interface | If what's being tested is an interface (e.g. a library with a public header file, like DebugLib) and the test is agnostic to a specific implementation, then the test should be scoped to the parent package.
Example: `MdePkg/Test/UnitTest/[Library/Protocol/Ppi/Guid]/`

A real-world example of this is the BaseSafeIntLib test in MdePkg.
`MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibHost.inf` -Host-Based Unit Tests for a Library/Driver (PEI/DXE/SMM) implementation | If what's being tested is a specific implementation (e.g. BaseDebugLibSerialPort for DebugLib), then the test should be scoped to the implementation directory itself, in a UnitTest (or GoogleTest) subdirectory.

Module Example: `MdeModulePkg/Universal/EsrtFmpDxe/UnitTest/`
Library Example: `MdePkg/Library/BaseMemoryLib/UnitTest/`
Library Example (GoogleTest): `SecurityPkg/Library/SecureBootVariableLib/GoogleTest/` -Host-Based Tests for a Functionality or Feature | If you're writing a functional test that operates at the module level (i.e. if it's more than a single file or library), the test should be located in the package-level Tests directory under the HostFuncTest subdirectory.
For example, if you were writing a test for the entire FMP Device Framework, you might put your test in:
`FmpDevicePkg/Test/HostFuncTest/FmpDeviceFramework`

If the feature spans multiple packages, it's location should be determined by the package owners related to the feature. -Non-Host-Based (PEI/DXE/SMM/Shell) Tests for a Functionality or Feature | Similar to Host-Based, if the feature is in one package, should be located in the `*Pkg/Test/[Shell/Dxe/Smm/Pei]Test` directory.

If the feature spans multiple packages, it's location should be determined by the package owners related to the feature.

USAGE EXAMPLES
PEI Example: MP_SERVICE_PPI. Or check MTRR configuration in a notification function.
SMM Example: a test in a protocol callback function. (It is different with the solution that SmmAgent+ShellApp)
DXE Example: a test in a UEFI event call back to check SPI/SMRAM status.
Shell Example: the SMM handler audit test has a shell-based app that interacts with an SMM handler to get information. The SMM paging audit test gathers information about both DXE and SMM. And the SMM paging functional test actually forces errors into SMM via a DXE driver. +| Code/Test | Location | +| ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Host-Based Unit Tests for a Library/Protocol/PPI/GUID Interface | If what's being tested is an interface (e.g. a library with a public header file, like DebugLib) and the test is agnostic to a specific implementation, then the test should be scoped to the parent package.
Example: `MdePkg/Test/UnitTest/[Library/Protocol/Ppi/Guid]/`

A real-world example of this is the BaseSafeIntLib test in MdePkg.
`MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibHost.inf` | +| Host-Based Unit Tests for a Library/Driver (PEI/DXE/SMM) implementation | If what's being tested is a specific implementation (e.g. BaseDebugLibSerialPort for DebugLib), then the test should be scoped to the implementation directory itself, in a UnitTest (or GoogleTest) subdirectory.

Module Example: `MdeModulePkg/Universal/EsrtFmpDxe/UnitTest/`
Library Example: `MdePkg/Library/BaseMemoryLib/UnitTest/`
Library Example (GoogleTest): `SecurityPkg/Library/SecureBootVariableLib/GoogleTest/` | +| Host-Based Tests for a Functionality or Feature | If you're writing a functional test that operates at the module level (i.e. if it's more than a single file or library), the test should be located in the package-level Tests directory under the HostFuncTest subdirectory.
For example, if you were writing a test for the entire FMP Device Framework, you might put your test in:
`FmpDevicePkg/Test/HostFuncTest/FmpDeviceFramework`

If the feature spans multiple packages, it's location should be determined by the package owners related to the feature. | +| Non-Host-Based (PEI/DXE/SMM/Shell) Tests for a Functionality or Feature | Similar to Host-Based, if the feature is in one package, should be located in the `*Pkg/Test/[Shell/Dxe/Smm/Pei]Test` directory.

If the feature spans multiple packages, it's location should be determined by the package owners related to the feature.

USAGE EXAMPLES
PEI Example: MP_SERVICE_PPI. Or check MTRR configuration in a notification function.
SMM Example: a test in a protocol callback function. (It is different with the solution that SmmAgent+ShellApp)
DXE Example: a test in a UEFI event call back to check SPI/SMRAM status.
Shell Example: the SMM handler audit test has a shell-based app that interacts with an SMM handler to get information. The SMM paging audit test gathers information about both DXE and SMM. And the SMM paging functional test actually forces errors into SMM via a DXE driver. | ### Example Directory Tree @@ -1679,12 +1684,12 @@ Non-Host-Based (PEI/DXE/SMM/Shell) Tests for a Functionality or Feature | Simi We don't know if these types will exist or be applicable yet, but if you write a support library or module that matches the following, please make sure they live in the correct place. -Code/Test | Location ---------- | -------- -Host-Based Library Implementations | Host-Based Implementations of common libraries (eg. MemoryAllocationLibHost) should live in the same package that declares the library interface in its .DEC file in the `*Pkg/HostLibrary` directory. Should have 'Host' in the name. -Host-Based Mocks and Stubs | Mock and Stub libraries should live in the `UefiTestFrameworkPkg/StubLibrary` with either 'Mock' or 'Stub' in the library name. +| Code/Test | Location | +| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Host-Based Library Implementations | Host-Based Implementations of common libraries (eg. MemoryAllocationLibHost) should live in the same package that declares the library interface in its .DEC file in the `*Pkg/HostLibrary` directory. Should have 'Host' in the name. | +| Host-Based Mocks and Stubs | Mock and Stub libraries should live in the `UefiTestFrameworkPkg/StubLibrary` with either 'Mock' or 'Stub' in the library name. | -### If still in doubt... +### If still in doubt Hop on GitHub and ask @corthon, @mdkinney, or @spbrogan. ;)