xref: /aosp_15_r20/external/pigweed/pw_unit_test/public/pw_unit_test/test_record_event_handler.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 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 #pragma once
15 
16 #include <string_view>
17 
18 #include "pw_json/builder.h"
19 #include "pw_unit_test/event_handler.h"
20 #include "pw_unit_test/internal/test_record_trie.h"
21 
22 namespace pw::unit_test {
23 namespace json_impl {
24 
25 inline constexpr const char* kSkipMacroIndicator = "(test skipped)";
26 
27 }  // namespace json_impl
28 
29 /// Predefined event handler implementation that outputs a test record (or
30 /// summary) in Chromium JSON Test Results Format. To use it, register the event
31 /// handler, call the ``RUN_ALL_TESTS`` macro, then extract the test record json
32 /// as a string using the ``GetTestRecordJsonString`` method. If you only want
33 /// to extract the failing tests, set the `failing_results_only` parameter to
34 /// true. See ``pw::unit_test::EventHandler`` for explanations of emitted
35 /// events.
36 /// @see
37 /// https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/testing/json_test_results_format.md
38 /// @warning This event handler uses dynamic allocation
39 /// (`new`/`delete`/`std::string`) to generate the test record json.
40 class TestRecordEventHandler : public EventHandler {
41  public:
42   /// Constructor for the event handler. Have to seconds_since_epoch since
43   /// calling std::time(nullptr) in pigweed is not supported.
44   ///
45   /// @param[in] seconds_since_epoch Seconds since epoch. Used in the test
46   /// record as the seconds since epoch for the start of the test run.
TestRecordEventHandler(int64_t seconds_since_epoch)47   TestRecordEventHandler(int64_t seconds_since_epoch)
48       : seconds_since_epoch_(seconds_since_epoch) {}
49 
50   /// Called when a test case completes. Record the test case result in the test
51   /// record trie.
52   ///
53   /// @param[in] test_case Test case that ended.
54   ///
55   /// @param[in] result Result of the test case.
TestCaseEnd(const TestCase & test_case,TestResult result)56   void TestCaseEnd(const TestCase& test_case, TestResult result) override {
57     test_record_trie_.AddTestResult(test_case, result);
58   }
59 
60   /// Called after all tests are run. Save the run tests summary for later use.
61   ///
62   /// @param[in] summary A test run summary. Contains counts of each test result
63   /// type.
RunAllTestsEnd(const RunTestsSummary & summary)64   void RunAllTestsEnd(const RunTestsSummary& summary) override {
65     run_tests_summary_ = summary;
66   }
67 
68   /// Called after each expect/assert statement within a test case with the
69   /// result of the expectation.
70   ///
71   /// We usually expect all tests to PASS. However, if the
72   /// GTEST_SKIP macro is used, the test is expected to be skipped and the
73   /// expectation expression is replaced with "(test skipped)"
74   ///
75   /// @param[in] test_case Test case that the expect statement lies in.
76   ///
77   /// @param[in] expectation Current expectation being checked for the test
78   /// case.
TestCaseExpect(const TestCase & test_case,const TestExpectation & expectation)79   void TestCaseExpect(const TestCase& test_case,
80                       const TestExpectation& expectation) override {
81     // TODO: b/329688428 - Check for test skips directly rather than doing a
82     // string comparison
83     if (std::string_view(json_impl::kSkipMacroIndicator) ==
84         expectation.expression) {
85       test_record_trie_.AddTestResultExpectation(test_case,
86                                                  TestResult::kSkipped);
87     }
88   }
89 
90   /// Converts the test record trie into a json string and returns it.
91   ///
92   /// @param[in] max_json_buffer_size The max size (in bytes) of the buffer to
93   /// allocate for the json string.
94   ///
95   /// @param[in] failing_results_only If true, the outputted test record will
96   /// only contain the failing tests.
97   ///
98   /// @returns The test record json as a string.
99   std::string GetTestRecordJsonString(size_t max_json_buffer_size,
100                                       bool failing_results_only = false) {
101     return test_record_trie_.GetTestRecordJsonString(run_tests_summary_,
102                                                      seconds_since_epoch_,
103                                                      max_json_buffer_size,
104                                                      failing_results_only);
105   }
106 
RunAllTestsStart()107   void RunAllTestsStart() override {}
TestProgramStart(const ProgramSummary &)108   void TestProgramStart(const ProgramSummary&) override {}
EnvironmentsSetUpEnd()109   void EnvironmentsSetUpEnd() override {}
TestSuiteStart(const TestSuite &)110   void TestSuiteStart(const TestSuite&) override {}
TestSuiteEnd(const TestSuite &)111   void TestSuiteEnd(const TestSuite&) override {}
EnvironmentsTearDownEnd()112   void EnvironmentsTearDownEnd() override {}
TestProgramEnd(const ProgramSummary &)113   void TestProgramEnd(const ProgramSummary&) override {}
TestCaseStart(const TestCase &)114   void TestCaseStart(const TestCase&) override {}
TestCaseDisabled(const TestCase &)115   void TestCaseDisabled(const TestCase&) override {}
116 
117  private:
118   // Seconds since epoch from the start of the test run.
119   int64_t seconds_since_epoch_;
120 
121   // A summary of the test run. Set once RunAllTestsEnd is called and used when
122   // the consumer of this event handler wants to generate the test record json
123   // string.
124   RunTestsSummary run_tests_summary_;
125 
126   // The entrypoint for interacting with the test record trie.
127   json_impl::TestRecordTrie test_record_trie_;
128 };
129 
130 }  // namespace pw::unit_test
131