text: #include "aos/testing/test_logging.h"
  
  #include <cstdio>
  #include <vector>
  
  #include "absl/base/call_once.h"
  #include "aos/logging/implementations.h"
  #include "aos/stl_mutex/stl_mutex.h"
  #include "aos/thread_local.h"
  #include "gtest/gtest.h"
  
  using ::aos::logging::LogMessage;
  
  namespace aos {
  namespace testing {
  namespace {
  
  class TestLogImplementation : public logging::HandleMessageLogImplementation {
   public:
    const ::std::vector<LogMessage> &messages() { return messages_; }
  
    ::aos::monotonic_clock::time_point monotonic_now() const override {
      return ::aos::monotonic_clock::now();
    }
  
    std::string_view MyName() override { return "Name"; }
  
    // This class has to be a singleton so that everybody can get access to the
    // same instance to read out the messages etc.
    static std::shared_ptr<TestLogImplementation> GetInstance() {
      static std::shared_ptr<TestLogImplementation> instance =
          std::make_unique<TestLogImplementation>();
      return instance;
    }
  
    // Clears out all of the messages already recorded.
    void ClearMessages() {
      std::unique_lock<aos::stl_mutex> locker(messages_mutex_);
      messages_.clear();
    }
  
    // Prints out all of the messages (like when a test fails).
    void PrintAllMessages() {
      std::unique_lock<aos::stl_mutex> locker(messages_mutex_);
      for (auto it = messages_.begin(); it != messages_.end(); ++it) {
        logging::internal::PrintMessage(stdout, *it);
      }
    }
  
    void SetOutputFile(const char *filename) {
      if (strcmp("-", filename) != 0) {
        FILE *newfile = fopen(filename, "w");
  
        if (newfile) {
          output_file_ = newfile;
        }
      }
    }
  
    void PrintMessagesAsTheyComeIn() { print_as_messages_come_in_ = true; }
  
    // Don't call these from outside this class.
    ~TestLogImplementation() {
      if (output_file_ != stdout) {
        fclose(output_file_);
      }
    }
  
   private:
    virtual void HandleMessage(const LogMessage &message) override {
      std::unique_lock<aos::stl_mutex> locker(messages_mutex_);
      if (message.level == FATAL || print_as_messages_come_in_) {
        logging::internal::PrintMessage(output_file_, message);
      }
  
      messages_.push_back(message);
    }
  
    ::std::vector<LogMessage> messages_;
    bool print_as_messages_come_in_ = false;
    FILE *output_file_ = stdout;
    aos::stl_mutex messages_mutex_;
  };
  
  class MyTestEventListener : public ::testing::EmptyTestEventListener {
    virtual void OnTestStart(const ::testing::TestInfo & /*test_info*/) {
      TestLogImplementation::GetInstance()->ClearMessages();
    }
    virtual void OnTestEnd(const ::testing::TestInfo &test_info) {
      if (test_info.result()->Failed()) {
        printf("Test %s failed. Use '--print-logs' to see all log messages.\n",
               test_info.name());
      }
    }
  
    virtual void OnTestPartResult(const ::testing::TestPartResult &result) {
      if (result.failed()) {
        const char *failure_type = "unknown";
        switch (result.type()) {
          case ::testing::TestPartResult::Type::kNonFatalFailure:
            failure_type = "EXPECT";
            break;
          case ::testing::TestPartResult::Type::kFatalFailure:
            failure_type = "ASSERT";
            break;
          case ::testing::TestPartResult::Type::kSuccess:
          case ::testing::TestPartResult::Type::kSkip:
            break;
        }
        log_do(ERROR, "%s: %d: gtest %s failure\n%s\n", result.file_name(),
               result.line_number(), failure_type, result.message());
      }
    }
  };
  
  void *DoEnableTestLogging() {
    logging::SetImplementation(TestLogImplementation::GetInstance());
  
    ::testing::UnitTest::GetInstance()->listeners().Append(
        new MyTestEventListener());
  
    return nullptr;
  }
  
  static absl::once_flag enable_test_logging_once;
  
  }  // namespace
  
  void EnableTestLogging() {
    absl::call_once(enable_test_logging_once, DoEnableTestLogging);
  }
  
  void SetLogFileName(const char *filename) {
    TestLogImplementation::GetInstance()->SetOutputFile(filename);
  }
  
  void ForcePrintLogsDuringTests() {
    TestLogImplementation::GetInstance()->PrintMessagesAsTheyComeIn();
  }
  
  }  // namespace testing
  }  // namespace aos
  