• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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