blob: d2b712bd4fb148c5bb92574fd4d6586b9194f446 [file]
/*
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#include "Logging.hpp"
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
using namespace kotlin;
using ::testing::_;
namespace {
std_support::span<char> FormatLogEntry(
std_support::span<char> buffer,
logging::Level level,
std::initializer_list<logging::Tag> tags,
int threadId,
kotlin::nanoseconds timestamp,
const char* format,
...) {
std_support::span<const logging::Tag> tagsSpan(std::data(tags), std::size(tags));
std::va_list args;
va_start(args, format);
auto result = logging::internal::FormatLogEntry(buffer, level, tagsSpan, threadId, timestamp, format, args);
va_end(args);
return result;
}
} // namespace
TEST(LoggingTest, FormatLogEntry_Debug_OneTag) {
std::array<char, 1024> buffer;
FormatLogEntry(buffer, logging::Level::kDebug, {logging::Tag::kRT}, 123, kotlin::nanoseconds(42'500'000'000), "Log #%d", 42);
EXPECT_THAT(buffer.data(), testing::StrEq("[DEBUG][rt][tid#123][42.500s] Log #42\n"));
}
TEST(LoggingTest, FormatLogEntry_Debug_TwoTags) {
std::array<char, 1024> buffer;
FormatLogEntry(buffer, logging::Level::kDebug, {logging::Tag::kRT, logging::Tag::kGC}, 123, kotlin::nanoseconds(42'500'000'000), "Log #%d", 42);
EXPECT_THAT(buffer.data(), testing::StrEq("[DEBUG][rt,gc][tid#123][42.500s] Log #42\n"));
}
TEST(LoggingTest, FormatLogEntry_Info_OneTag) {
std::array<char, 1024> buffer;
FormatLogEntry(buffer, logging::Level::kInfo, {logging::Tag::kRT}, 123, kotlin::nanoseconds(42'500'000'000), "Log #%d", 42);
EXPECT_THAT(buffer.data(), testing::StrEq("[INFO][rt][tid#123][42.500s] Log #42\n"));
}
TEST(LoggingTest, FormatLogEntry_Info_TwoTags) {
std::array<char, 1024> buffer;
FormatLogEntry(buffer, logging::Level::kInfo, {logging::Tag::kRT, logging::Tag::kGC}, 123, kotlin::nanoseconds(42'500'000'000), "Log #%d", 42);
EXPECT_THAT(buffer.data(), testing::StrEq("[INFO][rt,gc][tid#123][42.500s] Log #42\n"));
}
TEST(LoggingTest, FormatLogEntry_Warning_OneTag) {
std::array<char, 1024> buffer;
FormatLogEntry(buffer, logging::Level::kWarning, {logging::Tag::kRT}, 123, kotlin::nanoseconds(42'500'000'000), "Log #%d", 42);
EXPECT_THAT(buffer.data(), testing::StrEq("[WARNING][rt][tid#123][42.500s] Log #42\n"));
}
TEST(LoggingTest, FormatLogEntry_Warning_TwoTags) {
std::array<char, 1024> buffer;
FormatLogEntry(buffer, logging::Level::kWarning, {logging::Tag::kRT, logging::Tag::kGC}, 123, kotlin::nanoseconds(42'500'000'000), "Log #%d", 42);
EXPECT_THAT(buffer.data(), testing::StrEq("[WARNING][rt,gc][tid#123][42.500s] Log #42\n"));
}
TEST(LoggingTest, FormatLogEntry_Error_OneTag) {
std::array<char, 1024> buffer;
FormatLogEntry(buffer, logging::Level::kError, {logging::Tag::kRT}, 123, kotlin::nanoseconds(42'500'000'000), "Log #%d", 42);
EXPECT_THAT(buffer.data(), testing::StrEq("[ERROR][rt][tid#123][42.500s] Log #42\n"));
}
TEST(LoggingTest, FormatLogEntry_Error_TwoTags) {
std::array<char, 1024> buffer;
FormatLogEntry(buffer, logging::Level::kError, {logging::Tag::kRT, logging::Tag::kGC}, 123, kotlin::nanoseconds(42'500'000'000), "Log #%d", 42);
EXPECT_THAT(buffer.data(), testing::StrEq("[ERROR][rt,gc][tid#123][42.500s] Log #42\n"));
}
TEST(LoggingTest, FormatLogEntry_Overflow) {
std::array<char, 20> buffer;
FormatLogEntry(buffer, logging::Level::kError, {logging::Tag::kRT, logging::Tag::kGC}, 123, kotlin::nanoseconds(42'500'000'000), "Log #%d", 42);
// Only 18 characters are used for the log string contents, another 2 are \n and \0.
EXPECT_THAT(buffer.data(), testing::StrEq("[ERROR][rt,gc][tid\n"));
}
TEST(LoggingDeathTest, StderrLogger) {
auto logger = logging::internal::CreateStderrLogger();
EXPECT_DEATH(
{
logger->Log(logging::Level::kInfo, {}, "Message for the log");
std::abort();
},
"Message for the log");
}
namespace {
class LogFilter {
public:
explicit LogFilter(std::map<logging::Tag, logging::Level> tagToLevel) {
logLevels_.resize(static_cast<size_t>(logging::Tag::kEnumSize));
for (auto [tag, level] : tagToLevel) {
logLevels_[static_cast<size_t>(tag)] = static_cast<int32_t>(level);
}
}
bool Empty() const {
return std::all_of(logLevels_.begin(), logLevels_.end(), [](int32_t levelOrd){
return static_cast<logging::Level>(levelOrd) == logging::Level::kNone;
});
}
bool Enabled(logging::Level level, std::initializer_list<logging::Tag> tags) const {
std_support::span<const logging::Tag> tagsSpan(std::data(tags), std::size(tags));
return logging::internal::enabled(level, tagsSpan, logLevels_.data());
}
private:
std::vector<int32_t> logLevels_;
};
}
TEST(LoggingTest, LogFilter_EnableOne) {
LogFilter filter({{logging::Tag::kRT, logging::Level::kInfo}});
EXPECT_FALSE(filter.Empty());
EXPECT_FALSE(filter.Enabled(logging::Level::kDebug, {logging::Tag::kRT}));
EXPECT_TRUE(filter.Enabled(logging::Level::kInfo, {logging::Tag::kRT}));
EXPECT_TRUE(filter.Enabled(logging::Level::kWarning, {logging::Tag::kRT}));
EXPECT_TRUE(filter.Enabled(logging::Level::kError, {logging::Tag::kRT}));
EXPECT_FALSE(filter.Enabled(logging::Level::kDebug, {logging::Tag::kGC}));
EXPECT_FALSE(filter.Enabled(logging::Level::kInfo, {logging::Tag::kGC}));
EXPECT_FALSE(filter.Enabled(logging::Level::kWarning, {logging::Tag::kGC}));
EXPECT_FALSE(filter.Enabled(logging::Level::kError, {logging::Tag::kGC}));
EXPECT_FALSE(filter.Enabled(logging::Level::kDebug, {logging::Tag::kRT, logging::Tag::kGC}));
EXPECT_TRUE(filter.Enabled(logging::Level::kInfo, {logging::Tag::kRT, logging::Tag::kGC}));
EXPECT_TRUE(filter.Enabled(logging::Level::kWarning, {logging::Tag::kRT, logging::Tag::kGC}));
EXPECT_TRUE(filter.Enabled(logging::Level::kError, {logging::Tag::kRT, logging::Tag::kGC}));
EXPECT_FALSE(filter.Enabled(logging::Level::kDebug, {logging::Tag::kGC, logging::Tag::kRT}));
EXPECT_TRUE(filter.Enabled(logging::Level::kInfo, {logging::Tag::kGC, logging::Tag::kRT}));
EXPECT_TRUE(filter.Enabled(logging::Level::kWarning, {logging::Tag::kGC, logging::Tag::kRT}));
EXPECT_TRUE(filter.Enabled(logging::Level::kError, {logging::Tag::kGC, logging::Tag::kRT}));
}
TEST(LoggingTest, LogFilter_EnableTwo) {
LogFilter filter({{logging::Tag::kRT, logging::Level::kInfo}, {logging::Tag::kGC, logging::Level::kWarning}});
EXPECT_FALSE(filter.Empty());
EXPECT_FALSE(filter.Enabled(logging::Level::kDebug, {logging::Tag::kRT}));
EXPECT_TRUE(filter.Enabled(logging::Level::kInfo, {logging::Tag::kRT}));
EXPECT_TRUE(filter.Enabled(logging::Level::kWarning, {logging::Tag::kRT}));
EXPECT_TRUE(filter.Enabled(logging::Level::kError, {logging::Tag::kRT}));
EXPECT_FALSE(filter.Enabled(logging::Level::kDebug, {logging::Tag::kGC}));
EXPECT_FALSE(filter.Enabled(logging::Level::kInfo, {logging::Tag::kGC}));
EXPECT_TRUE(filter.Enabled(logging::Level::kWarning, {logging::Tag::kGC}));
EXPECT_TRUE(filter.Enabled(logging::Level::kError, {logging::Tag::kGC}));
EXPECT_FALSE(filter.Enabled(logging::Level::kDebug, {logging::Tag::kRT, logging::Tag::kGC}));
EXPECT_TRUE(filter.Enabled(logging::Level::kInfo, {logging::Tag::kRT, logging::Tag::kGC}));
EXPECT_TRUE(filter.Enabled(logging::Level::kWarning, {logging::Tag::kRT, logging::Tag::kGC}));
EXPECT_TRUE(filter.Enabled(logging::Level::kError, {logging::Tag::kRT, logging::Tag::kGC}));
EXPECT_FALSE(filter.Enabled(logging::Level::kDebug, {logging::Tag::kGC, logging::Tag::kRT}));
EXPECT_TRUE(filter.Enabled(logging::Level::kInfo, {logging::Tag::kGC, logging::Tag::kRT}));
EXPECT_TRUE(filter.Enabled(logging::Level::kWarning, {logging::Tag::kGC, logging::Tag::kRT}));
EXPECT_TRUE(filter.Enabled(logging::Level::kError, {logging::Tag::kGC, logging::Tag::kRT}));
}