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