#include "logtest.h"
#include <regex>
#include <sstream>
#include <catch2/matchers/catch_matchers_string.hpp>
#define TEST(name) TEST_CASE("log-formatter: " name, "[log-formatter]")
static inline void REGCHECK (const string& s, const string& re) {
WARN("checking '" << s << "' with regex '" << re <<"'");
CHECK(std::regex_search(std::string(s.c_str()), std::regex(std::string(re.c_str()))));
}
TEST("set_formatter") {
Ctx c;
string str;
set_logger([&str](const string& s, const Info&) {
str = s;
});
SECTION("callback") {
set_formatter([](std::string&, const Info&) -> string {
return "jopa";
});
}
SECTION("object") {
struct Formatter : IFormatter {
string format (std::string&, const Info&) const override {
return "jopa";
}
};
set_formatter(new Formatter());
}
panda_log_alert("hello");
REQUIRE(str == "jopa");
}
TEST("set formatter string") {
Ctx c;
Module panda_log_module("epta");
SECTION("level") {
set_formatter("LEVEL=%L");
panda_log_alert();
CHECK(c.fstr == "LEVEL=alert");
}
SECTION("module") {
SECTION("default") {
set_formatter("MODULE=%M");
panda_log_alert();
CHECK(c.fstr == "MODULE=epta");
}
SECTION("strip") {
set_formatter(" MOD=%4.1M ");
panda_log_alert(::panda_log_module, "");
CHECK(c.fstr == " ");
}
}
SECTION("function") {
set_formatter("FUNC=%F");
panda_log_alert();
CHECK_THAT(c.fstr, Catch::Matchers::StartsWith("FUNC=CATCH2_INTERNAL_TEST_"));
}
SECTION("file") {
SECTION("short name") {
set_formatter("FILE=%f");
panda_log_alert();
CHECK(c.fstr == "FILE=formatter.cc");
}
SECTION("full name") {
set_formatter("FILE=%1f");
panda_log_alert();
REGCHECK(c.fstr, "FILE=.*tests[\\/]log[\\/]formatter.cc");
}
}
SECTION("line") {
set_formatter("LINE=%l");
panda_log_alert();
CHECK(c.fstr == "LINE=83");
}
SECTION("message") {
set_formatter("MSG=%m");
panda_log_alert("mymsg");
CHECK(c.fstr == "MSG=mymsg");
panda_log_alert("mymsg1\nmymsg2");
CHECK(c.fstr == "MSG=mymsg1\nmymsg2");
}
SECTION("current time") {
string pat = "TIME=";
string re;
SECTION("Y4 date (dashed)") {
re = "\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}";
SECTION("low-res") {
pat += "%t";
}
SECTION("hi-res") {
pat += "%.1t";
re += "\\.\\d{1}";
}
}
SECTION("Y4 date(slashed)") {
re = "\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}:\\d{2}";
SECTION("low-res") {
pat += "%3t";
WARN(pat);
}
}
SECTION("Y2 date") {
re = "\\d{2}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}";
SECTION("low-res") {
pat += "%1t";
}
SECTION("hi-res") {
pat += "%1.2t";
re += "\\.\\d{2}";
}
}
SECTION("hms") {
re = "\\d{2}:\\d{2}:\\d{2}";
SECTION("low-res") {
pat += "%2t";
}
SECTION("hi-res") {
pat += "%2.3t";
re += "\\.\\d{3}";
}
}
SECTION("unix ts") {
re = "\\d+";
SECTION("low-res") {
pat += "%3t";
}
SECTION("hi-res") {
pat += "%3.9t";
re += "\\.\\d{9}";
}
}
set_formatter(pat);
panda_log_alert();
REGCHECK(c.fstr, re + '$');
}
SECTION("thread id") {
set_formatter("THREAD=%T");
panda_log_alert();
REGCHECK(c.fstr, "THREAD=\\d+");
}
SECTION("process id") {
set_formatter("PID=%p");
panda_log_alert();
REGCHECK(c.fstr, "PID=\\d+");
}
SECTION("process title") {
set_formatter("TITLE=%P");
set_program_name("Void Linux");
panda_log_alert();
REGCHECK(c.fstr, "TITLE=Void Linux");
}
SECTION("multiline message") {
set_formatter("MSG=%1m!");
panda_log_alert("msg1");
CHECK(c.fstr == "MSG=msg1!");
panda_log_alert("msg1\nmsg2");
CHECK(c.fstr == "MSG=msg1!\nMSG=msg2!");
panda_log_alert("msg1\nmsg2\n");
CHECK(c.fstr == "MSG=msg1!\nMSG=msg2!\nMSG=!");
panda_log_alert("\nmsg1\nmsg2");
CHECK(c.fstr == "MSG=!\nMSG=msg1!\nMSG=msg2!");
panda_log_alert("\n");
CHECK(c.fstr == "MSG=!\nMSG=!");
}
}
TEST_CASE("formatter synopsis", "[.]") {
struct Formatter : IFormatter {
string format (std::string& msg, const Info& info) const override {
std::stringstream ss;
ss << info.file << ":" << to_string(info.line) << "\t" << msg << std::endl;
auto ret = ss.str();
return string(ret.data(), ret.size());
}
};
set_formatter(new Formatter());
}