VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/UnitTestFrameworkPkg/ReadMe.md

Last change on this file was 108794, checked in by vboxsync, 4 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 75.6 KB
Line 
1# Unit Test Framework Package
2
3## About
4
5This package provides unit test frameworks capable of building tests for multiple contexts including
6the UEFI shell environment and host-based environments. It allows for unit test development to focus
7on the tests and leave error logging, result formatting, context persistence, and test running to the framework.
8The unit test framework works well for low level unit tests as well as system level tests and
9fits easily in automation frameworks.
10
11### Framework
12
13The first unit test framework is called **Framework** and is implemented as a set of EDK II libraries.
14The Framework supports both host-based unit tests and target-based unit tests that share the same
15source style, macros, and APIs. In some scenarios, the same unit test case sources can be built
16for both host-based unit test execution and target-based unit test execution. Host-based unit tests
17that require mocked interfaces can use the mocking infrastructure provided by
18[cmocka](https://api.cmocka.org/) that is included in the UnitTestFrameworkPkg as a submodule.
19
20### GoogleTest
21
22The second unit test framework supported by the UnitTestFrameworkPkg is
23[GoogleTest](http://google.github.io/googletest/) and can be used to implement host-based unit tests.
24[GoogleTest on GitHub](https://github.com/google/googletest) is included in the UnitTestFrameworkPkg
25as a submodule. Use of GoogleTest for target-based unit tests of EDK II components is not supported.
26Host-based unit tests that require mocked interfaces can use the mocking infrastructure included with
27GoogleTest called [gMock](https://github.com/google/googletest/tree/main/googlemock). Note that the
28gMock framework does not directly support mocking of free (C style) functions, so the FunctionMockLib
29(containing a set of macros that wrap gMock's MOCK_METHOD macro) was created within the
30UnitTestFrameworkPkg to enable this support. The details and usage of these macros in the
31FunctionMockLib are described later.
32
33GoogleTest requires less overhead to register test suites and test cases compared to the Framework.
34There are also a number of tools that layer on top of GoogleTest that improve developer productivity.
35One example is the VS Code extension
36[C++ TestMate](https://marketplace.visualstudio.com/items?itemName=matepek.vscode-catch2-test-adapter)
37that may be used to implement, run, and debug unit tests implemented using GoogleTest. The following
38is an example of the C++ TestMate JSON configuration to find unit tests and configure the environment
39for unit test execution.
40
41```
42"testMate.cpp.test.advancedExecutables": [
43 {
44 "pattern": "Build/**/*Test*",
45 "cwd": "${absDirpath}",
46 "env": {
47 "GTEST_CATCH_EXCEPTIONS": "0",
48 "ASAN_OPTIONS": "detect_leaks=0",
49 }
50 }
51],
52```
53
54If a component can be tested with host-based unit tests, then GoogleTest is recommended. The MdePkg
55contains a port of the BaseSafeIntLib unit tests in the GoogleTest style so the differences between
56GoogleTest and Framework unit tests can be reviewed. The paths to the BaseSafeIntLib unit tests are:
57
58* `MdePkg/Test/UnitTest/Library/BaseSafeIntLib`
59* `MdePkg/Test/GoogleTest/Library/BaseSafeIntLib`
60
61Furthermore, the SecurityPkg contains unit tests for the SecureBootVariableLib using mocks in both
62the Framework/cmocka and GoogleTest/gMock style so the differences between cmocka and gMock can be
63reviewed. The paths to the SecureBootVariableLib unit tests are:
64
65* `SecurityPkg/Library/SecureBootVariableLib/UnitTest`
66* `SecurityPkg/Library/SecureBootVariableLib/GoogleTest`
67
68## Framework and GoogleTest Feature Comparison
69
70| Feature | Framework | GoogleTest |
71|:----------------------------|:---------:|:----------:|
72| Host Based Unit Tests | YES | YES |
73| Target Based Unit Tests | YES | NO |
74| Unit Test Source Language | C | C++ |
75| Register Test Suite | YES | Auto |
76| Register Test Case | YES | Auto |
77| Expected Assert Tests | YES | YES |
78| Setup/Teardown Hooks | YES | YES |
79| Value-Parameterized Tests | NO | YES |
80| Typed Tests | NO | YES |
81| Type-Parameterized Tests | NO | YES |
82| Timeout Support | NO | YES |
83| Mocking Support | Cmocka | gMock |
84| JUNIT XML Reports | YES | YES |
85| Execute subset of tests | NO | YES |
86| VS Code Extensions | NO | YES |
87| Address Sanitizer | Cmocka | YES |
88
89## Framework Libraries
90
91### UnitTestLib
92
93The main "framework" library. The core of the framework is the Framework object, which can have any number
94of test cases and test suites registered with it. The Framework object is also what drives test execution.
95
96The Framework also provides helper macros and functions for checking test conditions and
97reporting errors. Status and error info will be logged into the test context. There are a number
98of Assert macros that make the unit test code friendly to view and easy to understand.
99
100Finally, the Framework also supports logging strings during the test execution. This data is logged
101to the test context and will be available in the test reporting phase. This should be used for
102logging test details and helpful messages to resolve test failures.
103
104### UnitTestPersistenceLib
105
106Persistence lib has the main job of saving and restoring test context to a storage medium so that for tests
107that require exiting the active process and then resuming state can be maintained. This is critical
108in supporting a system reboot in the middle of a test run.
109
110### UnitTestResultReportLib
111
112Library provides function to run at the end of a framework test run and handles formatting the report.
113This is a common customization point and allows the unit test framework to fit its output reports into
114other test infrastructure. In this package simple library instances have been supplied to output test
115results to the console as plain text.
116
117## Framework Samples
118
119There is a sample unit test provided as both an example of how to write a unit test and leverage
120many of the features of the framework. This sample can be found in the `Test/UnitTest/Sample/SampleUnitTest`
121directory.
122
123The sample is provided in PEI, SMM, DXE, and UEFI App flavors. It also has a flavor for the HOST_APPLICATION
124build type, which can be run on a host system without needing a target.
125
126## Framework Usage
127
128This section is built a lot like a "Getting Started". We'll go through some of the components that are needed
129when constructing a unit test and some of the decisions that are made by the test writer. We'll also describe
130how to check for expected conditions in test cases and a bit of the logging characteristics.
131
132Most of these examples will refer to the `SampleUnitTestUefiShell` app found in this package.
133
134### Framework Requirements - INF
135
136In our INF file, we'll need to bring in the `UnitTestLib` library. Conveniently, the interface
137header for the `UnitTestLib` is located in `MdePkg`, so you shouldn't need to depend on any other
138packages. As long as your DSC file knows where to find the lib implementation that you want to use,
139you should be good to go.
140
141See this example in `SampleUnitTestUefiShell.inf`...
142
143```
144[Packages]
145 MdePkg/MdePkg.dec
146
147[LibraryClasses]
148 UefiApplicationEntryPoint
149 BaseLib
150 DebugLib
151 UnitTestLib
152 PrintLib
153```
154
155Also, if you want your test to automatically be picked up by the Test Runner plugin, you will need
156to make sure that the module `BASE_NAME` contains the word `Test`...
157
158```
159[Defines]
160 BASE_NAME = SampleUnitTestUefiShell
161```
162
163### Framework Requirements - DSC
164
165In our DSC file, we'll need to bring in the INF file that was just created into the `[Components]`
166section so that the unit tests will be built.
167
168See this example in `UnitTestFrameworkPkg.dsc`...
169
170```
171[Components]
172 UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestUefiShell.inf
173```
174
175Also, based on the type of tests that are being created, the associated DSC include file from the
176UnitTestFrameworkPkg for Host or Target based tests should also be included at the top of the DSC
177file.
178
179```
180!include UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc
181```
182
183Lastly, in the case that the test build has specific dependent libraries associated with it,
184they should be added in the \<LibraryClasses\> sub-section for the INF file in the
185`[Components]` section of the DSC file.
186
187See this example in `SecurityPkgHostTest.dsc`...
188
189```
190[Components]
191 SecurityPkg/Library/SecureBootVariableLib/UnitTest/SecureBootVariableLibUnitTest.inf {
192 <LibraryClasses>
193 SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf
194 UefiRuntimeServicesTableLib|SecurityPkg/Library/SecureBootVariableLib/UnitTest/MockUefiRuntimeServicesTableLib.inf
195 PlatformPKProtectionLib|SecurityPkg/Library/SecureBootVariableLib/UnitTest/MockPlatformPKProtectionLib.inf
196 UefiLib|SecurityPkg/Library/SecureBootVariableLib/UnitTest/MockUefiLib.inf
197 }
198```
199
200### Framework Requirements - Code
201
202Not to state the obvious, but let's make sure we have the following include before getting too far along...
203
204```c
205#include <Library/UnitTestLib.h>
206```
207
208Now that we've got that squared away, let's look at our 'Main()' routine (or DriverEntryPoint() or whatever).
209
210### Framework Configuration
211
212Everything in the UnitTestFrameworkPkg framework is built around an object called -- conveniently -- the Framework.
213This Framework object will contain all the information about our test, the test suites and test cases associated
214with it, the current location within the test pass, and any results that have been recorded so far.
215
216To get started with a test, we must first create a Framework instance. The function for this is
217`InitUnitTestFramework`. It takes in `CHAR8` strings for the long name, short name, and test version.
218The long name and version strings are just for user presentation and relatively flexible. The short name
219will be used to name any cache files and/or test results, so should be a name that makes sense in that context.
220These strings are copied internally to the Framework, so using stack-allocated or literal strings is fine.
221
222In the `SampleUnitTestUefiShell` app, the module name is used as the short name, so the initialization looks like this.
223
224```c
225DEBUG(( DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSION ));
226
227//
228// Start setting up the test framework for running the tests.
229//
230Status = InitUnitTestFramework( &Framework, UNIT_TEST_APP_NAME, gEfiCallerBaseName, UNIT_TEST_APP_VERSION );
231```
232
233The `&Framework` returned here is the handle to the Framework. If it's successfully returned, we can start adding
234test suites and test cases.
235
236Test suites exist purely to help organize test cases and to differentiate the results in reports. If you're writing
237a small unit test, you can conceivably put all test cases into a single suite. However, if you end up with 20+ test
238cases, it may be beneficial to organize them according to purpose. You _must_ have at least one test suite, even if
239it's just a catch-all. The function to create a test suite is `CreateUnitTestSuite`. It takes in a handle to
240the Framework object, a `CHAR8` string for the suite title and package name, and optional function pointers for
241a setup function and a teardown function.
242
243The suite title is for user presentation. The package name is for xUnit type reporting and uses a '.'-separated
244hierarchical format (see 'SampleUnitTestApp' for example). If provided, the setup and teardown functions will be
245called once at the start of the suite (before _any_ tests have run) and once at the end of the suite (after _all_
246tests have run), respectively. If either or both of these are unneeded, pass `NULL`. The function prototypes are
247`UNIT_TEST_SUITE_SETUP` and `UNIT_TEST_SUITE_TEARDOWN`.
248
249Looking at `SampleUnitTestUefiShell` app, you can see that the first test suite is created as below...
250
251```c
252//
253// Populate the SimpleMathTests Unit Test Suite.
254//
255Status = CreateUnitTestSuite( &SimpleMathTests, Fw, "Simple Math Tests", "Sample.Math", NULL, NULL );
256```
257
258This test suite has no setup or teardown functions. The `&SimpleMathTests` returned here is a handle to the suite and
259will be used when adding test cases.
260
261Great! Now we've finished some of the cruft, red tape, and busy work. We're ready to add some tests. Adding a test
262to a test suite is accomplished with the -- you guessed it -- `AddTestCase` function. It takes in the suite handle;
263a `CHAR8` string for the description and class name; a function pointer for the test case itself; additional, optional
264function pointers for prerequisite check and cleanup routines; and an optional pointer to a context structure.
265
266Okay, that's a lot. Let's take it one piece at a time. The description and class name strings are very similar in
267usage to the suite title and package name strings in the test suites. The former is for user presentation and the
268latter is for xUnit parsing. The test case function pointer is what is executed as the "test" and the
269prototype should be `UNIT_TEST_FUNCTION`. The last three parameters require a little bit more explaining.
270
271The prerequisite check function has a prototype of `UNIT_TEST_PREREQUISITE` and -- if provided -- will be called
272immediately before the test case. If this function returns any error, the test case will not be run and will be
273recorded as `UNIT_TEST_ERROR_PREREQUISITE_NOT_MET`. The cleanup function (prototype `UNIT_TEST_CLEANUP`) will be called
274immediately after the test case to provide an opportunity to reset any global state that may have been changed in the
275test case. In the event of a prerequisite failure, the cleanup function will also be skipped. If either of these
276functions is not needed, pass `NULL`.
277
278The context pointer is entirely case-specific. It will be passed to the test case upon execution. One of the purposes
279of the context pointer is to allow test case reuse with different input data. (Another use is for testing that wraps
280around a system reboot, but that's beyond the scope of this guide.) The test case must know how to interpret the context
281pointer, so it could be a simple value, or it could be a complex structure. If unneeded, pass `NULL`.
282
283In `SampleUnitTestUefiShell` app, the first test case is added using the code below...
284
285```c
286AddTestCase( SimpleMathTests, "Adding 1 to 1 should produce 2", "Addition", OnePlusOneShouldEqualTwo, NULL, NULL, NULL );
287```
288
289This test case calls the function `OnePlusOneShouldEqualTwo` and has no prerequisite, cleanup, or context.
290
291Once all the suites and cases are added, it's time to run the Framework.
292
293```c
294//
295// Execute the tests.
296//
297Status = RunAllTestSuites( Framework );
298```
299
300### Framework - A Simple Test Case
301
302We'll take a look at the below test case from 'SampleUnitTestApp'...
303
304```c
305UNIT_TEST_STATUS
306EFIAPI
307OnePlusOneShouldEqualTwo (
308 IN UNIT_TEST_FRAMEWORK_HANDLE Framework,
309 IN UNIT_TEST_CONTEXT Context
310 )
311{
312 UINTN A, B, C;
313
314 A = 1;
315 B = 1;
316 C = A + B;
317
318 UT_ASSERT_EQUAL(C, 2);
319 return UNIT_TEST_PASSED;
320} // OnePlusOneShouldEqualTwo()
321```
322
323The prototype for this function matches the `UNIT_TEST_FUNCTION` prototype. It takes in a handle to the Framework
324itself and the context pointer. The context pointer could be cast and interpreted as anything within this test case,
325which is why it's important to configure contexts carefully. The test case returns a value of `UNIT_TEST_STATUS`, which
326will be recorded in the Framework and reported at the end of all suites.
327
328In this test case, the `UT_ASSERT_EQUAL` assertion is being used to establish that the business logic has functioned
329correctly. There are several assertion macros, and you are encouraged to use one that matches as closely to your
330intended test criterium as possible, because the logging is specific to the macro and more specific macros have more
331detailed logs. When in doubt, there are always `UT_ASSERT_TRUE` and `UT_ASSERT_FALSE`. Assertion macros that fail their
332test criterium will immediately return from the test case with `UNIT_TEST_ERROR_TEST_FAILED` and log an error string.
333_Note_ that this early return can have implications for memory leakage.
334
335At the end, if all test criteria pass, you should return `UNIT_TEST_PASSED`.
336
337### Framework - More Complex Cases
338
339To write more advanced tests, first look at all the Assertion and Logging macros provided in the framework.
340
341Beyond that, if you're writing host-based tests and want to take a dependency on the UnitTestFrameworkPkg, you can
342leverage the `cmocka.h` interface and write tests with all the features of the Cmocka framework.
343
344Documentation for Cmocka can be found here:
345https://api.cmocka.org/
346
347## GoogleTest Libraries
348
349### GoogleTestLib
350
351GoogleTestLib is the core library used for GoogleTest in EDK II. This library is mainly a wrapper
352around the GoogleTest and gMock header and source files. So all the standard
353[GoogleTest](http://google.github.io/googletest/) and
354[gMock](https://github.com/google/googletest/tree/main/googlemock) documentation for writing tests
355and using mocks applies.
356
357Additionally, to support the use of some primitive types that are not directly supported by
358GoogleTest and gMock (but are needed to allow gMock to be used in EDK II), some custom gMock
359actions and matchers were added to GoogleTestLib. These customizations are briefly described in
360the following tables.
361
362#### Custom Actions
363
364| Action Name | Similar gMock Generic Action | Usage |
365|:--- |:--- |:--- |
366| `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()` |
367
368#### Custom Matchers
369
370| Matcher Name | Similar gMock Generic Matcher | Usage |
371|:--- |:--- |:--- |
372| `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. |
373| `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. |
374
375### FunctionMockLib
376
377FunctionMockLib is the library that allows gMock to be used with free (C style) functions. This
378library contains a set of macros that wrap gMock's MOCK_METHOD macro to enable the standard gMock
379capabilities to be used with free functions. The details of how this is implemented is outside the
380scope of this document, but a brief description of each of the public macros in FunctionMockLib is
381described below. A full example of how to use these macros to create a mock is described in a
382later section.
383
384In total there are six public macros in FunctionMockLib. Four of the macros are related to creating
385the mock functions, and the other two macros are related to creating an interface that is necessary
386to contain the mock functions and connect them into the gMock framework.
387
388The macros used to create the interface are...
3891. `MOCK_INTERFACE_DECLARATION(MOCK)`
3902. `MOCK_INTERFACE_DEFINITION(MOCK)`
391
392These macros both take one argument which is the name of the interface for the mock. The
393`MOCK_INTERFACE_DECLARATION` macro is used to declare the interface in the `.h` file and the
394`MOCK_INTERFACE_DEFINITION` macro is used to define the interface in the `.cpp` file. For
395example, to create a mock for the `UefiLib`, a `MockUefiLib.h` file would be created and the
396below code would be added to it.
397
398```cpp
399struct MockUefiLib {
400 MOCK_INTERFACE_DECLARATION(MockUefiLib);
401};
402```
403
404Additionally, the below code would be written into a `MockUefiLib.cpp` file.
405
406```cpp
407MOCK_INTERFACE_DEFINITION(MockUefiLib);
408```
409
410The macros used to create the mock functions are...
4111. `MOCK_FUNCTION_DECLARATION(RET_TYPE, FUNC, ARGS)`
4122. `MOCK_FUNCTION_DEFINITION(MOCK, FUNC, NUM_ARGS, CALL_TYPE)`
4133. `MOCK_FUNCTION_INTERNAL_DECLARATION(RET_TYPE, FUNC, ARGS)`
4144. `MOCK_FUNCTION_INTERNAL_DEFINITION(MOCK, FUNC, NUM_ARGS, CALL_TYPE)`
415
416You will notice that there are two sets of macros: one to mock external functions and
417another to mock internal functions. Each set of macros has the exact same arguments, but
418they are used for slightly different use cases. The details of these different use cases
419is described in detail in a later section. For now, we will focus on the usage of the macro
420arguments since that is common between them.
421
422The `MOCK_FUNCTION_DECLARATION` macro is used to declare the mock function in the `.h` file,
423and it takes three arguments: return type, function name, and argument list. The
424`MOCK_FUNCTION_DEFINITION` macro is used to define the mock function in the `.cpp` file,
425and it takes four arguments: name of the interface for the mock, function name, number of
426arguments the function takes, and calling convention type of the function. For example, to
427continue with the `UefiLib` mock example above, the `GetVariable2` and `GetEfiGlobalVariable2`
428functions are declared in `UefiLib.h` as shown below.
429
430```cpp
431EFI_STATUS
432EFIAPI
433GetVariable2 (
434 IN CONST CHAR16 *Name,
435 IN CONST EFI_GUID *Guid,
436 OUT VOID **Value,
437 OUT UINTN *Size OPTIONAL
438 );
439
440EFI_STATUS
441EFIAPI
442GetEfiGlobalVariable2 (
443 IN CONST CHAR16 *Name,
444 OUT VOID **Value,
445 OUT UINTN *Size OPTIONAL
446 );
447```
448
449To declare mocks for these functions within the previously created `MockUefiLib` interface,
450the below code would be added to the `MockUefiLib.h` file. Note that the previously added
451interface declaration is also included in the code below for context.
452
453```cpp
454struct MockUefiLib {
455 MOCK_INTERFACE_DECLARATION (MockUefiLib);
456
457 MOCK_FUNCTION_DECLARATION (
458 EFI_STATUS,
459 GetVariable2,
460 (IN CONST CHAR16 *Name,
461 IN CONST EFI_GUID *Guid,
462 OUT VOID **Value,
463 OUT UINTN *Size OPTIONAL)
464 );
465
466 MOCK_FUNCTION_DECLARATION (
467 EFI_STATUS,
468 GetEfiGlobalVariable2,
469 (IN CONST CHAR16 *Name,
470 OUT VOID **Value,
471 OUT UINTN *Size OPTIONAL)
472 );
473};
474```
475
476Additionally, the below code would be added into the `MockUefiLib.cpp` file to provide
477the definitions for these mock functions. Again, the previously added interface
478definition is also included in the code below for context.
479
480```cpp
481MOCK_INTERFACE_DEFINITION(MockUefiLib);
482
483MOCK_FUNCTION_DEFINITION(MockUefiLib, GetVariable2, 4, EFIAPI);
484MOCK_FUNCTION_DEFINITION(MockUefiLib, GetEfiGlobalVariable2, 3, EFIAPI);
485```
486
487That concludes the basic overview on how to use the macros, but a more detailed
488description on how to name the mocks, where to put the files, how to build the
489mocks, and how to use the mocks is described in detail later.
490
491### SubhookLib
492
493SubhookLib is the library used by FunctionMockLib to implement the macros to
494mock internal functions: `MOCK_FUNCTION_INTERNAL_DECLARATION` and
495`MOCK_FUNCTION_INTERNAL_DEFINITION`. These macros require the additional
496functionality provided by SubhookLib because they create mock functions
497for functions that are already defined and compiled within the module being
498tested. More detail on this is provided in a later section, but for now it is
499sufficient to know that the SubhookLib allows a second definition of the
500function to be compiled into the test application and then hooked to during a
501test.
502
503This library is mainly a wrapper around the
504[subhook](https://github.com/tianocore/edk2-subhook) header and source files. It
505is important to note that the use of the mock function macros and the creation
506of mock functions requires no knowledge about the SubhookLib. The SubhookLib
507library is entirely hidden and encapsulated within FunctionMockLib, and it
508is only mentioned here to provide a complete explanation on all the libraries
509used in the implementation.
510
511## FunctionMockLib Mocks
512
513This section describes the details on how to use the mock function macros in
514FunctionMockLib to create mock functions, name them, organize their files,
515and build them so that they can be used within GoogleTest tests. The usage
516of the mock functions is detailed in a later section while this section
517simply details how to create them, build them, and where to put them.
518
519### FunctionMockLib Mocks - External vs. Internal
520
521The first question to ask when creating a mock function is if the function being
522mocked is external or internal to the module being tested. This is very important
523because the macros in FunctionMockLib used to create the mock function are named
524differently for these two use cases. Fortunately, the arguments to these macros
525and the usage of the mock functions within the tests are exactly the same.
526However, because of the different underlying implementations, two different sets
527of macros are used.
528
529A more detailed description of when to use the external vs. internal mock function
530macros is in the following sections, but the quick summary is as follows.
531
532* External mock function macros are used to mock functions that are outside the
533module being tested and use link-time replacement.
534* Internal mock function macros are used to mock functions that are inside the
535module being tested and use run-time replacement.
536
537The below table shows which macros to use in these two use cases. However, note that
538for the creation of the interface, the same macros are used in both cases.
539
540| Mock Function Use Case | Mock Interface Macros | Mock Function Macros |
541|:--- |:--- |:--- |
542| External mock functions | `MOCK_INTERFACE_DECLARATION`</br>`MOCK_INTERFACE_DEFINITION` | `MOCK_FUNCTION_DECLARATION`</br>`MOCK_FUNCTION_DEFINITION` |
543| Internal mock functions | `MOCK_INTERFACE_DECLARATION`</br>`MOCK_INTERFACE_DEFINITION` | `MOCK_FUNCTION_INTERNAL_DECLARATION`</br>`MOCK_FUNCTION_INTERNAL_DEFINITION` |
544
545#### FunctionMockLib Mocks - External mock function
546
547The external mock function macros are used to create mock function definitions
548for a library, global service, or protocol that is defined outside of the module
549being tested. These mock function definitions are linked into the test application
550instead of linking in the design function definitions. In other words, the
551external mock function macros use link-time replacement of the design functions.
552
553The `.h/.cpp` files for these mock functions are created within the package
554directory where the library, global table, or protocol that is being mocked is
555declared. These files are compiled into their own separate library (using
556an INF file) that can be shared and linked into many test applications, but more
557on that later.
558
559#### FunctionMockLib Mocks - Internal mock function
560
561The internal mock function macros are used to create mock function definitions
562for functions that are defined within the module being tested. These mock
563function definitions are compiled into the test application along with the design
564function definitions. This is possible because the mock functions are given a
565slightly different name during compilation. Then during test execution, the
566design function is hooked and replaced with the mock function. In other words,
567the internal mock function macros use run-time replacement of the design
568functions.
569
570The `.h/.cpp` files for these mock functions are created within the GoogleTest
571directory containing the specific tests that are using them. These files are
572compiled directly in the GoogleTest INF file that builds the test application,
573and they are not shared outside of that GoogleTest directory, but more on that
574later.
575
576### FunctionMockLib Mocks - Declaration
577
578The declaration of mock functions using the FunctionMockLib macros are done
579in header files. The name of the header file is determined by the interface
580(such as a library or a protocol) that is being created for the mock functions.
581The rules for naming the file are shown in the table below.
582
583| Interface Type | Header File Name |
584| :--- | :--- |
585| Library | Mock\<LibraryName\>Lib.h |
586| Global Table (e.g. gRT, gBS, etc.) | Mock\<GlobalTableLibraryName\>Lib.h |
587| Protocol | Mock\<ProtocolName\>Protocol.h |
588
589The below table shows examples for file names with each of the above cases.
590
591| Interface Type | Interface Name | Header File Name |
592| :--- | :--- | :--- |
593| Library | UefiLib | MockUefiLib.h |
594| Global Table (e.g. gRT, gBS, etc.) | UefiRuntimeServicesTableLib | MockUefiRuntimeServicesTableLib.h |
595| Protocol | EFI_USB_IO_PROTOCOL | MockEfiUsbIoProtocol.h |
596
597Once the header file name is known, the file needs to be created in the proper
598location. For internal mock functions, the location is simply the same
599GoogleTest directory that contains the INF file that builds the test application.
600For external mock functions, the location is within the `Test` directory under the
601package where the library, global table, or protocol that is being mocked is
602declared. The exact location depends on the interface type and is shown in the
603below table.
604
605| Interface Type | Header File Location |
606| :--- | :--- |
607| Library | \<PackageName\>/Test/Mock/Include/GoogleTest/Library |
608| Global Table (e.g. gRT, gBS, etc.) | \<PackageName\>/Test/Mock/Include/GoogleTest/Library |
609| Protocol | \<PackageName\>/Test/Mock/Include/GoogleTest/Protocol |
610
611The below table shows examples for file locations with each of the above cases.
612
613| Interface Type | Interface Name | Header File Location |
614| :--- | :--- | :--- |
615| Library | UefiLib | MdePkg/Test/Mock/Include/GoogleTest/Library/MockUefiLib.h |
616| Global Table (e.g. gRT, gBS, etc.) | UefiRuntimeServicesTableLib | MdePkg/Test/Mock/Include/GoogleTest/Library/MockUefiRuntimeServicesTableLib.h |
617| Protocol | EFI_USB_IO_PROTOCOL | MdePkg/Test/Mock/Include/GoogleTest/Protocol/MockEfiUsbIoProtocol.h |
618
619Now that the file location is known, the contents can be added to it. After the
620standard `#ifndef` for a header file is added at the top of the file, the
621`GoogleTestLib.h` and `FunctionMockLib.h` files are always added. Following these
622includes other EDK II related include files are added and must be wrapped in
623`extern "C" {}` because they are C include files. Failure to do this will cause
624link errors to occur. Note that a `#include` of the interface being mocked must
625also be added. This causes the declarations of the functions being mocked to be
626included in the compilation and allows the compilation to verify that the function
627signatures of the mock and design functions are identical.
628
629After all the needed includes have been added in the file , a `struct` is declared
630using the same name as the header file (which was determined using the rules
631above). Within this structure declaration a `MOCK_INTERFACE_DECLARATION` is
632added along with a `MOCK_FUNCTION_DECLARATION` (or a
633`MOCK_FUNCTION_INTERNAL_DECLARATION` if this interface is for internal mock
634functions) for each function in the interface. To build on the examples above,
635the complete `MockUefiLib.h` file would be as shown below. Note that for brevity
636only the `GetVariable2` and `GetEfiGlobalVariable2` declarations are included in
637the example.
638
639```cpp
640#ifndef MOCK_UEFI_LIB_H_
641#define MOCK_UEFI_LIB_H_
642
643#include <Library/GoogleTestLib.h>
644#include <Library/FunctionMockLib.h>
645extern "C" {
646 #include <Uefi.h>
647 #include <Library/UefiLib.h>
648}
649
650struct MockUefiLib {
651 MOCK_INTERFACE_DECLARATION (MockUefiLib);
652
653 MOCK_FUNCTION_DECLARATION (
654 EFI_STATUS,
655 GetVariable2,
656 (IN CONST CHAR16 *Name,
657 IN CONST EFI_GUID *Guid,
658 OUT VOID **Value,
659 OUT UINTN *Size OPTIONAL)
660 );
661
662 MOCK_FUNCTION_DECLARATION (
663 EFI_STATUS,
664 GetEfiGlobalVariable2,
665 (IN CONST CHAR16 *Name,
666 OUT VOID **Value,
667 OUT UINTN *Size OPTIONAL)
668 );
669};
670
671#endif
672```
673
674In the case of libraries, the function names in the mock declarations
675align exactly with the function names in the design. However, in the
676case of global tables and protocols, to eliminate possible function
677name collisions, the names are adjusted slightly in the mock
678declarations as shown in the below table.
679
680| Mock Function Use Case | Design Function Name | Mock Function Name |
681| :--- | :--- | :--- |
682| Library | GetVariable2 | GetVariable2 |
683| Global Table (e.g. gRT, gBS, etc.) | gRT->GetVariable | gRT_GetVariable |
684| Protocol | UsbIoProtocol->UsbPortReset | UsbIoProtocol_UsbPortReset |
685
686Lastly, when creating mock functions, there are two limitations to be
687aware of in gMock that extend into FunctionMockLib.
688
6891. gMock does not support mocking functions that have more than 15 arguments.
6902. gMock does not support mocking variadic functions.
691
692With those limitations in mind, that completes the mock function
693declarations, and now the mock function definitions for those declarations
694can be created.
695
696### FunctionMockLib Mocks - Definition
697
698The definition of mock functions using the FunctionMockLib macros are done
699in source files. The name of the source file is determined by the interface
700(such as a library or a protocol) that is being created for the mock functions.
701The rules for naming the file align with the naming of the file for declarations
702and are shown in the table below.
703
704| Interface Type | Source File Name |
705| :--- | :--- |
706| Library | Mock\<LibraryName\>Lib.cpp |
707| Global Table (e.g. gRT, gBS, etc.) | Mock\<GlobalTableLibraryName\>Lib.cpp |
708| Protocol | Mock\<ProtocolName\>Protocol.cpp |
709
710The below table shows examples for file names with each of the above cases.
711
712| Interface Type | Interface Name | Source File Name |
713| :--- | :--- | :--- |
714| Library | UefiLib | MockUefiLib.cpp |
715| Global Table (e.g. gRT, gBS, etc.) | UefiRuntimeServicesTableLib | MockUefiRuntimeServicesTableLib.cpp |
716| Protocol | EFI_USB_IO_PROTOCOL | MockEfiUsbIoProtocol.cpp |
717
718Once the source file name is known, the file needs to be created in the proper
719location. The location of the source file is aligned with the location for the
720header file. For internal mock functions, the location is simply the same
721GoogleTest directory that contains the INF file that builds the test application.
722For external mock functions, the location is within the `Test` directory under the
723package where the library, global table, or protocol that is being mocked is
724declared. The exact location depends on the interface type and is shown in the
725below table.
726
727| Interface Type | Source File Location |
728| :--- | :--- |
729| Library | \<PackageName\>/Test/Mock/Library/GoogleTest/Mock\<LibraryName\>Lib |
730| Global Table (e.g. gRT, gBS, etc.) | \<PackageName\>/Test/Mock/Library/GoogleTest/Mock\<GlobalTableLibraryName\>Lib |
731| Protocol | \<PackageName\>/Test/Mock/Library/GoogleTest/Mock\<ProtocolName\>Protocol |
732
733The below table shows examples for file locations with each of the above cases.
734
735| Interface Type | Interface Name | Source File Location |
736| :--- | :--- | :--- |
737| Library | UefiLib | MdePkg/Test/Mock/Library/GoogleTest/MockUefiLib/MockUefiLib.cpp |
738| Global Table (e.g. gRT, gBS, etc.) | UefiRuntimeServicesTableLib | MdePkg/Test/Mock/Library/GoogleTest/MockUefiRuntimeServicesTableLib/MockUefiRuntimeServicesTableLib.cpp |
739| Protocol | EFI_USB_IO_PROTOCOL | MdePkg/Test/Mock/Library/GoogleTest/MockEfiUsbIoProtocol/MockEfiUsbIoProtocol.cpp |
740
741Now that the file location is known, the contents can be added to it. At the top
742of the file, the header file containing the mock function declarations is always
743added. After this `#include`, the interface definition is created using
744`MOCK_INTERFACE_DEFINITION` with the interface name that was used in the mock
745function declaration header file. A `MOCK_FUNCTION_DEFINITION` is then added (or
746a `MOCK_FUNCTION_INTERNAL_DEFINITION` if this interface is for internal mock
747functions) for each function that was declared in the interface. To build on the
748prior declaration examples, the complete `MockUefiLib.cpp` file would be as shown
749below. Note that for brevity only the `GetVariable2` and `GetEfiGlobalVariable2`
750definitions are included in the example.
751
752```cpp
753#include <GoogleTest/Library/MockUefiLib.h>
754
755MOCK_INTERFACE_DEFINITION(MockUefiLib);
756
757MOCK_FUNCTION_DEFINITION(MockUefiLib, GetVariable2, 4, EFIAPI);
758MOCK_FUNCTION_DEFINITION(MockUefiLib, GetEfiGlobalVariable2, 3, EFIAPI);
759```
760
761When creating the defintions, there are a few things to keep in mind.
762
763First, when using `MOCK_FUNCTION_DEFINITION`, some functions being mocked do
764not specify a calling convention. In this case, it is fine to leave the last
765argument of `MOCK_FUNCTION_DEFINITION` empty. For example, if `GetVariable2`
766did not specify the `EFIAPI` calling convention in its declaration, then the
767below code would be used for the mock function definition.
768
769```cpp
770MOCK_FUNCTION_DEFINITION(MockUefiLib, GetVariable2, 4, );
771```
772
773Second, the function name used in `MOCK_FUNCTION_DEFINITION` must align with
774the function name used in the associated `MOCK_FUNCTION_DECLARATION` in the
775header file.
776
777Last, if the interface is mocking a global table or protocol, then the structure
778of function pointers for that interface must also be defined within the source
779file as a `static` structure with the mock function definitions being assigned
780to the associated entries in the structure. The address of this `static`
781structure is then assigned to the global table or protocol pointer. Note that
782this pointer must be wrapped in `extern "C" {}` because it needs C style
783linkage. Failure to do this will cause link errors to occur. For example, when
784creating the definition of the mock for the global runtime services table, the
785complete `MockUefiRuntimeServicesTableLib.cpp` file would be as shown below.
786Note that for brevity only the `GetVariable` and `SetVariable` definitions are
787included in the example.
788
789```cpp
790#include <GoogleTest/Library/MockUefiRuntimeServicesTableLib.h>
791
792MOCK_INTERFACE_DEFINITION(MockUefiRuntimeServicesTableLib);
793
794MOCK_FUNCTION_DEFINITION(MockUefiRuntimeServicesTableLib, gRT_GetVariable, 5, EFIAPI);
795MOCK_FUNCTION_DEFINITION(MockUefiRuntimeServicesTableLib, gRT_SetVariable, 5, EFIAPI);
796
797static EFI_RUNTIME_SERVICES localRt = {
798 {0}, // EFI_TABLE_HEADER
799
800 NULL, // EFI_GET_TIME
801 NULL, // EFI_SET_TIME
802 NULL, // EFI_GET_WAKEUP_TIME
803 NULL, // EFI_SET_WAKEUP_TIME
804
805 NULL, // EFI_SET_VIRTUAL_ADDRESS_MAP
806 NULL, // EFI_CONVERT_POINTER
807
808 gRT_GetVariable, // EFI_GET_VARIABLE
809 NULL, // EFI_GET_NEXT_VARIABLE_NAME
810 gRT_SetVariable, // EFI_SET_VARIABLE
811
812 NULL, // EFI_GET_NEXT_HIGH_MONO_COUNT
813 NULL, // EFI_RESET_SYSTEM
814
815 NULL, // EFI_UPDATE_CAPSULE
816 NULL, // EFI_QUERY_CAPSULE_CAPABILITIES
817
818 NULL, // EFI_QUERY_VARIABLE_INFO
819};
820
821extern "C" {
822 EFI_RUNTIME_SERVICES* gRT = &localRt;
823}
824```
825
826That completes the mock function definitions. So now these mock function
827definitions can be compiled.
828
829### FunctionMockLib Mocks - Build
830
831The building of mock functions using FunctionMockLib is done slightly
832differently for external and internal function mocks. External mock
833functions are built using their own separate INF file and internal mock
834functions are built as source files directly referenced in the GoogleTest
835INF file that builds the test application.
836
837#### FunctionMockLib Mocks - Build External Mock Functions
838
839The building of external mock functions is done using their own separate INF
840file which is placed in the same location as the associated source file
841containing the mock function definitions. The name of the INF file is exactly
842the same as the mock function definitions file, but uses the `.inf` extension
843rather than `.cpp`.
844
845Within the `.inf` file the `BASE_NAME` should be set to the same name as the
846file (minus the extension), the `MODULE_TYPE` should be set to
847`HOST_APPLICATION`, and the `LIBRARY_CLASS` should be the same as the
848`BASE_NAME` but without the `Mock` prefix.
849
850The `[Sources]` section will contain the single mock function definition
851source file, the `[Packages]` section will contain all the necessary DEC
852files to compile the mock functions (which at a minimum will include the
853`UnitTestFrameworkPkg.dec` file), the `[LibraryClasses]` section will contain
854the `GoogleTestLib`, and the `[BuildOptions]` will need to append the `/EHsc`
855compilation flag to all MSFT builds to enable proper use of the C++ exception
856handler. Below is the complete `MockUefiLib.inf` as an example.
857
858```
859[Defines]
860 INF_VERSION = 0x00010005
861 BASE_NAME = MockUefiLib
862 FILE_GUID = 47211F7A-6D90-4DFB-BDF9-610B69197C2E
863 MODULE_TYPE = HOST_APPLICATION
864 VERSION_STRING = 1.0
865 LIBRARY_CLASS = UefiLib
866
867#
868# The following information is for reference only and not required by the build tools.
869#
870# VALID_ARCHITECTURES = IA32 X64
871#
872
873[Sources]
874 MockUefiLib.cpp
875
876[Packages]
877 MdePkg/MdePkg.dec
878 UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
879
880[LibraryClasses]
881 GoogleTestLib
882
883[BuildOptions]
884 MSFT:*_*_*_CC_FLAGS = /EHsc
885```
886
887To ensure that this specific set of mock functions are always buildable even
888if no test uses it yet, this created INF file needs to be added into the
889`[Components]` section of the associated `Test` DSC file for the package in
890which this INF file resides. For example, the above `MockUefiLib.inf` would
891need to be added to the `MdePkg/Test/MdePkgHostTest.dsc` file as shown below.
892
893```
894[Components]
895 MdePkg/Test/Mock/Library/GoogleTest/MockUefiLib/MockUefiLib.inf
896```
897
898This created INF file will also be referenced within the necessary `Test` DSC
899files in order to include the mock function definitions in the test
900applications which use this set of mock functions, but more on that later.
901
902One small additional requirement is that if this INF file is added into a
903package that does not yet have any other external mock functions in it, then
904that package's DEC file will need to have the mock include directory (more
905specifically the `Test/Mock/Include` directory) added to its `[Includes]`
906section so that test files who want to use the mock functions will be able to
907locate the mock function header file. For example, if `MockUefiLib.inf` were
908the first mock added to the `MdePkg`, then the below snippet would need to be
909added to the `MdePkg.dec` file.
910
911```
912[Includes]
913 Test/Mock/Include
914```
915
916#### FunctionMockLib Mocks - Build Internal Mock Functions
917
918The building of internal mock functions is done using the GoogleTest INF file
919that already needs to exist to build the test application. This is easy to
920manage since the source and header files for the internal mock functions are
921also located in the same GoogleTest directory as the GoogleTest INF file that
922will reference them.
923
924The only additions that are required to the GoogleTest INF file are that the
925mock function definitions file be added to the `[Sources]` section, the
926`UnitTestFrameworkPkg.dec` file be added to the `[Packages]` section, and the
927`GoogleTestLib` and `SubhookLib` be added to the `[LibraryClasses]` section.
928Below is a minimal contrived example for a `MyModuleGoogleTest.inf` that uses a
929`MockMyModuleInternalFunctions.cpp` source file for its internal mock functions.
930
931```
932[Defines]
933 INF_VERSION = 0x00010017
934 BASE_NAME = MyModuleGoogleTest
935 FILE_GUID = 814B09B9-2D51-4786-8A77-2E10CD1C55F3
936 VERSION_STRING = 1.0
937 MODULE_TYPE = HOST_APPLICATION
938
939#
940# The following information is for reference only and not required by the build tools.
941#
942# VALID_ARCHITECTURES = IA32 X64
943#
944
945[Sources]
946 MyModuleGoogleTest.cpp
947 MockMyModuleInternalFunctions.cpp
948
949[Packages]
950 MdePkg/MdePkg.dec
951 UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
952
953[LibraryClasses]
954 GoogleTestLib
955 SubhookLib
956```
957
958## GoogleTest Samples
959
960There is a sample unit test provided as both an example of how to write a unit test and leverage
961many of the GoogleTest features. This sample can be found in the `Test/GoogleTest/Sample/SampleGoogleTest`
962directory.
963
964The sample is provided for the HOST_APPLICATION build type, which can be run on a host system without
965needing a target.
966
967There is also a sample unit test provided as both an example of how to write a unit test with
968mock functions and leverage some of the gMock features. This sample can be found in the
969`SecurityPkg/Library/SecureBootVariableLib/GoogleTest` directory.
970
971It too is provided for the HOST_APPLICATION build type, which can be run on a host system without
972needing a target.
973
974## GoogleTest Usage
975
976This section is built a lot like a "Getting Started". We'll go through some of the components that are needed
977when constructing a unit test and some of the decisions that are made by the test writer. We'll also describe
978how to check for expected conditions in test cases and a bit of the logging characteristics.
979
980Most of these examples will refer to the `SampleGoogleTestHost` app found in this package, but
981the examples related to mock functions will refer to the `SecureBootVariableLibGoogleTest` app
982found in the `SecurityPkg`.
983
984### GoogleTest Requirements - INF
985
986In our INF file, we'll need to bring in the `GoogleTestLib` library. Conveniently, the interface
987header for the `GoogleTestLib` is in `UnitTestFrameworkPkg`, so you shouldn't need to depend on any other
988packages. As long as your DSC file knows where to find the lib implementation that you want to use,
989you should be good to go.
990
991See this example in `SampleGoogleTestHost.inf`...
992
993```
994[Packages]
995 MdePkg/MdePkg.dec
996 UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
997
998[LibraryClasses]
999 GoogleTestLib
1000 BaseLib
1001 DebugLib
1002```
1003
1004Also, if you want your test to automatically be picked up by the Test Runner plugin, you will need
1005to make sure that the module `BASE_NAME` contains the word `Test`...
1006
1007```
1008[Defines]
1009 BASE_NAME = SampleGoogleTestHost
1010```
1011
1012### GoogleTest Requirements - DSC
1013
1014In our DSC file, we'll need to bring in the INF file that was just created into the `[Components]`
1015section so that the unit tests will be built.
1016
1017See this example in `UnitTestFrameworkPkgHostTest.dsc`...
1018
1019```
1020[Components]
1021 UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/SampleGoogleTestHost.inf
1022```
1023
1024Also, based on the type of tests that are being created, the associated DSC include file from the
1025UnitTestFrameworkPkg for Host or Target based tests should also be included at the top of the DSC
1026file. This provides the default defines and library class mappings requires for unit testing.
1027
1028```
1029!include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc
1030```
1031
1032 > **NOTE**: DSC files for host based unit tests must **not** include default mappings from packages such as `MdePkg/MdeLibs.dsc.inc`. This DSC files provides default defines and library mappings for firmware builds that may not be compatible with host based unit test builds. Instead, the DSC file for host based unit tests must provide all the settings required for host based unit tests.
1033
1034Lastly, in the case that the test build has specific dependent libraries associated with it,
1035they should be added in the \<LibraryClasses\> sub-section for the INF file in the
1036`[Components]` section of the DSC file. Note that it is within this sub-section where you can
1037control whether the design or mock version of a component is linked into the test exectuable.
1038
1039See this example in `SecurityPkgHostTest.dsc` where the `SecureBootVariableLib` design is
1040being tested using mock versions of `UefiRuntimeServicesTableLib`, `PlatformPKProtectionLib`,
1041and `UefiLib`...
1042
1043```
1044[Components]
1045 SecurityPkg/Library/SecureBootVariableLib/GoogleTest/SecureBootVariableLibGoogleTest.inf {
1046 <LibraryClasses>
1047 SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf
1048 UefiRuntimeServicesTableLib|MdePkg/Test/Mock/Library/GoogleTest/MockUefiRuntimeServicesTableLib/MockUefiRuntimeServicesTableLib.inf
1049 PlatformPKProtectionLib|SecurityPkg/Test/Mock/Library/GoogleTest/MockPlatformPKProtectionLib/MockPlatformPKProtectionLib.inf
1050 UefiLib|MdePkg/Test/Mock/Library/GoogleTest/MockUefiLib/MockUefiLib.inf
1051 }
1052```
1053
1054### GoogleTest Requirements - Code
1055
1056GoogleTest applications are implemented in C++, so make sure that your test file has
1057a `.cpp` extension. With that behind us, not to state the obvious, but let's make sure
1058we have the following includes before getting too far along in the file...
1059
1060```cpp
1061#include <Library/GoogleTestLib.h>
1062extern "C" {
1063 #include <Uefi.h>
1064 #include <Library/BaseLib.h>
1065 #include <Library/DebugLib.h>
1066}
1067```
1068
1069The first include brings in the GoogleTest definitions. Other EDK II related include
1070files must be wrapped in `extern "C" {}` because they are C include files. Link
1071failures will occur if this is not done.
1072
1073Also, when using GoogleTest it is helpful to add a `using` declaration for its
1074`testing` namespace. This `using` statement greatly reduces the amount of code you
1075need to write in the tests when referencing the utilities within the `testing`
1076namespace. For example, instead of writing `::testing::Return` or `::testing::Test`,
1077you can just write `Return` or `Test` respectively, and these types of references
1078occur numerous times within the tests.
1079
1080Lastly, in the case that tests within a GoogleTest application require the usage of
1081mock functions, it is also necessary to include the header files for those interfaces
1082as well. As an example, the `SecureBootVariableLibGoogleTest` uses the mock versions
1083of `UefiLib` and `UefiRuntimeServicesTableLib`. So its test file contains the below
1084includes. Note that the `using` declaration mentioned above is also shown in the code
1085below for completeness of the example.
1086
1087```cpp
1088#include <Library/GoogleTestLib.h>
1089#include <GoogleTest/Library/MockUefiLib.h>
1090#include <GoogleTest/Library/MockUefiRuntimeServicesTableLib.h>
1091
1092extern "C" {
1093 #include <Uefi.h>
1094 ...
1095}
1096
1097using namespace testing;
1098```
1099
1100Now that we've got that squared away, let's look at our 'Main()' routine (or DriverEntryPoint() or whatever).
1101
1102### GoogleTest Configuration
1103
1104Unlike the Framework, GoogleTest does not require test suites or test cases to
1105be registered. Instead, the test cases declare the test suite name and test
1106case name as part of their implementation. The only requirement for GoogleTest
1107is to have a `main()` function that initializes the GoogleTest infrastructure
1108and calls the service `RUN_ALL_TESTS()` to run all the unit tests.
1109
1110```cpp
1111int main(int argc, char* argv[]) {
1112 testing::InitGoogleTest(&argc, argv);
1113 return RUN_ALL_TESTS();
1114}
1115```
1116
1117### GoogleTest - A Simple Test Case
1118
1119Below is a sample test case from `SampleGoogleTestHost`.
1120
1121```cpp
1122TEST(SimpleMathTests, OnePlusOneShouldEqualTwo) {
1123 UINTN A;
1124 UINTN B;
1125 UINTN C;
1126
1127 A = 1;
1128 B = 1;
1129 C = A + B;
1130
1131 ASSERT_EQ (C, 2);
1132}
1133```
1134
1135This uses the simplest form of a GoogleTest unit test using `TEST()` that
1136declares the test suite name and the unit test name within that test suite.
1137The unit test performs actions and typically makes calls to the code under test
1138and contains test assertions to verify that the code under test behaves as
1139expected for the given inputs.
1140
1141In this test case, the `ASSERT_EQ` assertion is being used to establish that the business logic has functioned
1142correctly. There are several assertion macros, and you are encouraged to use one that matches as closely to your
1143intended test criterium as possible, because the logging is specific to the macro and more specific macros have more
1144detailed logs. When in doubt, there are always `ASSERT_TRUE` and `ASSERT_FALSE`. Assertion macros that fail their
1145test criterium will immediately return from the test case with a failed status and log an error string.
1146_Note_ that this early return can have implications for memory leakage.
1147
1148For most `ASSERT` macros in GoogleTest there is also an equivalent `EXPECT` macro. Both macro versions
1149will ultimately cause the `TEST` to fail if the check fails. However, the difference between the two
1150macro versions is that when the check fails, the `ASSERT` version immediately returns from the `TEST`
1151while the `EXPECT` version continues running the `TEST`.
1152
1153There is no return status from a GooglTest unit test. If no assertions (or expectations) are
1154triggered then the unit test has a passing status.
1155
1156### GoogleTest - A gMock Test Case
1157
1158Below is a sample test case from `SecureBootVariableLibGoogleTest`. Although
1159actually, the test case is not written exactly like this in the test file, but
1160more on that in a bit.
1161
1162```cpp
1163TEST(SetSecureBootModeTest, SetVarError) {
1164 MockUefiRuntimeServicesTableLib RtServicesMock;
1165 UINT8 SecureBootMode;
1166 EFI_STATUS Status;
1167
1168 // Any random magic number can be used for these tests
1169 SecureBootMode = 0xAB;
1170
1171 EXPECT_CALL(RtServicesMock, gRT_SetVariable)
1172 .WillOnce(Return(EFI_INVALID_PARAMETER));
1173
1174 Status = SetSecureBootMode(SecureBootMode);
1175 EXPECT_EQ(Status, EFI_INVALID_PARAMETER);
1176}
1177```
1178
1179Keep in mind that this test is written to verify that `SetSecureBootMode()` will
1180return `EFI_INVALID_PARAMETER` when the call to `gRT->SetVariable()` within the
1181implementation of `SetSecureBootMode()` returns `EFI_INVALID_PARAMETER`. With that
1182in mind, let's discuss how a mock function is used to accomplish this in the test.
1183
1184In this test case, the `MockUefiRuntimeServicesTableLib` interface is instantiated as
1185`RtServicesMock` which enables its associated mock functions. These interface
1186instantiations that contain the mock functions are very important for mock function
1187based unit tests because without these instantiations, the mock functions within that
1188interface will not exist and can not be used.
1189
1190The next line of interest is the `EXPECT_CALL`, which is a standard part of the gMock
1191framework. This macro is telling the test that a call is expected to occur to a
1192specific function on a specific interface. The first argument is the name of the
1193interface object that was instantiated in this test, and the second argument is the
1194name of the mock function within that interface that is expected to be called. The
1195`WillOnce(Return(EFI_INVALID_PARAMETER))` associated with this `EXPECT_CALL` states
1196that the `gRT_SetVariable()` function (remember from earlier in this documentation
1197that this refers to the `gRT->SetVariable()` function) will be called once during
1198this test, and when it does get called, we want it to return `EFI_INVALID_PARAMETER`.
1199
1200Once this `EXPECT_CALL` has been setup, the call to `SetSecureBootMode()` occurs in
1201the test, and its return value is saved in `Status` so that it can be tested. Based
1202on the `EXPECT_CALL` that was setup earlier, when `SetSecureBootMode()` internally
1203calls `gRT->SetVariable()`, it returns `EFI_INVALID_PARAMETER`. This value should
1204then be returned by `SetSecureBootMode()`, and the
1205`EXPECT_EQ(Status, EFI_INVALID_PARAMETER)` verifies this is the case.
1206
1207There is much more that can be done with `EXPECT_CALL` and mock functions, but we
1208will leave those details to be explained in the gMock documentation.
1209
1210Now it was mentioned earlier that this test case is not written exactly like this
1211in the test file, and the next section describes how this test is slightly
1212refactored to reduce the total amount of code in the entire test suite.
1213
1214### GoogleTest - A gMock Test Case (refactored)
1215
1216The sample test case from `SecureBootVariableLibGoogleTest` in the prior section is
1217actually written as shown below.
1218
1219```cpp
1220class SetSecureBootModeTest : public Test {
1221 protected:
1222 MockUefiRuntimeServicesTableLib RtServicesMock;
1223 UINT8 SecureBootMode;
1224 EFI_STATUS Status;
1225
1226 void SetUp() override {
1227 // Any random magic number can be used for these tests
1228 SecureBootMode = 0xAB;
1229 }
1230};
1231
1232TEST_F(SetSecureBootModeTest, SetVarError) {
1233 EXPECT_CALL(RtServicesMock, gRT_SetVariable)
1234 .WillOnce(Return(EFI_INVALID_PARAMETER));
1235
1236 Status = SetSecureBootMode(SecureBootMode);
1237 EXPECT_EQ(Status, EFI_INVALID_PARAMETER);
1238}
1239```
1240
1241This code may at first seem more complicated, but you will notice that the code
1242with in it is still the same. There is still a `MockUefiRuntimeServicesTableLib`
1243instantiation, there is still a `SecureBootMode` and `Status` variable defined,
1244there is still an `EXPECT_CALL`, and etc. However, the benefit of constructing
1245the test this way is that the new `TEST_F()` requires less code than the prior
1246`TEST()`.
1247
1248This is made possible by the usage of what GoogleTest calls a _test fixture_.
1249This concept of a test fixture allows multiple tests to use (or more specifically
1250inherit from a base class) a common set of variables and initial conditions.
1251Notice that using `TEST_F()` requires the first argument to be a name that aligns
1252with a test fixture (in this case `SetSecureBootModeTest`), and the second
1253argument is the name of the test (just like in the `TEST()` macro).
1254
1255All `TEST_F()` tests that use a specific test fixture can be thought of as having
1256all of that test fixture's variables automatically defined in the test as well as
1257having that text fixture's `SetUp()` function called before entering the test.
1258
1259This means that another `TEST_F()` can be written without needing to worry about
1260defining a bunch of variables or instantiating a bunch of interfaces for mock
1261functions. For example, the below test (also in `SecureBootVariableLibGoogleTest`)
1262uses the same test fixture and makes use of its `RtServicesMock`, `Status`, and
1263`SecureBootMode` variables.
1264
1265```cpp
1266TEST_F(SetSecureBootModeTest, PropogateModeToSetVar) {
1267 EXPECT_CALL(RtServicesMock,
1268 gRT_SetVariable(
1269 Char16StrEq(EFI_CUSTOM_MODE_NAME),
1270 BufferEq(&gEfiCustomModeEnableGuid, sizeof(EFI_GUID)),
1271 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
1272 sizeof(SecureBootMode),
1273 BufferEq(&SecureBootMode, sizeof(SecureBootMode))))
1274 .WillOnce(Return(EFI_SUCCESS));
1275
1276 Status = SetSecureBootMode(SecureBootMode);
1277 EXPECT_EQ(Status, EFI_SUCCESS);
1278}
1279```
1280
1281The biggest benefit is that the `TEST_F()` code can now focus on what is being
1282tested and not worry about any repetitive setup. There is more that can be done
1283with test fixtures, but we will leave those details to be explained in the
1284gMock documentation.
1285
1286Now, as for what is in the above test, it is slightly more complicated than the
1287first test. So let's explain this added complexity and what it is actually
1288testing. In this test, there is still an `EXPECT_CALL` for the
1289`gRT_SetVariable()` function. However, in this test we are stating that we
1290expect the input arguments passed to `gRT_SetVariable()` be specific values.
1291The order they are provided in the `EXPECT_CALL` align with the order of the
1292arguments in the `gRT_SetVariable()` function. In this case the order of the
1293`gRT_SetVariable()` arguments is as shown below.
1294
1295```cpp
1296IN CHAR16 *VariableName,
1297IN EFI_GUID *VendorGuid,
1298IN UINT32 Attributes,
1299IN UINTN DataSize,
1300IN VOID *Data
1301```
1302
1303So in the `EXPECT_CALL` we are stating that the call to `gRT_SetVariable()`
1304will be made with the below input argument values.
1305
13061. `VariableName` is equal to the `EFI_CUSTOM_MODE_NAME` string
13072. `VendorGuid` is equal to the `gEfiCustomModeEnableGuid` GUID (which has a byte length of `sizeof(EFI_GUID)`)
13083. `Attributes` is equal to `EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS`
13094. `DataSize` is equal to `sizeof(SecureBootMode)`
13105. `Data` is equal to `SecureBootMode` (which has a byte length of `sizeof(SecureBootMode)`)
1311
1312If any one of these input arguments does not match in the actual call to
1313`gRT_SetVariable()` in the design, then the test will fail. There is much more
1314that can be done with `EXPECT_CALL` and mock functions, but again we will
1315leave those details to be explained in the gMock documentation.
1316
1317### GoogleTest - More Complex Cases
1318
1319To write more advanced tests, take a look at the
1320[GoogleTest User's Guide](http://google.github.io/googletest/).
1321
1322## Development
1323
1324### Iterating on a Single Test
1325
1326When using the EDK2 Pytools for CI testing, the host-based unit tests will be built and run on any build that includes
1327the `NOOPT` build target.
1328
1329If you are trying to iterate on a single test, a convenient pattern is to build only that test module. For example,
1330the following command will build only the SafeIntLib host-based test from the MdePkg...
1331
1332```bash
1333stuart_ci_build -c .pytool/CISettings.py TOOL_CHAIN_TAG=VS2022 -p MdePkg -t NOOPT BUILDMODULE=MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.inf
1334```
1335
1336### Hooking BaseLib
1337
1338Most unit test mocking can be performed by the functions provided in the UnitTestFrameworkPkg libraries, but since
1339BaseLib is consumed by the Framework itself, it requires different techniques to substitute parts of the
1340functionality.
1341
1342To solve some of this, the UnitTestFrameworkPkg consumes a special implementation of BaseLib for host-based tests.
1343This implementation contains a [hook table](https://github.com/tianocore/edk2/blob/e188ecc8b4aed8fdd26b731d43883861f5e5e7b4/MdePkg/Test/UnitTest/Include/Library/UnitTestHostBaseLib.h#L507)
1344that can be used to substitute test functionality for any of the BaseLib functions. By default, this implementation
1345will use the underlying BaseLib implementation, so the unit test writer only has to supply minimal code to test a
1346particular case.
1347
1348### Debugging the Framework Itself
1349
1350While most of the tests that are produced by the UnitTestFrameworkPkg are easy to step through in a debugger, the Framework
1351itself consumes code (mostly Cmocka) that sets its own build flags. These flags cause parts of the Framework to not
1352export symbols and captures exceptions, and as such are harder to debug. We have provided a Stuart parameter to force
1353symbolic debugging to be enabled.
1354
1355You can run a build by adding the `BLD_*_UNIT_TESTING_DEBUG=TRUE` parameter to enable this build option.
1356
1357```bash
1358stuart_ci_build -c .pytool/CISettings.py TOOL_CHAIN_TAG=VS2022 -p MdePkg -t NOOPT BLD_*_UNIT_TESTING_DEBUG=TRUE
1359```
1360
1361## Building and Running Host-Based Tests
1362
1363The EDK2 CI infrastructure provides a convenient way to run all host-based tests -- in the the entire tree or just
1364selected packages -- and aggregate all the reports, including highlighting any failures. This functionality is
1365provided through the Stuart build system (published by EDK2-PyTools) and the `NOOPT` build target. The sections that
1366follow use Framework examples. Unit tests based on GoogleTest are built and run the same way. The text output and
1367JUNIT XML output format have small differences.
1368
1369### Building Locally
1370
1371First, to make sure you're working with the latest PyTools, run the following command:
1372
1373```bash
1374# Would recommend running this in a Python venv, but that's out of scope for this doc.
1375python -m pip install --upgrade -r ./pip-requirements.txt
1376```
1377
1378After that, the following commands will set up the build and run the host-based tests.
1379
1380```bash
1381# Setup repo for building
1382# stuart_setup -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=<GCC5, VS2022, etc.>
1383stuart_setup -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=VS2022
1384
1385# Update all binary dependencies
1386# stuart_update -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=<GCC5, VS2022, etc.>
1387stuart_update -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=VS2022
1388
1389# Build and run the tests
1390# stuart_ci_build -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=<GCC5, VS2022, etc.> -t NOOPT [-p <Package Name>]
1391stuart_ci_build -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=VS2022 -t NOOPT -p MdePkg
1392```
1393
1394#### Disabling Address Sanitizer
1395
1396By default, the address sanitizer feature is enabled for all host based unit test builds. It can be disabled for
1397development/debug purposes by setting the DSC define `UNIT_TESTING_ADDRESS_SANITIZER_ENABLE` to `FALSE`.
1398
1399```
1400stuart_ci_build -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=VS2022 -t NOOPT -p MdePkg BLD_*_UNIT_TESTING_ADDRESS_SANITIZER_ENABLE=FALSE
1401```
1402
1403### Evaluating the Results
1404
1405In your immediate output, any build failures will be highlighted. You can see these below as "WARNING" and "ERROR" messages.
1406
1407```text
1408(edk_env) PS C:\_uefi\edk2> stuart_ci_build -c .\.pytool\CISettings.py TOOL_CHAIN_TAG=VS2022 -t NOOPT -p MdePkg
1409
1410SECTION - Init SDE
1411SECTION - Loading Plugins
1412SECTION - Start Invocable Tool
1413SECTION - Getting Environment
1414SECTION - Loading plugins
1415SECTION - Building MdePkg Package
1416PROGRESS - --Running MdePkg: Host Unit Test Compiler Plugin NOOPT --
1417WARNING - Allowing Override for key TARGET_ARCH
1418PROGRESS - Start time: 2020-07-27 17:18:08.521672
1419PROGRESS - Setting up the Environment
1420PROGRESS - Running Pre Build
1421PROGRESS - Running Build NOOPT
1422PROGRESS - Running Post Build
1423SECTION - Run Host based Unit Tests
1424SUBSECTION - Testing for architecture: X64
1425WARNING - TestBaseSafeIntLibHost.exe Test Failed
1426WARNING - Test SafeInt8ToUint8 - UT_ASSERT_EQUAL(0x5b:5b, Result:5c)
1427c:\_uefi\edk2\MdePkg\Test\UnitTest\Library\BaseSafeIntLib\TestBaseSafeIntLib.c:35: error: Failure!
1428ERROR - Plugin Failed: Host-Based Unit Test Runner returned 1
1429CRITICAL - Post Build failed
1430PROGRESS - End time: 2020-07-27 17:18:19.792313 Total time Elapsed: 0:00:11
1431ERROR - --->Test Failed: Host Unit Test Compiler Plugin NOOPT returned 1
1432ERROR - Overall Build Status: Error
1433PROGRESS - There were 1 failures out of 1 attempts
1434SECTION - Summary
1435ERROR - Error
1436
1437(edk_env) PS C:\_uefi\edk2>
1438```
1439
1440If a test fails, you can run it manually to get more details...
1441
1442```text
1443(edk_env) PS C:\_uefi\edk2> .\Build\MdePkg\HostTest\NOOPT_VS2022\X64\TestBaseSafeIntLibHost.exe
1444
1445Int Safe Lib Unit Test Application v0.1
1446---------------------------------------------------------
1447------------ RUNNING ALL TEST SUITES --------------
1448---------------------------------------------------------
1449---------------------------------------------------------
1450RUNNING TEST SUITE: Int Safe Conversions Test Suite
1451---------------------------------------------------------
1452[==========] Running 71 test(s).
1453[ RUN ] Test SafeInt8ToUint8
1454[ ERROR ] --- UT_ASSERT_EQUAL(0x5b:5b, Result:5c)
1455[ LINE ] --- c:\_uefi\edk2\MdePkg\Test\UnitTest\Library\BaseSafeIntLib\TestBaseSafeIntLib.c:35: error: Failure!
1456[ FAILED ] Test SafeInt8ToUint8
1457[ RUN ] Test SafeInt8ToUint16
1458[ OK ] Test SafeInt8ToUint16
1459[ RUN ] Test SafeInt8ToUint32
1460[ OK ] Test SafeInt8ToUint32
1461[ RUN ] Test SafeInt8ToUintn
1462[ OK ] Test SafeInt8ToUintn
1463...
1464```
1465
1466You can also, if you are so inclined, read the output from the exact instance of the test that was run during
1467`stuart_ci_build`. The output file can be found on a path that looks like:
1468
1469`Build/<Package>/HostTest/<Arch>/<TestName>.<TestSuiteName>.<Arch>.result.xml`
1470
1471A sample of this output looks like:
1472
1473```xml
1474<!--
1475 Excerpt taken from:
1476 Build\MdePkg\HostTest\NOOPT_VS2022\X64\TestBaseSafeIntLibHost.exe.Int Safe Conversions Test Suite.X64.result.xml
1477 -->
1478<?xml version="1.0" encoding="UTF-8" ?>
1479<testsuites>
1480 <testsuite name="Int Safe Conversions Test Suite" time="0.000" tests="71" failures="1" errors="0" skipped="0" >
1481 <testcase name="Test SafeInt8ToUint8" time="0.000" >
1482 <failure><![CDATA[UT_ASSERT_EQUAL(0x5c:5c, Result:5b)
1483c:\_uefi\MdePkg\Test\UnitTest\Library\BaseSafeIntLib\TestBaseSafeIntLib.c:35: error: Failure!]]></failure>
1484 </testcase>
1485 <testcase name="Test SafeInt8ToUint16" time="0.000" >
1486 </testcase>
1487 <testcase name="Test SafeInt8ToUint32" time="0.000" >
1488 </testcase>
1489 <testcase name="Test SafeInt8ToUintn" time="0.000" >
1490 </testcase>
1491```
1492
1493### Manually Running Unit Test Executables
1494
1495The host based unit test executed using `stuart_ci_build` sets up the environment to run host based unit tests
1496including environment variable settings. If host based unit test executable are run manually either from a
1497shell or using VS Code extensions such as `C++ TestMate`, then the environment must be setup correctly.
1498
1499#### Windows Environment Variable Settings
1500
1501```
1502set GTEST_CATCH_EXCEPTIONS=0
1503set ASAN_OPTIONS=detect_leaks=0
1504```
1505
1506#### Linux Environment Variable Settings
1507
1508```
1509export GTEST_CATCH_EXCEPTIONS=0
1510export ASAN_OPTIONS=detect_leaks=0
1511```
1512
1513### XML Reporting Mode
1514
1515Unit test applications using Framework are built using Cmocka that requires the
1516following environment variables to be set to generate structured XML output
1517rather than text:
1518
1519```
1520CMOCKA_MESSAGE_OUTPUT=xml
1521CMOCKA_XML_FILE=<absolute or relative path to output file>
1522```
1523
1524Unit test applications using GoogleTest require the following environment
1525variable to be set to generate structured XML output rather than text:
1526
1527```
1528GTEST_OUTPUT=xml:<absolute or relative path to output file>
1529```
1530
1531This mode is used by the test running plugin to aggregate the results for CI test status reporting in the web view.
1532
1533### Code Coverage
1534
1535Host based Unit Tests will automatically enable coverage data.
1536
1537For Windows, this is primarily leveraged for pipeline builds, but this can be leveraged locally using the
1538OpenCppCoverage windows tool to parse coverage data to cobertura xml format.
1539
1540- Windows Prerequisite
1541 ```bash
1542 Download and install https://github.com/OpenCppCoverage/OpenCppCoverage/releases
1543 python -m pip install --upgrade -r ./pip-requirements.txt
1544 stuart_ci_build -c .pytool/CISettings.py -t NOOPT TOOL_CHAIN_TAG=VS2022 -p MdeModulePkg
1545 Open Build/coverage.xml
1546 ```
1547
1548 - How to see code coverage data on IDE Visual Studio
1549 ```
1550 Open Visual Studio VS2022 or above version
1551 Click "Tools" -> "OpenCppCoverage Settings"
1552 Fill your execute file into "Program to run:"
1553 Click "Tools" -> "Run OpenCppCoverage"
1554 ```
1555
1556
1557For Linux, this is primarily leveraged for pipeline builds, but this can be leveraged locally using the
1558lcov linux tool, and parsed using the lcov_cobertura python tool to parse it to cobertura xml format.
1559
1560- Linux Prerequisite
1561 ```bash
1562 sudo apt-get install -y lcov
1563 python -m pip install --upgrade -r ./pip-requirements.txt
1564 stuart_ci_build -c .pytool/CISettings.py -t NOOPT TOOL_CHAIN_TAG=GCC5 -p MdeModulePkg
1565 Open Build/coverage.xml
1566 ```
1567 - How to see code coverage data on IDE Visual Studio Code
1568 ```
1569 Download plugin "Coverage Gutters"
1570 Press Hot Key "Ctrl + Shift + P" and click option "Coverage Gutters: Display Coverage"
1571 ```
1572
1573
1574### Important Note
1575
1576This works on both Windows and Linux but is currently limited to x64 architectures. Working on getting others, but we
1577also welcome contributions.
1578
1579## Framework Known Limitations
1580
1581### PEI, DXE, SMM
1582
1583While sample tests have been provided for these execution environments, only cursory build validation
1584has been performed. Care has been taken while designing the frameworks to allow for execution during
1585boot phases, but only UEFI Shell and host-based tests have been thoroughly evaluated. Full support for
1586PEI, DXE, and SMM is forthcoming, but should be considered beta/staging for now.
1587
1588### Host-Based Support vs Other Tests
1589
1590The host-based test framework is powered internally by the Cmocka framework. As such, it has abilities
1591that the target-based tests don't (yet). It would be awesome if this meant that it was a super set of
1592the target-based tests, and it worked just like the target-based tests but with more features. Unfortunately,
1593this is not the case. While care has been taken to keep them as close as possible, there are a few known
1594inconsistencies that we're still ironing out. For example, the logging messages in the target-based tests
1595are cached internally and associated with the running test case. They can be saved later as part of the
1596reporting lib. This isn't currently possible with host-based. Only the assertion failures are logged.
1597
1598We will continue trying to make these as similar as possible.
1599
1600## Unit Test Location/Layout Rules
1601
1602Code/Test | Location
1603--------- | --------
1604Host-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.<br/>Example: `MdePkg/Test/UnitTest/[Library/Protocol/Ppi/Guid]/`<br/><br/>A real-world example of this is the BaseSafeIntLib test in MdePkg.<br/>`MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibHost.inf`
1605Host-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.<br/><br/>Module Example: `MdeModulePkg/Universal/EsrtFmpDxe/UnitTest/`<br/>Library Example: `MdePkg/Library/BaseMemoryLib/UnitTest/`<br/>Library Example (GoogleTest): `SecurityPkg/Library/SecureBootVariableLib/GoogleTest/`
1606Host-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.<br/>For example, if you were writing a test for the entire FMP Device Framework, you might put your test in:<br/>`FmpDevicePkg/Test/HostFuncTest/FmpDeviceFramework`<br/><br/>If the feature spans multiple packages, it's location should be determined by the package owners related to the feature.
1607Non-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.<br/><br/>If the feature spans multiple packages, it's location should be determined by the package owners related to the feature.<br/><br/>USAGE EXAMPLES<br/>PEI Example: MP_SERVICE_PPI. Or check MTRR configuration in a notification function.<br/> SMM Example: a test in a protocol callback function. (It is different with the solution that SmmAgent+ShellApp)<br/>DXE Example: a test in a UEFI event call back to check SPI/SMRAM status. <br/> 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.
1608
1609### Example Directory Tree
1610
1611```text
1612<PackageName>Pkg/
1613 ComponentY/
1614 ComponentY.inf
1615 ComponentY.c
1616 GoogleTest/
1617 ComponentYHostGoogleTest.inf # Host-Based Test for Driver Module
1618 ComponentYGoogleTest.cpp
1619 UnitTest/
1620 ComponentYHostUnitTest.inf # Host-Based Test for Driver Module
1621 ComponentYUnitTest.c
1622
1623 Library/
1624 GeneralPurposeLibBase/
1625 ...
1626
1627 GeneralPurposeLibSerial/
1628 ...
1629
1630 SpecificLibDxe/
1631 SpecificLibDxe.c
1632 SpecificLibDxe.inf
1633 GoogleTest/ # Host-Based Test for Specific Library Implementation
1634 SpecificLibDxeHostGoogleTest.cpp
1635 SpecificLibDxeHostGoogleTest.inf
1636 UnitTest/ # Host-Based Test for Specific Library Implementation
1637 SpecificLibDxeHostUnitTest.c
1638 SpecificLibDxeHostUnitTest.inf
1639 Test/
1640 <Package>HostTest.dsc # Host-Based Test Apps
1641 GoogleTest/
1642 InterfaceX
1643 InterfaceXHostGoogleTest.inf # Host-Based App (should be in Test/<Package>HostTest.dsc)
1644 InterfaceXUnitTest.cpp # Test Logic
1645
1646 GeneralPurposeLib/ # Host-Based Test for any implementation of GeneralPurposeLib
1647 GeneralPurposeLibTest.cpp
1648 GeneralPurposeLibHostUnitTest.inf
1649
1650 UnitTest/
1651 InterfaceX
1652 InterfaceXHostUnitTest.inf # Host-Based App (should be in Test/<Package>HostTest.dsc)
1653 InterfaceXPeiUnitTest.inf # PEIM Target-Based Test (if applicable)
1654 InterfaceXDxeUnitTest.inf # DXE Target-Based Test (if applicable)
1655 InterfaceXSmmUnitTest.inf # SMM Target-Based Test (if applicable)
1656 InterfaceXShellUnitTest.inf # Shell App Target-Based Test (if applicable)
1657 InterfaceXUnitTest.c # Test Logic
1658
1659 GeneralPurposeLib/ # Host-Based Test for any implementation of GeneralPurposeLib
1660 GeneralPurposeLibTest.c
1661 GeneralPurposeLibHostUnitTest.inf
1662
1663 Mock/
1664 Include/
1665 GoogleTest/
1666 Library/
1667 MockGeneralPurposeLib.h
1668
1669 Library/
1670 GoogleTest/
1671 MockGeneralPurposeLib/
1672 MockGeneralPurposeLib.cpp
1673 MockGeneralPurposeLib.inf
1674
1675 <Package>Pkg.dsc # Standard Modules and any Target-Based Test Apps (including in Test/)
1676```
1677
1678### Future Locations in Consideration
1679
1680We 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.
1681
1682Code/Test | Location
1683--------- | --------
1684Host-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.
1685Host-Based Mocks and Stubs | Mock and Stub libraries should live in the `UefiTestFrameworkPkg/StubLibrary` with either 'Mock' or 'Stub' in the library name.
1686
1687### If still in doubt...
1688
1689Hop on GitHub and ask @corthon, @mdkinney, or @spbrogan. ;)
1690
1691## Copyright
1692
1693Copyright (c) Microsoft Corporation.
1694SPDX-License-Identifier: BSD-2-Clause-Patent
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette