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