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