.. _module-pw_unit_test:

============
pw_unit_test
============
.. pigweed-module::
   :name: pw_unit_test

.. tab-set::

   .. tab-item:: mylib_test.cpp

      .. code-block:: c++

         #include "mylib.h"

         #include "pw_unit_test/framework.h"

         namespace {

         TEST(MyTestSuite, MyTestCase) {
           pw::InlineString<32> expected = "(╯°□°)╯︵ ┻━┻";
           pw::InlineString<32> actual = mylib::flip_table();
           EXPECT_STREQ(expected.c_str(), actual.c_str());
         }

         }

   .. tab-item:: BUILD.bazel

      .. code-block:: python

         load("@pigweed//pw_build:pigweed.bzl", "pw_cc_test")

         cc_library(
             name = "mylib",
             srcs = ["mylib.cc"],
             hdrs = ["mylib.h"],
             includes = ["."],
             deps = ["@pigweed//pw_string"],
         )

         pw_cc_test(
             name = "mylib_test",
             srcs = ["mylib_test.cc"],
             deps = [
                 "@pigweed//pw_unit_test",
                 ":mylib",
             ],
         )

   .. tab-item:: mylib.cc

      .. code-block:: c++

         #include "mylib.h"

         #include "pw_string/string.h"

         namespace mylib {

         pw::InlineString<32> flip_table() {
           pw::InlineString<32> textmoji = "(╯°□°)╯︵ ┻━┻";
           return textmoji;
         }

         }

   .. tab-item:: mylib.h

      .. code-block:: c++

         #include "pw_string/string.h"

         namespace mylib {

         pw::InlineString<32> flip_table();

         }

.. _GoogleTest: https://google.github.io/googletest/

``pw_unit_test`` provides a `GoogleTest`_-compatible unit testing framework for
Pigweed-based projects. The default backend is a lightweight subset of
GoogleTest that uses embedded-friendly primitives.

.. grid:: 1

   .. grid-item-card:: :octicon:`rocket` Quickstart
      :link: module-pw_unit_test-quickstart
      :link-type: ref
      :class-item: sales-pitch-cta-primary

      Set up your project for testing and learn testing basics.

.. grid:: 2

   .. grid-item-card:: :octicon:`list-unordered` Guides
      :link: module-pw_unit_test-guides
      :link-type: ref
      :class-item: sales-pitch-cta-secondary

      Learn how to do common tasks.

   .. grid-item-card:: :octicon:`code-square` C++ API reference
      :link: module-pw_unit_test-cpp
      :link-type: ref
      :class-item: sales-pitch-cta-secondary

      Get detailed C++ API reference information.

.. grid:: 2

   .. grid-item-card:: :octicon:`code-square` Bazel API reference
      :link: module-pw_unit_test-bazel
      :link-type: ref
      :class-item: sales-pitch-cta-secondary

      Get detailed Bazel API reference information.

   .. grid-item-card:: :octicon:`code-square` GN API reference
      :link: module-pw_unit_test-gn
      :link-type: ref
      :class-item: sales-pitch-cta-secondary

      Get detailed GN API reference information.

.. grid:: 2

   .. grid-item-card:: :octicon:`code-square` CMake API reference
      :link: module-pw_unit_test-cmake
      :link-type: ref
      :class-item: sales-pitch-cta-secondary

      Get detailed CMake API reference information.

   .. grid-item-card:: :octicon:`code-square` Python API reference
      :link: module-pw_unit_test-py
      :link-type: ref
      :class-item: sales-pitch-cta-secondary

      Get detailed Python API reference information.

.. _module-pw_unit_test-quickstart:

----------
Quickstart
----------

Set up your build system
========================
.. tab-set::

   .. tab-item:: Bazel

      Load the :ref:`module-pw_unit_test-pw_cc_test` rule and create a target
      that depends on ``@pigweed//pw_unit_test`` as well as the code you want
      to test:

      .. code-block:: python

         load("@pigweed//pw_build:pigweed.bzl", "pw_cc_test")

         cc_library(
             name = "mylib",
             srcs = ["mylib.cc"],
             hdrs = ["mylib.h"],
             includes = ["."],
             deps = ["..."],
         )

         pw_cc_test(
             name = "mylib_test",
             srcs = ["mylib_test.cc"],
             deps = [
                 "@pigweed//pw_unit_test",
                 ":mylib",
             ],
         )

      This assumes that your Bazel ``WORKSPACE`` has a `repository
      <https://bazel.build/concepts/build-ref#repositories>`_ named ``@pigweed``
      that points to the upstream Pigweed repository.

      See also :ref:`module-pw_unit_test-bazel`.

   .. tab-item:: GN

      Import ``$dir_pw_unit_test/test.gni`` and create a ``pw_test`` rule that
      depends on the code you want to test:

      .. code-block:: python

         import("$dir_pw_unit_test/test.gni")

         pw_source_set("mylib") {
           sources = [ "mylib.cc" ]
         }

         pw_test("mylib_test") {
           sources = [ "mylib_test.cc" ]
           deps = [ ":mylib" ]
         }

      See :ref:`module-pw_unit_test-gn` for more information.

``pw_unit_test`` generates a simple ``main`` function for running tests on
:ref:`target-host`. See :ref:`module-pw_unit_test-main` to learn how to
create your own ``main`` function for running on-device tests.

Write tests
===========
Create test suites and test cases:

.. code-block:: c++

   #include "mylib.h"

   #include "pw_unit_test/framework.h"

   namespace {

   TEST(MyTestSuite, MyTestCase) {
     pw::InlineString<32> expected = "(╯°□°)╯︵ ┻━┻";
     pw::InlineString<32> actual = app::flip_table();
     EXPECT_STREQ(expected.c_str(), actual.c_str());
   }

   }

``pw_unit_test`` provides a standard set of ``TEST``, ``EXPECT``, ``ASSERT``
and ``FAIL`` macros. The default backend, ``pw_unit_test:light``, offers an
embedded-friendly implementation which prioritizes small code size.

Alternativley, users can opt into a larger set of assertion macros, matchers,
and more detailed error messages by using the ``pw_unit_test:googletest``
backend. See :ref:`module-pw_unit_test-backends`.

See `GoogleTest Primer <https://google.github.io/googletest/primer.html>`_ for
the basics of using GoogleTest.

Run tests
=========
.. tab-set::

   .. tab-item:: Bazel

      .. code-block:: console

         $ bazel test //src:mylib_test

   .. tab-item:: GN

      Run the generated test binary:

      .. code-block:: console

         $ ./out/.../mylib_test

.. _module-pw_unit_test-guides:

------
Guides
------

.. _module-pw_unit_test-backends:

Choose a backend
================
The default backend, ``pw_unit_test:light``, is a lightweight subset of
GoogleTest that uses embedded-friendly primitives. It's also highly portable
because it offloads the responsibility of test reporting and output to the
underlying system, communicating its results through a common interface. This
lets you write unit tests once and run them under many different environments.

If the :ref:`subset <module-pw_unit_test-compatibility>` of GoogleTest that
``pw_unit_test:light`` supports doesn't meet your needs, you can access the
full upstream GoogleTest API through ``pw_unit_test:googletest``. See
:ref:`module-pw_unit_test-upstream`.

.. _module-pw_unit_test-main:

Create a custom ``main`` function
=================================
For simple unit tests that run on :ref:`target-host` the workflow outlined in
:ref:`module-pw_unit_test-quickstart` is all you need. Pigweed's build templates
generate a simple ``main`` function to run the tests with.

To do more complex testing, such as on-device testing:

1. Create your own ``main`` function:

   .. code-block:: c++

      #include "pw_unit_test/framework.h"
      // pw_unit_test:light requires an event handler to be configured.
      #include "pw_unit_test/simple_printing_event_handler.h"

      void WriteString(std::string_view string, bool newline) {
        printf("%s", string.data());
        if (newline) {
          printf("\n");
        }
      }

      int main() {
        // Make the binary compatible with pw_unit_test:googletest. Has no effect
        // when using pw_unit_test:light.
        testing::InitGoogleTest();
        // Set up the event handler for pw_unit_test:light.
        pw::unit_test::SimplePrintingEventHandler handler(WriteString);
        pw::unit_test::RegisterEventHandler(&handler);
        return RUN_ALL_TESTS();
      }

   See :ref:`module-pw_unit_test-event-handlers` for more information about
   handling events.

2. Set the build argument that instructs your build system to use your custom
   ``main`` function:

   * Bazel: :option:`pw_unit_test_main`
   * GN: :option:`pw_unit_test_MAIN`

.. _module-pw_unit_test-event-handlers:

Create event handlers
=====================
.. _//pw_unit_test/public/pw_unit_test/event_handler.h: https://cs.opensource.google/pigweed/pigweed/+/main:pw_unit_test/public/pw_unit_test/event_handler.h

The ``pw::unit_test::EventHandler`` class defines the interface through which
``pw_unit_test:light`` communicates the results of its test runs. If you're
using a :ref:`custom main function <module-pw_unit_test-main>` you need to
register an event handler to receive test output from the framework.

.. _module-pw_unit_test-predefined-event-handlers:

Predefined event handlers
-------------------------
Pigweed provides some standard event handlers to simplify the process of
getting started with ``pw_unit_test:light``. All event handlers provide for
GoogleTest-style output using the shared
:cpp:class:`pw::unit_test::GoogleTestStyleEventHandler` base. Example
output:

.. code-block::

   [==========] Running all tests.
   [ RUN      ] Status.Default
   [       OK ] Status.Default
   [ RUN      ] Status.ConstructWithStatusCode
   [       OK ] Status.ConstructWithStatusCode
   [ RUN      ] Status.AssignFromStatusCode
   [       OK ] Status.AssignFromStatusCode
   [ RUN      ] Status.CompareToStatusCode
   [       OK ] Status.CompareToStatusCode
   [ RUN      ] Status.Ok_OkIsTrue
   [       OK ] Status.Ok_OkIsTrue
   [ RUN      ] Status.NotOk_OkIsFalse
   [       OK ] Status.NotOk_OkIsFalse
   [ RUN      ] Status.KnownString
   [       OK ] Status.KnownString
   [ RUN      ] Status.UnknownString
   [       OK ] Status.UnknownString
   [==========] Done running all tests.
   [  PASSED  ] 8 test(s).

.. _module-pw_unit_test-subset:

Run a subset of test suites
===========================
.. note:: This feature is only supported in C++17.

.. _//pw_unit_test/light_public_overrides/pw_unit_test/framework_backend.h: https://cs.opensource.google/pigweed/pigweed/+/main:pw_unit_test/light_public_overrides/pw_unit_test/framework_backend.h

To run only a subset of registered test suites, use the
``pw::unit_test::SetTestSuitesToRun`` function. See
`//pw_unit_test/light_public_overrides/pw_unit_test/framework_backend.h`_.

This is useful when you've got a lot of test suites bundled up into a
:ref:`single test binary <module-pw_unit_test-main>` and you only need
to run some of them.

.. _module-pw_unit_test-skip:

Skip tests in Bazel
===================
Use ``target_compatible_with`` in Bazel to skip tests. The following test is
skipped when :ref:`using upstream GoogleTest <module-pw_unit_test-upstream>`:

.. code-block::

   load("//pw_build:pigweed.bzl", "pw_cc_test")

   pw_cc_test(
       name = "no_upstream_test",
       srcs = ["no_upstream_test.cc"],
        target_compatible_with = select({
            "//pw_unit_test:light_setting": [],
            "//conditions:default": ["@platforms//:incompatible"],
        }),
   }

.. _module-pw_unit_test-static:

Run tests in static libraries
=============================
To run tests in a static library, use the
:c:macro:`PW_UNIT_TEST_LINK_FILE_CONTAINING_TEST` macro.

Linkers usually ignore tests through static libraries (i.e. ``.a`` files)
because test registration relies on the test instance's static constructor
adding itself to a global list of tests. When linking against a static library,
static constructors in an object file are ignored unless at least one entity
in that object file is linked.

.. _module-pw_unit_test-upstream:

Use upstream GoogleTest
=======================
To use the upstream GoogleTest backend (``pw_unit_test:googletest``) instead
of the default backend:

.. _GoogleTestHandlerAdapter: https://cs.opensource.google/pigweed/pigweed/+/main:pw_unit_test/public/pw_unit_test/googletest_handler_adapter.h

1. Clone the GoogleTest repository into your project. See
   :ref:`module-pw_third_party_googletest`.

2. :ref:`Create a custom main function <module-pw_unit_test-main>`.

3. Combine `GoogleTestHandlerAdapter`_ with a :ref:`predefined event
   handler <module-pw_unit_test-predefined-event-handlers>` to enable your
   ``main`` function to work with upstream GoogleTest without modification.

   .. code-block:: c++

      #include "pw_unit_test/framework.h"
      #include "pw_unit_test/logging_event_handler.h"

      int main() {
        testing::InitGoogleTest();
        pw::unit_test::LoggingEventHandler logger;
        pw::unit_test::RegisterEventHandler(&logger);
        return RUN_ALL_TESTS();
      }

4. If your tests needs GoogleTest functionality not included in the default
   ``pw_unit_test:light`` backend, include the upstream GoogleTest headers
   (e.g. ``gtest/gtest.h``) directly and guard your target definition to avoid
   compiling with ``pw_unit_test:light`` (the default backend).

.. _module-pw_unit_test-serial-runner:

Run tests over serial
=====================
To accelerate automated unit test bringup for devices with plain-text logging,
``pw_unit_test`` provides a serial-based test runner in Python that triggers a
device flash and evaluates whether the test passed or failed based on the
produced output.

To set up a serial test runner in Python:

.. _//pw_unit_test/py/pw_unit_test/serial_test_runner.py: https://cs.opensource.google/pigweed/pigweed/+/main:pw_unit_test/py/pw_unit_test/serial_test_runner.py

1. Implement a ``SerialTestingDevice`` class for your device. See
   `//pw_unit_test/py/pw_unit_test/serial_test_runner.py`_.
2. Configure your device code to wait to run unit tests until
   ``DEFAULT_TEST_START_CHARACTER`` is sent over the serial connection.

.. _module-pw_unit_test-rpc:

Run tests over RPC
==================
.. _//pw_unit_test/pw_unit_test_proto/unit_test.proto: https://cs.opensource.google/pigweed/pigweed/+/main:pw_unit_test/pw_unit_test_proto/unit_test.proto

``pw_unit_test`` provides an RPC service which runs unit tests on demand and
streams the results back to the client. The service is defined in
`//pw_unit_test/pw_unit_test_proto/unit_test.proto`_.

The RPC service is primarily intended for use with the default
``pw_unit_test:light`` backend. It has some support for the upstream GoogleTest
backend (``pw_unit_test:googletest``), however some features (such as test suite
filtering) are missing.

To set up RPC-based unit tests in your application:

1. Depend on the relevant target for your build system:

   * Bazel: ``@pigweed//pw_unit_test:rpc_service``
   * GN: ``$dir_pw_unit_test:rpc_service``

2. Create a ``pw::unit_test::UnitTestService`` instance.

3. Register the instance with your RPC server.

   .. code-block:: c++

      #include "pw_rpc/server.h"
      #include "pw_unit_test/unit_test_service.h"

      pw::rpc::Channel channels[] = {
        pw::rpc::Channel::Create<1>(&my_output),
      };
      pw::rpc::Server server(channels);

      pw::unit_test::UnitTestService unit_test_service;

      void RegisterServices() {
        server.RegisterService(unit_test_services);
      }

   See :ref:`module-pw_rpc` for more guidance around setting up RPC.

4. Run tests that have been flashed to a device by calling
   ``pw_unit_test.rpc.run_tests()`` in Python. The argument should be an RPC
   client services object that has the unit testing RPC service enabled. By
   default, the results output via logging. The return value is a
   ``TestRecord`` dataclass instance containing the results of the test run.

   .. code-block:: python

      import serial

      from pw_hdlc import rpc
      from pw_unit_test.rpc import run_tests

      PROTO = Path(
          os.environ['PW_ROOT'],
          'pw_unit_test/pw_unit_test_proto/unit_test.proto'
      )
      serial_device = serial.Serial(device, baud)
      with rpc.SerialReader(serial_device) as reader:
          with rpc.HdlcRpcClient(
              reader, PROTO, rpc.default_channels(serial_device.write)
          ) as client:
              run_tests(client.rpcs())

.. _module-pw_unit_test-cpp:

-----------------
C++ API reference
-----------------

.. _module-pw_unit_test-compatibility:

``pw_unit_test:light`` API compatibility
========================================
``pw_unit_test:light`` offers a number of primitives for test declaration,
assertion, event handlers, and configuration.

.. note::

   The ``googletest_test_matchers`` target which provides Pigweed-specific
   ``StatusIs``, ``IsOkAndHolds``, ``ASSERT_OK``, and ``ASSERT_OK_AND_ASSIGN``
   isn't part of the ``pw_unit_test:light`` backend. These matchers are only
   usable when including the full upstream GoogleTest backend.

Missing features include:

* GoogleMock and matchers (e.g. :c:macro:`EXPECT_THAT`).
* Death tests (e.g. :c:macro:`EXPECT_DEATH`). ``EXPECT_DEATH_IF_SUPPORTED``
  does nothing but silently passes.
* Value-parameterized tests.
* Stream messages (e.g. ``EXPECT_TRUE(...) << "My message"``) will compile, but
  no message will be logged.

See :ref:`module-pw_unit_test-upstream` for guidance on using the
upstream GoogleTest backend (``pw_unit_test:googletest``) instead of
``pw_unit_test:light``.

.. _module-pw_unit_test-declare:

Test declaration
================
Note that ``TEST_F`` may allocate fixtures separately from the stack.
Large variables should be stored in test fixture fields,
rather than stack variables. This allows the test framework to statically ensure
that enough space is available to store these variables.

.. doxygendefine:: TEST
.. doxygendefine:: GTEST_TEST
.. doxygendefine:: TEST_F
.. doxygendefine:: FRIEND_TEST

.. _module-pw_unit_test-control:

Test control
============

.. doxygendefine:: FAIL
.. doxygendefine:: GTEST_FAIL
.. doxygendefine:: SUCCEED
.. doxygendefine:: GTEST_SUCCEED
.. doxygendefine:: GTEST_SKIP
.. doxygendefine:: ADD_FAILURE
.. doxygendefine:: RUN_ALL_TESTS
.. doxygendefine:: GTEST_HAS_DEATH_TEST
.. doxygendefine:: EXPECT_DEATH_IF_SUPPORTED
.. doxygendefine:: ASSERT_DEATH_IF_SUPPORTED

.. _module-pw_unit_test-api-expect:

Expectations
============
When a test fails an expectation, the framework marks the test as a failure
and then continues executing the test. They're useful when you want to
verify multiple dimensions of the same feature and see all the errors at the
same time.

.. doxygendefine:: EXPECT_TRUE
.. doxygendefine:: EXPECT_FALSE
.. doxygendefine:: EXPECT_EQ
.. doxygendefine:: EXPECT_NE
.. doxygendefine:: EXPECT_GT
.. doxygendefine:: EXPECT_GE
.. doxygendefine:: EXPECT_LT
.. doxygendefine:: EXPECT_LE
.. doxygendefine:: EXPECT_NEAR
.. doxygendefine:: EXPECT_FLOAT_EQ
.. doxygendefine:: EXPECT_DOUBLE_EQ
.. doxygendefine:: EXPECT_STREQ
.. doxygendefine:: EXPECT_STRNE

.. _module-pw_unit_test-api-assert:

Assertions
==========
Assertions work the same as expectations except they stop the execution of the
test as soon as a failed condition is met.

.. doxygendefine:: ASSERT_TRUE
.. doxygendefine:: ASSERT_FALSE
.. doxygendefine:: ASSERT_EQ
.. doxygendefine:: ASSERT_NE
.. doxygendefine:: ASSERT_GT
.. doxygendefine:: ASSERT_GE
.. doxygendefine:: ASSERT_LT
.. doxygendefine:: ASSERT_LE
.. doxygendefine:: ASSERT_NEAR
.. doxygendefine:: ASSERT_FLOAT_EQ
.. doxygendefine:: ASSERT_DOUBLE_EQ
.. doxygendefine:: ASSERT_STREQ
.. doxygendefine:: ASSERT_STRNE

.. _module-pw_unit_test-api-event-handlers:

Event handlers
==============
.. doxygenfunction:: pw::unit_test::RegisterEventHandler(EventHandler* event_handler)
.. doxygenclass:: pw::unit_test::EventHandler
   :members:
.. doxygenclass:: pw::unit_test::GoogleTestHandlerAdapter
.. doxygenclass:: pw::unit_test::GoogleTestStyleEventHandler
.. doxygenclass:: pw::unit_test::SimplePrintingEventHandler
.. doxygenclass:: pw::unit_test::LoggingEventHandler
.. doxygenclass:: pw::unit_test::PrintfEventHandler
.. doxygenclass:: pw::unit_test::MultiEventHandler
.. doxygenclass:: pw::unit_test::TestRecordEventHandler

.. _module-pw_unit_test-cpp-config:

Configuration
=============
.. doxygendefine:: PW_UNIT_TEST_CONFIG_EVENT_BUFFER_SIZE
.. doxygendefine:: PW_UNIT_TEST_CONFIG_MEMORY_POOL_SIZE

.. _module-pw_unit_test-cpp-helpers:

Helpers
=======
.. doxygendefine:: PW_UNIT_TEST_LINK_FILE_CONTAINING_TEST

.. _module-pw_unit_test-py:

--------------------
Python API reference
--------------------

.. _module-pw_unit_test-py-serial_test_runner:

``pw_unit_test.serial_test_runner``
===================================
.. automodule:: pw_unit_test.serial_test_runner
   :members:
     DEFAULT_TEST_START_CHARACTER,
     SerialTestingDevice,
     run_device_test,

.. _module-pw_unit_test-py-rpc:

``pw_unit_test.rpc``
====================
.. automodule:: pw_unit_test.rpc
   :members: EventHandler, run_tests, TestRecord

.. _module-pw_unit_test-helpers:

----------------------
Build helper libraries
----------------------
The following helper libraries can simplify setup and are supported in all
build systems.

.. object:: simple_printing_event_handler

   When running tests, output test results as plain text over ``pw_sys_io``.

.. object:: simple_printing_main

   Implements a ``main()`` function that simply runs tests using the
   ``simple_printing_event_handler``.

.. object:: logging_event_handler

   When running tests, log test results as plain text using
   :ref:`module-pw_log`. Make sure your target has set a ``pw_log`` backend.

.. object:: logging_main

   Implements a ``main()`` function that simply runs tests using the
   ``logging_event_handler``.

.. _module-pw_unit_test-bazel:

-------------------
Bazel API reference
-------------------

See also :ref:`module-pw_unit_test-helpers`.

.. _module-pw_unit_test-pw_cc_test:

``pw_cc_test``
==============
.. _cc_test: https://bazel.build/reference/be/c-cpp#cc_test

``pw_cc_test`` is a wrapper for `cc_test`_ that provides some defaults, such as
a dependency on ``@pigweed//pw_unit_test:main``. It supports and passes through
all the arguments recognized by ``cc_test``.

.. _module-pw_unit_test-bazel-args:

Bazel build arguments
=====================
.. option:: pw_unit_test_backend <target>

   The GoogleTest implementation to use for Pigweed unit tests. This library
   provides ``gtest/gtest.h`` and related headers. Defaults to
   ``@pigweed//pw_unit_test:light``, which implements a subset of GoogleTest.

   Type: string (Bazel target label)

   Usage: toolchain-controlled only

.. option:: pw_unit_test_main <target>

   Implementation of a main function for ``pw_cc_test`` unit test binaries.

   Type: string (Bazel target label)

   Usage: toolchain-controlled only

.. _module-pw_unit_test-gn:

------------
GN reference
------------
See also :ref:`module-pw_unit_test-helpers`.

.. _module-pw_unit_test-pw_test:

``pw_test``
===========
``pw_test`` defines a single unit test suite.

Targets
-------

.. object:: <target_name>

   The test suite within a single binary. The test code is linked against
   the target set in the build arg ``pw_unit_test_MAIN``.

.. object:: <target_name>.run

   If ``pw_unit_test_AUTOMATIC_RUNNER`` is set, this target runs the test as
   part of the build.

.. object:: <target_name>.lib

   The test sources without ``pw_unit_test_MAIN``.

Arguments
---------
All GN executable arguments are accepted and forwarded to the underlying
``pw_executable``.

.. option:: enable_if

   Boolean indicating whether the test should be built. If false, replaces the
   test with an empty target. Default true.

.. _get_target_outputs: https://gn.googlesource.com/gn/+/main/docs/reference.md#func_get_target_outputs

.. option:: source_gen_deps

   List of target labels that generate source files used by this test. The
   labels must meet the constraints of GN's `get_target_outputs`_, namely they must have been previously defined in the
   current file. This argument is required if a test uses generated source files
   and ``enable_if`` can evaluate to false.

.. option:: test_main

   Target label to add to the tests's dependencies to provide the ``main()``
   function. Defaults to ``pw_unit_test_MAIN``. Set to ``""`` if ``main()``
   is implemented in the test's ``sources``.

.. option:: test_automatic_runner_args

   Array of args to pass to :ref:`automatic test
   runner <module-pw_unit_test-serial-runner>`. Defaults to
   ``pw_unit_test_AUTOMATIC_RUNNER_ARGS``.

.. option:: envvars

   Array of ``key=value`` strings representing environment variables to set
   when invoking the automatic test runner.

Example
-------

.. code-block::

   import("$dir_pw_unit_test/test.gni")

   pw_test("large_test") {
     sources = [ "large_test.cc" ]
     enable_if = device_has_1m_flash
   }

.. _module-pw_unit_test-pw_test_group:

``pw_test_group``
=================
``pw_test_group`` defines a collection of tests or other test groups.

Targets
-------
.. object:: <target_name>

   The test group itself.

.. object:: <target_name>.run

   If ``pw_unit_test_AUTOMATIC_RUNNER`` is set, this target runs all of the
   tests in the group and all of its group dependencies individually. See
   :ref:`module-pw_unit_test-serial-runner`.

.. object:: <target_name>.lib

   The sources of all of the tests in this group and their dependencies.

.. object:: <target_name>.bundle

   All of the tests in the group and its dependencies bundled into a single binary.

.. object:: <target_name>.bundle.run

   Automatic runner for the test bundle.

Arguments
---------
.. option:: tests

   List of the ``pw_test`` targets in the group.

.. option:: group_deps

   List of other ``pw_test_group`` targets on which this one depends.

.. option:: enable_if

   Boolean indicating whether the group target should be created. If false, an
   empty GN group is created instead. Default true.

Example
-------
.. code-block::

   import("$dir_pw_unit_test/test.gni")

   pw_test_group("tests") {
     tests = [
       ":bar_test",
       ":foo_test",
     ]
   }

   pw_test("foo_test") {
     # ...
   }

   pw_test("bar_test") {
     # ...
   }

.. _module-pw_unit_test-pw_facade_test:

``pw_facade_test``
==================
Pigweed facade test templates allow individual unit tests to build under the
current device target configuration while overriding specific build arguments.
This allows these tests to replace a facade's backend for the purpose of testing
the facade layer.

Facade tests are disabled by default. To build and run facade tests, set the GN
arg :option:`pw_unit_test_FACADE_TESTS_ENABLED` to ``true``.

.. warning::
   Facade tests are costly because each facade test will trigger a re-build of
   every dependency of the test. While this sounds excessive, it's the only
   technically correct way to handle this type of test.

.. warning::
   Some facade test configurations may not be compatible with your target. Be
   careful when running a facade test on a system that heavily depends on the
   facade being tested.

.. _module-pw_unit_test-gn-args:

GN build arguments
==================
.. option:: pw_unit_test_BACKEND <source_set>

   The GoogleTest implementation to use for Pigweed unit tests. This library
   provides ``gtest/gtest.h`` and related headers. Defaults to
   ``pw_unit_test:light``, which implements a subset of GoogleTest.

   Type: string (GN path to a source set)

   Usage: toolchain-controlled only

.. option:: pw_unit_test_MAIN <source_set>

   Implementation of a main function for ``pw_test`` unit test binaries.
   See :ref:`module-pw_unit_test-main`.

   Type: string (GN path to a source set)

   Usage: toolchain-controlled only

.. option:: pw_unit_test_AUTOMATIC_RUNNER <executable>

   Path to a test runner to automatically run unit tests after they are built.
   See :ref:`module-pw_unit_test-serial-runner`.

   If set, a ``pw_test`` target's ``<target_name>.run`` action invokes the
   test runner specified by this argument, passing the path to the unit test to
   run. If this is unset, the ``pw_test`` target's ``<target_name>.run`` step
   will do nothing.

   Targets that don't support parallelized execution of tests (e.g. an
   on-device test runner that must flash a device and run the test in serial)
   should set ``pw_unit_test_POOL_DEPTH`` to ``1``.

   Type: string (name of an executable on ``PATH``, or a path to an executable)

   Usage: toolchain-controlled only

.. option:: pw_unit_test_AUTOMATIC_RUNNER_ARGS <args>

   An optional list of strings to pass as args to the test runner specified by
   ``pw_unit_test_AUTOMATIC_RUNNER``.

   Type: list of strings (args to pass to ``pw_unit_test_AUTOMATIC_RUNNER``)

   Usage: toolchain-controlled only

.. option:: pw_unit_test_AUTOMATIC_RUNNER_TIMEOUT <timeout_seconds>

   An optional timeout to apply when running the automatic runner. Timeout is
   in seconds. Defaults to empty which means no timeout.

   Type: string (number of seconds to wait before killing test runner)

   Usage: toolchain-controlled only

.. option:: pw_unit_test_POOL_DEPTH <pool_depth>

   The maximum number of unit tests that may be run concurrently for the
   current toolchain. Setting this to 0 disables usage of a pool, allowing
   unlimited parallelization.

   Note: A single target with two toolchain configurations (e.g. ``release``
   and ``debug``) uses two separate test runner pools by default. Set
   ``pw_unit_test_POOL_TOOLCHAIN`` to the same toolchain for both targets to
   merge the pools and force serialization.

   Type: integer

   Usage: toolchain-controlled only

.. option:: pw_unit_test_POOL_TOOLCHAIN <toolchain>

   The toolchain to use when referring to the ``pw_unit_test`` runner pool.
   When this is disabled, the current toolchain is used. This means that every
   toolchain will use its own pool definition. If two toolchains should share
   the same pool, this argument should be by one of the toolchains to the GN
   path of the other toolchain.

   Type: string (GN path to a toolchain)

   Usage: toolchain-controlled only

.. option:: pw_unit_test_EXECUTABLE_TARGET_TYPE <template name>

   The name of the GN target type used to build ``pw_unit_test`` executables.

   Type: string (name of a GN template)

   Usage: toolchain-controlled only

.. option:: pw_unit_test_EXECUTABLE_TARGET_TYPE_FILE <gni file path>

   The path to the ``.gni`` file that defines
   ``pw_unit_test_EXECUTABLE_TARGET_TYPE``.

   If ``pw_unit_test_EXECUTABLE_TARGET_TYPE`` is not the default of
   ``pw_executable``, this ``.gni`` file is imported to provide the template
   definition.

   Type: string (path to a .gni file)

   Usage: toolchain-controlled only

.. option:: pw_unit_test_FACADE_TESTS_ENABLED <boolean>

   Controls whether to build and run facade tests. Facade tests add considerably
   to build time, so they are disabled by default.

.. option:: pw_unit_test_TESTONLY <boolean>

   Controls the ``testonly`` variable in ``pw_test``, ``pw_test_group``, and
   miscellaneous testing targets. This is useful if your test libraries (e.g.
   GoogleTest) used by pw_unit_test have the ``testonly`` flag set. False by
   default for backwards compatibility.

.. _module-pw_unit_test-cmake:

---------------
CMake reference
---------------
See also :ref:`module-pw_unit_test-helpers`.

.. _module-pw_unit_test-pw_add_test:

``pw_add_test``
===============
``pw_add_test`` declares a single unit test suite.

.. tip::
   Upstream Pigweed tests can be disabled in downstream projects by setting
   ``pw_unit_test_ENABLE_PW_ADD_TEST`` to ``OFF`` before adding the ``pigweed``
   directory to an existing cmake build.

   .. code-block:: cmake

      set(pw_unit_test_ENABLE_PW_ADD_TEST OFF)
      add_subdirectory(path/to/pigweed pigweed)
      set(pw_unit_test_ENABLE_PW_ADD_TEST ON)

   See also: :ref:`module-pw_build-existing-cmake-project`.

Targets
-------
.. object:: {NAME}

   Depends on ``${NAME}.run`` if ``pw_unit_test_AUTOMATIC_RUNNER`` is set, else
   it depends on ``${NAME}.bin``.

.. object:: {NAME}.lib

   Contains the provided test sources as a library target, which can then be
   linked into a test executable.

.. object:: {NAME}.bin

   A standalone executable which contains only the test sources specified in the
   ``pw_unit_test`` template.

.. object:: {NAME}.run

   Runs the unit test executable after building it if
   ``pw_unit_test_AUTOMATIC_RUNNER`` is set, else it fails to build.

Required arguments
------------------
.. option:: NAME

   Name to use for the produced test targets specified above.

Optional arguments
------------------
.. option:: SOURCES

   Source files for this library.

.. option:: HEADERS

   Header files for this library.

.. option:: PRIVATE_DEPS

   Private ``pw_target_link_targets`` arguments.
.. option:: PRIVATE_INCLUDES

   Public ``target_include_directories`` argument.

.. option:: PRIVATE_DEFINES

   Private ``target_compile_definitions`` arguments.

.. option:: PRIVATE_COMPILE_OPTIONS

   Private ``target_compile_options`` arguments.

.. option:: PRIVATE_LINK_OPTIONS

   Private ``target_link_options`` arguments.

Example
-------

.. code-block::

   include($ENV{PW_ROOT}/pw_unit_test/test.cmake)

   pw_add_test(my_module.foo_test
     SOURCES
       foo_test.cc
     PRIVATE_DEPS
       my_module.foo
   )

.. _module-pw_unit_test-pw_add_test_group:

``pw_add_test_group``
=====================
``pw_add_test_group`` defines a collection of tests or other test groups.

Targets
-------
.. object:: {NAME}

   Depends on ``${NAME}.run`` if ``pw_unit_test_AUTOMATIC_RUNNER`` is set, else
   it depends on ``${NAME}.bin``.

.. object:: {NAME}.bundle

   Depends on ``${NAME}.bundle.run`` if ``pw_unit_test_AUTOMATIC_RUNNER`` is
   set, else it depends on ``${NAME}.bundle.bin``.

.. object:: {NAME}.lib

   Depends on ``${NAME}.bundle.lib``.

.. object:: {NAME}.bin

   Depends on the provided ``TESTS``'s ``<test_dep>.bin`` targets.

.. object:: {NAME}.run

   Depends on the provided ``TESTS``'s ``<test_dep>.run`` targets if
   ``pw_unit_test_AUTOMATIC_RUNNER`` is set, else it fails to build.

.. object:: {NAME}.bundle.lib

   Contains the provided tests bundled as a library target, which can then be
   linked into a test executable.

.. object:: {NAME}.bundle.bin

   Standalone executable which contains the bundled tests.

.. object:: {NAME}.bundle.run

   Runs the ``{NAME}.bundle.bin`` test bundle executable after building it if
   ``pw_unit_test_AUTOMATIC_RUNNER`` is set, else it fails to build.

Required arguments
------------------
.. option:: NAME

   The name of the executable target to be created.

.. option:: TESTS

   ``pw_add_test`` targets and ``pw_add_test_group`` bundles to be
   included in this test bundle.

Example
-------
.. code-block::

   include($ENV{PW_ROOT}/pw_unit_test/test.cmake)

   pw_add_test_group(tests
     TESTS
       bar_test
       foo_test
   )

   pw_add_test(foo_test
     # ...
   )

   pw_add_test(bar_test
     # ...
   )

.. _module-pw_unit_test-cmake-args:

CMake build arguments
=====================
.. option:: pw_unit_test_BACKEND <target>

   The GoogleTest implementation to use for Pigweed unit tests. This library
   provides ``gtest/gtest.h`` and related headers. Defaults to
   ``pw_unit_test.light``, which implements a subset of GoogleTest.

   Type: string (CMake target name)

   Usage: toolchain-controlled only

.. option:: pw_unit_test_AUTOMATIC_RUNNER <executable>

   Path to a test runner to automatically run unit tests after they're built.

   If set, a ``pw_test`` target's ``${NAME}`` and ``${NAME}.run`` targets will
   invoke the test runner specified by this argument, passing the path to the
   unit test to run. If this is unset, the ``pw_test`` target's ``${NAME}`` will
   only build the unit test(s) and ``${NAME}.run`` will fail to build.

   Type: string (name of an executable on the PATH, or path to an executable)

   Usage: toolchain-controlled only

.. option:: pw_unit_test_AUTOMATIC_RUNNER_ARGS <args>

   An optional list of strings to pass as args to the test runner specified
   by ``pw_unit_test_AUTOMATIC_RUNNER``.

   Type: list of strings (args to pass to pw_unit_test_AUTOMATIC_RUNNER)

   Usage: toolchain-controlled only

.. option:: pw_unit_test_AUTOMATIC_RUNNER_TIMEOUT_SECONDS <timeout_seconds>

   An optional timeout to apply when running the automatic runner. Timeout is
   in seconds. Defaults to empty which means no timeout.

   Type: string (number of seconds to wait before killing test runner)

   Usage: toolchain-controlled only

.. option:: pw_unit_test_ADD_EXECUTABLE_FUNCTION <function name>

   The name of the CMake function used to build ``pw_unit_test`` executables.
   The provided function must take a ``NAME`` and a ``TEST_LIB`` argument which
   are the expected name of the executable target and the target which provides
   the unit test(s).

   Type: string (name of a CMake function)

   Usage: toolchain-controlled only

.. option:: pw_unit_test_ADD_EXECUTABLE_FUNCTION_FILE <cmake file path>

   The path to the ``.cmake`` file that defines
   ``pw_unit_test_ADD_EXECUTABLE_FUNCTION``.

   Type: string (path to a ``.cmake`` file)

   Usage: toolchain-controlled only
