// // pattern_layout_test.cxx // logger_test // // Created by Sam Jaffe on 4/13/19. // #include #include "resource_factory/prototype_factory.hpp" #include "logger/detail/layout.h" #include "logger/exception.h" #include "logger/log_manager.h" #include "logger/logpacket.h" #include "logger/properties.h" // Thursday, April 4, 2019 6:17:20 PM GMT namespace { constexpr const int NOW = 1554401840; } std::shared_ptr GetPatternLayout(std::string const & fmt) { using namespace logging; using namespace logging::property; properties props{_obj({{"pattern", _v(fmt)}})}; return layouts::instance().get("PatternLayout", props); } std::string DoFormat(std::string const & fmt, logging::logpacket const & pkt) { std::stringstream ss; GetPatternLayout(fmt)->format(ss, pkt); return ss.str(); } using namespace logging; logpacket getpkt(std::string const & msg) { return logpacket{{}, level::error, {}, "UNIT_TEST", msg}; }; TEST(PatternLayoutTest, EmptyFormatterCanParse) { EXPECT_NO_THROW(GetPatternLayout("")); } TEST(PatternLayoutTest, ThrowsForEndOfStringAfterPct) { EXPECT_THROW(GetPatternLayout("%"), logging::format_parsing_exception); } TEST(PatternLayoutTest, RawStringFmtReturnsSelf) { using testing::Eq; EXPECT_THAT(DoFormat("TEST STRING", {}), Eq("TEST STRING")); } TEST(PatternLayoutTest, NCharReturnsNewLine) { using testing::Eq; EXPECT_THAT(DoFormat("%n", {}), Eq("\n")); } TEST(PatternLayoutTest, DoublePctIsLiteral) { using testing::Eq; EXPECT_THAT(DoFormat("%%", {}), Eq("%")); } TEST(PatternLayoutTest, CatchesRawContentBeforeFmt) { using testing::Eq; EXPECT_THAT(DoFormat("TEST%%", {}), Eq("TEST%")); } TEST(PatternLayoutTest, CatchesRawContentAfterFmt) { using testing::Eq; EXPECT_THAT(DoFormat("%%TEST", {}), Eq("%TEST")); } TEST(PatternLayoutTest, HandlesDateFormatter) { using testing::Eq; EXPECT_THAT(DoFormat("%d", {{NOW,0}}), Eq("2019-04-04 18:17:20,000")); } TEST(PatternLayoutTest, FormatsMilliseconds) { using testing::Eq; EXPECT_THAT(DoFormat("%d", {{NOW,123000}}), Eq("2019-04-04 18:17:20,123")); } TEST(PatternLayoutTest, ThrowsIfCustomFmtUnterminated) { using testing::Eq; EXPECT_THROW(GetPatternLayout("%d{%"), logging::format_parsing_exception); } TEST(PatternLayoutTest, SupportsCustomFormatWithBrace) { using testing::Eq; EXPECT_THAT(DoFormat("%d{%Y}", {{NOW,0}}), Eq("2019")); } TEST(PatternLayoutTest, FormatsCustomMilliseconds) { using testing::Eq; EXPECT_THAT(DoFormat("%d{%_ms}", {{NOW,123000}}), Eq("123")); } TEST(PatternLayoutTest, SupportsISO8601Format) { using testing::Eq; EXPECT_THAT(DoFormat("%d{ISO8601}", {{NOW,0}}), Eq("2019-04-04T18:17:20.000Z")); } TEST(PatternLayoutTest, SupportsSingleDayFormat) { using testing::Eq; EXPECT_THAT(DoFormat("%d{ABSOLUTE}", {{NOW,0}}), Eq("18:17:20,000")); } TEST(PatternLayoutTest, SupportsHumanDateFormat) { using testing::Eq; EXPECT_THAT(DoFormat("%d{DATE}", {{NOW,0}}), Eq("04 Apr 2019 18:17:20,000")); } TEST(PatternLayoutTest, LoggerIdIsCToken) { using testing::Eq; EXPECT_THAT(DoFormat("%c", getpkt("HELLO")), Eq("UNIT_TEST")); } TEST(PatternLayoutTest, LogLevelIsPToken) { using testing::Eq; EXPECT_THAT(DoFormat("%p", getpkt("HELLO")), Eq("ERROR")); } TEST(PatternLayoutTest, LogMessageIsMToken) { using testing::Eq; EXPECT_THAT(DoFormat("%m", getpkt("HELLO")), Eq("HELLO")); } TEST(PatternLayoutTest, ThrowsOnUnknownToken) { using testing::Eq; EXPECT_THROW(GetPatternLayout("%q"), logging::unknown_format_specifier); } TEST(PatternLayoutTest, TokenCanBeTruncatedInFormat) { using testing::Eq; EXPECT_THAT(DoFormat("%.3m", getpkt("HELLO")), Eq("HEL")); EXPECT_THAT(DoFormat("%.5c", getpkt("HELLO")), Eq("UNIT_")); EXPECT_THAT(DoFormat("%.1t", getpkt("HELLO")), Eq("?")); } TEST(PatternLayoutTest, TokenCanBeLeftPadded) { using testing::Eq; EXPECT_THAT(DoFormat("%6m", getpkt("HELLO")), Eq(" HELLO")); } TEST(PatternLayoutTest, TokenCanBeRightPadded) { using testing::Eq; EXPECT_THAT(DoFormat("%-6m", getpkt("HELLO")), Eq("HELLO ")); } TEST(PatternLayoutTest, TokenCanBeSizeBound) { using testing::Eq; EXPECT_THAT(DoFormat("%6.8m", getpkt("HELLO")), Eq(" HELLO")); EXPECT_THAT(DoFormat("%6.8m", getpkt("HELLO FRIEND")), Eq("HELLO FR")); } #include "header_test_obj.h" #include "logger/logger.h" using namespace logging; using namespace logging::property; properties const PATTERN_HEADER_SCHEMA{_obj({ {"configuration", _obj({ {"appenders", _obj({ {"Stub", _obj({ {"PatternLayout", _obj({ {"pattern", _v("%m")}, {"header", _v("HEADER-")}, {"footer", _v("-FOOTER")} })} })} })}, {"loggers", _obj({ {"root", _obj({{"appenders", _obj({{"ref", _v("Stub")}})}})} })} })} })}; using PatternLayoutHeaderTest = HeaderFooterTest; TEST_F(PatternLayoutHeaderTest, ProvidesHeader) { manager mgr; mgr.configure(PATTERN_HEADER_SCHEMA); using testing::Eq; EXPECT_THAT(appender->sstream.str(), Eq("HEADER-")); mgr.get().log(level::error, "HELLO"); EXPECT_THAT(appender->sstream.str(), Eq("HEADER-HELLO")); } TEST_F(PatternLayoutHeaderTest, ProvidesFooter) { using testing::Eq; { manager mgr; mgr.configure(PATTERN_HEADER_SCHEMA); appender->sstream.str(""); mgr.get().log(level::error, "HELLO"); } EXPECT_THAT(appender->sstream.str(), Eq("HELLO-FOOTER")); }