File indexing completed on 2026-11-09 09:29:07
0001
0002
0003
0004
0005
0006
0007
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& ) const override {
0033
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 ) 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 ) override {
0048 throw std::runtime_error("timing output failed");
0049 }
0050 };
0051
0052
0053
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
0075
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);
0101 }
0102 std::_Exit(44);
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 }
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 }