• 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)36 void Framework::RegisterTest(TestInfo* new_test) {
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   }
96 
97   if (event_handler_ != nullptr) {
98     event_handler_->TestCaseEnd(current_test_->test_case(), current_result_);
99   }
100 
101   current_test_ = nullptr;
102 }
103 
ExpectationResult(const char * expression,const char * evaluated_expression,int line,bool success)104 void Framework::ExpectationResult(const char* expression,
105                                   const char* evaluated_expression,
106                                   int line,
107                                   bool success) {
108   if (!success) {
109     current_result_ = TestResult::kFailure;
110     exit_status_ = 1;
111   }
112 
113   if (event_handler_ == nullptr) {
114     return;
115   }
116 
117   TestExpectation expectation = {
118       .expression = expression,
119       .evaluated_expression = evaluated_expression,
120       .line_number = line,
121       .success = success,
122   };
123 
124   event_handler_->TestCaseExpect(current_test_->test_case(), expectation);
125 }
126 
ShouldRunTest(const TestInfo & test_info)127 bool Framework::ShouldRunTest(const TestInfo& test_info) {
128 #if PW_CXX_STANDARD_IS_SUPPORTED(17)
129   // Test suite filtering is only supported if using C++17.
130   if (!test_suites_to_run_.empty()) {
131     std::string_view test_suite(test_info.test_case().suite_name);
132 
133     bool suite_matches =
134         std::any_of(test_suites_to_run_.begin(),
135                     test_suites_to_run_.end(),
136                     [&](auto& name) { return test_suite == name; });
137 
138     if (!suite_matches) {
139       return false;
140     }
141   }
142 #endif  // PW_CXX_STANDARD_IS_SUPPORTED(17)
143 
144   return test_info.enabled();
145 }
146 
enabled() const147 bool TestInfo::enabled() const {
148   constexpr size_t kStringSize = sizeof("DISABLED_") - 1;
149   return std::strncmp("DISABLED_", test_case().test_name, kStringSize) != 0 &&
150          std::strncmp("DISABLED_", test_case().suite_name, kStringSize) != 0;
151 }
152 
153 }  // namespace internal
154 }  // namespace unit_test
155 }  // namespace pw
156