1.. _module-pw_unit_test: 2 3============ 4pw_unit_test 5============ 6``pw_unit_test`` provides a `GoogleTest`_-compatible unit testing API for 7Pigweed. The default implementation is the embedded-friendly 8``pw_unit_test:light`` backend. Upstream GoogleTest may be used as well (see 9`Using upstream GoogleTest`_). 10 11.. _GoogleTest: https://github.com/google/googletest 12 13.. note:: 14 15 This documentation is currently incomplete. 16 17------------------------------------------- 18pw_unit_test:light: GoogleTest for Embedded 19------------------------------------------- 20``pw_unit_test:light`` implements a subset of `GoogleTest`_ with lightweight, 21embedded-friendly primitives. It is also highly portable and can run on almost 22any system from bare metal to a full-fledged desktop OS. It does this by 23offloading the responsibility of test reporting and output to the underlying 24system, communicating its results through a common interface. Unit tests can be 25written once and run under many different environments, empowering developers to 26write robust, high quality code. 27 28``pw_unit_test:light`` usage is the same as GoogleTest; 29refer to the `GoogleTest documentation <https://google.github.io/googletest/>`_ 30for examples of how to define unit test cases. 31 32``pw_unit_test:light`` is still under development and lacks many features 33expected in a complete testing framework; nevertheless, it is already used 34heavily within Pigweed. 35 36.. note:: 37 38 Many of GoogleTest's more advanced features are not yet implemented. Missing 39 features include: 40 41 * Any GoogleMock features (e.g. :c:macro:`EXPECT_THAT`) 42 * Floating point comparison macros (e.g. :c:macro:`EXPECT_FLOAT_EQ`) 43 * Death tests (e.g. :c:macro:`EXPECT_DEATH`); ``EXPECT_DEATH_IF_SUPPORTED`` 44 does nothing but silently passes 45 * Value-parameterized tests 46 47 To request a feature addition, please 48 `let us know <mailto:pigweed@googlegroups.com>`_. 49 50 See `Using upstream GoogleTest`_ below for information 51 about using upstream GoogleTest instead. 52 53The EventHandler interface 54========================== 55The ``EventHandler`` class in ``public/pw_unit_test/event_handler.h`` defines 56the interface through which ``pw_unit_test:light`` communicates the results of 57its test runs. A platform using the ``pw_unit_test:light`` backend must register 58an event handler with the unit testing framework to receive test output. 59 60As the framework runs tests, it calls the event handler's callback functions to 61notify the system of various test events. The system can then choose to perform 62any necessary handling or aggregation of these events, and report them back to 63the developer. 64 65Predefined event handlers 66------------------------- 67Pigweed provides some standard event handlers upstream to simplify the process 68of getting started using ``pw_unit_test:light``. All event handlers provide for 69GoogleTest-style output using the shared 70:cpp:class:`pw::unit_test::GoogleTestStyleEventHandler` base. 71 72.. code-block:: 73 74 [==========] Running all tests. 75 [ RUN ] Status.Default 76 [ OK ] Status.Default 77 [ RUN ] Status.ConstructWithStatusCode 78 [ OK ] Status.ConstructWithStatusCode 79 [ RUN ] Status.AssignFromStatusCode 80 [ OK ] Status.AssignFromStatusCode 81 [ RUN ] Status.CompareToStatusCode 82 [ OK ] Status.CompareToStatusCode 83 [ RUN ] Status.Ok_OkIsTrue 84 [ OK ] Status.Ok_OkIsTrue 85 [ RUN ] Status.NotOk_OkIsFalse 86 [ OK ] Status.NotOk_OkIsFalse 87 [ RUN ] Status.KnownString 88 [ OK ] Status.KnownString 89 [ RUN ] Status.UnknownString 90 [ OK ] Status.UnknownString 91 [==========] Done running all tests. 92 [ PASSED ] 8 test(s). 93 94.. cpp:namespace-push:: pw::unit_test 95 96.. cpp:class:: GoogleTestStyleEventHandler 97 98 Provides GoogleTest-style output for ``pw_unit_test:light`` events. Must be 99 extended to define how to output the results. 100 101.. cpp:class:: SimplePrintingEventHandler : public GoogleTestStyleEventHandler 102 103 An event handler that writes GoogleTest-style output to a specified sink. 104 105.. cpp:class:: LoggingEventHandler : public GoogleTestStyleEventHandler 106 107 An event handler which uses the ``pw_log`` module to output test results, to 108 integrate with the system's existing logging setup. 109 110.. cpp:class:: PrintfEventHandler : public GoogleTestStyleEventHandler 111 112 A C++14-compatible event handler that uses ``std::printf`` to output test 113 results. 114 115.. cpp:namespace-pop:: 116 117Test filtering 118============== 119If using C++17, filters can be set on the test framework to run only a subset of 120the registered unit tests. This is useful when many tests are bundled into a 121single application image. 122 123Currently, only a test suite filter is supported. This is set by calling 124``pw::unit_test::SetTestSuitesToRun`` with a list of suite names. 125 126.. note:: 127 128 Test filtering is only supported in C++17. 129 130Tests in static libraries 131========================= 132The linker usually ignores tests linked through a static library (``.a`` file). 133This is because test registration relies on the test instance's static 134constructor adding itself to a global list of tests. When linking against a 135static library, static constructors in an object file will be ignored unless at 136least one entity in that object file is linked. 137 138Pigweed's ``pw_unit_test`` implementation provides the 139:c:macro:`PW_UNIT_TEST_LINK_FILE_CONTAINING_TEST` macro to support running tests 140in a static library. 141 142.. c:macro:: PW_UNIT_TEST_LINK_FILE_CONTAINING_TEST(test_suite_name, test_name) 143 144 Ensures tests in a static library are linked and executed. Provide the test 145 suite name and test name for one test in the file linked into a static 146 library. Any test in the file may be used, but it is recommended to use the 147 first for consistency. The test must be in a static library that is a 148 dependency of this target. Referring to a test that does not exist causes a 149 linker error. 150 151.. _running-tests: 152 153------------- 154Running tests 155------------- 156To run unit tests, link the tests into a single binary with the unit testing 157framework, configure the backend if needed, and call the ``RUN_ALL_TESTS`` 158macro. 159 160The following example shows how to write a main function that runs 161``pw_unit_test`` with the ``light`` backend. 162 163.. code-block:: cpp 164 165 #include "gtest/gtest.h" 166 167 // pw_unit_test:light requires an event handler to be configured. 168 #include "pw_unit_test/simple_printing_event_handler.h" 169 170 void WriteString(const std::string_view& string, bool newline) { 171 printf("%s", string.data()); 172 if (newline) { 173 printf("\n"); 174 } 175 } 176 177 int main() { 178 // Since we are using pw_unit_test:light, set up an event handler. 179 pw::unit_test::SimplePrintingEventHandler handler(WriteString); 180 pw::unit_test::RegisterEventHandler(&handler); 181 return RUN_ALL_TESTS(); 182 } 183 184Build system integration 185======================== 186``pw_unit_test`` integrates directly into Pigweed's GN and CMake build systems. 187 188The ``pw_unit_test`` module provides a few optional libraries to simplify setup: 189 190- ``simple_printing_event_handler``: When running tests, output test results 191 as plain text over ``pw_sys_io``. 192- ``simple_printing_main``: Implements a ``main()`` function that simply runs 193 tests using the ``simple_printing_event_handler``. 194- ``logging_event_handler``: When running tests, log test results as 195 plain text using pw_log (ensure your target has set a ``pw_log`` backend). 196- ``logging_main``: Implements a ``main()`` function that simply runs tests 197 using the ``logging_event_handler``. 198 199 200GN 201-- 202To define simple unit tests, set the ``pw_unit_test_MAIN`` build variable to a 203target which configures the test framework as described in the 204:ref:`running-tests` section, and use the ``pw_test`` template to register your 205test code. 206 207.. code-block:: 208 209 import("$dir_pw_unit_test/test.gni") 210 211 pw_test("foo_test") { 212 sources = [ "foo_test.cc" ] 213 } 214 215pw_test template 216```````````````` 217``pw_test`` defines a single unit test suite. It creates several sub-targets. 218 219* ``<target_name>``: The test suite within a single binary. The test code is 220 linked against the target set in the build arg ``pw_unit_test_MAIN``. 221* ``<target_name>.run``: If ``pw_unit_test_AUTOMATIC_RUNNER`` is set, this 222 target runs the test as part of the build. 223* ``<target_name>.lib``: The test sources without ``pw_unit_test_MAIN``. 224 225**Arguments** 226 227* All GN executable arguments are accepted and forwarded to the underlying 228 ``pw_executable``. 229* ``enable_if``: Boolean indicating whether the test should be built. If false, 230 replaces the test with an empty target. Default true. 231* ``test_main``: Target label to add to the tests's dependencies to provide the 232 ``main()`` function. Defaults to ``pw_unit_test_MAIN``. Set to ``""`` if 233 ``main()`` is implemented in the test's ``sources``. 234* ``test_automatic_runner_args``: Array of args to pass to automatic test 235 runner. Defaults to ``pw_unit_test_AUTOMATIC_RUNNER_ARGS``. 236 237**Example** 238 239.. code:: 240 241 import("$dir_pw_unit_test/test.gni") 242 243 pw_test("large_test") { 244 sources = [ "large_test.cc" ] 245 enable_if = device_has_1m_flash 246 } 247 248pw_test_group template 249`````````````````````` 250``pw_test_group`` defines a collection of tests or other test groups. It creates 251several sub-targets: 252 253* ``<target_name>``: The test group itself. 254* ``<target_name>.run``: If ``pw_unit_test_AUTOMATIC_RUNNER`` is set, this 255 target runs all of the tests in the group and all of its group dependencies 256 individually. 257* ``<target_name>.lib``: The sources of all of the tests in this group and its 258 dependencies. 259* ``<target_name>.bundle``: All of the tests in the group and its dependencies 260 bundled into a single binary. 261* ``<target_name>.bundle.run``: Automatic runner for the test bundle. 262 263**Arguments** 264 265* ``tests``: List of the ``pw_test`` targets in the group. 266* ``group_deps``: List of other ``pw_test_group`` targets on which this one 267 depends. 268* ``enable_if``: Boolean indicating whether the group target should be created. 269 If false, an empty GN group is created instead. Default true. 270 271**Example** 272 273.. code:: 274 275 import("$dir_pw_unit_test/test.gni") 276 277 pw_test_group("tests") { 278 tests = [ 279 ":bar_test", 280 ":foo_test", 281 ] 282 } 283 284 pw_test("foo_test") { 285 # ... 286 } 287 288 pw_test("bar_test") { 289 # ... 290 } 291 292pw_facade_test template 293``````````````````````` 294Pigweed facade test templates allow individual unit tests to build under the 295current device target configuration while overriding specific build arguments. 296This allows these tests to replace a facade's backend for the purpose of testing 297the facade layer. 298 299Facade tests are disabled by default. To build and run facade tests, set the GN 300arg :option:`pw_unit_test_FACADE_TESTS_ENABLED` to ``true``. 301 302.. warning:: 303 Facade tests are costly because each facade test will trigger a re-build of 304 every dependency of the test. While this sounds excessive, it's the only 305 technically correct way to handle this type of test. 306 307.. warning:: 308 Some facade test configurations may not be compatible with your target. Be 309 careful when running a facade test on a system that heavily depends on the 310 facade being tested. 311 312Build arguments 313``````````````` 314.. option:: pw_unit_test_GOOGLETEST_BACKEND <source_set> 315 316 The GoogleTest implementation to use for Pigweed unit tests. This library 317 provides "gtest/gtest.h" and related headers. Defaults to pw_unit_test:light, 318 which implements a subset of GoogleTest. 319 320 Type: string (GN path to a source set) 321 Usage: toolchain-controlled only 322 323.. option:: pw_unit_test_MAIN <source_set> 324 325 Implementation of a main function for ``pw_test`` unit test binaries. 326 327 Type: string (GN path to a source set) 328 Usage: toolchain-controlled only 329 330.. option:: pw_unit_test_AUTOMATIC_RUNNER <executable> 331 332 Path to a test runner to automatically run unit tests after they are built. 333 334 If set, a ``pw_test`` target's ``<target_name>.run`` action will invoke the 335 test runner specified by this argument, passing the path to the unit test to 336 run. If this is unset, the ``pw_test`` target's ``<target_name>.run`` step 337 will do nothing. 338 339 Targets that don't support parallelized execution of tests (e.g. a on-device 340 test runner that must flash a device and run the test in serial) should set 341 pw_unit_test_POOL_DEPTH to 1. 342 343 Type: string (name of an executable on the PATH, or path to an executable) 344 Usage: toolchain-controlled only 345 346.. option:: pw_unit_test_AUTOMATIC_RUNNER_ARGS <args> 347 348 An optional list of strings to pass as args to the test runner specified by 349 pw_unit_test_AUTOMATIC_RUNNER. 350 351 Type: list of strings (args to pass to pw_unit_test_AUTOMATIC_RUNNER) 352 Usage: toolchain-controlled only 353 354.. option:: pw_unit_test_AUTOMATIC_RUNNER_TIMEOUT <timeout_seconds> 355 356 An optional timeout to apply when running the automatic runner. Timeout is 357 in seconds. Defaults to empty which means no timeout. 358 359 Type: string (number of seconds to wait before killing test runner) 360 Usage: toolchain-controlled only 361 362.. option:: pw_unit_test_POOL_DEPTH <pool_depth> 363 364 The maximum number of unit tests that may be run concurrently for the 365 current toolchain. Setting this to 0 disables usage of a pool, allowing 366 unlimited parallelization. 367 368 Note: A single target with two toolchain configurations (e.g. release/debug) 369 will use two separate test runner pools by default. Set 370 pw_unit_test_POOL_TOOLCHAIN to the same toolchain for both targets to 371 merge the pools and force serialization. 372 373 Type: integer 374 Usage: toolchain-controlled only 375 376.. option:: pw_unit_test_POOL_TOOLCHAIN <toolchain> 377 378 The toolchain to use when referring to the pw_unit_test runner pool. When 379 this is disabled, the current toolchain is used. This means that every 380 toolchain will use its own pool definition. If two toolchains should share 381 the same pool, this argument should be by one of the toolchains to the GN 382 path of the other toolchain. 383 384 Type: string (GN path to a toolchain) 385 Usage: toolchain-controlled only 386 387.. option:: pw_unit_test_EXECUTABLE_TARGET_TYPE <template name> 388 389 The name of the GN target type used to build pw_unit_test executables. 390 391 Type: string (name of a GN template) 392 Usage: toolchain-controlled only 393 394.. option:: pw_unit_test_EXECUTABLE_TARGET_TYPE_FILE <gni file path> 395 396 The path to the .gni file that defines pw_unit_test_EXECUTABLE_TARGET_TYPE. 397 398 If pw_unit_test_EXECUTABLE_TARGET_TYPE is not the default of 399 `pw_executable`, this .gni file is imported to provide the template 400 definition. 401 402 Type: string (path to a .gni file) 403 Usage: toolchain-controlled only 404 405.. option:: pw_unit_test_FACADE_TESTS_ENABLED <boolean> 406 407 Controls whether to build and run facade tests. Facade tests add considerably 408 to build time, so they are disabled by default. 409 410CMake 411----- 412pw_add_test function 413```````````````````` 414``pw_add_test`` declares a single unit test suite. It creates several 415sub-targets. 416 417* ``{NAME}`` depends on ``${NAME}.run`` if ``pw_unit_test_AUTOMATIC_RUNNER`` is 418 set, else it depends on ``${NAME}.bin`` 419* ``{NAME}.lib`` contains the provided test sources as a library target, which 420 can then be linked into a test executable. 421* ``{NAME}.bin`` is a standalone executable which contains only the test sources 422 specified in the pw_unit_test_template. 423* ``{NAME}.run`` which runs the unit test executable after building it if 424 ``pw_unit_test_AUTOMATIC_RUNNER`` is set, else it fails to build. 425 426**Required Arguments** 427 428* ``NAME``: name to use for the produced test targets specified above 429 430**Optional Arguments** 431 432* ``SOURCES`` - source files for this library 433* ``HEADERS``- header files for this library 434* ``PRIVATE_DEPS``- private pw_target_link_targets arguments 435* ``PRIVATE_INCLUDES``- public target_include_directories argument 436* ``PRIVATE_DEFINES``- private target_compile_definitions arguments 437* ``PRIVATE_COMPILE_OPTIONS``- private target_compile_options arguments 438* ``PRIVATE_LINK_OPTIONS``- private target_link_options arguments 439 440**Example** 441 442.. code:: 443 444 include($ENV{PW_ROOT}/pw_unit_test/test.cmake) 445 446 pw_add_test(my_module.foo_test 447 SOURCES 448 foo_test.cc 449 PRIVATE_DEPS 450 my_module.foo 451 ) 452 453pw_add_test_group function 454`````````````````````````` 455``pw_add_test_group`` defines a collection of tests or other test groups. It 456creates several sub-targets: 457 458* ``{NAME}`` depends on ``${NAME}.run`` if ``pw_unit_test_AUTOMATIC_RUNNER`` is 459 set, else it depends on ``${NAME}.bin``. 460* ``{NAME}.bundle`` depends on ``${NAME}.bundle.run`` if 461 ``pw_unit_test_AUTOMATIC_RUNNER`` is set, else it depends on 462 ``${NAME}.bundle.bin``. 463* ``{NAME}.lib`` depends on ``${NAME}.bundle.lib``. 464* ``{NAME}.bin`` depends on the provided ``TESTS``'s ``<test_dep>.bin`` targets. 465* ``{NAME}.run`` depends on the provided ``TESTS``'s ``<test_dep>.run`` targets 466 if ``pw_unit_test_AUTOMATIC_RUNNER`` is set, else it fails to build. 467* ``{NAME}.bundle.lib`` contains the provided tests bundled as a library target, 468 which can then be linked into a test executable. 469* ``{NAME}.bundle.bin`` standalone executable which contains the bundled tests. 470* ``{NAME}.bundle.run`` runs the ``{NAME}.bundle.bin`` test bundle executable 471 after building it if ``pw_unit_test_AUTOMATIC_RUNNER`` is set, else it fails 472 to build. 473 474**Required Arguments** 475 476* ``NAME`` - The name of the executable target to be created. 477* ``TESTS`` - ``pw_add_test`` targets and ``pw_add_test_group`` bundles to be 478 included in this test bundle 479 480**Example** 481 482.. code:: 483 484 include($ENV{PW_ROOT}/pw_unit_test/test.cmake) 485 486 pw_add_test_group(tests 487 TESTS 488 bar_test 489 foo_test 490 ) 491 492 pw_add_test(foo_test 493 # ... 494 ) 495 496 pw_add_test(bar_test 497 # ... 498 ) 499 500Build arguments 501``````````````` 502.. option:: pw_unit_test_GOOGLETEST_BACKEND <target> 503 504 The GoogleTest implementation to use for Pigweed unit tests. This library 505 provides "gtest/gtest.h" and related headers. Defaults to pw_unit_test.light, 506 which implements a subset of GoogleTest. 507 508 Type: string (CMake target name) 509 Usage: toolchain-controlled only 510 511.. option:: pw_unit_test_AUTOMATIC_RUNNER <executable> 512 513 Path to a test runner to automatically run unit tests after they are built. 514 515 If set, a ``pw_test`` target's ``${NAME}`` and ``${NAME}.run`` targets will 516 invoke the test runner specified by this argument, passing the path to the 517 unit test to run. If this is unset, the ``pw_test`` target's ``${NAME}`` will 518 only build the unit test(s) and ``${NAME}.run`` will fail to build. 519 520 Type: string (name of an executable on the PATH, or path to an executable) 521 Usage: toolchain-controlled only 522 523.. option:: pw_unit_test_AUTOMATIC_RUNNER_ARGS <args> 524 525 An optional list of strings to pass as args to the test runner specified 526 by pw_unit_test_AUTOMATIC_RUNNER. 527 528 Type: list of strings (args to pass to pw_unit_test_AUTOMATIC_RUNNER) 529 Usage: toolchain-controlled only 530 531.. option:: pw_unit_test_AUTOMATIC_RUNNER_TIMEOUT_SECONDS <timeout_seconds> 532 533 An optional timeout to apply when running the automatic runner. Timeout is 534 in seconds. Defaults to empty which means no timeout. 535 536 Type: string (number of seconds to wait before killing test runner) 537 Usage: toolchain-controlled only 538 539.. option:: pw_unit_test_ADD_EXECUTABLE_FUNCTION <function name> 540 541 The name of the CMake function used to build pw_unit_test executables. The 542 provided function must take a ``NAME`` and a ``TEST_LIB`` argument which are 543 the expected name of the executable target and the target which provides the 544 unit test(s). 545 546 Type: string (name of a CMake function) 547 Usage: toolchain-controlled only 548 549.. option:: pw_unit_test_ADD_EXECUTABLE_FUNCTION_FILE <cmake file path> 550 551 The path to the .cmake file that defines pw_unit_test_ADD_EXECUTABLE_FUNCTION. 552 553 Type: string (path to a .cmake file) 554 Usage: toolchain-controlled only 555 556 557RPC service 558=========== 559``pw_unit_test`` provides an RPC service which runs unit tests on demand and 560streams the results back to the client. The service is defined in 561``pw_unit_test_proto/unit_test.proto``, and implemented by the GN target 562``$dir_pw_unit_test:rpc_service``. 563 564The RPC service is primarily intended for use with the default 565``pw_unit_test:light`` backend. It has some support for the GoogleTest backend, 566however some features (such as test suite filtering) are missing. 567 568To set up RPC-based unit tests in your application, instantiate a 569``pw::unit_test::UnitTestService`` and register it with your RPC server. 570 571.. code:: c++ 572 573 #include "pw_rpc/server.h" 574 #include "pw_unit_test/unit_test_service.h" 575 576 // Server setup; refer to pw_rpc docs for more information. 577 pw::rpc::Channel channels[] = { 578 pw::rpc::Channel::Create<1>(&my_output), 579 }; 580 pw::rpc::Server server(channels); 581 582 pw::unit_test::UnitTestService unit_test_service; 583 584 void RegisterServices() { 585 server.RegisterService(unit_test_services); 586 } 587 588All tests flashed to an attached device can be run via python by calling 589``pw_unit_test.rpc.run_tests()`` with a RPC client services object that has 590the unit testing RPC service enabled. By default, the results will output via 591logging. 592 593.. code:: python 594 595 from pw_hdlc.rpc import HdlcRpcClient 596 from pw_unit_test.rpc import run_tests 597 598 PROTO = Path(os.environ['PW_ROOT'], 599 'pw_unit_test/pw_unit_test_proto/unit_test.proto') 600 601 client = HdlcRpcClient(serial.Serial(device, baud), PROTO) 602 run_tests(client.rpcs()) 603 604pw_unit_test.rpc 605---------------- 606.. automodule:: pw_unit_test.rpc 607 :members: EventHandler, run_tests 608 609Module Configuration Options 610============================ 611The following configurations can be adjusted via compile-time configuration of 612this module. 613 614.. c:macro:: PW_UNIT_TEST_CONFIG_EVENT_BUFFER_SIZE 615 616 The size of the event buffer that the UnitTestService contains. 617 This buffer is used to encode events. By default this is set to 618 128 bytes. 619 620.. c:macro:: PW_UNIT_TEST_CONFIG_MEMORY_POOL_SIZE 621 622 The size of the memory pool to use for test fixture instances. By default this 623 is set to 16K. 624 625Using upstream GoogleTest 626========================= 627Upstream `GoogleTest`_ may be used as the backend for ``pw_unit_test``. A clone 628of the GoogleTest repository is required. See the 629:ref:`third_party/googletest documentation <module-pw_third_party_googletest>` 630for details. 631 632When using upstream `GoogleTest`_ as the backend, the 633:cpp:class:`pw::unit_test::GoogleTestHandlerAdapter` can be used in conjunction 634with the above mentioned `EventHandler Interface <#the-eventhandler-interface>`_ 635and `Predefined event handlers`_. An example of how you can use the adapter in 636conjunction with an ``EventHandler`` is shown below. 637 638 .. code-block:: c++ 639 640 testing::InitGoogleTest(); 641 auto* unit_test = testing::UnitTest::GetInstance(); 642 643 pw::unit_test::LoggingEventHandler logger; 644 pw::unit_test::GoogleTestHandlerAdapter listener_adapter(logger); 645 unit_test->listeners().Append(&listener_adapter); 646 647 const auto status = RUN_ALL_TESTS(); 648 649.. cpp:namespace-push:: pw::unit_test 650 651.. cpp:class:: GoogleTestHandlerAdapter 652 653 A GoogleTest Event Listener that fires GoogleTest emitted events to an 654 appropriate ``EventHandler``. 655 656.. cpp::namespace-pop:: 657