• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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 #include "pw_unit_test/internal/framework.h"
16 
17 #include <algorithm>
18 #include <cstring>
19 
20 #include "pw_assert/check.h"
21 
22 namespace pw {
23 namespace unit_test {
24 
RegisterEventHandler(EventHandler * event_handler)25 void RegisterEventHandler(EventHandler* event_handler) {
26   internal::Framework::Get().RegisterEventHandler(event_handler);
27 }
28 
29 namespace internal {
30 
31 // Singleton instance of the unit test framework class.
32 Framework Framework::framework_;
33 
34 // Linked list of all test cases in the test executable. This is static as it is
35 // populated using static initialization.
36 TestInfo* Framework::tests_ = nullptr;
37 
RegisterTest(TestInfo * new_test) const38 void Framework::RegisterTest(TestInfo* new_test) const {
39   // If the test list is empty, set new_test as the first test.
40   if (tests_ == nullptr) {
41     tests_ = new_test;
42     return;
43   }
44 
45   // Append the test case to the end of the test list.
46   TestInfo* info = tests_;
47   for (; info->next() != nullptr; info = info->next()) {
48   }
49   info->set_next(new_test);
50 }
51 
RunAllTests()52 int Framework::RunAllTests() {
53   exit_status_ = 0;
54   run_tests_summary_.passed_tests = 0;
55   run_tests_summary_.failed_tests = 0;
56   run_tests_summary_.skipped_tests = 0;
57   run_tests_summary_.disabled_tests = 0;
58 
59   if (event_handler_ != nullptr) {
60     event_handler_->RunAllTestsStart();
61   }
62   for (const TestInfo* test = tests_; test != nullptr; test = test->next()) {
63     if (ShouldRunTest(*test)) {
64       test->run();
65     } else if (!test->enabled()) {
66       run_tests_summary_.disabled_tests++;
67 
68       if (event_handler_ != nullptr) {
69         event_handler_->TestCaseDisabled(test->test_case());
70       }
71     } else {
72       run_tests_summary_.skipped_tests++;
73     }
74   }
75   if (event_handler_ != nullptr) {
76     event_handler_->RunAllTestsEnd(run_tests_summary_);
77   }
78   return exit_status_;
79 }
80 
StartTest(const TestInfo & test)81 void Framework::StartTest(const TestInfo& test) {
82   current_test_ = &test;
83   current_result_ = TestResult::kSuccess;
84 
85   if (event_handler_ != nullptr) {
86     event_handler_->TestCaseStart(test.test_case());
87   }
88 }
89 
EndCurrentTest()90 void Framework::EndCurrentTest() {
91   switch (current_result_) {
92     case TestResult::kSuccess:
93       run_tests_summary_.passed_tests++;
94       break;
95     case TestResult::kFailure:
96       run_tests_summary_.failed_tests++;
97       break;
98     case TestResult::kSkipped:
99       run_tests_summary_.skipped_tests++;
100       break;
101   }
102 
103   if (event_handler_ != nullptr) {
104     event_handler_->TestCaseEnd(current_test_->test_case(), current_result_);
105   }
106 
107   current_test_ = nullptr;
108 }
109 
CurrentTestSkip(int line)110 void Framework::CurrentTestSkip(int line) {
111   if (current_result_ == TestResult::kSuccess) {
112     current_result_ = TestResult::kSkipped;
113   }
114   return CurrentTestExpectSimple(
115       "(test skipped)", "(test skipped)", line, true);
116 }
117 
CurrentTestExpectSimple(const char * expression,const char * evaluated_expression,int line,bool success)118 void Framework::CurrentTestExpectSimple(const char* expression,
119                                         const char* evaluated_expression,
120                                         int line,
121                                         bool success) {
122   PW_CHECK_NOTNULL(
123       current_test_,
124       "EXPECT/ASSERT was called when no test was running! EXPECT/ASSERT cannot "
125       "be used from static constructors/destructors or before or after "
126       "RUN_ALL_TESTS().");
127 
128   if (!success) {
129     current_result_ = TestResult::kFailure;
130     exit_status_ = 1;
131   }
132 
133   if (event_handler_ == nullptr) {
134     return;
135   }
136 
137   TestExpectation expectation = {
138       .expression = expression,
139       .evaluated_expression = evaluated_expression,
140       .line_number = line,
141       .success = success,
142   };
143 
144   event_handler_->TestCaseExpect(current_test_->test_case(), expectation);
145 }
146 
ShouldRunTest(const TestInfo & test_info) const147 bool Framework::ShouldRunTest(const TestInfo& test_info) const {
148 #if PW_CXX_STANDARD_IS_SUPPORTED(17)
149   // Test suite filtering is only supported if using C++17.
150   if (!test_suites_to_run_.empty()) {
151     std::string_view test_suite(test_info.test_case().suite_name);
152 
153     bool suite_matches =
154         std::any_of(test_suites_to_run_.begin(),
155                     test_suites_to_run_.end(),
156                     [&](auto& name) { return test_suite == name; });
157 
158     if (!suite_matches) {
159       return false;
160     }
161   }
162 #endif  // PW_CXX_STANDARD_IS_SUPPORTED(17)
163 
164   return test_info.enabled();
165 }
166 
enabled() const167 bool TestInfo::enabled() const {
168   constexpr size_t kStringSize = sizeof("DISABLED_") - 1;
169   return std::strncmp("DISABLED_", test_case().test_name, kStringSize) != 0 &&
170          std::strncmp("DISABLED_", test_case().suite_name, kStringSize) != 0;
171 }
172 
173 }  // namespace internal
174 }  // namespace unit_test
175 }  // namespace pw
176