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.

A few typos in Readme.md are also fixed.

Cc: Michael Kubacki <mikuback@linux.microsoft.com>
Cc: Sean Brogan <sean.brogan@microsoft.com>
Cc: Andrew Fish <afish@apple.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com>
Reviewed-by: Michael Kubacki <mikuback@linux.microsoft.com>
Acked-by: Leif Lindholm <quic_llindhol@quicinc.com>
This commit is contained in:
Michael D Kinney 2022-06-20 19:52:03 -07:00 committed by mergify[bot]
parent c1b073a9dc
commit cef0c5c684
13 changed files with 611 additions and 31 deletions

3
.gitmodules vendored
View File

@ -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

View File

@ -93,6 +93,7 @@ that are covered by additional licenses.
- `MdeModulePkg/Library/BrotliCustomDecompressLib/brotli <https://github.com/google/brotli/blob/666c3280cc11dc433c303d79a83d4ffbdd12cc8d/LICENSE>`__
- `MdeModulePkg/Universal/RegularExpressionDxe/oniguruma <https://github.com/kkos/oniguruma/blob/abfc8ff81df4067f309032467785e06975678f0d/COPYING>`__
- `UnitTestFrameworkPkg/Library/CmockaLib/cmocka <https://github.com/tianocore/edk2-cmocka/blob/f5e2cd77c88d9f792562888d2b70c5a396bfbf7a/COPYING>`__
- `UnitTestFrameworkPkg/Library/GoogleTestLib/googletest <https://github.com/google/googletest/blob/86add13493e5c881d7e4ba77fb91c1f57752b3a4/LICENSE>`__
- `RedfishPkg/Library/JsonLib/jansson <https://github.com/akheron/jansson/blob/2882ead5bb90cf12a01b07b2c2361e24960fae02/LICENSE>`__
The EDK II Project is composed of packages. The maintainers for each package

View File

@ -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

View File

@ -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

View File

@ -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."

@ -0,0 +1 @@
Subproject commit 86add13493e5c881d7e4ba77fb91c1f57752b3a4

View File

@ -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/e188ecc8b4aed8fdd26b731d43883861f5e5e7b4/MdePkg/Test/UnitTest/Include/Library/UnitTestHostBaseLib.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>.result.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)

View File

@ -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();
}

View File

@ -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

View File

@ -23,14 +23,16 @@
[Components]
#
# Build HOST_APPLICATION that tests the SampleUnitTest
# Build HOST_APPLICATIONs that test the SampleUnitTest
#
UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestHost.inf
UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/SampleGoogleTestHost.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/MemoryAllocationLibPosix.inf
UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf

View File

@ -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

View File

@ -16,11 +16,15 @@
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 @@
#
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 } }

View File

@ -14,6 +14,7 @@
CpuLib|MdePkg/Library/BaseCpuLibNull/BaseCpuLibNull.inf
CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLibNull/BaseCacheMaintenanceLibNull.inf
CmockaLib|UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf
GoogleTestLib|UnitTestFrameworkPkg/Library/GoogleTestLib/GoogleTestLib.inf
UnitTestLib|UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf
DebugLib|UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf
MemoryAllocationLib|UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf
@ -31,6 +32,7 @@
#
# 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
@ -50,7 +52,7 @@
#
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