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