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 #include "pw_unit_test/unit_test_service.h"
16
17 #include "pw_containers/vector.h"
18 #include "pw_log/log.h"
19 #include "pw_protobuf/decoder.h"
20 #include "pw_unit_test/framework.h"
21
22 namespace pw::unit_test {
23
Run(ConstByteSpan request,RawServerWriter & writer)24 void UnitTestService::Run(ConstByteSpan request, RawServerWriter& writer) {
25 writer_ = std::move(writer);
26 verbose_ = false;
27
28 // List of test suite names to run. The string views in this vector point to
29 // data in the raw protobuf request message, so it is only valid for the
30 // duration of this function.
31 pw::Vector<std::string_view, 16> suites_to_run;
32
33 protobuf::Decoder decoder(request);
34
35 Status status;
36 while ((status = decoder.Next()).ok()) {
37 switch (static_cast<TestRunRequest::Fields>(decoder.FieldNumber())) {
38 case TestRunRequest::Fields::REPORT_PASSED_EXPECTATIONS:
39 decoder.ReadBool(&verbose_)
40 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
41 break;
42
43 case TestRunRequest::Fields::TEST_SUITE: {
44 std::string_view suite_name;
45 if (!decoder.ReadString(&suite_name).ok()) {
46 break;
47 }
48
49 if (!suites_to_run.full()) {
50 suites_to_run.push_back(suite_name);
51 } else {
52 PW_LOG_ERROR("Maximum of %u test suite filters supported",
53 static_cast<unsigned>(suites_to_run.max_size()));
54 writer_.Finish(Status::InvalidArgument())
55 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
56 return;
57 }
58
59 break;
60 }
61 }
62 }
63
64 if (status != Status::OutOfRange()) {
65 writer_.Finish(status)
66 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
67 return;
68 }
69
70 PW_LOG_INFO("Starting unit test run");
71
72 RegisterEventHandler(&handler_);
73 SetTestSuitesToRun(suites_to_run);
74 PW_LOG_DEBUG("%u test suite filters applied",
75 static_cast<unsigned>(suites_to_run.size()));
76
77 RUN_ALL_TESTS();
78
79 RegisterEventHandler(nullptr);
80 SetTestSuitesToRun({});
81
82 PW_LOG_INFO("Unit test run complete");
83
84 writer_.Finish().IgnoreError(); // TODO(pwbug/387): Handle Status properly
85 }
86
WriteTestRunStart()87 void UnitTestService::WriteTestRunStart() {
88 // Write out the key for the start field (even though the message is empty).
89 WriteEvent(
90 [&](Event::StreamEncoder& event) { event.GetTestRunStartEncoder(); });
91 }
92
WriteTestRunEnd(const RunTestsSummary & summary)93 void UnitTestService::WriteTestRunEnd(const RunTestsSummary& summary) {
94 WriteEvent([&](Event::StreamEncoder& event) {
95 TestRunEnd::StreamEncoder test_run_end = event.GetTestRunEndEncoder();
96 test_run_end.WritePassed(summary.passed_tests)
97 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
98 test_run_end.WriteFailed(summary.failed_tests)
99 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
100 test_run_end.WriteSkipped(summary.skipped_tests)
101 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
102 test_run_end.WriteDisabled(summary.disabled_tests)
103 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
104 });
105 }
106
WriteTestCaseStart(const TestCase & test_case)107 void UnitTestService::WriteTestCaseStart(const TestCase& test_case) {
108 WriteEvent([&](Event::StreamEncoder& event) {
109 TestCaseDescriptor::StreamEncoder descriptor =
110 event.GetTestCaseStartEncoder();
111 descriptor.WriteSuiteName(test_case.suite_name)
112 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
113 descriptor.WriteTestName(test_case.test_name)
114 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
115 descriptor.WriteFileName(test_case.file_name)
116 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
117 });
118 }
119
WriteTestCaseEnd(TestResult result)120 void UnitTestService::WriteTestCaseEnd(TestResult result) {
121 WriteEvent([&](Event::StreamEncoder& event) {
122 event.WriteTestCaseEnd(static_cast<TestCaseResult>(result))
123 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
124 });
125 }
126
WriteTestCaseDisabled(const TestCase & test_case)127 void UnitTestService::WriteTestCaseDisabled(const TestCase& test_case) {
128 WriteEvent([&](Event::StreamEncoder& event) {
129 TestCaseDescriptor::StreamEncoder descriptor =
130 event.GetTestCaseDisabledEncoder();
131 descriptor.WriteSuiteName(test_case.suite_name)
132 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
133 descriptor.WriteTestName(test_case.test_name)
134 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
135 descriptor.WriteFileName(test_case.file_name)
136 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
137 });
138 }
139
WriteTestCaseExpectation(const TestExpectation & expectation)140 void UnitTestService::WriteTestCaseExpectation(
141 const TestExpectation& expectation) {
142 if (!verbose_ && expectation.success) {
143 return;
144 }
145
146 WriteEvent([&](Event::StreamEncoder& event) {
147 TestCaseExpectation::StreamEncoder test_case_expectation =
148 event.GetTestCaseExpectationEncoder();
149 test_case_expectation.WriteExpression(expectation.expression)
150 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
151 test_case_expectation
152 .WriteEvaluatedExpression(expectation.evaluated_expression)
153 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
154 test_case_expectation.WriteLineNumber(expectation.line_number)
155 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
156 test_case_expectation.WriteSuccess(expectation.success)
157 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
158 });
159 }
160
161 } // namespace pw::unit_test
162