]> git.proxmox.com Git - mirror_edk2.git/blob - UnitTestFrameworkPkg/ReadMe.md
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UnitTestFrameworkPkg / ReadMe.md
1 # Unit Test Framework Package
2
3 ## About
4
5 This package provides unit test frameworks capable of building tests for multiple contexts including
6 the UEFI shell environment and host-based environments. It allows for unit test development to focus
7 on the tests and leave error logging, result formatting, context persistence, and test running to the framework.
8 The unit test framework works well for low level unit tests as well as system level tests and
9 fits easily in automation frameworks.
10
11 ### Framework
12
13 The first unit test framework is called **Framework** and is implemented as a set of EDK II libraries.
14 The Framework supports both host-based unit tests and target-based unit tests that share the same
15 source style, macros, and APIs. In some scenarios, the same unit test case sources can be built
16 for both host-based unit test execution and target-based unit test execution. Host-based unit tests
17 that 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
22 The second unit test framework supported by the UnitTestFrameworkPkg is
23 [GoogleTest](http://google.github.io/googletest/) that can be used to implement host-based unit tests.
24 Use of GoogleTest for target-based unit tests of EDK II components is not supported. If a
25 host-based unit test requires mocked interfaces, then the Framework with cmocka support should be
26 used instead. Enabling support for mocked interfaces with GoogleTest is being actively investigated.
27 [GoogleTest on GitHub](https://github.com/google/googletest) is included in the UnitTestFrameworkPkg
28 as a submodule.
29
30 GoogleTest requires less overhead to register test suites and test cases compared to the Framework.
31 There are also a number of tools that layer on top of GoogleTest that improve developer productivity.
32 One example is the VS Code extension
33 [C++ TestMate](https://marketplace.visualstudio.com/items?itemName=matepek.vscode-catch2-test-adapter)
34 that may be used to implement, run, and debug unit tests implemented using GoogleTest.
35
36 If a component can be tested with host-based unit tests without support for mocked interfaces,
37 then GoogleTest is recommended. The MdePkg contains a port of the BaseSafeIntLib unit tests in
38 the GoogleTest style so the differences between GoogleTest and Framework unit tests can be reviewed.
39 The paths to the BaseSafeIntLib unit tests are:
40
41 * MdePkg\Test\UnitTest\Library\BaseSafeIntLib
42 * MdePkg\Test\GoogleTest\Library\BaseSafeIntLib
43
44 ## Framework and GoogleTest Feature Comparison
45
46 | Feature | Framework | GoogleTest |
47 |:----------------------------|:---------:|:----------:|
48 | Host Based Unit Tests | YES | YES |
49 | Target Based Unit Tests | YES | NO |
50 | Unit Test Source Language | C | C++ |
51 | Register Test Suite | YES | Auto |
52 | Register Test Case | YES | Auto |
53 | Death/Expected Assert Tests | YES | YES |
54 | Setup/Teardown Hooks | YES | YES |
55 | Value-Parameterized Tests | NO | YES |
56 | Typed Tests | NO | YES |
57 | Type-Parameterized Tests | NO | YES |
58 | Timeout Support | NO | YES |
59 | Mocking Support | Cmocka | NO |
60 | JUNIT XML Reports | YES | YES |
61 | Execute subset of tests | NO | YES |
62 | VS Code Extensions | NO | YES |
63
64 ## Framework Libraries
65
66 ### UnitTestLib
67
68 The main "framework" library. The core of the framework is the Framework object, which can have any number
69 of test cases and test suites registered with it. The Framework object is also what drives test execution.
70
71 The Framework also provides helper macros and functions for checking test conditions and
72 reporting errors. Status and error info will be logged into the test context. There are a number
73 of Assert macros that make the unit test code friendly to view and easy to understand.
74
75 Finally, the Framework also supports logging strings during the test execution. This data is logged
76 to the test context and will be available in the test reporting phase. This should be used for
77 logging test details and helpful messages to resolve test failures.
78
79 ### UnitTestPersistenceLib
80
81 Persistence lib has the main job of saving and restoring test context to a storage medium so that for tests
82 that require exiting the active process and then resuming state can be maintained. This is critical
83 in supporting a system reboot in the middle of a test run.
84
85 ### UnitTestResultReportLib
86
87 Library provides function to run at the end of a framework test run and handles formatting the report.
88 This is a common customization point and allows the unit test framework to fit its output reports into
89 other test infrastructure. In this package simple library instances have been supplied to output test
90 results to the console as plain text.
91
92 ## Framework Samples
93
94 There is a sample unit test provided as both an example of how to write a unit test and leverage
95 many of the features of the framework. This sample can be found in the `Test/UnitTest/Sample/SampleUnitTest`
96 directory.
97
98 The sample is provided in PEI, SMM, DXE, and UEFI App flavors. It also has a flavor for the HOST_APPLICATION
99 build type, which can be run on a host system without needing a target.
100
101 ## Framework Usage
102
103 This section is built a lot like a "Getting Started". We'll go through some of the components that are needed
104 when constructing a unit test and some of the decisions that are made by the test writer. We'll also describe
105 how to check for expected conditions in test cases and a bit of the logging characteristics.
106
107 Most of these examples will refer to the SampleUnitTestUefiShell app found in this package.
108
109 ### Framework Requirements - INF
110
111 In our INF file, we'll need to bring in the `UnitTestLib` library. Conveniently, the interface
112 header for the `UnitTestLib` is located in `MdePkg`, so you shouldn't need to depend on any other
113 packages. As long as your DSC file knows where to find the lib implementation that you want to use,
114 you should be good to go.
115
116 See this example in 'SampleUnitTestUefiShell.inf'...
117
118 ```
119 [Packages]
120 MdePkg/MdePkg.dec
121
122 [LibraryClasses]
123 UefiApplicationEntryPoint
124 BaseLib
125 DebugLib
126 UnitTestLib
127 PrintLib
128 ```
129
130 Also, if you want you test to automatically be picked up by the Test Runner plugin, you will need
131 to make sure that the module `BASE_NAME` contains the word `Test`...
132
133 ```
134 [Defines]
135 BASE_NAME = SampleUnitTestUefiShell
136 ```
137
138 ### Framework Requirements - Code
139
140 Not to state the obvious, but let's make sure we have the following include before getting too far along...
141
142 ```c
143 #include <Library/UnitTestLib.h>
144 ```
145
146 Now that we've got that squared away, let's look at our 'Main()'' routine (or DriverEntryPoint() or whatever).
147
148 ### Framework Configuration
149
150 Everything in the UnitTestFrameworkPkg framework is built around an object called -- conveniently -- the Framework.
151 This Framework object will contain all the information about our test, the test suites and test cases associated
152 with it, the current location within the test pass, and any results that have been recorded so far.
153
154 To get started with a test, we must first create a Framework instance. The function for this is
155 `InitUnitTestFramework`. It takes in `CHAR8` strings for the long name, short name, and test version.
156 The long name and version strings are just for user presentation and relatively flexible. The short name
157 will be used to name any cache files and/or test results, so should be a name that makes sense in that context.
158 These strings are copied internally to the Framework, so using stack-allocated or literal strings is fine.
159
160 In the 'SampleUnitTestUefiShell' app, the module name is used as the short name, so the initialization looks like this.
161
162 ```c
163 DEBUG(( DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSION ));
164
165 //
166 // Start setting up the test framework for running the tests.
167 //
168 Status = InitUnitTestFramework( &Framework, UNIT_TEST_APP_NAME, gEfiCallerBaseName, UNIT_TEST_APP_VERSION );
169 ```
170
171 The `&Framework` returned here is the handle to the Framework. If it's successfully returned, we can start adding
172 test suites and test cases.
173
174 Test suites exist purely to help organize test cases and to differentiate the results in reports. If you're writing
175 a small unit test, you can conceivably put all test cases into a single suite. However, if you end up with 20+ test
176 cases, it may be beneficial to organize them according to purpose. You _must_ have at least one test suite, even if
177 it's just a catch-all. The function to create a test suite is `CreateUnitTestSuite`. It takes in a handle to
178 the Framework object, a `CHAR8` string for the suite title and package name, and optional function pointers for
179 a setup function and a teardown function.
180
181 The suite title is for user presentation. The package name is for xUnit type reporting and uses a '.'-separated
182 hierarchical format (see 'SampleUnitTestApp' for example). If provided, the setup and teardown functions will be
183 called once at the start of the suite (before _any_ tests have run) and once at the end of the suite (after _all_
184 tests have run), respectively. If either or both of these are unneeded, pass `NULL`. The function prototypes are
185 `UNIT_TEST_SUITE_SETUP` and `UNIT_TEST_SUITE_TEARDOWN`.
186
187 Looking at 'SampleUnitTestUefiShell' app, you can see that the first test suite is created as below...
188
189 ```c
190 //
191 // Populate the SimpleMathTests Unit Test Suite.
192 //
193 Status = CreateUnitTestSuite( &SimpleMathTests, Fw, "Simple Math Tests", "Sample.Math", NULL, NULL );
194 ```
195
196 This test suite has no setup or teardown functions. The `&SimpleMathTests` returned here is a handle to the suite and
197 will be used when adding test cases.
198
199 Great! Now we've finished some of the cruft, red tape, and busy work. We're ready to add some tests. Adding a test
200 to a test suite is accomplished with the -- you guessed it -- `AddTestCase` function. It takes in the suite handle;
201 a `CHAR8` string for the description and class name; a function pointer for the test case itself; additional, optional
202 function pointers for prerequisite check and cleanup routines; and an optional pointer to a context structure.
203
204 Okay, that's a lot. Let's take it one piece at a time. The description and class name strings are very similar in
205 usage to the suite title and package name strings in the test suites. The former is for user presentation and the
206 latter is for xUnit parsing. The test case function pointer is what is executed as the "test" and the
207 prototype should be `UNIT_TEST_FUNCTION`. The last three parameters require a little bit more explaining.
208
209 The prerequisite check function has a prototype of `UNIT_TEST_PREREQUISITE` and -- if provided -- will be called
210 immediately before the test case. If this function returns any error, the test case will not be run and will be
211 recorded as `UNIT_TEST_ERROR_PREREQUISITE_NOT_MET`. The cleanup function (prototype `UNIT_TEST_CLEANUP`) will be called
212 immediately after the test case to provide an opportunity to reset any global state that may have been changed in the
213 test case. In the event of a prerequisite failure, the cleanup function will also be skipped. If either of these
214 functions is not needed, pass `NULL`.
215
216 The context pointer is entirely case-specific. It will be passed to the test case upon execution. One of the purposes
217 of the context pointer is to allow test case reuse with different input data. (Another use is for testing that wraps
218 around a system reboot, but that's beyond the scope of this guide.) The test case must know how to interpret the context
219 pointer, so it could be a simple value, or it could be a complex structure. If unneeded, pass `NULL`.
220
221 In 'SampleUnitTestUefiShell' app, the first test case is added using the code below...
222
223 ```c
224 AddTestCase( SimpleMathTests, "Adding 1 to 1 should produce 2", "Addition", OnePlusOneShouldEqualTwo, NULL, NULL, NULL );
225 ```
226
227 This test case calls the function `OnePlusOneShouldEqualTwo` and has no prerequisite, cleanup, or context.
228
229 Once all the suites and cases are added, it's time to run the Framework.
230
231 ```c
232 //
233 // Execute the tests.
234 //
235 Status = RunAllTestSuites( Framework );
236 ```
237
238 ### Framework - A Simple Test Case
239
240 We'll take a look at the below test case from 'SampleUnitTestApp'...
241
242 ```c
243 UNIT_TEST_STATUS
244 EFIAPI
245 OnePlusOneShouldEqualTwo (
246 IN UNIT_TEST_FRAMEWORK_HANDLE Framework,
247 IN UNIT_TEST_CONTEXT Context
248 )
249 {
250 UINTN A, B, C;
251
252 A = 1;
253 B = 1;
254 C = A + B;
255
256 UT_ASSERT_EQUAL(C, 2);
257 return UNIT_TEST_PASSED;
258 } // OnePlusOneShouldEqualTwo()
259 ```
260
261 The prototype for this function matches the `UNIT_TEST_FUNCTION` prototype. It takes in a handle to the Framework
262 itself and the context pointer. The context pointer could be cast and interpreted as anything within this test case,
263 which is why it's important to configure contexts carefully. The test case returns a value of `UNIT_TEST_STATUS`, which
264 will be recorded in the Framework and reported at the end of all suites.
265
266 In this test case, the `UT_ASSERT_EQUAL` assertion is being used to establish that the business logic has functioned
267 correctly. There are several assertion macros, and you are encouraged to use one that matches as closely to your
268 intended test criterium as possible, because the logging is specific to the macro and more specific macros have more
269 detailed logs. When in doubt, there are always `UT_ASSERT_TRUE` and `UT_ASSERT_FALSE`. Assertion macros that fail their
270 test criterium will immediately return from the test case with `UNIT_TEST_ERROR_TEST_FAILED` and log an error string.
271 _Note_ that this early return can have implications for memory leakage.
272
273 At the end, if all test criteria pass, you should return `UNIT_TEST_PASSED`.
274
275 ### Framework - More Complex Cases
276
277 To write more advanced tests, first look at all the Assertion and Logging macros provided in the framework.
278
279 Beyond that, if you're writing host-based tests and want to take a dependency on the UnitTestFrameworkPkg, you can
280 leverage the `cmocka.h` interface and write tests with all the features of the Cmocka framework.
281
282 Documentation for Cmocka can be found here:
283 https://api.cmocka.org/
284
285 ## GoogleTest Samples
286
287 There is a sample unit test provided as both an example of how to write a unit test and leverage
288 many of the GoogleTest features. This sample can be found in the `Test/GoogleTest/Sample/SampleGoogleTest`
289 directory.
290
291 The sample is provided for the HOST_APPLICATION build type, which can be run on a host system without
292 needing a target.
293
294 ## GoogleTest Usage
295
296 This section is built a lot like a "Getting Started". We'll go through some of the components that are needed
297 when constructing a unit test and some of the decisions that are made by the test writer. We'll also describe
298 how to check for expected conditions in test cases and a bit of the logging characteristics.
299
300 Most of these examples will refer to the SampleGoogleTestHost app found in this package.
301
302 ### GoogleTest Requirements - INF
303
304 In our INF file, we'll need to bring in the `GoogleTest` library. Conveniently, the interface
305 header for the `GoogleTest` is in `UnitTestFrameworkPkg`, so you shouldn't need to depend on any other
306 packages. As long as your DSC file knows where to find the lib implementation that you want to use,
307 you should be good to go.
308
309 See this example in 'SampleGoogleTestHost.inf'...
310
311 ```
312 [Packages]
313 MdePkg/MdePkg.dec
314 UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
315
316 [LibraryClasses]
317 GoogleTestLib
318 BaseLib
319 DebugLib
320 ```
321
322 Also, if you want you test to automatically be picked up by the Test Runner plugin, you will need
323 to make sure that the module `BASE_NAME` contains the word `Test`...
324
325 ```
326 [Defines]
327 BASE_NAME = SampleGoogleTestHost
328 ```
329
330 ### GoogleTest Requirements - Code
331
332 Not to state the obvious, but let's make sure we have the following include before getting too far along...
333
334 ```
335 #include <gtest/gtest.h>
336 extern "C" {
337 #include <Uefi.h>
338 #include <Library/BaseLib.h>
339 #include <Library/DebugLib.h>
340 }
341 ```
342
343 GoogleTest applications are implemented in C++. The first include brings in the
344 GoogleTest definitions. Other EDK II related include files must be wrapped in
345 `extern "C" {}` because they are C include files. Link failures will occur if
346 this is not done.
347
348 Now that we've got that squared away, let's look at our 'Main()'' routine (or DriverEntryPoint() or whatever).
349
350 ### GoogleTest Configuration
351
352 Unlike the Framework, GoogleTest does not require test suites or test cases to
353 be registered. Instead, the test cases declare the test suite name and test
354 case name as part of their implementation. The only requirement for GoogleTest
355 is to have a `main()` function that initialize the GoogleTest infrastructure and
356 call the service `RUN_ALL_TESTS()` to run all the unit tests.
357
358 ```c
359 int main(int argc, char* argv[]) {
360 testing::InitGoogleTest(&argc, argv);
361 return RUN_ALL_TESTS();
362 }
363 ```
364
365 ### GoogleTest - A Simple Test Case
366
367 We'll look at the below test case from 'SampleGoogleTestHost'...
368
369 ```c
370 TEST(SimpleMathTests, OnePlusOneShouldEqualTwo) {
371 UINTN A;
372 UINTN B;
373 UINTN C;
374
375 A = 1;
376 B = 1;
377 C = A + B;
378
379 ASSERT_EQ (C, 2);
380 }
381 ```
382
383 This uses the simplest form of a GoogleTest unit test using `TEST()` that
384 declares the test suite name and the unit test name within that test suite.
385 The unit test performs actions and typically makes calls to the code under test
386 and contains test assertions to verify that the code under test behaves as
387 expected for the given inputs.
388
389 In this test case, the `ASSERT_EQ` assertion is being used to establish that the business logic has functioned
390 correctly. There are several assertion macros, and you are encouraged to use one that matches as closely to your
391 intended test criterium as possible, because the logging is specific to the macro and more specific macros have more
392 detailed logs. When in doubt, there are always `ASSERT_TRUE` and `ASSERT_FALSE`. Assertion macros that fail their
393 test criterium will immediately return from the test case with a failed status and log an error string.
394 _Note_ that this early return can have implications for memory leakage.
395
396 There is no return status from a GooglTest unit test. If no assertions are
397 triggered then the unit test has a passing status.
398
399 ### GoogleTest - More Complex Cases
400
401 To write more advanced tests, take a look at the
402 [GoogleTest User's Guide](http://google.github.io/googletest/).
403
404 ## Development
405
406 ### Iterating on a Single Test
407
408 When using the EDK2 Pytools for CI testing, the host-based unit tests will be built and run on any build that includes
409 the `NOOPT` build target.
410
411 If you are trying to iterate on a single test, a convenient pattern is to build only that test module. For example,
412 the following command will build only the SafeIntLib host-based test from the MdePkg...
413
414 ```bash
415 stuart_ci_build -c .pytool/CISettings.py TOOL_CHAIN_TAG=VS2017 -p MdePkg -t NOOPT BUILDMODULE=MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.inf
416 ```
417
418 ### Hooking BaseLib
419
420 Most unit test mocking can be performed by the functions provided in the UnitTestFrameworkPkg libraries, but since
421 BaseLib is consumed by the Framework itself, it requires different techniques to substitute parts of the
422 functionality.
423
424 To solve some of this, the UnitTestFrameworkPkg consumes a special implementation of BaseLib for host-based tests.
425 This implementation contains a [hook table](https://github.com/tianocore/edk2/blob/e188ecc8b4aed8fdd26b731d43883861f5e5e7b4/MdePkg/Test/UnitTest/Include/Library/UnitTestHostBaseLib.h#L507)
426 that can be used to substitute test functionality for any of the BaseLib functions. By default, this implementation
427 will use the underlying BaseLib implementation, so the unit test writer only has to supply minimal code to test a
428 particular case.
429
430 ### Debugging the Framework Itself
431
432 While most of the tests that are produced by the UnitTestFrameworkPkg are easy to step through in a debugger, the Framework
433 itself consumes code (mostly Cmocka) that sets its own build flags. These flags cause parts of the Framework to not
434 export symbols and captures exceptions, and as such are harder to debug. We have provided a Stuart parameter to force
435 symbolic debugging to be enabled.
436
437 You can run a build by adding the `BLD_*_UNIT_TESTING_DEBUG=TRUE` parameter to enable this build option.
438
439 ```bash
440 stuart_ci_build -c .pytool/CISettings.py TOOL_CHAIN_TAG=VS2019 -p MdePkg -t NOOPT BLD_*_UNIT_TESTING_DEBUG=TRUE
441 ```
442
443 ## Building and Running Host-Based Tests
444
445 The EDK2 CI infrastructure provides a convenient way to run all host-based tests -- in the the entire tree or just
446 selected packages -- and aggregate all the reports, including highlighting any failures. This functionality is
447 provided through the Stuart build system (published by EDK2-PyTools) and the `NOOPT` build target. The sections that
448 follow use Framework examples. Unit tests based on GoogleTest are built and run the same way. The text output and
449 JUNIT XML output format have small differences.
450
451 ### Building Locally
452
453 First, to make sure you're working with the latest PyTools, run the following command:
454
455 ```bash
456 # Would recommend running this in a Python venv, but that's out of scope for this doc.
457 python -m pip install --upgrade -r ./pip-requirements.txt
458 ```
459
460 After that, the following commands will set up the build and run the host-based tests.
461
462 ```bash
463 # Setup repo for building
464 # stuart_setup -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=<GCC5, VS2019, etc.>
465 stuart_setup -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=VS2019
466
467 # Update all binary dependencies
468 # stuart_update -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=<GCC5, VS2019, etc.>
469 stuart_update -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=VS2019
470
471 # Build and run the tests
472 # stuart_ci_build -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=<GCC5, VS2019, etc.> -t NOOPT [-p <Package Name>]
473 stuart_ci_build -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=VS2019 -t NOOPT -p MdePkg
474 ```
475
476 ### Evaluating the Results
477
478 In your immediate output, any build failures will be highlighted. You can see these below as "WARNING" and "ERROR" messages.
479
480 ```text
481 (edk_env) PS C:\_uefi\edk2> stuart_ci_build -c .\.pytool\CISettings.py TOOL_CHAIN_TAG=VS2019 -t NOOPT -p MdePkg
482
483 SECTION - Init SDE
484 SECTION - Loading Plugins
485 SECTION - Start Invocable Tool
486 SECTION - Getting Environment
487 SECTION - Loading plugins
488 SECTION - Building MdePkg Package
489 PROGRESS - --Running MdePkg: Host Unit Test Compiler Plugin NOOPT --
490 WARNING - Allowing Override for key TARGET_ARCH
491 PROGRESS - Start time: 2020-07-27 17:18:08.521672
492 PROGRESS - Setting up the Environment
493 PROGRESS - Running Pre Build
494 PROGRESS - Running Build NOOPT
495 PROGRESS - Running Post Build
496 SECTION - Run Host based Unit Tests
497 SUBSECTION - Testing for architecture: X64
498 WARNING - TestBaseSafeIntLibHost.exe Test Failed
499 WARNING - Test SafeInt8ToUint8 - UT_ASSERT_EQUAL(0x5b:5b, Result:5c)
500 c:\_uefi\edk2\MdePkg\Test\UnitTest\Library\BaseSafeIntLib\TestBaseSafeIntLib.c:35: error: Failure!
501 ERROR - Plugin Failed: Host-Based Unit Test Runner returned 1
502 CRITICAL - Post Build failed
503 PROGRESS - End time: 2020-07-27 17:18:19.792313 Total time Elapsed: 0:00:11
504 ERROR - --->Test Failed: Host Unit Test Compiler Plugin NOOPT returned 1
505 ERROR - Overall Build Status: Error
506 PROGRESS - There were 1 failures out of 1 attempts
507 SECTION - Summary
508 ERROR - Error
509
510 (edk_env) PS C:\_uefi\edk2>
511 ```
512
513 If a test fails, you can run it manually to get more details...
514
515 ```text
516 (edk_env) PS C:\_uefi\edk2> .\Build\MdePkg\HostTest\NOOPT_VS2019\X64\TestBaseSafeIntLibHost.exe
517
518 Int Safe Lib Unit Test Application v0.1
519 ---------------------------------------------------------
520 ------------ RUNNING ALL TEST SUITES --------------
521 ---------------------------------------------------------
522 ---------------------------------------------------------
523 RUNNING TEST SUITE: Int Safe Conversions Test Suite
524 ---------------------------------------------------------
525 [==========] Running 71 test(s).
526 [ RUN ] Test SafeInt8ToUint8
527 [ ERROR ] --- UT_ASSERT_EQUAL(0x5b:5b, Result:5c)
528 [ LINE ] --- c:\_uefi\edk2\MdePkg\Test\UnitTest\Library\BaseSafeIntLib\TestBaseSafeIntLib.c:35: error: Failure!
529 [ FAILED ] Test SafeInt8ToUint8
530 [ RUN ] Test SafeInt8ToUint16
531 [ OK ] Test SafeInt8ToUint16
532 [ RUN ] Test SafeInt8ToUint32
533 [ OK ] Test SafeInt8ToUint32
534 [ RUN ] Test SafeInt8ToUintn
535 [ OK ] Test SafeInt8ToUintn
536 ...
537 ```
538
539 You can also, if you are so inclined, read the output from the exact instance of the test that was run during
540 `stuart_ci_build`. The output file can be found on a path that looks like:
541
542 `Build/<Package>/HostTest/<Arch>/<TestName>.<TestSuiteName>.<Arch>.result.xml`
543
544 A sample of this output looks like:
545
546 ```xml
547 <!--
548 Excerpt taken from:
549 Build\MdePkg\HostTest\NOOPT_VS2019\X64\TestBaseSafeIntLibHost.exe.Int Safe Conversions Test Suite.X64.result.xml
550 -->
551 <?xml version="1.0" encoding="UTF-8" ?>
552 <testsuites>
553 <testsuite name="Int Safe Conversions Test Suite" time="0.000" tests="71" failures="1" errors="0" skipped="0" >
554 <testcase name="Test SafeInt8ToUint8" time="0.000" >
555 <failure><![CDATA[UT_ASSERT_EQUAL(0x5c:5c, Result:5b)
556 c:\_uefi\MdePkg\Test\UnitTest\Library\BaseSafeIntLib\TestBaseSafeIntLib.c:35: error: Failure!]]></failure>
557 </testcase>
558 <testcase name="Test SafeInt8ToUint16" time="0.000" >
559 </testcase>
560 <testcase name="Test SafeInt8ToUint32" time="0.000" >
561 </testcase>
562 <testcase name="Test SafeInt8ToUintn" time="0.000" >
563 </testcase>
564 ```
565
566 ### XML Reporting Mode
567
568 Unit test applications using Framework are built using Cmocka that requires the
569 following environment variables to be set to generate structured XML output
570 rather than text:
571
572 ```
573 CMOCKA_MESSAGE_OUTPUT=xml
574 CMOCKA_XML_FILE=<absolute or relative path to output file>
575 ```
576
577 Unit test applications using GoogleTest require the following environment
578 variable to be set to generate structured XML output rather than text:
579
580 ```
581 GTEST_OUTPUT=xml:<absolute or relative path to output file>
582 ```
583
584 This mode is used by the test running plugin to aggregate the results for CI test status reporting in the web view.
585
586 ### Code Coverage
587
588 Host based Unit Tests will automatically enable coverage data.
589
590 For Windows, This is primarily leverage for pipeline builds, but this can be leveraged locally using the
591 OpenCppCoverage windows tool to parse coverage data to cobertura xml format.
592
593 - Windows Prerequisite
594 ```bash
595 Download and install https://github.com/OpenCppCoverage/OpenCppCoverage/releases
596 python -m pip install --upgrade -r ./pip-requirements.txt
597 stuart_ci_build -c .pytool/CISettings.py -t NOOPT TOOL_CHAIN_TAG=VS2019 -p MdeModulePkg
598 Open Build/coverage.xml
599 ```
600
601 - How to see code coverage data on IDE Visual Studio
602 ```
603 Open Visual Studio VS2019 or above version
604 Click "Tools" -> "OpenCppCoverage Settings"
605 Fill your execute file into "Program to run:"
606 Click "Tools" -> "Run OpenCppCoverage"
607 ```
608
609
610 For Linux, This is primarily leveraged for pipeline builds, but this can be leveraged locally using the
611 lcov linux tool, and parsed using the lcov_cobertura python tool to parse it to cobertura xml format.
612
613 - Linux Prerequisite
614 ```bash
615 sudo apt-get install -y lcov
616 python -m pip install --upgrade -r ./pip-requirements.txt
617 stuart_ci_build -c .pytool/CISettings.py -t NOOPT TOOL_CHAIN_TAG=GCC5 -p MdeModulePkg
618 Open Build/coverage.xml
619 ```
620 - How to see code coverage data on IDE Visual Studio Code
621 ```
622 Download plugin "Coverage Gutters"
623 Press Hot Key "Ctrl + Shift + P" and click option "Coverage Gutters: Display Coverage"
624 ```
625
626
627 ### Important Note
628
629 This works on both Windows and Linux but is currently limited to x64 architectures. Working on getting others, but we
630 also welcome contributions.
631
632 ## Framework Known Limitations
633
634 ### PEI, DXE, SMM
635
636 While sample tests have been provided for these execution environments, only cursory build validation
637 has been performed. Care has been taken while designing the frameworks to allow for execution during
638 boot phases, but only UEFI Shell and host-based tests have been thoroughly evaluated. Full support for
639 PEI, DXE, and SMM is forthcoming, but should be considered beta/staging for now.
640
641 ### Host-Based Support vs Other Tests
642
643 The host-based test framework is powered internally by the Cmocka framework. As such, it has abilities
644 that the target-based tests don't (yet). It would be awesome if this meant that it was a super set of
645 the target-based tests, and it worked just like the target-based tests but with more features. Unfortunately,
646 this is not the case. While care has been taken to keep them as close as possible, there are a few known
647 inconsistencies that we're still ironing out. For example, the logging messages in the target-based tests
648 are cached internally and associated with the running test case. They can be saved later as part of the
649 reporting lib. This isn't currently possible with host-based. Only the assertion failures are logged.
650
651 We will continue trying to make these as similar as possible.
652
653 ## Unit Test Location/Layout Rules
654
655 Code/Test | Location
656 --------- | --------
657 Host-Based Unit Tests for a Library/Protocol/PPI/GUID Interface | If what's being tested is an interface (e.g. a library with a public header file, like DebugLib), 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`
658 Host-Based Unit Tests for a Library/Driver (PEI/DXE/SMM) implementation | If what's being tested is a specific implementation (e.g. BaseDebugLibSerialPort for DebugLib), the test should be scoped to the implementation directory itself, in a UnitTest subdirectory.<br/><br/>Module Example: `MdeModulePkg/Universal/EsrtFmpDxe/UnitTest/`<br/>Library Example: `MdePkg/Library/BaseMemoryLib/UnitTest/`
659 Host-Based Tests for a Functionality or Feature | If you're writing a functional test that operates at the module level (i.e. if it's more than a single file or library), the test should be located in the package-level Tests directory under the HostFuncTest subdirectory.<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.
660 Non-Host-Based (PEI/DXE/SMM/Shell) Tests for a Functionality or Feature | Similar to Host-Based, if the feature is in one package, should be located in the `*Pkg/Test/[Shell/Dxe/Smm/Pei]Test` directory.<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.
661
662 ### Example Directory Tree
663
664 ```text
665 <PackageName>Pkg/
666 ComponentY/
667 ComponentY.inf
668 ComponentY.c
669 GoogleTest/
670 ComponentYHostGoogleTest.inf # Host-Based Test for Driver Module
671 ComponentYGoogleTest.cpp
672 UnitTest/
673 ComponentYHostUnitTest.inf # Host-Based Test for Driver Module
674 ComponentYUnitTest.c
675
676 Library/
677 GeneralPurposeLibBase/
678 ...
679
680 GeneralPurposeLibSerial/
681 ...
682
683 SpecificLibDxe/
684 SpecificLibDxe.c
685 SpecificLibDxe.inf
686 GoogleTest/ # Host-Based Test for Specific Library Implementation
687 SpecificLibDxeHostGoogleTest.cpp
688 SpecificLibDxeHostGoogleTest.inf
689 UnitTest/ # Host-Based Test for Specific Library Implementation
690 SpecificLibDxeHostUnitTest.c
691 SpecificLibDxeHostUnitTest.inf
692 Test/
693 <Package>HostTest.dsc # Host-Based Test Apps
694 GoogleTest/
695 InterfaceX
696 InterfaceXHostGoogleTest.inf # Host-Based App (should be in Test/<Package>HostTest.dsc)
697 InterfaceXUnitTest.cpp # Test Logic
698
699 GeneralPurposeLib/ # Host-Based Test for any implementation of GeneralPurposeLib
700 GeneralPurposeLibTest.cpp
701 GeneralPurposeLibHostUnitTest.inf
702
703 UnitTest/
704 InterfaceX
705 InterfaceXHostUnitTest.inf # Host-Based App (should be in Test/<Package>HostTest.dsc)
706 InterfaceXPeiUnitTest.inf # PEIM Target-Based Test (if applicable)
707 InterfaceXDxeUnitTest.inf # DXE Target-Based Test (if applicable)
708 InterfaceXSmmUnitTest.inf # SMM Target-Based Test (if applicable)
709 InterfaceXShellUnitTest.inf # Shell App Target-Based Test (if applicable)
710 InterfaceXUnitTest.c # Test Logic
711
712 GeneralPurposeLib/ # Host-Based Test for any implementation of GeneralPurposeLib
713 GeneralPurposeLibTest.c
714 GeneralPurposeLibHostUnitTest.inf
715
716 <Package>Pkg.dsc # Standard Modules and any Target-Based Test Apps (including in Test/)
717
718 ```
719
720 ### Future Locations in Consideration
721
722 We don't know if these types will exist or be applicable yet, but if you write a support library or module that matches the following, please make sure they live in the correct place.
723
724 Code/Test | Location
725 --------- | --------
726 Host-Based Library Implementations | Host-Based Implementations of common libraries (eg. MemoryAllocationLibHost) should live in the same package that declares the library interface in its .DEC file in the `*Pkg/HostLibrary` directory. Should have 'Host' in the name.
727 Host-Based Mocks and Stubs | Mock and Stub libraries should live in the `UefiTestFrameworkPkg/StubLibrary` with either 'Mock' or 'Stub' in the library name.
728
729 ### If still in doubt...
730
731 Hop on GitHub and ask @corthon, @mdkinney, or @spbrogan. ;)
732
733 ## Copyright
734
735 Copyright (c) Microsoft Corporation.
736 SPDX-License-Identifier: BSD-2-Clause-Patent