回复: [edk2-devel] [Patch V2 3/7] UnitTestFrameworkPkg: Add googletest submodule and GoogleTestLib

gaoliming via groups.io gaoliming=byosoft.com.cn at groups.io
Tue Nov 8 07:47:15 UTC 2022


Mike:
  For new submodule, I think it is also required to be mentioned in License
Details section in Edk2\ReadMe.rst

Thanks
Liming
> -----邮件原件-----
> 发件人: devel at edk2.groups.io <devel at edk2.groups.io> 代表 Michael D
> Kinney
> 发送时间: 2022年11月5日 4:25
> 收件人: devel at edk2.groups.io
> 抄送: Michael Kubacki <mikuback at linux.microsoft.com>; Sean Brogan
> <sean.brogan at microsoft.com>
> 主题: [edk2-devel] [Patch V2 3/7] UnitTestFrameworkPkg: Add googletest
> submodule and GoogleTestLib
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4134
> 
> Add submodule for googletest and add GoogleTestLib that is
> required for GoogleTest based unit tests. Add GoogleTest
> documentation to Readme.md along with a port of the sample
> unit test to the GoogleTest style.
> 
> Cc: Michael Kubacki <mikuback at linux.microsoft.com>
> Cc: Sean Brogan <sean.brogan at microsoft.com>
> Signed-off-by: Michael D Kinney <michael.d.kinney at intel.com>
> Reviewed-by: Michael Kubacki <mikuback at linux.microsoft.com>
> ---
>  .gitmodules                                   |   3 +
>  .../Include/Library/GoogleTestLib.h           |  14 +
>  .../Library/GoogleTestLib/GoogleTestLib.inf   |  36 +++
>  .../Library/GoogleTestLib/GoogleTestLib.uni   |  14 +
>  .../Library/GoogleTestLib/googletest          |   1 +
>  UnitTestFrameworkPkg/ReadMe.md                | 255
> +++++++++++++++--
>  .../SampleGoogleTest/SampleGoogleTest.cpp     | 263
> ++++++++++++++++++
>  .../SampleGoogleTest/SampleGoogleTestHost.inf |  35 +++
>  .../Test/UnitTestFrameworkPkgHostTest.dsc     |   4 +-
>  .../UnitTestFrameworkPkg.ci.yaml              |   4 +-
>  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec |   8 +
>  .../UnitTestFrameworkPkgHost.dsc.inc          |   4 +-
>  12 files changed, 610 insertions(+), 31 deletions(-)
>  create mode 100644
> UnitTestFrameworkPkg/Include/Library/GoogleTestLib.h
>  create mode 100644
> UnitTestFrameworkPkg/Library/GoogleTestLib/GoogleTestLib.inf
>  create mode 100644
> UnitTestFrameworkPkg/Library/GoogleTestLib/GoogleTestLib.uni
>  create mode 160000
> UnitTestFrameworkPkg/Library/GoogleTestLib/googletest
>  create mode 100644
> UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/SampleG
> oogleTest.cpp
>  create mode 100644
> UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/SampleG
> oogleTestHost.inf
> 
> diff --git a/.gitmodules b/.gitmodules
> index b845c9ee3ff0..8011a88d9d25 100644
> --- a/.gitmodules
> +++ b/.gitmodules
> @@ -20,3 +20,6 @@
>  [submodule "RedfishPkg/Library/JsonLib/jansson"]
>  	path = RedfishPkg/Library/JsonLib/jansson
>  	url = https://github.com/akheron/jansson
> +[submodule "UnitTestFrameworkPkg/Library/GoogleTestLib/googletest"]
> +	path = UnitTestFrameworkPkg/Library/GoogleTestLib/googletest
> +	url = https://github.com/google/googletest.git
> diff --git a/UnitTestFrameworkPkg/Include/Library/GoogleTestLib.h
> b/UnitTestFrameworkPkg/Include/Library/GoogleTestLib.h
> new file mode 100644
> index 000000000000..ebec766d4cf7
> --- /dev/null
> +++ b/UnitTestFrameworkPkg/Include/Library/GoogleTestLib.h
> @@ -0,0 +1,14 @@
> +/** @file
> +  GoogleTestLib class with APIs from the googletest project
> +
> +  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef GOOGLE_TEST_LIB_H_
> +#define GOOGLE_TEST_LIB_H_
> +
> +#include <gtest/gtest.h>
> +
> +#endif
> diff --git a/UnitTestFrameworkPkg/Library/GoogleTestLib/GoogleTestLib.inf
> b/UnitTestFrameworkPkg/Library/GoogleTestLib/GoogleTestLib.inf
> new file mode 100644
> index 000000000000..68db75d7023f
> --- /dev/null
> +++ b/UnitTestFrameworkPkg/Library/GoogleTestLib/GoogleTestLib.inf
> @@ -0,0 +1,36 @@
> +## @file
> +#  This module provides GoogleTest Library implementation.
> +#
> +#  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION     = 0x00010005
> +  BASE_NAME       = GoogleTestLib
> +  MODULE_UNI_FILE = GoogleTestLib.uni
> +  FILE_GUID       = A90E4751-AD30-43CC-980B-01E356B49ADF
> +  MODULE_TYPE     = BASE
> +  VERSION_STRING  = 0.1
> +  LIBRARY_CLASS   = GoogleTestLib|HOST_APPLICATION
> +
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64
> +#
> +
> +[Sources]
> +  googletest/googletest/src/gtest-all.cc
> +
> +[Packages]
> +  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
> +
> +[BuildOptions]
> +  MSFT:*_*_*_CC_FLAGS     == /c /EHsc /Zi
> +  MSFT:NOOPT_*_*_CC_FLAGS =  /Od
> +
> +  GCC:*_*_*_CC_FLAGS     == -g -c
> +
> +  GCC:NOOPT_*_*_CC_FLAGS =  -O0
> +  GCC:*_*_IA32_CC_FLAGS  =  -m32
> +  GCC:*_*_X64_CC_FLAGS   =  -m64
> diff --git a/UnitTestFrameworkPkg/Library/GoogleTestLib/GoogleTestLib.uni
> b/UnitTestFrameworkPkg/Library/GoogleTestLib/GoogleTestLib.uni
> new file mode 100644
> index 000000000000..14c862a23744
> --- /dev/null
> +++ b/UnitTestFrameworkPkg/Library/GoogleTestLib/GoogleTestLib.uni
> @@ -0,0 +1,14 @@
> +// /** @file
> +// This module provides GoogleTest Library implementation.
> +//
> +// This module provides GoogleTest Library implementation.
> +//
> +// Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +#string STR_MODULE_ABSTRACT             #language en-US
> "GoogleTest Library implementation"
> +
> +#string STR_MODULE_DESCRIPTION          #language en-US "This
> module provides GoogleTest Library implementation."
> diff --git a/UnitTestFrameworkPkg/Library/GoogleTestLib/googletest
> b/UnitTestFrameworkPkg/Library/GoogleTestLib/googletest
> new file mode 160000
> index 000000000000..86add13493e5
> --- /dev/null
> +++ b/UnitTestFrameworkPkg/Library/GoogleTestLib/googletest
> @@ -0,0 +1 @@
> +Subproject commit 86add13493e5c881d7e4ba77fb91c1f57752b3a4
> diff --git a/UnitTestFrameworkPkg/ReadMe.md
> b/UnitTestFrameworkPkg/ReadMe.md
> index e696412cb3cf..9ce04b7f3eb6 100644
> --- a/UnitTestFrameworkPkg/ReadMe.md
> +++ b/UnitTestFrameworkPkg/ReadMe.md
> @@ -2,12 +2,67 @@
> 
>  ## About
> 
> -This package adds a unit test framework capable of building tests for
multiple
> contexts including
> +This package provides unit test frameworks capable of building tests for
> multiple contexts including
>  the UEFI shell environment and host-based environments. It allows for
unit
> test development to focus
> -on the tests and leave error logging, result formatting, context
persistance,
> and test running to the framework.
> +on the tests and leave error logging, result formatting, context
persistence,
> and test running to the framework.
>  The unit test framework works well for low level unit tests as well as
system
> level tests and
>  fits easily in automation frameworks.
> 
> +### Framework
> +
> +The first unit test framework is called **Framework** and is implemented
> as a set of EDK II libraries.
> +The Framework supports both host-based unit tests and target-based unit
> tests that share the same
> +source style, macros, and APIs. In some scenarios, the same unit test
case
> sources can be built
> +for both host-based unit test execution and target-based unit test
execution.
> Host-based unit tests
> +that require mocked interfaces can use the mocking infrastructure
provided
> by
> +[cmocka](https://api.cmocka.org/) that is included in the
> UnitTestFrameworkPkg as a submodule.
> +
> +### GoogleTest
> +
> +The second unit test framework supported by the UnitTestFrameworkPkg is
> +[GoogleTest](http://google.github.io/googletest/) that can be used to
> implement host-based unit tests.
> +Use of GoogleTest for target-based unit tests of EDK II components is not
> supported. If a
> +host-based unit test requires mocked interfaces, then the Framework with
> cmocka support should be
> +used instead. Enabling support for mocked interfaces with GoogleTest is
> being actively investigated.
> +[GoogleTest on GitHub](https://github.com/google/googletest) is included
in
> the UnitTestFrameworkPkg
> +as a submodule.
> +
> +GoogleTest requires less overhead to register test suites and test cases
> compared to the Framework.
> +There are also a number of tools that layer on top of GoogleTest that
improve
> developer productivity.
> +One example is the VS Code extension
> +[C++
> TestMate](https://marketplace.visualstudio.com/items?itemName=matepek.
> vscode-catch2-test-adapter)
> +that may be used to implement, run, and debug unit tests implemented
using
> GoogleTest.
> +
> +If a component can be tested with host-based unit tests without support
for
> mocked interfaces,
> +then GoogleTest is recommended. The MdePkg contains a port of the
> BaseSafeIntLib unit tests in
> +the GoogleTest style so the differences between GoogleTest and Framework
> unit tests can be reviewed.
> +The paths to the BaseSafeIntLib unit tests are:
> +
> +* MdePkg\Test\UnitTest\Library\BaseSafeIntLib
> +* MdePkg\Test\GoogleTest\Library\BaseSafeIntLib
> +
> +## 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    |
> +| Death/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  |     NO     |
> +| JUNIT XML Reports           |    YES    |    YES     |
> +| Execute subset of tests     |    NO     |    YES     |
> +| VS Code Extensions          |    NO     |    YES     |
> +
> +## Framework Libraries
> +
>  ### UnitTestLib
> 
>  The main "framework" library. The core of the framework is the Framework
> object, which can have any number
> @@ -31,10 +86,10 @@ in supporting a system reboot in the middle of a test
> run.
> 
>  Library provides function to run at the end of a framework test run and
> handles formatting the report.
>  This is a common customization point and allows the unit test framework
to
> fit its output reports into
> -other test infrastructure. In this package a simple library instances has
been
> supplied to output test
> +other test infrastructure. In this package simple library instances have
been
> supplied to output test
>  results to the console as plain text.
> 
> -## Samples
> +## Framework Samples
> 
>  There is a sample unit test provided as both an example of how to write a
> unit test and leverage
>  many of the features of the framework. This sample can be found in the
> `Test/UnitTest/Sample/SampleUnitTest`
> @@ -43,7 +98,7 @@ directory.
>  The sample is provided in PEI, SMM, DXE, and UEFI App flavors. It also
has a
> flavor for the HOST_APPLICATION
>  build type, which can be run on a host system without needing a target.
> 
> -## Usage
> +## Framework Usage
> 
>  This section is built a lot like a "Getting Started". We'll go through
some of
> the components that are needed
>  when constructing a unit test and some of the decisions that are made by
> the test writer. We'll also describe
> @@ -51,7 +106,7 @@ how to check for expected conditions in test cases and
> a bit of the logging char
> 
>  Most of these examples will refer to the SampleUnitTestUefiShell app
found
> in this package.
> 
> -### Requirements - INF
> +### Framework Requirements - INF
> 
>  In our INF file, we'll need to bring in the `UnitTestLib` library.
Conveniently,
> the interface
>  header for the `UnitTestLib` is located in `MdePkg`, so you shouldn't
need to
> depend on any other
> @@ -80,7 +135,7 @@ to make sure that the module `BASE_NAME` contains
> the word `Test`...
>    BASE_NAME      = SampleUnitTestUefiShell
>  ```
> 
> -### Requirements - Code
> +### Framework Requirements - Code
> 
>  Not to state the obvious, but let's make sure we have the following
include
> before getting too far along...
> 
> @@ -90,9 +145,9 @@ Not to state the obvious, but let's make sure we have
> the following include befo
> 
>  Now that we've got that squared away, let's look at our 'Main()'' routine
(or
> DriverEntryPoint() or whatever).
> 
> -### Configuring the Framework
> +### Framework Configuration
> 
> -Everything in the UnitTestPkg framework is built around an object called
--
> conveniently -- the Framework.
> +Everything in the UnitTestFrameworkPkg framework is built around an
object
> called -- conveniently -- the Framework.
>  This Framework object will contain all the information about our test,
the
> test suites and test cases associated
>  with it, the current location within the test pass, and any results that
have
> been recorded so far.
> 
> @@ -102,7 +157,7 @@ The long name and version strings are just for user
> presentation and relatively
>  will be used to name any cache files and/or test results, so should be a
name
> that makes sense in that context.
>  These strings are copied internally to the Framework, so using
> stack-allocated or literal strings is fine.
> 
> -In the 'SampleUnitTestUefiShell' app, the module name is used as the
short
> name, so the init looks like this.
> +In the 'SampleUnitTestUefiShell' app, the module name is used as the
short
> name, so the initialization looks like this.
> 
>  ```c
>  DEBUG(( DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME,
> UNIT_TEST_APP_VERSION ));
> @@ -144,11 +199,11 @@ will be used when adding test cases.
>  Great! Now we've finished some of the cruft, red tape, and busy work.
We're
> ready to add some tests. Adding a test
>  to a test suite is accomplished with the -- you guessed it --
`AddTestCase`
> function. It takes in the suite handle;
>  a `CHAR8` string for the description and class name; a function pointer
for
> the test case itself; additional, optional
> -function pointers for prerequisite check and cleanup routines; and and
> optional pointer to a context structure.
> +function pointers for prerequisite check and cleanup routines; and an
> optional pointer to a context structure.
> 
>  Okay, that's a lot. Let's take it one piece at a time. The description
and class
> name strings are very similar in
>  usage to the suite title and package name strings in the test suites. The
> former is for user presentation and the
> -latter is for xUnit parsing. The test case function pointer is what is
actually
> executed as the "test" and the
> +latter is for xUnit parsing. The test case function pointer is what is
executed
> as the "test" and the
>  prototype should be `UNIT_TEST_FUNCTION`. The last three parameters
> require a little bit more explaining.
> 
>  The prerequisite check function has a prototype of
> `UNIT_TEST_PREREQUISITE` and -- if provided -- will be called
> @@ -180,7 +235,7 @@ Once all the suites and cases are added, it's time to
> run the Framework.
>  Status = RunAllTestSuites( Framework );
>  ```
> 
> -### A Simple Test Case
> +### Framework - A Simple Test Case
> 
>  We'll take a look at the below test case from 'SampleUnitTestApp'...
> 
> @@ -217,9 +272,9 @@ _Note_ that this early return can have implications
for
> memory leakage.
> 
>  At the end, if all test criteria pass, you should return
`UNIT_TEST_PASSED`.
> 
> -### More Complex Cases
> +### Framework - More Complex Cases
> 
> -To write more advanced tests, first take a look at all the Assertion and
> Logging macros provided in the framework.
> +To write more advanced tests, first look at all the Assertion and Logging
> macros provided in the framework.
> 
>  Beyond that, if you're writing host-based tests and want to take a
> dependency on the UnitTestFrameworkPkg, you can
>  leverage the `cmocka.h` interface and write tests with all the features
of the
> Cmocka framework.
> @@ -227,6 +282,125 @@ leverage the `cmocka.h` interface and write tests
> with all the features of the C
>  Documentation for Cmocka can be found here:
>  https://api.cmocka.org/
> 
> +## GoogleTest Samples
> +
> +There is a sample unit test provided as both an example of how to write a
> unit test and leverage
> +many of the GoogleTest features. This sample can be found in the
> `Test/GoogleTest/Sample/SampleGoogleTest`
> +directory.
> +
> +The sample is provided for the HOST_APPLICATION build type, which can be
> run on a host system without
> +needing a target.
> +
> +## GoogleTest Usage
> +
> +This section is built a lot like a "Getting Started". We'll go through
some of
> the components that are needed
> +when constructing a unit test and some of the decisions that are made by
> the test writer. We'll also describe
> +how to check for expected conditions in test cases and a bit of the
logging
> characteristics.
> +
> +Most of these examples will refer to the SampleGoogleTestHost app found
in
> this package.
> +
> +### GoogleTest Requirements - INF
> +
> +In our INF file, we'll need to bring in the `GoogleTest` library.
Conveniently,
> the interface
> +header for the `GoogleTest` is in `UnitTestFrameworkPkg`, so you
shouldn't
> need to depend on any other
> +packages. As long as your DSC file knows where to find the lib
> implementation that you want to use,
> +you should be good to go.
> +
> +See this example in 'SampleGoogleTestHost.inf'...
> +
> +```
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
> +
> +[LibraryClasses]
> +  GoogleTestLib
> +  BaseLib
> +  DebugLib
> +```
> +
> +Also, if you want you 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`...
> +
> +```
> +[Defines]
> +  BASE_NAME      = SampleGoogleTestHost
> +```
> +
> +### GoogleTest Requirements - Code
> +
> +Not to state the obvious, but let's make sure we have the following
include
> before getting too far along...
> +
> +```
> +#include <gtest/gtest.h>
> +extern "C" {
> +  #include <Uefi.h>
> +  #include <Library/BaseLib.h>
> +  #include <Library/DebugLib.h>
> +}
> +```
> +
> +GoogleTest applications are implemented in C++. The first include brings
in
> the
> +GoogleTest definitions. Other EDK II related include files must be
wrapped in
> +`extern "C" {}` because they are C include files. Link failures will
occur if
> +this is not done.
> +
> +Now that we've got that squared away, let's look at our 'Main()'' routine
(or
> DriverEntryPoint() or whatever).
> +
> +### GoogleTest Configuration
> +
> +Unlike the Framework, GoogleTest does not require test suites or test
cases
> to
> +be registered. Instead, the test cases declare the test suite name and
test
> +case name as part of their implementation. The only requirement for
> GoogleTest
> +is to have a `main()` function that initialize the GoogleTest
infrastructure and
> +call the service `RUN_ALL_TESTS()` to run all the unit tests.
> +
> +```c
> +int main(int argc, char* argv[]) {
> +  testing::InitGoogleTest(&argc, argv);
> +  return RUN_ALL_TESTS();
> +}
> +```
> +
> +### GoogleTest - A Simple Test Case
> +
> +We'll look at the below test case from 'SampleGoogleTestHost'...
> +
> +```c
> +TEST(SimpleMathTests, OnePlusOneShouldEqualTwo) {
> +  UINTN  A;
> +  UINTN  B;
> +  UINTN  C;
> +
> +  A = 1;
> +  B = 1;
> +  C = A + B;
> +
> +  ASSERT_EQ (C, 2);
> +}
> +```
> +
> +This uses the simplest form of a GoogleTest unit test using `TEST()` that
> +declares the test suite name and the unit test name within that test
suite.
> +The unit test performs actions and typically makes calls to the code
under
> test
> +and contains test assertions to verify that the code under test behaves
as
> +expected for the given inputs.
> +
> +In this test case, the `ASSERT_EQ` assertion is being used to establish
that
> the business logic has functioned
> +correctly. There are several assertion macros, and you are encouraged to
> use one that matches as closely to your
> +intended test criterium as possible, because the logging is specific to
the
> macro and more specific macros have more
> +detailed logs. When in doubt, there are always `ASSERT_TRUE` and
> `ASSERT_FALSE`. Assertion macros that fail their
> +test criterium will immediately return from the test case with a failed
status
> and log an error string.
> +_Note_ that this early return can have implications for memory leakage.
> +
> +There is no return status from a GooglTest unit test. If no assertions
are
> +triggered then the unit test has a passing status.
> +
> +### GoogleTest - More Complex Cases
> +
> +To write more advanced tests, take a look at the
> +[GoogleTest User's Guide](http://google.github.io/googletest/).
> +
>  ## Development
> 
>  ### Iterating on a Single Test
> @@ -243,11 +417,11 @@ stuart_ci_build -c .pytool/CISettings.py
> TOOL_CHAIN_TAG=VS2017 -p MdePkg -t NOOP
> 
>  ### Hooking BaseLib
> 
> -Most unit test mocking can be performed by the functions provided in the
> UnitTestFramework libraries, but since
> +Most unit test mocking can be performed by the functions provided in the
> UnitTestFrameworkPkg libraries, but since
>  BaseLib is consumed by the Framework itself, it requires different
techniques
> to substitute parts of the
>  functionality.
> 
> -To solve some of this, the UnitTestFramework consumes a special
> implementation of BaseLib for host-based tests.
> +To solve some of this, the UnitTestFrameworkPkg consumes a special
> implementation of BaseLib for host-based tests.
>  This implementation contains a [hook
> table](https://github.com/tianocore/edk2/blob/e188ecc8b4aed8fdd26b731d
> 43883861f5e5e7b4/MdePkg/Test/UnitTest/Include/Library/UnitTestHostBase
> Lib.h#L507)
>  that can be used to substitute test functionality for any of the BaseLib
> functions. By default, this implementation
>  will use the underlying BaseLib implementation, so the unit test writer
only
> has to supply minimal code to test a
> @@ -255,7 +429,7 @@ particular case.
> 
>  ### Debugging the Framework Itself
> 
> -While most of the tests that are produced by the UnitTestFramework are
> easy to step through in a debugger, the Framework
> +While most of the tests that are produced by the UnitTestFrameworkPkg are
> easy to step through in a debugger, the Framework
>  itself consumes code (mostly Cmocka) that sets its own build flags. These
> flags cause parts of the Framework to not
>  export symbols and captures exceptions, and as such are harder to debug.
> We have provided a Stuart parameter to force
>  symbolic debugging to be enabled.
> @@ -269,15 +443,17 @@ stuart_ci_build -c .pytool/CISettings.py
> TOOL_CHAIN_TAG=VS2019 -p MdePkg -t NOOP
>  ## Building and Running Host-Based Tests
> 
>  The EDK2 CI infrastructure provides a convenient way to run all
host-based
> tests -- in the the entire tree or just
> -selected packages -- and aggregate all the the reports, including
highlighting
> any failures. This functionality is
> -provided through the Stuart build system (published by EDK2-PyTools) and
> the `NOOPT` build target.
> +selected packages -- and aggregate all the reports, including
highlighting any
> failures. This functionality is
> +provided through the Stuart build system (published by EDK2-PyTools) and
> the `NOOPT` build target. The sections that
> +follow use Framework examples. Unit tests based on GoogleTest are built
> and run the same way. The text output and
> +JUNIT XML output format have small differences.
> 
>  ### Building Locally
> 
>  First, to make sure you're working with the latest PyTools, run the
following
> command:
> 
>  ```bash
> -# Would recommend to run this in a Python venv, but that's out of scope
for
> this doc.
> +# Would recommend running this in a Python venv, but that's out of scope
for
> this doc.
>  python -m pip install --upgrade -r ./pip-requirements.txt
>  ```
> 
> @@ -361,7 +537,7 @@ RUNNING TEST SUITE: Int Safe Conversions Test
> Suite
>  ```
> 
>  You can also, if you are so inclined, read the output from the exact
instance
> of the test that was run during
> -`stuart_ci_build`. The ouput file can be found on a path that looks like:
> +`stuart_ci_build`. The output file can be found on a path that looks
like:
> 
> 
> `Build/<Package>/HostTest/<Arch>/<TestName>.<TestSuiteName>.<Arch>.re
> sult.xml`
> 
> @@ -389,22 +565,30 @@
> c:\_uefi\MdePkg\Test\UnitTest\Library\BaseSafeIntLib\TestBaseSafeIntLib.c:
> 35: er
> 
>  ### XML Reporting Mode
> 
> -Since these applications are built using the CMocka framework, they can
also
> use the following env variables to output
> -in a structured XML rather than text:
> +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:
> 
> -```text
> +```
>  CMOCKA_MESSAGE_OUTPUT=xml
>  CMOCKA_XML_FILE=<absolute or relative path to output file>
>  ```
> 
> +Unit test applications using GoogleTest require the following environment
> +variable to be set to generate structured XML output rather than text:
> +
> +```
> +GTEST_OUTPUT=xml:<absolute or relative path to output file>
> +```
> +
>  This mode is used by the test running plugin to aggregate the results for
CI
> test status reporting in the web view.
> 
>  ### Important Note
> 
> -This works on both Windows and Linux, but is currently limited to x64
> architectures. Working on getting others, but we
> +This works on both Windows and Linux but is currently limited to x64
> architectures. Working on getting others, but we
>  also welcome contributions.
> 
> -## Known Limitations
> +## Framework Known Limitations
> 
>  ### PEI, DXE, SMM
> 
> @@ -418,7 +602,7 @@ PEI, DXE, and SMM is forthcoming, but should be
> considered beta/staging for now.
>  The host-based test framework is powered internally by the Cmocka
> framework. As such, it has abilities
>  that the target-based tests don't (yet). It would be awesome if this
meant
> that it was a super set of
>  the target-based tests, and it worked just like the target-based tests
but
> with more features. Unfortunately,
> -this is not the case. While care has been taken to keep them as close a
> possible, there are a few known
> +this is not the case. While care has been taken to keep them as close as
> possible, there are a few known
>  inconsistencies that we're still ironing out. For example, the logging
> messages in the target-based tests
>  are cached internally and associated with the running test case. They can
be
> saved later as part of the
>  reporting lib. This isn't currently possible with host-based. Only the
assertion
> failures are logged.
> @@ -441,6 +625,9 @@ Non-Host-Based (PEI/DXE/SMM/Shell) Tests for a
> Functionality or Feature   | Simi
>    ComponentY/
>      ComponentY.inf
>      ComponentY.c
> +    GoogleTest/
> +      ComponentYHostGoogleTest.inf    # Host-Based Test for Driver
> Module
> +      ComponentYGoogleTest.cpp
>      UnitTest/
>        ComponentYHostUnitTest.inf      # Host-Based Test for Driver
> Module
>        ComponentYUnitTest.c
> @@ -455,11 +642,23 @@ Non-Host-Based (PEI/DXE/SMM/Shell) Tests for a
> Functionality or Feature   | Simi
>      SpecificLibDxe/
>        SpecificLibDxe.c
>        SpecificLibDxe.inf
> +      GoogleTest/                    # Host-Based Test for Specific
> Library Implementation
> +        SpecificLibDxeHostGoogleTest.cpp
> +        SpecificLibDxeHostGoogleTest.inf
>        UnitTest/                      # Host-Based Test for Specific
> Library Implementation
>          SpecificLibDxeHostUnitTest.c
>          SpecificLibDxeHostUnitTest.inf
>    Test/
>      <Package>HostTest.dsc             # Host-Based Test Apps
> +    GoogleTest/
> +      InterfaceX
> +        InterfaceXHostGoogleTest.inf  # Host-Based App (should be in
> Test/<Package>HostTest.dsc)
> +        InterfaceXUnitTest.cpp        # Test Logic
> +
> +      GeneralPurposeLib/              # Host-Based Test for any
> implementation of GeneralPurposeLib
> +        GeneralPurposeLibTest.cpp
> +        GeneralPurposeLibHostUnitTest.inf
> +
>      UnitTest/
>        InterfaceX
>          InterfaceXHostUnitTest.inf    # Host-Based App (should be in
> Test/<Package>HostTest.dsc)
> diff --git
> a/UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/Sampl
> eGoogleTest.cpp
> b/UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/Sampl
> eGoogleTest.cpp
> new file mode 100644
> index 000000000000..c83e58596a82
> --- /dev/null
> +++
> b/UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/Sampl
> eGoogleTest.cpp
> @@ -0,0 +1,263 @@
> +/** @file
> +  This is a sample to demonstrates the use of GoogleTest that supports
host
> +  execution environments.
> +
> +  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <gtest/gtest.h>
> +extern "C" {
> +  #include <Uefi.h>
> +  #include <Library/BaseLib.h>
> +  #include <Library/DebugLib.h>
> +}
> +
> +/**
> +  Sample unit test that verifies the expected result of an unsigned
integer
> +  addition operation.
> +**/
> +TEST(SimpleMathTests, OnePlusOneShouldEqualTwo) {
> +  UINTN  A;
> +  UINTN  B;
> +  UINTN  C;
> +
> +  A = 1;
> +  B = 1;
> +  C = A + B;
> +
> +  ASSERT_EQ (C, (UINTN)2);
> +}
> +
> +/**
> +  Sample unit test that verifies that a global BOOLEAN is updatable.
> +**/
> +class GlobalBooleanVarTests : public ::testing::Test {
> +  public:
> +    BOOLEAN  SampleGlobalTestBoolean  = FALSE;
> +};
> +
> +TEST_F(GlobalBooleanVarTests, GlobalBooleanShouldBeChangeable) {
> +  SampleGlobalTestBoolean = TRUE;
> +  ASSERT_TRUE (SampleGlobalTestBoolean);
> +
> +  SampleGlobalTestBoolean = FALSE;
> +  ASSERT_FALSE (SampleGlobalTestBoolean);
> +}
> +
> +/**
> +  Sample unit test that logs a warning message and verifies that a global
> +  pointer is updatable.
> +**/
> +class GlobalVarTests : public ::testing::Test {
> +  public:
> +    VOID  *SampleGlobalTestPointer = NULL;
> +
> +  protected:
> +  void SetUp() override {
> +    ASSERT_EQ ((UINTN)SampleGlobalTestPointer, (UINTN)NULL);
> +  }
> +  void TearDown() {
> +    SampleGlobalTestPointer = NULL;
> +  }
> +};
> +
> +TEST_F(GlobalVarTests, GlobalPointerShouldBeChangeable) {
> +  SampleGlobalTestPointer = (VOID *)-1;
> +  ASSERT_EQ ((UINTN)SampleGlobalTestPointer, (UINTN)((VOID *)-1));
> +}
> +
> +
> +/**
> +  Set PcdDebugPropertyMask for each MacroTestsAssertsEnabledDisabled
> test
> +**/
> +class MacroTestsAssertsEnabledDisabled : public
> testing::TestWithParam<UINT8> {
> +  void SetUp() {
> +    PatchPcdSet8 (PcdDebugPropertyMask, GetParam());
> +  }
> +};
> +
> +/**
> +  Sample unit test using the ASSERT_TRUE() macro.
> +**/
> +TEST_P(MacroTestsAssertsEnabledDisabled, MacroAssertTrue) {
> +  UINT64  Result;
> +
> +  //
> +  // This test passes because expression always evaluated to TRUE.
> +  //
> +  ASSERT_TRUE (TRUE);
> +
> +  //
> +  // This test passes because expression always evaluates to TRUE.
> +  //
> +  Result = LShiftU64 (BIT0, 1);
> +  ASSERT_TRUE (Result == BIT1);
> +}
> +
> +/**
> +  Sample unit test using the ASSERT_FALSE() macro.
> +**/
> +TEST_P(MacroTestsAssertsEnabledDisabled, MacroAssertFalse) {
> +  UINT64  Result;
> +
> +  //
> +  // This test passes because expression always evaluated to FALSE.
> +  //
> +  ASSERT_FALSE (FALSE);
> +
> +  //
> +  // This test passes because expression always evaluates to FALSE.
> +  //
> +  Result = LShiftU64 (BIT0, 1);
> +  ASSERT_FALSE (Result == BIT0);
> +}
> +
> +/**
> +  Sample unit test using the ASSERT_EQ() macro.
> +**/
> +TEST_P(MacroTestsAssertsEnabledDisabled, MacroAssertEqual) {
> +  UINT64  Result;
> +
> +  //
> +  // This test passes because both values are always equal.
> +  //
> +  ASSERT_EQ (1, 1);
> +
> +  //
> +  // This test passes because both values are always equal.
> +  //
> +  Result = LShiftU64 (BIT0, 1);
> +  ASSERT_EQ (Result, (UINT64)BIT1);
> +}
> +
> +/**
> +  Sample unit test using the ASSERT_STREQ() macro.
> +**/
> +TEST_P(MacroTestsAssertsEnabledDisabled, MacroAssertMemEqual) {
> +  CHAR8  *String1;
> +  CHAR8  *String2;
> +
> +  //
> +  // This test passes because String1 and String2 are the same.
> +  //
> +  String1 = (CHAR8 *)"Hello";
> +  String2 = (CHAR8 *)"Hello";
> +  ASSERT_STREQ (String1, String2);
> +}
> +
> +/**
> +  Sample unit test using the ASSERT_NE() macro.
> +**/
> +TEST_P(MacroTestsAssertsEnabledDisabled, MacroAssertNotEqual) {
> +  UINT64  Result;
> +
> +  //
> +  // This test passes because both values are never equal.
> +  //
> +  ASSERT_NE (0, 1);
> +
> +  //
> +  // This test passes because both values are never equal.
> +  //
> +  Result = LShiftU64 (BIT0, 1);
> +  ASSERT_NE (Result, (UINT64)BIT0);
> +}
> +
> +/**
> +  Sample unit test using the ASSERT_TRUE() and ASSERT(FALSE)
> +  and EFI_EFFOR() macros to check status
> +**/
> +TEST_P(MacroTestsAssertsEnabledDisabled, MacroAssertNotEfiError) {
> +  //
> +  // This test passes because the status is not an EFI error.
> +  //
> +  ASSERT_FALSE (EFI_ERROR (EFI_SUCCESS));
> +
> +  //
> +  // This test passes because the status is not an EFI error.
> +  //
> +  ASSERT_FALSE (EFI_ERROR (EFI_WARN_BUFFER_TOO_SMALL));
> +}
> +
> +/**
> +  Sample unit test using the ASSERT_EQ() macro to compare EFI_STATUS
> values.
> +**/
> +TEST_P(MacroTestsAssertsEnabledDisabled, MacroAssertStatusEqual) {
> +  //
> +  // This test passes because the status value are always equal.
> +  //
> +  ASSERT_EQ (EFI_SUCCESS, EFI_SUCCESS);
> +}
> +
> +/**
> +  Sample unit test using ASSERT_NE() macro to make sure a pointer is not
> NULL.
> +**/
> +TEST_P(MacroTestsAssertsEnabledDisabled, MacroAssertNotNull) {
> +  UINT64  Result;
> +
> +  //
> +  // This test passes because the pointer is never NULL.
> +  //
> +  ASSERT_NE (&Result, (UINT64 *)NULL);
> +}
> +
> +/**
> +  Sample unit test using that should not generate any ASSERTs()
> +**/
> +TEST_P(MacroTestsAssertsEnabledDisabled, MacroExpectNoAssertFailure) {
> +  //
> +  // This test passes because it never triggers an ASSERT().
> +  //
> +  ASSERT (TRUE);
> +
> +  //
> +  // This test passes because DecimalToBcd() does not ASSERT() if the
> +  // value passed in is <= 99.
> +  //
> +  DecimalToBcd8 (99);
> +}
> +
> +/**
> +  Sample unit test using the ASSERT_DEATH() macro to test expected
> ASSERT()s.
> +**/
> +TEST_P(MacroTestsAssertsEnabledDisabled, MacroExpectAssertFailure) {
> +  //
> +  // Skip tests that verify an ASSERT() is triggered if ASSERT()s are
disabled.
> +  //
> +  if ((PcdGet8 (PcdDebugPropertyMask) & BIT0) == 0x00) {
> +    return;
> +  }
> +
> +  //
> +  // This test passes because it directly triggers an ASSERT().
> +  //
> +  ASSERT_DEATH (ASSERT (FALSE), "");
> +
> +  //
> +  // This test passes because DecimalToBcd() generates an ASSERT() if the
> +  // value passed in is >= 100.  The expected ASSERT() is caught by the
unit
> +  // test framework and ASSERT_DEATH() returns without an error.
> +  //
> +  ASSERT_DEATH (DecimalToBcd8 (101), "");
> +}
> +
> +INSTANTIATE_TEST_SUITE_P(ValidInput,
> +                         MacroTestsAssertsEnabledDisabled,
> +                         ::testing::Values(PcdGet8
> (PcdDebugPropertyMask) | BIT0, PcdGet8 (PcdDebugPropertyMask) &
> (~BIT0)));
> +
> +/**
> +  Sample unit test using the SCOPED_TRACE() macro for trace messages.
> +**/
> +TEST(MacroTestsMessages, MacroTraceMessage) {
> +  //
> +  // Example of logging.
> +  //
> +  SCOPED_TRACE ("SCOPED_TRACE message\n");
> +}
> +
> +int main(int argc, char* argv[]) {
> +  testing::InitGoogleTest(&argc, argv);
> +  return RUN_ALL_TESTS();
> +}
> diff --git
> a/UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/Sampl
> eGoogleTestHost.inf
> b/UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/Sampl
> eGoogleTestHost.inf
> new file mode 100644
> index 000000000000..37e7c86910ed
> --- /dev/null
> +++
> b/UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/Sampl
> eGoogleTestHost.inf
> @@ -0,0 +1,35 @@
> +## @file
> +# This is a sample to demonstrates the use of GoogleTest that supports
host
> +# execution environments.
> +#
> +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> +  INF_VERSION    = 0x00010005
> +  BASE_NAME      = SampleGoogleTestHost
> +  FILE_GUID      = 7D8BBFBB-7977-4AEE-A59F-257BF5C2F87C
> +  MODULE_TYPE    = HOST_APPLICATION
> +  VERSION_STRING = 1.0
> +
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64
> +#
> +
> +[Sources]
> +  SampleGoogleTest.cpp
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
> +
> +[LibraryClasses]
> +  GoogleTestLib
> +  BaseLib
> +  DebugLib
> +
> +[Pcd]
> +  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask
> diff --git a/UnitTestFrameworkPkg/Test/UnitTestFrameworkPkgHostTest.dsc
> b/UnitTestFrameworkPkg/Test/UnitTestFrameworkPkgHostTest.dsc
> index 184fdec87acf..708ef7f9ab35 100644
> --- a/UnitTestFrameworkPkg/Test/UnitTestFrameworkPkgHostTest.dsc
> +++ b/UnitTestFrameworkPkg/Test/UnitTestFrameworkPkgHostTest.dsc
> @@ -23,14 +23,16 @@ [PcdsPatchableInModule]
> 
>  [Components]
>    #
> -  # Build HOST_APPLICATION that tests the SampleUnitTest
> +  # Build HOST_APPLICATIONs that test the SampleUnitTest
>    #
> 
> UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTe
> stHost.inf
> +
> UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/SampleG
> oogleTestHost.inf
> 
>    #
>    # Build HOST_APPLICATION Libraries
>    #
>    UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf
> +  UnitTestFrameworkPkg/Library/GoogleTestLib/GoogleTestLib.inf
>    UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf
> 
> UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllo
> cationLibPosix.inf
>    UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf
> diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.ci.yaml
> b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.ci.yaml
> index 77d51e13484c..072df6208c92 100644
> --- a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.ci.yaml
> +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.ci.yaml
> @@ -78,7 +78,8 @@
>      "SpellCheck": {
>          "AuditOnly": False,           # Fails test but run in AuditOnly
> mode to collect log
>          "IgnoreFiles": [             # use gitignore syntax to ignore
> errors in matching files
> -            "Library/CmockaLib/cmocka/**/*.*"  # not going to spell
> check a submodule
> +            "Library/CmockaLib/cmocka/**/*.*",  # not going to spell
> check a submodule
> +            "Library/GoogleTestLib/googletest/**/*.*"  # not going to
> spell check a submodule
>          ],
>          "ExtendWords": [             # words to extend to the
> dictionary for this package
>              "testcase",
> @@ -91,6 +92,7 @@
>              "NOFAILURE",
>              "cmockery",
>              "DHAVE", # build flag for cmocka in the INF
> +            "gtest", # file name in GoogleTestLib.inf
>              "corthon",      # Contact GitHub account in Readme
>              "mdkinney",     # Contact GitHub account in Readme
>              "spbrogan"      # Contact GitHub account in Readme
> diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
> b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
> index 069289f00969..ed12f32009d8 100644
> --- a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
> +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
> @@ -16,11 +16,15 @@ [Defines]
>    PACKAGE_VERSION   = 1.00
> 
>  [Includes]
> +  Include
>    Library/CmockaLib/cmocka/include
> +  Library/GoogleTestLib/googletest/googletest/include
> +  Library/GoogleTestLib/googletest/googlemock/include
> 
>  [Includes.Common.Private]
>    PrivateInclude
>    Library/CmockaLib/cmocka/include/cmockery
> +  Library/GoogleTestLib/googletest/googletest
> 
>  [LibraryClasses.Common.Private]
>    ## @libraryclass Allows save and restore unit test internal state
> @@ -35,6 +39,10 @@ [LibraryClasses.Common.Private]
>    #
>    UnitTestBootLib|PrivateInclude/Library/UnitTestBootLib.h
> 
> +  ## @libraryclass GoogleTest infrastructure
> +  #
> +  GoogleTestLib|Include/Library/GoogleTestLib.h
> +
>  [Guids]
>    gUnitTestFrameworkPkgTokenSpaceGuid = { 0x833d3aba, 0x39b4, 0x43a2,
> { 0xb9, 0x30, 0x7a, 0x34, 0x53, 0x39, 0x31, 0xb3 } }
> 
> diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc
> b/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc
> index f249813713a8..6d5f651f689f 100644
> --- a/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc
> +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc
> @@ -14,6 +14,7 @@ [LibraryClasses.common.HOST_APPLICATION]
>    CpuLib|MdePkg/Library/BaseCpuLibNull/BaseCpuLibNull.inf
> 
> CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLibNull/Base
> CacheMaintenanceLibNull.inf
>    CmockaLib|UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf
> +
> GoogleTestLib|UnitTestFrameworkPkg/Library/GoogleTestLib/GoogleTestLib.i
> nf
> 
> UnitTestLib|UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.i
> nf
> 
> DebugLib|UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosi
> x.inf
> 
> MemoryAllocationLib|UnitTestFrameworkPkg/Library/Posix/MemoryAllocatio
> nLibPosix/MemoryAllocationLibPosix.inf
> @@ -30,6 +31,7 @@ [BuildOptions.common.EDKII.HOST_APPLICATION]
>    #
>    # MSFT
>    #
> +  MSFT:*_*_*_CC_FLAGS               = /EHsc
>    MSFT:*_*_*_DLINK_FLAGS            ==
> /out:"$(BIN_DIR)\$(MODULE_NAME_GUID).exe"
> /pdb:"$(BIN_DIR)\$(MODULE_NAME_GUID).pdb" /IGNORE:4001 /NOLOGO
> /SUBSYSTEM:CONSOLE /DEBUG /STACK:0x40000,0x40000
> /NODEFAULTLIB:libcmt.lib libcmtd.lib
>    MSFT:*_*_IA32_DLINK_FLAGS         = /MACHINE:I386
>    MSFT:*_*_X64_DLINK_FLAGS          = /MACHINE:AMD64
> @@ -49,7 +51,7 @@ [BuildOptions.common.EDKII.HOST_APPLICATION]
>    #
>    GCC:*_*_IA32_DLINK_FLAGS == -o $(BIN_DIR)/$(MODULE_NAME_GUID)
> -m32 -no-pie
>    GCC:*_*_X64_DLINK_FLAGS  == -o
> $(BIN_DIR)/$(MODULE_NAME_GUID) -m64 -no-pie
> -  GCC:*_*_*_DLINK2_FLAGS   == -lgcov
> +  GCC:*_*_*_DLINK2_FLAGS   == -lgcov -lpthread -lstdc++ -lm
> 
>    #
>    # Need to do this link via gcc and not ld as the pathing to libraries
changes
> from OS version to OS version
> --
> 2.37.1.windows.1
> 
> 
> 
> 
> 
> 
> 






-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#96075): https://edk2.groups.io/g/devel/message/96075
Mute This Topic: https://groups.io/mt/94885945/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list