xref: /aosp_15_r20/external/pigweed/pw_compilation_testing/docs.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_compilation_testing:
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker======================
4*61c4878aSAndroid Build Coastguard Workerpw_compilation_testing
5*61c4878aSAndroid Build Coastguard Worker======================
6*61c4878aSAndroid Build Coastguard WorkerThe pw_compilation_testing module provides for negative compilation (NC)
7*61c4878aSAndroid Build Coastguard Workertesting. Negative compilation tests ensure that code that should not compile
8*61c4878aSAndroid Build Coastguard Workerdoes not compile. Negative compilation testing is helpful in a variety of
9*61c4878aSAndroid Build Coastguard Workerscenarios, for example:
10*61c4878aSAndroid Build Coastguard Worker
11*61c4878aSAndroid Build Coastguard Worker- Testing for compiler errors, such as ``[[nodiscard]]`` checks.
12*61c4878aSAndroid Build Coastguard Worker- Testing that a template cannot be instantiated with certain types.
13*61c4878aSAndroid Build Coastguard Worker- Testing that a ``static_assert`` statement is triggered as expected.
14*61c4878aSAndroid Build Coastguard Worker- For a ``constexpr`` function, testing that a ``PW_ASSERT`` is triggered as
15*61c4878aSAndroid Build Coastguard Worker  expected.
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard WorkerNegative compilation tests are only supported in GN currently. Negative
18*61c4878aSAndroid Build Coastguard Workercompilation tests are not currently supported in GN on Windows due to
19*61c4878aSAndroid Build Coastguard Worker`b/241565082 <https://issues.pigweed.dev/241565082>`_.
20*61c4878aSAndroid Build Coastguard Worker
21*61c4878aSAndroid Build Coastguard Worker.. warning::
22*61c4878aSAndroid Build Coastguard Worker
23*61c4878aSAndroid Build Coastguard Worker  This module is in an early, experimental state. Do not use it unless you have
24*61c4878aSAndroid Build Coastguard Worker  consulted with the Pigweed team.
25*61c4878aSAndroid Build Coastguard Worker
26*61c4878aSAndroid Build Coastguard Worker---------------------------------
27*61c4878aSAndroid Build Coastguard WorkerNegative compilation test example
28*61c4878aSAndroid Build Coastguard Worker---------------------------------
29*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
30*61c4878aSAndroid Build Coastguard Worker
31*61c4878aSAndroid Build Coastguard Worker   #include "pw_unit_test/framework.h"
32*61c4878aSAndroid Build Coastguard Worker   #include "pw_compilation_testing/negative_compilation.h"
33*61c4878aSAndroid Build Coastguard Worker
34*61c4878aSAndroid Build Coastguard Worker   template <int kValue>
35*61c4878aSAndroid Build Coastguard Worker   struct MyStruct {
36*61c4878aSAndroid Build Coastguard Worker     static_assert(kValue % 2 == 0, "wrong number!");
37*61c4878aSAndroid Build Coastguard Worker
38*61c4878aSAndroid Build Coastguard Worker     constexpr int MultiplyOdd(int runtime_value) const {
39*61c4878aSAndroid Build Coastguard Worker       PW_ASSERT(runtime_value % 2 == 0);
40*61c4878aSAndroid Build Coastguard Worker       return kValue * runtime_value;
41*61c4878aSAndroid Build Coastguard Worker     }
42*61c4878aSAndroid Build Coastguard Worker   };
43*61c4878aSAndroid Build Coastguard Worker
44*61c4878aSAndroid Build Coastguard Worker   [[maybe_unused]] MyStruct<16> this_one_works;
45*61c4878aSAndroid Build Coastguard Worker
46*61c4878aSAndroid Build Coastguard Worker   // NC tests cannot be compiled, so they are created in preprocessor #if or
47*61c4878aSAndroid Build Coastguard Worker   // #elif blocks. These NC tests check that a static_assert statement fails if
48*61c4878aSAndroid Build Coastguard Worker   // the code is compiled.
49*61c4878aSAndroid Build Coastguard Worker   #if PW_NC_TEST(NegativeOddNumber)
50*61c4878aSAndroid Build Coastguard Worker   PW_NC_EXPECT("wrong number!");
51*61c4878aSAndroid Build Coastguard Worker   [[maybe_unused]] MyStruct<-1> illegal;
52*61c4878aSAndroid Build Coastguard Worker   #elif PW_NC_TEST(PositiveOddNumber)
53*61c4878aSAndroid Build Coastguard Worker   PW_NC_EXPECT("wrong number!");
54*61c4878aSAndroid Build Coastguard Worker   [[maybe_unused]] MyStruct<5> this_is_illegal;
55*61c4878aSAndroid Build Coastguard Worker   #endif  // PW_NC_TEST
56*61c4878aSAndroid Build Coastguard Worker
57*61c4878aSAndroid Build Coastguard Worker   struct Foo {
58*61c4878aSAndroid Build Coastguard Worker     // Negative compilation tests can go anywhere in a source file.
59*61c4878aSAndroid Build Coastguard Worker   #if PW_NC_TEST(IllegalValueAsClassMember)
60*61c4878aSAndroid Build Coastguard Worker     PW_NC_EXPECT("wrong number!");
61*61c4878aSAndroid Build Coastguard Worker     MyStruct<12> also_illegal;
62*61c4878aSAndroid Build Coastguard Worker   #endif  // PW_NC_TEST
63*61c4878aSAndroid Build Coastguard Worker   };
64*61c4878aSAndroid Build Coastguard Worker
65*61c4878aSAndroid Build Coastguard Worker   TEST(MyStruct, MultiplyOdd) {
66*61c4878aSAndroid Build Coastguard Worker     MyStruct<5> five;
67*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(five.MultiplyOdd(3), 15);
68*61c4878aSAndroid Build Coastguard Worker
69*61c4878aSAndroid Build Coastguard Worker     // This NC test checks that a specific PW_ASSERT() fails when expected.
70*61c4878aSAndroid Build Coastguard Worker     // This only works in an NC test if the PW_ASSERT() fails while the compiler
71*61c4878aSAndroid Build Coastguard Worker     // is executing constexpr code. The test code is used in a constexpr
72*61c4878aSAndroid Build Coastguard Worker     // statement to force compile-time evaluation.
73*61c4878aSAndroid Build Coastguard Worker     #if PW_NC_TEST(MyStruct_MultiplyOdd_AssertsOnOddNumber)
74*61c4878aSAndroid Build Coastguard Worker     [[maybe_unused]] constexpr auto fail = [] {
75*61c4878aSAndroid Build Coastguard Worker       PW_NC_EXPECT("PW_ASSERT\(runtime_value % 2 == 0\);");
76*61c4878aSAndroid Build Coastguard Worker       MyStruct<3> my_struct;
77*61c4878aSAndroid Build Coastguard Worker       return my_struct.MultiplyOdd(4);  // Even number, PW_ASSERT should fail.
78*61c4878aSAndroid Build Coastguard Worker     }();
79*61c4878aSAndroid Build Coastguard Worker     #endif  // PW_NC_TEST
80*61c4878aSAndroid Build Coastguard Worker   }
81*61c4878aSAndroid Build Coastguard Worker
82*61c4878aSAndroid Build Coastguard Worker   // PW_NC_TESTs can be conditionally executed using preprocessor conditionals.
83*61c4878aSAndroid Build Coastguard Worker   #if PW_CXX_STANDARD_IS_SUPPORTED(20)
84*61c4878aSAndroid Build Coastguard Worker   #if PW_NC_TEST(RequiresSomeCpp20Feature)
85*61c4878aSAndroid Build Coastguard Worker   [[maybe_unused]] constinit MyStruct<4> constinit_works;
86*61c4878aSAndroid Build Coastguard Worker   #endif // PW_NC_TEST
87*61c4878aSAndroid Build Coastguard Worker   #endif // PW_CXX_STANDARD_IS_SUPPORTED(20)
88*61c4878aSAndroid Build Coastguard Worker
89*61c4878aSAndroid Build Coastguard Worker------------------------------------
90*61c4878aSAndroid Build Coastguard WorkerCreating a negative compilation test
91*61c4878aSAndroid Build Coastguard Worker------------------------------------
92*61c4878aSAndroid Build Coastguard Worker- Declare a ``pw_cc_negative_compilation_test()`` GN target or set
93*61c4878aSAndroid Build Coastguard Worker  ``negative_compilation_test = true`` in a ``pw_test()`` target.
94*61c4878aSAndroid Build Coastguard Worker- Add the test to the build in a toolchain with negative compilation testing
95*61c4878aSAndroid Build Coastguard Worker  enabled (``pw_compilation_testing_NEGATIVE_COMPILATION_ENABLED = true``).
96*61c4878aSAndroid Build Coastguard Worker- In the test source files, add
97*61c4878aSAndroid Build Coastguard Worker  ``#include "pw_compilation_testing/negative_compilation.h"``.
98*61c4878aSAndroid Build Coastguard Worker- Use the ``PW_NC_TEST(TestName)`` macro in a ``#if`` statement.
99*61c4878aSAndroid Build Coastguard Worker- Immediately after the ``PW_NC_TEST(TestName)``, provide one or more
100*61c4878aSAndroid Build Coastguard Worker  Python-style regular expressions with the ``PW_NC_EXPECT()`` macro, one per
101*61c4878aSAndroid Build Coastguard Worker  line.
102*61c4878aSAndroid Build Coastguard Worker- Execute the tests by running the build.
103*61c4878aSAndroid Build Coastguard Worker
104*61c4878aSAndroid Build Coastguard WorkerTo simplify parsing, all ``PW_NC_TEST()`` statements must fit on a single line
105*61c4878aSAndroid Build Coastguard Workerand cannot have any other code before or after them. ``PW_NC_EXPECT()``
106*61c4878aSAndroid Build Coastguard Workerstatements may span multiple lines, but must contain a single regular expression
107*61c4878aSAndroid Build Coastguard Workeras a string literal. The string may be comprised of multiple implicitly
108*61c4878aSAndroid Build Coastguard Workerconcatenated string literals. The ``PW_NC_EXPECT()`` statement cannot contain
109*61c4878aSAndroid Build Coastguard Workeranything else except for ``//``-style comments.
110*61c4878aSAndroid Build Coastguard Worker
111*61c4878aSAndroid Build Coastguard WorkerTest assertions
112*61c4878aSAndroid Build Coastguard Worker===============
113*61c4878aSAndroid Build Coastguard WorkerNegative compilation tests must have at least one assertion about the
114*61c4878aSAndroid Build Coastguard Workercompilation output. The assertion macros must be placed immediately after the
115*61c4878aSAndroid Build Coastguard Workerline with the ``PW_NC_TEST()`` or the test will fail.
116*61c4878aSAndroid Build Coastguard Worker
117*61c4878aSAndroid Build Coastguard Worker.. c:macro:: PW_NC_EXPECT(regex_string_literal)
118*61c4878aSAndroid Build Coastguard Worker
119*61c4878aSAndroid Build Coastguard Worker  When negative compilation tests are run, checks the compilation output for the
120*61c4878aSAndroid Build Coastguard Worker  provided regular expression. The argument to the ``PW_NC_EXPECT()`` statement
121*61c4878aSAndroid Build Coastguard Worker  must be a string literal. The literal is interpreted character-for-character
122*61c4878aSAndroid Build Coastguard Worker  as a Python raw string literal and compiled as a Python `re
123*61c4878aSAndroid Build Coastguard Worker  <https://docs.python.org/3/library/re.html>`_ regular expression.
124*61c4878aSAndroid Build Coastguard Worker
125*61c4878aSAndroid Build Coastguard Worker  For example, ``PW_NC_EXPECT("something (went|has gone) wrong!")`` searches the
126*61c4878aSAndroid Build Coastguard Worker  failed compilation output with the Python regular expression
127*61c4878aSAndroid Build Coastguard Worker  ``re.compile("something (went|has gone) wrong!")``.
128*61c4878aSAndroid Build Coastguard Worker
129*61c4878aSAndroid Build Coastguard Worker.. c:macro:: PW_NC_EXPECT_GCC(regex_string_literal)
130*61c4878aSAndroid Build Coastguard Worker
131*61c4878aSAndroid Build Coastguard Worker   Same as :c:macro:`PW_NC_EXPECT`, but only applies when compiling with GCC.
132*61c4878aSAndroid Build Coastguard Worker
133*61c4878aSAndroid Build Coastguard Worker.. c:macro:: PW_NC_EXPECT_CLANG(regex_string_literal)
134*61c4878aSAndroid Build Coastguard Worker
135*61c4878aSAndroid Build Coastguard Worker   Same as :c:macro:`PW_NC_EXPECT`, but only applies when compiling with Clang.
136*61c4878aSAndroid Build Coastguard Worker
137*61c4878aSAndroid Build Coastguard Worker.. admonition:: Test expectation tips
138*61c4878aSAndroid Build Coastguard Worker   :class: tip
139*61c4878aSAndroid Build Coastguard Worker
140*61c4878aSAndroid Build Coastguard Worker   Be as specific as possible, but avoid compiler-specific error text. Try
141*61c4878aSAndroid Build Coastguard Worker   matching against the following:
142*61c4878aSAndroid Build Coastguard Worker
143*61c4878aSAndroid Build Coastguard Worker   - ``static_assert`` messages.
144*61c4878aSAndroid Build Coastguard Worker   - Contents of specific failing lines of source code:
145*61c4878aSAndroid Build Coastguard Worker     ``PW_NC_EXPECT("PW_ASSERT\(!empty\(\));")``.
146*61c4878aSAndroid Build Coastguard Worker   - Comments on affected lines: ``PW_NC_EXPECT("// Cannot construct from
147*61c4878aSAndroid Build Coastguard Worker     nullptr")``.
148*61c4878aSAndroid Build Coastguard Worker   - Function names: ``PW_NC_EXPECT("SomeFunction\(\).*private")``.
149*61c4878aSAndroid Build Coastguard Worker
150*61c4878aSAndroid Build Coastguard Worker   Do not match against the following:
151*61c4878aSAndroid Build Coastguard Worker
152*61c4878aSAndroid Build Coastguard Worker   - Source file paths.
153*61c4878aSAndroid Build Coastguard Worker   - Source line numbers.
154*61c4878aSAndroid Build Coastguard Worker   - Compiler-specific wording of error messages, except when necessary.
155*61c4878aSAndroid Build Coastguard Worker
156*61c4878aSAndroid Build Coastguard Worker------
157*61c4878aSAndroid Build Coastguard WorkerDesign
158*61c4878aSAndroid Build Coastguard Worker------
159*61c4878aSAndroid Build Coastguard WorkerThe basic flow for negative compilation testing is as follows.
160*61c4878aSAndroid Build Coastguard Worker
161*61c4878aSAndroid Build Coastguard Worker- The user defines negative compilation tests in preprocessor ``#if`` blocks
162*61c4878aSAndroid Build Coastguard Worker  using the ``PW_NC_TEST()`` and :c:macro:`PW_NC_EXPECT` macros.
163*61c4878aSAndroid Build Coastguard Worker- The build invokes the ``pw_compilation_testing.generator`` script. The
164*61c4878aSAndroid Build Coastguard Worker  generator script:
165*61c4878aSAndroid Build Coastguard Worker
166*61c4878aSAndroid Build Coastguard Worker  - finds ``PW_NC_TEST()`` statements and extracts a list of test cases,
167*61c4878aSAndroid Build Coastguard Worker  - finds all associated :c:macro:`PW_NC_EXPECT` statements, and
168*61c4878aSAndroid Build Coastguard Worker  - generates build targets for each negative compilation tests,
169*61c4878aSAndroid Build Coastguard Worker    passing the test information and expectations to the targets.
170*61c4878aSAndroid Build Coastguard Worker
171*61c4878aSAndroid Build Coastguard Worker- The build compiles the test source file with all tests disabled.
172*61c4878aSAndroid Build Coastguard Worker- The build invokes the negative compilation test targets, which run the
173*61c4878aSAndroid Build Coastguard Worker  ``pw_compilation_testing.runner`` script. The test runner script:
174*61c4878aSAndroid Build Coastguard Worker
175*61c4878aSAndroid Build Coastguard Worker  - invokes the compiler, setting a preprocessor macro that enables the ``#if``
176*61c4878aSAndroid Build Coastguard Worker    block for the test.
177*61c4878aSAndroid Build Coastguard Worker  - captures the compilation output, and
178*61c4878aSAndroid Build Coastguard Worker  - checks the compilation output for the :c:macro:`PW_NC_EXPECT` expressions.
179*61c4878aSAndroid Build Coastguard Worker
180*61c4878aSAndroid Build Coastguard Worker- If compilation failed, and the output matches the test case's
181*61c4878aSAndroid Build Coastguard Worker  :c:macro:`PW_NC_EXPECT` expressions, the test passes.
182*61c4878aSAndroid Build Coastguard Worker- If compilation succeeded or the :c:macro:`PW_NC_EXPECT` expressions did not
183*61c4878aSAndroid Build Coastguard Worker  match the output, the test fails.
184*61c4878aSAndroid Build Coastguard Worker
185*61c4878aSAndroid Build Coastguard WorkerExisting frameworks
186*61c4878aSAndroid Build Coastguard Worker===================
187*61c4878aSAndroid Build Coastguard WorkerPigweed's negative compilation tests were inspired by Chromium's `no-compile
188*61c4878aSAndroid Build Coastguard Workertests <https://www.chromium.org/developers/testing/no-compile-tests/>`_
189*61c4878aSAndroid Build Coastguard Workertests and a similar framework used internally at Google. Pigweed's negative
190*61c4878aSAndroid Build Coastguard Workercompilation testing framework improves on these systems in a few respects:
191*61c4878aSAndroid Build Coastguard Worker
192*61c4878aSAndroid Build Coastguard Worker- Trivial integration with unit tests. Negative compilation tests can easily be
193*61c4878aSAndroid Build Coastguard Worker  placed alongside other unit tests instead of in separate files.
194*61c4878aSAndroid Build Coastguard Worker- Safer, more natural macro-based API for test declarations. Other systems use
195*61c4878aSAndroid Build Coastguard Worker  ``#ifdef`` macro checks to define test cases, which fail silently when there
196*61c4878aSAndroid Build Coastguard Worker  are typos. Pigweed's framework uses function-like macros, which provide a
197*61c4878aSAndroid Build Coastguard Worker  clean and natural API, catch typos, and ensure the test is integrated with the
198*61c4878aSAndroid Build Coastguard Worker  NC test framework.
199*61c4878aSAndroid Build Coastguard Worker- More readable, flexible test assertions. Other frameworks place assertions in
200*61c4878aSAndroid Build Coastguard Worker  comments after test names, while Pigweed's framework uses function-like
201*61c4878aSAndroid Build Coastguard Worker  macros. Pigweed also supports compiler-specific assertions.
202*61c4878aSAndroid Build Coastguard Worker- Assertions are required. This helps ensure that compilation fails for the
203*61c4878aSAndroid Build Coastguard Worker  expected reason and not for an accidental typo or unrelated issue.
204