diff options
Diffstat (limited to 'src/lib/log/tests/log_formatter_unittest.cc')
-rw-r--r-- | src/lib/log/tests/log_formatter_unittest.cc | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/src/lib/log/tests/log_formatter_unittest.cc b/src/lib/log/tests/log_formatter_unittest.cc new file mode 100644 index 0000000..4bd0405 --- /dev/null +++ b/src/lib/log/tests/log_formatter_unittest.cc @@ -0,0 +1,181 @@ +// Copyright (C) 2011-2022 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> +#include <gtest/gtest.h> + +#include <util/unittests/resource.h> +#include <util/unittests/check_valgrind.h> + +#include <log/log_formatter.h> +#include <log/logger_level.h> + +#include <vector> +#include <string> + +using namespace std; + +namespace { + +class FormatterTest : public ::testing::Test { +protected: + typedef pair<isc::log::Severity, string> Output; + typedef isc::log::Formatter<FormatterTest> Formatter; + vector<Output> outputs; +public: + void output(const isc::log::Severity& prefix, const string& message) { + outputs.push_back(Output(prefix, message)); + } + // Just shortcut for new string + boost::shared_ptr<string> s(const char* text) { + return (boost::make_shared<string>(text)); + } +}; + +// Create an inactive formatter and check it doesn't produce any output +TEST_F(FormatterTest, inactive) { + Formatter(); + EXPECT_EQ(0, outputs.size()); +} + +// Create an active formatter and check it produces output. Does no arg +// substitution yet +TEST_F(FormatterTest, active) { + Formatter(isc::log::INFO, s("Text of message"), this); + ASSERT_EQ(1, outputs.size()); + EXPECT_EQ(isc::log::INFO, outputs[0].first); + EXPECT_EQ("Text of message", outputs[0].second); +} + +// No output even when we have an arg on the inactive formatter +TEST_F(FormatterTest, inactiveArg) { + Formatter().arg("Hello"); + EXPECT_EQ(0, outputs.size()); +} + +// Create an active formatter and replace a placeholder with string +TEST_F(FormatterTest, stringArg) { + { + SCOPED_TRACE("C++ string"); + Formatter(isc::log::INFO, s("Hello %1"), this).arg(string("World")); + ASSERT_EQ(1, outputs.size()); + EXPECT_EQ(isc::log::INFO, outputs[0].first); + EXPECT_EQ("Hello World", outputs[0].second); + } + { + SCOPED_TRACE("C++ string"); + Formatter(isc::log::INFO, s("Hello %1"), this).arg(string("Internet")); + ASSERT_EQ(2, outputs.size()); + EXPECT_EQ(isc::log::INFO, outputs[1].first); + EXPECT_EQ("Hello Internet", outputs[1].second); + } +} + +// Test the .deactivate() method +TEST_F(FormatterTest, deactivate) { + Formatter(isc::log::INFO, s("Text of message"), this).deactivate(); + // If there was no .deactivate, it should have output it. + // But not now. + ASSERT_EQ(0, outputs.size()); +} + +// Can convert to string +TEST_F(FormatterTest, intArg) { + Formatter(isc::log::INFO, s("The answer is %1"), this).arg(42); + ASSERT_EQ(1, outputs.size()); + EXPECT_EQ(isc::log::INFO, outputs[0].first); + EXPECT_EQ("The answer is 42", outputs[0].second); +} + +// Can use multiple arguments at different places +TEST_F(FormatterTest, multiArg) { + Formatter(isc::log::INFO, s("The %2 are %1"), this).arg("switched"). + arg("arguments"); + ASSERT_EQ(1, outputs.size()); + EXPECT_EQ(isc::log::INFO, outputs[0].first); + EXPECT_EQ("The arguments are switched", outputs[0].second); +} + +#ifdef ENABLE_LOGGER_CHECKS + +TEST_F(FormatterTest, mismatchedPlaceholders) { + // Throws MismatchedPlaceholders exception if the placeholder is missing + // for a supplied argument. + EXPECT_THROW(Formatter(isc::log::INFO, s("Missing the second %1"), this). + arg("argument").arg("missing"), + isc::log::MismatchedPlaceholders); + +#ifdef EXPECT_DEATH + // Likewise, if there's a redundant placeholder (or missing argument), the + // check detects it and aborts the program. Due to the restriction of the + // current implementation, it doesn't throw. + if (!isc::util::unittests::runningOnValgrind()) { + EXPECT_DEATH({ + isc::util::unittests::dontCreateCoreDumps(); + Formatter(isc::log::INFO, s("Too many arguments in %1 %2"), this). + arg("only one"); + }, ".*"); + } +#endif /* EXPECT_DEATH */ + // Mixed case of above two: the exception will be thrown due to the missing + // placeholder. The other check is disabled due to that. + EXPECT_THROW(Formatter(isc::log::INFO, s("Missing the first %2"), this). + arg("missing").arg("argument"), + isc::log::MismatchedPlaceholders); +} + +#else + +// If logger checks are not enabled, nothing is thrown +TEST_F(FormatterTest, mismatchedPlaceholders) { + Formatter(isc::log::INFO, s("Missing the second %1"), this). + arg("argument").arg("missing"); + ASSERT_EQ(1, outputs.size()); + EXPECT_EQ(isc::log::INFO, outputs[0].first); + EXPECT_EQ("Missing the second argument " + "@@Missing logger placeholder '%2' for value 'missing'@@", + outputs[0].second); + + EXPECT_NO_THROW(Formatter(isc::log::INFO, + s("Too many arguments in %1 %2"), this). + arg("only one")); + ASSERT_EQ(2, outputs.size()); + EXPECT_EQ(isc::log::INFO, outputs[1].first); + EXPECT_EQ("Too many arguments in only one %2 " + "@@Excess logger placeholder '%2' still exists@@", + outputs[1].second); + + EXPECT_NO_THROW(Formatter(isc::log::INFO, s("Missing the first %2"), this). + arg("missing").arg("argument")); + ASSERT_EQ(3, outputs.size()); + EXPECT_EQ(isc::log::INFO, outputs[2].first); + EXPECT_EQ("Missing the first argument " + "@@Missing logger placeholder '%1' for value 'missing'@@", + outputs[2].second); +} + +#endif /* ENABLE_LOGGER_CHECKS */ + +// Can replace multiple placeholders +TEST_F(FormatterTest, multiPlaceholder) { + Formatter(isc::log::INFO, s("The %1 is the %1"), this). + arg("first rule of tautology club"); + ASSERT_EQ(1, outputs.size()); + EXPECT_EQ(isc::log::INFO, outputs[0].first); + EXPECT_EQ("The first rule of tautology club is " + "the first rule of tautology club", outputs[0].second); +} + +// Test we can cope with replacement containing the placeholder +TEST_F(FormatterTest, noRecurse) { + // If we recurse, this will probably eat all the memory and crash + Formatter(isc::log::INFO, s("%1"), this).arg("%1 %1"); + ASSERT_EQ(1, outputs.size()); + EXPECT_EQ(isc::log::INFO, outputs[0].first); + EXPECT_EQ("%1 %1", outputs[0].second); +} + +} |