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