You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Conception/drake-master/common/test/text_logging_test.cc

183 lines
5.5 KiB

#include "drake/common/text_logging.h"
#include <string>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
// The BUILD.bazel rules must supply this flag. This test code is compiled and
// run twice -- once with spdlog, and once without.
#ifndef TEXT_LOGGING_TEST_SPDLOG
#error Missing a required definition to compile this test case.
#endif
// Check for the expected HAVE_SPDLOG value.
#if TEXT_LOGGING_TEST_SPDLOG
#ifndef HAVE_SPDLOG
#error Missing HAVE_SPDLOG.
#endif
#else
#ifdef HAVE_SPDLOG
#error Unwanted HAVE_SPDLOG.
#endif
#endif
namespace {
class Formattable {
public:
std::string to_string() const { return "OK"; }
};
} // namespace
DRAKE_FORMATTER_AS(, , Formattable, x, x.to_string())
namespace {
using drake::logging::kHaveSpdlog;
// Call each API function and macro to ensure that all of them compile.
// These should all compile and run both with and without spdlog.
GTEST_TEST(TextLoggingTest, SmokeTestFormattable) {
Formattable obj;
drake::log()->trace("drake::log()->trace test: {} {}", "OK", obj);
drake::log()->debug("drake::log()->debug test: {} {}", "OK", obj);
drake::log()->info("drake::log()->info test: {} {}", "OK", obj);
drake::log()->warn("drake::log()->warn test: {} {}", "OK", obj);
drake::log()->error("drake::log()->error test: {} {}", "OK", obj);
drake::log()->critical("drake::log()->critical test: {} {}", "OK", obj);
DRAKE_LOGGER_TRACE("DRAKE_LOGGER_TRACE macro test: {}, {}",
"OK", obj);
DRAKE_LOGGER_DEBUG("DRAKE_LOGGER_DEBUG macro test: {}, {}",
"OK", obj);
}
// Check that floating point values format sensibly. We'll just test fmt
// directly, since we know that spdlog uses it internally.
GTEST_TEST(TextLoggingTest, FloatingPoint) {
EXPECT_EQ(fmt::format("{:#}", 1.0), "1.0");
// This number is particularly challenging.
EXPECT_EQ(fmt::format("{}", 0.009), "0.009");
}
// Check that the constexpr bool is set correctly.
GTEST_TEST(TextLoggingTest, ConstantTest) {
#if TEXT_LOGGING_TEST_SPDLOG
EXPECT_TRUE(kHaveSpdlog);
#else
EXPECT_FALSE(kHaveSpdlog);
#endif
}
// Check that the "warn once" idiom compiles and doesn't crash at runtime.
GTEST_TEST(TextLoggingTest, WarnOnceTest) {
static const drake::logging::Warn log_once(
"The log_once happened as expected.");
}
// Abuse gtest internals to verify that logging actually prints when enabled,
// and that the default level is INFO.
GTEST_TEST(TextLoggingTest, CaptureOutputTest) {
testing::internal::CaptureStderr();
drake::log()->trace("bad sentinel");
drake::log()->debug("bad sentinel");
drake::log()->info("good sentinel");
std::string output = testing::internal::GetCapturedStderr();
#if TEXT_LOGGING_TEST_SPDLOG
EXPECT_TRUE(output.find("good sentinel") != std::string::npos);
EXPECT_TRUE(output.find("bad sentinel") == std::string::npos);
#else
EXPECT_EQ(output, "");
#endif
}
// Verify that DRAKE_LOGGER macros succeed in avoiding evaluation of their
// arguments.
GTEST_TEST(TextLoggingTest, DrakeMacrosDontEvaluateArguments) {
int tracearg = 0, debugarg = 0;
// Shouldn't increment argument whether the macro expanded or not, since
// logging is off.
#if TEXT_LOGGING_TEST_SPDLOG
drake::log()->set_level(spdlog::level::off);
#endif
DRAKE_LOGGER_TRACE("tracearg={}", ++tracearg);
DRAKE_LOGGER_DEBUG("debugarg={}", ++debugarg);
EXPECT_EQ(tracearg, 0);
EXPECT_EQ(debugarg, 0);
tracearg = 0;
debugarg = 0;
// Should increment arg only if the macro expanded.
#if TEXT_LOGGING_TEST_SPDLOG
drake::log()->set_level(spdlog::level::trace);
#endif
DRAKE_LOGGER_TRACE("tracearg={}", ++tracearg);
DRAKE_LOGGER_DEBUG("debugarg={}", ++debugarg);
#ifndef NDEBUG
EXPECT_EQ(tracearg, kHaveSpdlog ? 1 : 0);
EXPECT_EQ(debugarg, kHaveSpdlog ? 1 : 0);
#else
EXPECT_EQ(tracearg, 0);
EXPECT_EQ(debugarg, 0);
#endif
tracearg = 0;
debugarg = 0;
// Only DEBUG should increment arg since trace is not enabled.
#if TEXT_LOGGING_TEST_SPDLOG
drake::log()->set_level(spdlog::level::debug);
#endif
DRAKE_LOGGER_TRACE("tracearg={}", ++tracearg);
DRAKE_LOGGER_DEBUG("debugarg={}", ++debugarg);
#ifndef NDEBUG
EXPECT_EQ(tracearg, 0);
EXPECT_EQ(debugarg, kHaveSpdlog ? 1 : 0);
#else
EXPECT_EQ(tracearg, 0);
EXPECT_EQ(debugarg, 0);
#endif
tracearg = 0;
debugarg = 0;
}
GTEST_TEST(TextLoggingTest, SetLogLevel) {
using drake::logging::set_log_level;
#if TEXT_LOGGING_TEST_SPDLOG
EXPECT_THROW(set_log_level("bad"), std::runtime_error);
const std::vector<std::string> levels = {
"trace", "debug", "info", "warn", "err", "critical", "off"};
const std::string first_level = set_log_level("unchanged");
std::string prev_level = "off";
set_log_level(prev_level);
for (const std::string& level : levels) {
EXPECT_EQ(set_log_level(level), prev_level);
prev_level = level;
}
set_log_level(first_level);
#else
ASSERT_EQ(drake::logging::set_log_level("anything really"), "");
#endif
}
GTEST_TEST(TextLoggingTest, SetLogPattern) {
using drake::logging::set_log_pattern;
#if TEXT_LOGGING_TEST_SPDLOG
set_log_pattern("%v");
set_log_pattern("%+");
#else
set_log_pattern("anything really");
#endif
}
} // anon namespace
// To enable compiling without depending on @spdlog, we need to provide our own
// main routine. The default drake_cc_googletest_main depends on @spdlog.
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}