• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 // The Pigweed unit test framework requires C++17 to use its full functionality.
16 #pragma once
17 
18 #include <cstddef>
19 #include <cstdint>
20 #include <cstring>
21 #include <new>
22 
23 #include "pw_polyfill/standard.h"
24 #include "pw_preprocessor/compiler.h"
25 #include "pw_preprocessor/util.h"
26 #include "pw_span/span.h"
27 #include "pw_unit_test/config.h"
28 #include "pw_unit_test/event_handler.h"
29 
30 #if PW_CXX_STANDARD_IS_SUPPORTED(17)
31 #include <string_view>
32 
33 #include "pw_string/string_builder.h"
34 #endif  // PW_CXX_STANDARD_IS_SUPPORTED(17)
35 
36 #define GTEST_TEST(test_suite_name, test_name)                           \
37   _PW_TEST_SUITE_NAMES_MUST_BE_UNIQUE(void /* TEST */, test_suite_name); \
38   _PW_TEST(test_suite_name, test_name, ::pw::unit_test::internal::Test)
39 
40 // TEST() is a pretty generic macro name which could conflict with other code.
41 // If GTEST_DONT_DEFINE_TEST is set, don't alias GTEST_TEST to TEST.
42 #if !(defined(GTEST_DONT_DEFINE_TEST) && GTEST_DONT_DEFINE_TEST)
43 #define TEST(test_suite_name, test_name) GTEST_TEST(test_suite_name, test_name)
44 #endif  // !GTEST_DONT_DEFINE_TEST
45 
46 #define TEST_F(test_fixture, test_name)                                \
47   _PW_TEST_SUITE_NAMES_MUST_BE_UNIQUE(int /* TEST_F */, test_fixture); \
48   _PW_TEST(test_fixture, test_name, test_fixture)
49 
50 #define EXPECT_TRUE(expr) static_cast<void>(_PW_TEST_BOOL(expr, true))
51 #define EXPECT_FALSE(expr) static_cast<void>(_PW_TEST_BOOL(expr, false))
52 #define EXPECT_EQ(lhs, rhs) static_cast<void>(_PW_TEST_OP(lhs, rhs, ==))
53 #define EXPECT_NE(lhs, rhs) static_cast<void>(_PW_TEST_OP(lhs, rhs, !=))
54 #define EXPECT_GT(lhs, rhs) static_cast<void>(_PW_TEST_OP(lhs, rhs, >))
55 #define EXPECT_GE(lhs, rhs) static_cast<void>(_PW_TEST_OP(lhs, rhs, >=))
56 #define EXPECT_LT(lhs, rhs) static_cast<void>(_PW_TEST_OP(lhs, rhs, <))
57 #define EXPECT_LE(lhs, rhs) static_cast<void>(_PW_TEST_OP(lhs, rhs, <=))
58 #define EXPECT_STREQ(lhs, rhs) static_cast<void>(_PW_TEST_C_STR(lhs, rhs, ==))
59 #define EXPECT_STRNE(lhs, rhs) static_cast<void>(_PW_TEST_C_STR(lhs, rhs, !=))
60 
61 #define ASSERT_TRUE(expr) _PW_TEST_ASSERT(_PW_TEST_BOOL(expr, true))
62 #define ASSERT_FALSE(expr) _PW_TEST_ASSERT(_PW_TEST_BOOL(expr, false))
63 #define ASSERT_EQ(lhs, rhs) _PW_TEST_ASSERT(_PW_TEST_OP(lhs, rhs, ==))
64 #define ASSERT_NE(lhs, rhs) _PW_TEST_ASSERT(_PW_TEST_OP(lhs, rhs, !=))
65 #define ASSERT_GT(lhs, rhs) _PW_TEST_ASSERT(_PW_TEST_OP(lhs, rhs, >))
66 #define ASSERT_GE(lhs, rhs) _PW_TEST_ASSERT(_PW_TEST_OP(lhs, rhs, >=))
67 #define ASSERT_LT(lhs, rhs) _PW_TEST_ASSERT(_PW_TEST_OP(lhs, rhs, <))
68 #define ASSERT_LE(lhs, rhs) _PW_TEST_ASSERT(_PW_TEST_OP(lhs, rhs, <=))
69 #define ASSERT_STREQ(lhs, rhs) _PW_TEST_ASSERT(_PW_TEST_C_STR(lhs, rhs, ==))
70 #define ASSERT_STRNE(lhs, rhs) _PW_TEST_ASSERT(_PW_TEST_C_STR(lhs, rhs, !=))
71 
72 // Generates a non-fatal failure with a generic message.
73 #define ADD_FAILURE()                                                  \
74   ::pw::unit_test::internal::Framework::Get().CurrentTestExpectSimple( \
75       "(line is not executed)", "(line was executed)", __LINE__, false)
76 
77 // Generates a fatal failure with a generic message.
78 #define GTEST_FAIL() return ADD_FAILURE()
79 
80 // Skips test at runtime, which is neither successful nor failed. Skip aborts
81 // current function.
82 #define GTEST_SKIP() \
83   return ::pw::unit_test::internal::Framework::Get().CurrentTestSkip(__LINE__)
84 
85 // Define either macro to 1 to omit the definition of FAIL(), which is a
86 // generic name and clashes with some other libraries.
87 #if !(defined(GTEST_DONT_DEFINE_FAIL) && GTEST_DONT_DEFINE_FAIL)
88 #define FAIL() GTEST_FAIL()
89 #endif  // !GTEST_DONT_DEFINE_FAIL
90 
91 // Generates a success with a generic message.
92 #define GTEST_SUCCEED()                                                \
93   ::pw::unit_test::internal::Framework::Get().CurrentTestExpectSimple( \
94       "(success)", "(success)", __LINE__, true)
95 
96 // Define either macro to 1 to omit the definition of SUCCEED(), which
97 // is a generic name and clashes with some other libraries.
98 #if !(defined(GTEST_DONT_DEFINE_SUCCEED) && GTEST_DONT_DEFINE_SUCCEED)
99 #define SUCCEED() GTEST_SUCCEED()
100 #endif  // !GTEST_DONT_DEFINE_SUCCEED
101 
102 // pw_unit_test framework entry point. Runs every registered test case and
103 // dispatches the results through the event handler. Returns a status of zero
104 // if all tests passed, or nonzero if there were any failures.
105 // This is compatible with GoogleTest.
106 //
107 // In order to receive test output, an event handler must be registered before
108 // this is called:
109 //
110 //   int main() {
111 //     MyEventHandler handler;
112 //     pw::unit_test::RegisterEventHandler(&handler);
113 //     return RUN_ALL_TESTS();
114 //   }
115 //
116 #define RUN_ALL_TESTS() \
117   ::pw::unit_test::internal::Framework::Get().RunAllTests()
118 
119 // Death tests are not supported. The *_DEATH_IF_SUPPORTED macros do nothing.
120 #define GTEST_HAS_DEATH_TEST 0
121 
122 #define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
123   if (0) {                                          \
124     static_cast<void>(statement);                   \
125     static_cast<void>(regex);                       \
126   }                                                 \
127   static_assert(true, "Macros must be terminated with a semicolon")
128 
129 #define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
130   EXPECT_DEATH_IF_SUPPORTED(statement, regex)
131 
132 namespace pw {
133 
134 #if PW_CXX_STANDARD_IS_SUPPORTED(17)
135 
136 namespace string {
137 
138 // This function is used to print unknown types that are used in EXPECT or
139 // ASSERT statements in tests.
140 //
141 // You can add support for displaying custom types by defining a ToString
142 // template specialization. For example:
143 //
144 //   namespace pw {
145 //
146 //   template <>
147 //   StatusWithSize ToString<MyType>(const MyType& value,
148 //                                   span<char> buffer) {
149 //     return string::Format("<MyType|%d>", value.id);
150 //   }
151 //
152 //   }  // namespace pw
153 //
154 // See the documentation in pw_string/string_builder.h for more information.
155 template <typename T>
UnknownTypeToString(const T & value,span<char> buffer)156 StatusWithSize UnknownTypeToString(const T& value, span<char> buffer) {
157   StringBuilder sb(buffer);
158   sb << '<' << sizeof(value) << "-byte object at 0x" << &value << '>';
159   return sb.status_with_size();
160 }
161 
162 }  // namespace string
163 
164 #endif  // PW_CXX_STANDARD_IS_SUPPORTED(17)
165 
166 namespace unit_test {
167 
168 // Sets the event handler for a test run. Must be called before RUN_ALL_TESTS()
169 // to receive test output.
170 void RegisterEventHandler(EventHandler* event_handler);
171 
172 namespace internal {
173 
174 class Test;
175 class TestInfo;
176 
177 // Used to tag arguments to EXPECT_STREQ/EXPECT_STRNE so they are treated like C
178 // strings rather than pointers.
179 struct CStringArg {
180   const char* const c_str;
181 };
182 
183 // Singleton test framework class responsible for managing and running test
184 // cases. This implementation is internal to Pigweed test; free functions
185 // wrapping its functionality are exposed as the public interface.
186 class Framework {
187  public:
Framework()188   constexpr Framework()
189       : current_test_(nullptr),
190         current_result_(TestResult::kSuccess),
191         run_tests_summary_{.passed_tests = 0,
192                            .failed_tests = 0,
193                            .skipped_tests = 0,
194                            .disabled_tests = 0},
195         exit_status_(0),
196         event_handler_(nullptr),
197         memory_pool_() {}
198 
Get()199   static Framework& Get() { return framework_; }
200 
201   // Registers a single test case with the framework. The framework owns the
202   // registered unit test. Called during static initialization.
203   void RegisterTest(TestInfo* test) const;
204 
205   // Sets the handler to which the framework dispatches test events. During a
206   // test run, the framework owns the event handler.
RegisterEventHandler(EventHandler * event_handler)207   void RegisterEventHandler(EventHandler* event_handler) {
208     event_handler_ = event_handler;
209   }
210 
211   // Runs all registered test cases, returning a status of 0 if all succeeded or
212   // nonzero if there were any failures. Test events that occur during the run
213   // are sent to the registered event handler, if any.
214   int RunAllTests();
215 
216 #if PW_CXX_STANDARD_IS_SUPPORTED(17)
217   // Only run test suites whose names are included in the provided list during
218   // the next test run. This is C++17 only; older versions of C++ will run all
219   // non-disabled tests.
SetTestSuitesToRun(span<std::string_view> test_suites)220   void SetTestSuitesToRun(span<std::string_view> test_suites) {
221     test_suites_to_run_ = test_suites;
222   }
223 #endif  // PW_CXX_STANDARD_IS_SUPPORTED(17)
224 
225   bool ShouldRunTest(const TestInfo& test_info) const;
226 
227   // Whether the current test is skipped.
IsSkipped()228   bool IsSkipped() const { return current_result_ == TestResult::kSkipped; }
229 
230   // Constructs an instance of a unit test class and runs the test.
231   //
232   // Tests are constructed within a static memory pool at run time instead of
233   // being statically allocated to avoid blowing up the size of the test binary
234   // in cases where users have large test fixtures (e.g. containing buffers)
235   // reused many times. Instead, only a small, fixed-size TestInfo struct is
236   // statically allocated per test case, with a run() function that references
237   // this method instantiated for its test class.
238   template <typename TestInstance>
CreateAndRunTest(const TestInfo & test_info)239   static void CreateAndRunTest(const TestInfo& test_info) {
240     static_assert(
241         sizeof(TestInstance) <= sizeof(memory_pool_),
242         "The test memory pool is too small for this test. Either increase "
243         "PW_UNIT_TEST_CONFIG_MEMORY_POOL_SIZE or decrease the size of your "
244         "test fixture.");
245 
246     Framework& framework = Get();
247     framework.StartTest(test_info);
248 
249     // Reset the memory pool to a marker value to help detect use of
250     // uninitialized memory.
251     std::memset(&framework.memory_pool_, 0xa5, sizeof(framework.memory_pool_));
252 
253     // Construct the test object within the static memory pool. The StartTest
254     // function has already been called by the TestInfo at this point.
255     TestInstance* test_instance = new (&framework.memory_pool_) TestInstance;
256     test_instance->PigweedTestRun();
257 
258     // Manually call the destructor as it is not called automatically for
259     // objects constructed using placement new.
260     test_instance->~TestInstance();
261 
262     framework.EndCurrentTest();
263   }
264 
265   // Runs an expectation function for the currently active test case.
266   template <typename Expectation, typename Lhs, typename Rhs>
CurrentTestExpect(Expectation expectation,const Lhs & lhs,const Rhs & rhs,const char * expectation_string,const char * expression,int line)267   bool CurrentTestExpect(Expectation expectation,
268                          const Lhs& lhs,
269                          const Rhs& rhs,
270                          [[maybe_unused]] const char* expectation_string,
271                          const char* expression,
272                          int line) {
273     // Size of the buffer into which to write the string with the evaluated
274     // version of the arguments. This buffer is allocated on the unit test's
275     // stack, so it shouldn't be too large.
276     // TODO(hepler): Make this configurable.
277     [[maybe_unused]] constexpr size_t kExpectationBufferSizeBytes = 128;
278 
279     const bool success = expectation(lhs, rhs);
280     CurrentTestExpectSimple(
281         expression,
282 #if PW_CXX_STANDARD_IS_SUPPORTED(17)
283         MakeString<kExpectationBufferSizeBytes>(ConvertForPrint(lhs),
284                                                 ' ',
285                                                 expectation_string,
286                                                 ' ',
287                                                 ConvertForPrint(rhs))
288             .c_str(),
289 #else
290         "(evaluation requires C++17)",
291 #endif  // PW_CXX_STANDARD_IS_SUPPORTED(17)
292         line,
293         success);
294     return success;
295   }
296 
297   // Skips the current test and dispatches an event for it.
298   void CurrentTestSkip(int line);
299 
300   // Dispatches an event indicating the result of an expectation.
301   void CurrentTestExpectSimple(const char* expression,
302                                const char* evaluated_expression,
303                                int line,
304                                bool success);
305 
306  private:
307   // Convert char* to void* so that they are printed as pointers instead of
308   // strings in EXPECT_EQ and other macros. EXPECT_STREQ wraps its pointers in a
309   // CStringArg so its pointers are treated like C strings.
ConvertForPrint(const char * str)310   static constexpr const void* ConvertForPrint(const char* str) { return str; }
311 
ConvertForPrint(char * str)312   static constexpr const void* ConvertForPrint(char* str) { return str; }
313 
ConvertForPrint(CStringArg value)314   static constexpr const char* ConvertForPrint(CStringArg value) {
315     return value.c_str;
316   }
317 
318   template <typename T>
ConvertForPrint(T && value)319   static constexpr T ConvertForPrint(T&& value) {
320     return std::forward<T>(value);
321   }
322 
323   // Sets current_test_ and dispatches an event indicating that a test started.
324   void StartTest(const TestInfo& test);
325 
326   // Dispatches event indicating that a test finished and clears current_test_.
327   void EndCurrentTest();
328 
329   // Singleton instance of the framework class.
330   static Framework framework_;
331 
332   // Linked list of all registered test cases. This is static as it tests are
333   // registered using static initialization.
334   static TestInfo* tests_;
335 
336   // The current test case which is running.
337   const TestInfo* current_test_;
338 
339   // Overall result of the current test case (pass/fail/skip).
340   TestResult current_result_;
341 
342   // Overall result of the ongoing test run, which covers multiple tests.
343   RunTestsSummary run_tests_summary_;
344 
345   // Program exit status returned by RunAllTests for GoogleTest compatibility.
346   int exit_status_;
347 
348   // Handler to which to dispatch test events.
349   EventHandler* event_handler_;
350 
351 #if PW_CXX_STANDARD_IS_SUPPORTED(17)
352   span<std::string_view> test_suites_to_run_;
353 #else
354   span<const char*> test_suites_to_run_;  // Always empty in C++14.
355 #endif  // PW_CXX_STANDARD_IS_SUPPORTED(17)
356 
357   std::aligned_storage_t<config::kMemoryPoolSize, alignof(std::max_align_t)>
358       memory_pool_;
359 };
360 
361 // Information about a single test case, including a pointer to a function which
362 // constructs and runs the test class. These are statically allocated instead of
363 // the test classes, as test classes can be very large.
364 class TestInfo {
365  public:
TestInfo(const char * const test_suite_name,const char * const test_name,const char * const file_name,void (* run_func)(const TestInfo &))366   TestInfo(const char* const test_suite_name,
367            const char* const test_name,
368            const char* const file_name,
369            void (*run_func)(const TestInfo&))
370       : test_case_{
371         .suite_name = test_suite_name,
372         .test_name = test_name,
373         .file_name = file_name,
374        }, run_(run_func) {
375     Framework::Get().RegisterTest(this);
376   }
377 
378   // The name of the suite to which the test case belongs, the name of the test
379   // case itself, and the path to the file in which the test case is located.
test_case()380   const TestCase& test_case() const { return test_case_; }
381 
382   bool enabled() const;
383 
run()384   void run() const { run_(*this); }
385 
next()386   TestInfo* next() const { return next_; }
set_next(TestInfo * next)387   void set_next(TestInfo* next) { next_ = next; }
388 
389  private:
390   TestCase test_case_;
391 
392   // Function which runs the test case. Refers to Framework::CreateAndRunTest
393   // instantiated for the test case's class.
394   void (*run_)(const TestInfo&);
395 
396   // TestInfo structs are registered with the test framework and stored as a
397   // linked list.
398   TestInfo* next_ = nullptr;
399 };
400 
401 // Base class for all test cases or custom test fixtures.
402 // Every unit test created using the TEST or TEST_F macro defines a class that
403 // inherits from this (or a subclass of this).
404 //
405 // For example, given the following test definition:
406 //
407 //   TEST(MyTest, SaysHello) {
408 //     ASSERT_STREQ(SayHello(), "Hello, world!");
409 //   }
410 //
411 // A new class is defined for the test, e.g. MyTest_SaysHello_Test. This class
412 // inherits from the Test class and implements its PigweedTestBody function with
413 // the block provided to the TEST macro.
414 class Test {
415  public:
416   Test(const Test&) = delete;
417   Test& operator=(const Test&) = delete;
418 
419   virtual ~Test() = default;
420 
421   // Runs the unit test.
PigweedTestRun()422   void PigweedTestRun() {
423     SetUp();
424     // TODO(deymo): Skip the test body if there's a fatal error in SetUp().
425     if (!Framework::Get().IsSkipped()) {
426       PigweedTestBody();
427     }
428     TearDown();
429   }
430 
431  protected:
432   Test() = default;
433 
434   // Called immediately before executing the test body.
435   //
436   // Setup and cleanup can typically be done in the test fixture's constructor
437   // and destructor, but there are cases where SetUp/TearDown must be used
438   // instead. See the Google Test documentation for more information.
SetUp()439   virtual void SetUp() {}
440 
441   // Called immediately after executing the test body.
TearDown()442   virtual void TearDown() {}
443 
444  private:
445   friend class internal::Framework;
446 
447   // The user-provided body of the test case. Populated by the TEST macro.
448   virtual void PigweedTestBody() = 0;
449 };
450 
451 // Checks that a test suite name is valid.
HasNoUnderscores(const char * suite)452 constexpr bool HasNoUnderscores(const char* suite) {
453   const char* disabled_prefix = "DISABLED_";
454 
455   for (; *suite != '\0'; ++suite) {
456     if (*suite == *disabled_prefix) {
457       disabled_prefix += 1;
458     } else {
459       disabled_prefix = "";
460       if (*suite == '_') {
461         return false;
462       }
463     }
464   }
465   return true;
466 }
467 
468 }  // namespace internal
469 
470 #if PW_CXX_STANDARD_IS_SUPPORTED(17)
SetTestSuitesToRun(span<std::string_view> test_suites)471 inline void SetTestSuitesToRun(span<std::string_view> test_suites) {
472   internal::Framework::Get().SetTestSuitesToRun(test_suites);
473 }
474 #endif  // PW_CXX_STANDARD_IS_SUPPORTED(17)
475 
476 }  // namespace unit_test
477 }  // namespace pw
478 
479 #define _PW_TEST(test_suite_name, test_name, parent_class)                     \
480   static_assert(sizeof(#test_suite_name) > 1,                                  \
481                 "The test suite name must not be empty");                      \
482   static_assert(::pw::unit_test::internal::HasNoUnderscores(#test_suite_name), \
483                 "The test suite name (" #test_suite_name                       \
484                 ") cannot contain underscores");                               \
485   static_assert(sizeof(#test_name) > 1, "The test name must not be empty");    \
486                                                                                \
487   _PW_TEST_CLASS(test_suite_name,                                              \
488                  test_name,                                                    \
489                  test_suite_name##_##test_name##_Test,                         \
490                  parent_class)
491 
492 #define _PW_TEST_CLASS(suite, name, class_name, parent_class)               \
493   class class_name final : public parent_class {                            \
494    private:                                                                 \
495     void PigweedTestBody() override;                                        \
496   };                                                                        \
497                                                                             \
498   extern "C" {                                                              \
499                                                                             \
500   /* Declare the TestInfo as non-const since const variables do not work */ \
501   /* with the PW_UNIT_TEST_LINK_FILE_CONTAINING_TEST macro. */              \
502   /* NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) */  \
503   ::pw::unit_test::internal::TestInfo _pw_unit_test_Info_##suite##_##name(  \
504       #suite,                                                               \
505       #name,                                                                \
506       __FILE__,                                                             \
507       ::pw::unit_test::internal::Framework::CreateAndRunTest<class_name>);  \
508                                                                             \
509   } /* extern "C" */                                                        \
510                                                                             \
511   void class_name::PigweedTestBody()
512 
513 #define _PW_TEST_ASSERT(expectation)                                           \
514   do {                                                                         \
515     if (!(expectation)) {                                                      \
516       return static_cast<void>(0); /* Prevent using ASSERT in constructors. */ \
517     }                                                                          \
518   } while (0)
519 
520 #define _PW_TEST_BOOL(expr, value)                               \
521   ::pw::unit_test::internal::Framework::Get().CurrentTestExpect( \
522       [](bool lhs, bool rhs) { return lhs == rhs; },             \
523       static_cast<bool>(expr),                                   \
524       value,                                                     \
525       "is",                                                      \
526       #expr " is " #value,                                       \
527       __LINE__)
528 
529 #define _PW_TEST_OP(lhs, rhs, op)                                \
530   ::pw::unit_test::internal::Framework::Get().CurrentTestExpect( \
531       [](const auto& _pw_lhs, const auto& _pw_rhs) {             \
532         return _pw_lhs op _pw_rhs;                               \
533       },                                                         \
534       (lhs),                                                     \
535       (rhs),                                                     \
536       #op,                                                       \
537       #lhs " " #op " " #rhs,                                     \
538       __LINE__)
539 
540 #define _PW_TEST_C_STR(lhs, rhs, op)                             \
541   ::pw::unit_test::internal::Framework::Get().CurrentTestExpect( \
542       [](const auto& _pw_lhs, const auto& _pw_rhs) {             \
543         return std::strcmp(_pw_lhs.c_str, _pw_rhs.c_str) op 0;   \
544       },                                                         \
545       ::pw::unit_test::internal::CStringArg{lhs},                \
546       ::pw::unit_test::internal::CStringArg{rhs},                \
547       #op,                                                       \
548       #lhs " " #op " " #rhs,                                     \
549       __LINE__)
550 
551 // Checks that test suite names between TEST and TEST_F declarations are unique.
552 // This works by declaring a function named for the test suite. The function
553 // takes no arguments but is declared with different return types in the TEST
554 // and TEST_F macros. If a TEST and TEST_F use the same test suite name, the
555 // function declarations conflict, resulting in a compilation error.
556 //
557 // This catches most conflicts, but a runtime check is ultimately needed since
558 // tests may be declared in different translation units.
559 #if !defined(__clang__) && !defined(__GNUC___) && __GNUC__ <= 8
560 // For some reason GCC8 is unable to ignore -Wredundant-decls here.
561 #define _PW_TEST_SUITE_NAMES_MUST_BE_UNIQUE(return_type, test_suite)
562 #else  // All other compilers.
563 #define _PW_TEST_SUITE_NAMES_MUST_BE_UNIQUE(return_type, test_suite)           \
564   PW_MODIFY_DIAGNOSTICS_PUSH();                                                \
565   PW_MODIFY_DIAGNOSTIC(ignored, "-Wredundant-decls");                          \
566   extern "C" return_type /* use extern "C" to escape namespacing */            \
567       PwUnitTestSuiteNamesMustBeUniqueBetweenTESTandTEST_F_##test_suite(void); \
568   PW_MODIFY_DIAGNOSTICS_POP()
569 #endif  // GCC8 or older.
570 
571 // Alias Test as ::testing::Test for GoogleTest compatibility.
572 namespace testing {
573 
574 using Test = ::pw::unit_test::internal::Test;
575 
576 }  // namespace testing
577