blob: 15cb64bb4d3ba3737af11f7048c216f05db498e5 [file] [log] [blame]
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -05001#include "aos/testing/test_logging.h"
Brian Silvermanf665d692013-02-17 22:11:39 -08002
Stephan Pleinesad3085f2024-05-30 10:50:50 -07003#include <string.h>
4
5#include <algorithm>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07006#include <cstdio>
Stephan Pleinesad3085f2024-05-30 10:50:50 -07007#include <memory>
8#include <mutex>
9#include <string_view>
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050010#include <vector>
Brian Silvermanf665d692013-02-17 22:11:39 -080011
Austin Schuha0c41ba2020-09-10 22:59:14 -070012#include "absl/base/call_once.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070013#include "gtest/gtest.h"
14
John Park33858a32018-09-28 23:05:48 -070015#include "aos/logging/implementations.h"
Brian Silverman1463c092020-10-30 17:28:24 -070016#include "aos/stl_mutex/stl_mutex.h"
Stephan Pleinesad3085f2024-05-30 10:50:50 -070017#include "aos/time/time.h"
Brian Silvermanb3616972013-03-05 19:58:10 -080018
19using ::aos::logging::LogMessage;
brians343bc112013-02-10 01:53:46 +000020
Stephan Pleinesf63bde82024-01-13 15:59:33 -080021namespace aos::testing {
Brian Silvermanb3616972013-03-05 19:58:10 -080022namespace {
23
Brian Silvermanbe858a12014-04-30 17:37:28 -070024class TestLogImplementation : public logging::HandleMessageLogImplementation {
Brian Silvermanb3616972013-03-05 19:58:10 -080025 public:
26 const ::std::vector<LogMessage> &messages() { return messages_; }
27
Austin Schuh82c0c822019-05-27 19:55:20 -070028 ::aos::monotonic_clock::time_point monotonic_now() const override {
Austin Schuh82c0c822019-05-27 19:55:20 -070029 return ::aos::monotonic_clock::now();
30 }
31
Austin Schuhad9e5eb2021-11-19 20:33:55 -080032 std::string_view MyName() override { return "Name"; }
33
Brian Silvermanb3616972013-03-05 19:58:10 -080034 // This class has to be a singleton so that everybody can get access to the
35 // same instance to read out the messages etc.
Austin Schuha0c41ba2020-09-10 22:59:14 -070036 static std::shared_ptr<TestLogImplementation> GetInstance() {
37 static std::shared_ptr<TestLogImplementation> instance =
38 std::make_unique<TestLogImplementation>();
John Parkb5e47302020-01-08 19:58:18 -080039 return instance;
Brian Silvermanb3616972013-03-05 19:58:10 -080040 }
41
42 // Clears out all of the messages already recorded.
43 void ClearMessages() {
Brian Silverman1463c092020-10-30 17:28:24 -070044 std::unique_lock<aos::stl_mutex> locker(messages_mutex_);
Brian Silvermanb3616972013-03-05 19:58:10 -080045 messages_.clear();
46 }
47
48 // Prints out all of the messages (like when a test fails).
49 void PrintAllMessages() {
Brian Silverman1463c092020-10-30 17:28:24 -070050 std::unique_lock<aos::stl_mutex> locker(messages_mutex_);
Brian Silvermanb3616972013-03-05 19:58:10 -080051 for (auto it = messages_.begin(); it != messages_.end(); ++it) {
52 logging::internal::PrintMessage(stdout, *it);
53 }
54 }
55
Philipp Schradere41ed9d2015-03-15 22:57:13 +000056 void SetOutputFile(const char *filename) {
57 if (strcmp("-", filename) != 0) {
58 FILE *newfile = fopen(filename, "w");
59
60 if (newfile) {
61 output_file_ = newfile;
62 }
63 }
64 }
65
66 void PrintMessagesAsTheyComeIn() { print_as_messages_come_in_ = true; }
67
Austin Schuha0c41ba2020-09-10 22:59:14 -070068 // Don't call these from outside this class.
Philipp Schradere41ed9d2015-03-15 22:57:13 +000069 ~TestLogImplementation() {
70 if (output_file_ != stdout) {
71 fclose(output_file_);
72 }
73 }
Brian Silvermanb3616972013-03-05 19:58:10 -080074
Austin Schuha0c41ba2020-09-10 22:59:14 -070075 private:
Brian Silvermanbe858a12014-04-30 17:37:28 -070076 virtual void HandleMessage(const LogMessage &message) override {
Brian Silverman1463c092020-10-30 17:28:24 -070077 std::unique_lock<aos::stl_mutex> locker(messages_mutex_);
Philipp Schradere41ed9d2015-03-15 22:57:13 +000078 if (message.level == FATAL || print_as_messages_come_in_) {
79 logging::internal::PrintMessage(output_file_, message);
Brian Silvermanb3616972013-03-05 19:58:10 -080080 }
81
82 messages_.push_back(message);
83 }
84
85 ::std::vector<LogMessage> messages_;
Philipp Schradere41ed9d2015-03-15 22:57:13 +000086 bool print_as_messages_come_in_ = false;
87 FILE *output_file_ = stdout;
Brian Silverman1463c092020-10-30 17:28:24 -070088 aos::stl_mutex messages_mutex_;
Brian Silvermanb3616972013-03-05 19:58:10 -080089};
90
91class MyTestEventListener : public ::testing::EmptyTestEventListener {
Austin Schuh82c0c822019-05-27 19:55:20 -070092 virtual void OnTestStart(const ::testing::TestInfo & /*test_info*/) {
Brian Silvermanb3616972013-03-05 19:58:10 -080093 TestLogImplementation::GetInstance()->ClearMessages();
94 }
95 virtual void OnTestEnd(const ::testing::TestInfo &test_info) {
96 if (test_info.result()->Failed()) {
Philipp Schradere41ed9d2015-03-15 22:57:13 +000097 printf("Test %s failed. Use '--print-logs' to see all log messages.\n",
Brian Silvermanb3616972013-03-05 19:58:10 -080098 test_info.name());
Brian Silvermanb3616972013-03-05 19:58:10 -080099 }
100 }
Brian Silvermanb91a37d2013-03-09 17:54:30 -0800101
Austin Schuha0c41ba2020-09-10 22:59:14 -0700102 virtual void OnTestPartResult(const ::testing::TestPartResult &result) {
Brian Silvermanb91a37d2013-03-09 17:54:30 -0800103 if (result.failed()) {
104 const char *failure_type = "unknown";
105 switch (result.type()) {
106 case ::testing::TestPartResult::Type::kNonFatalFailure:
107 failure_type = "EXPECT";
108 break;
109 case ::testing::TestPartResult::Type::kFatalFailure:
110 failure_type = "ASSERT";
111 break;
112 case ::testing::TestPartResult::Type::kSuccess:
James Kuszmaulf4bf9fe2021-05-10 22:58:24 -0700113 case ::testing::TestPartResult::Type::kSkip:
Brian Silvermanb91a37d2013-03-09 17:54:30 -0800114 break;
115 }
Austin Schuha0c41ba2020-09-10 22:59:14 -0700116 log_do(ERROR, "%s: %d: gtest %s failure\n%s\n", result.file_name(),
117 result.line_number(), failure_type, result.message());
Brian Silvermanb91a37d2013-03-09 17:54:30 -0800118 }
119 }
Brian Silvermanb3616972013-03-05 19:58:10 -0800120};
121
122void *DoEnableTestLogging() {
Tyler Chatow4b471e12020-01-05 20:19:36 -0800123 logging::SetImplementation(TestLogImplementation::GetInstance());
Brian Silvermanb3616972013-03-05 19:58:10 -0800124
125 ::testing::UnitTest::GetInstance()->listeners().Append(
126 new MyTestEventListener());
127
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -0500128 return nullptr;
Brian Silvermanb3616972013-03-05 19:58:10 -0800129}
130
John Parkb5e47302020-01-08 19:58:18 -0800131static absl::once_flag enable_test_logging_once;
Brian Silvermanb3616972013-03-05 19:58:10 -0800132
133} // namespace
brians343bc112013-02-10 01:53:46 +0000134
Brian Silvermanb3616972013-03-05 19:58:10 -0800135void EnableTestLogging() {
John Parkb5e47302020-01-08 19:58:18 -0800136 absl::call_once(enable_test_logging_once, DoEnableTestLogging);
Brian Silvermanb3616972013-03-05 19:58:10 -0800137}
138
Austin Schuha0c41ba2020-09-10 22:59:14 -0700139void SetLogFileName(const char *filename) {
Philipp Schradere41ed9d2015-03-15 22:57:13 +0000140 TestLogImplementation::GetInstance()->SetOutputFile(filename);
141}
142
143void ForcePrintLogsDuringTests() {
144 TestLogImplementation::GetInstance()->PrintMessagesAsTheyComeIn();
145}
146
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800147} // namespace aos::testing