Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-09 09:29:07

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Utilities/Logger.hpp"
0012 #include "Acts/Utilities/ScopedTimer.hpp"
0013 
0014 #include <cerrno>
0015 #include <cstdlib>
0016 #include <exception>
0017 #include <memory>
0018 #include <sstream>
0019 #include <stdexcept>
0020 #include <string>
0021 
0022 #if defined(__unix__) || defined(__APPLE__)
0023 #include <sys/wait.h>
0024 #include <unistd.h>
0025 #endif
0026 
0027 namespace ActsTests {
0028 namespace {
0029 
0030 class ThrowingFilterPolicy final : public Acts::Logging::OutputFilterPolicy {
0031  public:
0032   bool doPrint(const Acts::Logging::Level& /*level*/) const override {
0033     // Use a non-standard exception to exercise the catch-all handler.
0034     throw 42;
0035   }
0036 
0037   Acts::Logging::Level level() const override { return Acts::Logging::INFO; }
0038 
0039   std::unique_ptr<Acts::Logging::OutputFilterPolicy> clone(
0040       Acts::Logging::Level /*level*/) const override {
0041     return std::make_unique<ThrowingFilterPolicy>();
0042   }
0043 };
0044 
0045 class ThrowingStreamBuffer final : public std::streambuf {
0046  public:
0047   int_type overflow(int_type /*character*/) override {
0048     throw std::runtime_error("timing output failed");
0049   }
0050 };
0051 
0052 // Cover the simple timer and both averaging timer output branches, including
0053 // destruction while an unrelated exception is already being unwound.
0054 void checkDestruction(const Acts::Logger& logger) {
0055   auto run = [&](bool unwind) {
0056     Acts::ScopedTimer timer("simple", logger);
0057     Acts::AveragingScopedTimer empty("empty", logger);
0058     Acts::AveragingScopedTimer populated("populated", logger);
0059     {
0060       auto sample = populated.sample();
0061     }
0062     if (unwind) {
0063       throw std::logic_error("original exception");
0064     }
0065   };
0066 
0067   BOOST_CHECK_NO_THROW(run(false));
0068   BOOST_CHECK_EXCEPTION(run(true), std::logic_error, [](const auto& error) {
0069     return std::string(error.what()) == "original exception";
0070   });
0071 }
0072 
0073 #if defined(__unix__) || defined(__APPLE__)
0074 // Each timer/branch runs in its own child so termination cannot mask failures
0075 // in another destructor or stop the test runner.
0076 void checkTermination(const Acts::Logger& logger) {
0077   for (int kind : {0, 1, 2}) {
0078     for (bool unwind : {false, true}) {
0079       const auto child = fork();
0080       BOOST_REQUIRE(child >= 0);
0081       if (child == 0) {
0082         std::set_terminate([] { std::_Exit(42); });
0083         try {
0084           auto failIfRequested = [&] {
0085             if (unwind) {
0086               throw std::logic_error("original exception");
0087             }
0088           };
0089           if (kind == 0) {
0090             Acts::ScopedTimer timer("simple", logger);
0091             failIfRequested();
0092           } else {
0093             Acts::AveragingScopedTimer timer("averaging", logger);
0094             if (kind == 2) {
0095               auto sample = timer.sample();
0096             }
0097             failIfRequested();
0098           }
0099         } catch (...) {
0100           std::_Exit(43);  // A swallowed logging failure during unwinding.
0101         }
0102         std::_Exit(44);  // A swallowed logging failure on normal destruction.
0103       }
0104       int status = 0;
0105       pid_t waited = 0;
0106       do {
0107         waited = waitpid(child, &status, 0);
0108       } while (waited == -1 && errno == EINTR);
0109       BOOST_REQUIRE_EQUAL(waited, child);
0110       BOOST_REQUIRE(WIFEXITED(status));
0111       BOOST_CHECK_EQUAL(WEXITSTATUS(status), 42);
0112     }
0113   }
0114 }
0115 #endif
0116 
0117 }  // namespace
0118 
0119 BOOST_AUTO_TEST_SUITE(ScopedTimerTests)
0120 
0121 BOOST_AUTO_TEST_CASE(LoggingOutput) {
0122   std::ostringstream output;
0123   auto logger = Acts::getDefaultLogger("timers", Acts::Logging::INFO, &output);
0124   {
0125     Acts::ScopedTimer timer("simple", *logger);
0126   }
0127   BOOST_CHECK(output.str().find("simple took ") != std::string::npos);
0128   BOOST_CHECK(output.str().find(" ms") != std::string::npos);
0129 
0130   output.str("");
0131   {
0132     Acts::AveragingScopedTimer timer("empty", *logger);
0133   }
0134   BOOST_CHECK(output.str().find("empty took 0 ms total (no samples)") !=
0135               std::string::npos);
0136 
0137   output.str("");
0138   {
0139     Acts::AveragingScopedTimer timer("populated", *logger);
0140     auto sample = timer.sample();
0141   }
0142   BOOST_CHECK(output.str().find("populated took ") != std::string::npos);
0143   BOOST_CHECK(output.str().find("us per sample (#1)") != std::string::npos);
0144 }
0145 
0146 #if defined(__unix__) || defined(__APPLE__)
0147 BOOST_AUTO_TEST_CASE(ThrowingFilterTerminates) {
0148   std::ostringstream output;
0149   Acts::Logger logger(
0150       std::make_unique<Acts::Logging::DefaultPrintPolicy>(&output),
0151       std::make_unique<ThrowingFilterPolicy>());
0152   BOOST_CHECK_THROW(logger.doPrint(Acts::Logging::INFO), int);
0153   checkTermination(logger);
0154   BOOST_CHECK(output.str().empty());
0155 }
0156 
0157 BOOST_AUTO_TEST_CASE(ThrowingOutputTerminates) {
0158   ThrowingStreamBuffer buffer;
0159   std::ostream output(&buffer);
0160   output.exceptions(std::ios::badbit | std::ios::failbit);
0161   auto logger = Acts::getDefaultLogger("timers", Acts::Logging::INFO, &output);
0162   BOOST_CHECK_THROW(logger->log(Acts::Logging::INFO, "test"), std::exception);
0163   output.clear();
0164   checkTermination(*logger);
0165 }
0166 
0167 #ifdef ACTS_ENABLE_LOG_FAILURE_THRESHOLD
0168 BOOST_AUTO_TEST_CASE(FailureThresholdTerminates) {
0169   Acts::Logging::ScopedFailureThreshold threshold(Acts::Logging::INFO);
0170   std::ostringstream output;
0171   auto logger = Acts::getDefaultLogger("timers", Acts::Logging::INFO, &output);
0172   checkTermination(*logger);
0173 }
0174 #endif
0175 #endif
0176 
0177 BOOST_AUTO_TEST_CASE(DisabledOutput) {
0178   checkDestruction(Acts::getDummyLogger());
0179 }
0180 
0181 BOOST_AUTO_TEST_SUITE_END()
0182 
0183 }  // namespace ActsTests