| /* |
| * Copyright (c) 2021 Daniel R. Carvalho |
| * All rights reserved |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer; |
| * redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution; |
| * neither the name of the copyright holders nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "base/gtest/logging.hh" |
| #include "base/logging.hh" |
| |
| using namespace gem5; |
| |
| /** Temporarily redirects cerr to gtestLogOutput. */ |
| class LoggingFixture : public ::testing::Test |
| { |
| public: |
| void SetUp() override { old = std::cerr.rdbuf(gtestLogOutput.rdbuf()); } |
| void TearDown() override { std::cerr.rdbuf(old); } |
| |
| private: |
| /** Used to restore cerr's streambuf. */ |
| std::streambuf *old; |
| }; |
| |
| /** Test the most basic print. */ |
| TEST_F(LoggingFixture, BasicPrint) |
| { |
| Logger logger("test: "); |
| |
| // Tests that the logger will automatically add '\n' to the end of the |
| // message if it does not already have '\n' in the end |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), "message"); |
| ASSERT_EQ(gtestLogOutput.str(), "File:10: test: message\n"); |
| |
| // Tests that the logger won't add '\n' if it already has '\n' in the end |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), "message\n"); |
| ASSERT_EQ(gtestLogOutput.str(), "File:10: test: message\n"); |
| |
| // Tests that the logger won't remove '\n's if multiple are provided |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), "sample message\n\n"); |
| ASSERT_EQ(gtestLogOutput.str(), "File:10: test: sample message\n\n"); |
| |
| // A more complete/complex test case |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), "sample message\nwith \n3 lines"); |
| ASSERT_EQ(gtestLogOutput.str(), |
| "File:10: test: sample message\nwith \n3 lines\n"); |
| } |
| |
| /** Test the variadic-arg print for chars. */ |
| TEST_F(LoggingFixture, VariadicCharPrint) |
| { |
| Logger logger("test: "); |
| |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), (const char *)"%s message", |
| "sample"); |
| ASSERT_EQ(gtestLogOutput.str(), "File:10: test: sample message\n"); |
| |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), |
| (const char *)"sample %s with %d arguments\n", "message", 2); |
| ASSERT_EQ(gtestLogOutput.str(), |
| "File:10: test: sample message with 2 arguments\n"); |
| } |
| |
| /** Test the variadic-arg print for strings. */ |
| TEST_F(LoggingFixture, VariadicStringPrint) |
| { |
| Logger logger("test: "); |
| |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), std::string("%s message"), "sample"); |
| ASSERT_EQ(gtestLogOutput.str(), "File:10: test: sample message\n"); |
| |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), |
| std::string("sample %s with %d arguments\n"), "message", 2); |
| ASSERT_EQ(gtestLogOutput.str(), |
| "File:10: test: sample message with 2 arguments\n"); |
| } |
| |
| /** Test the variadic-arg print for chars with arguments missing. */ |
| TEST_F(LoggingFixture, VariadicCharMissingPrint) |
| { |
| Logger logger("test: "); |
| |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), (const char *)"%s message"); |
| ASSERT_EQ(gtestLogOutput.str(), "File:10: test: <extra arg>% message\n"); |
| |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), (const char *)"%s mes%ca%cge", |
| "sample", 's'); |
| ASSERT_EQ(gtestLogOutput.str(), |
| "File:10: test: sample messa<extra arg>%ge\n"); |
| } |
| |
| /** Test the variadic-arg print for strings with arguments missing. */ |
| TEST_F(LoggingFixture, VariadicStringMissingPrint) |
| { |
| Logger logger("test: "); |
| |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), std::string("%s message")); |
| ASSERT_EQ(gtestLogOutput.str(), "File:10: test: <extra arg>% message\n"); |
| |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), std::string("%s mes%ca%cge"), |
| "sample", 's'); |
| ASSERT_EQ(gtestLogOutput.str(), |
| "File:10: test: sample messa<extra arg>%ge\n"); |
| } |
| |
| /** Test that no message is shown when printing with a disabled logger. */ |
| TEST_F(LoggingFixture, DisabledPrint) |
| { |
| class DisabledLogger : public Logger |
| { |
| public: |
| DisabledLogger(const char *prefix) |
| : Logger(prefix) |
| { |
| enabled = false; |
| } |
| } logger("test: "); |
| |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), "message"); |
| ASSERT_EQ(gtestLogOutput.str(), ""); |
| } |
| |
| /** Test printing with the warn logger, enabled and disabled. */ |
| TEST_F(LoggingFixture, WarnLoggerPrint) |
| { |
| Logger::setLevel(Logger::WARN); |
| Logger &logger = Logger::getWarn(); |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), "message"); |
| ASSERT_EQ(gtestLogOutput.str(), "File:10: warn: message\n"); |
| |
| // PANIC does not include WARN |
| Logger::setLevel(Logger::PANIC); |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), "message"); |
| ASSERT_EQ(gtestLogOutput.str(), ""); |
| |
| Logger::setLevel(Logger::NUM_LOG_LEVELS); |
| } |
| |
| /** Test printing with the info logger, enabled and disabled. */ |
| TEST_F(LoggingFixture, InfoLoggerPrint) |
| { |
| Logger::setLevel(Logger::INFO); |
| Logger &logger = Logger::getInfo(); |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), "message"); |
| ASSERT_EQ(gtestLogOutput.str(), "File:10: info: message\n"); |
| |
| // PANIC does not include INFO |
| Logger::setLevel(Logger::PANIC); |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), "message"); |
| ASSERT_EQ(gtestLogOutput.str(), ""); |
| |
| Logger::setLevel(Logger::NUM_LOG_LEVELS); |
| } |
| |
| /** Test printing with the hack logger, enabled and disabled. */ |
| TEST_F(LoggingFixture, HackLoggerPrint) |
| { |
| Logger::setLevel(Logger::HACK); |
| Logger &logger = Logger::getHack(); |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), "message"); |
| ASSERT_EQ(gtestLogOutput.str(), "File:10: hack: message\n"); |
| |
| // PANIC does not include HACK |
| Logger::setLevel(Logger::PANIC); |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), "message"); |
| ASSERT_EQ(gtestLogOutput.str(), ""); |
| |
| Logger::setLevel(Logger::NUM_LOG_LEVELS); |
| } |
| |
| /** Test printing with the fatal logger, enabled and disabled. */ |
| TEST_F(LoggingFixture, FatalLoggerPrint) |
| { |
| Logger &logger = Logger::getFatal(); |
| |
| // The actual value of memory usage is not relevant |
| Logger::setLevel(Logger::FATAL); |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), "message"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| testing::HasSubstr("File:10: fatal: message\nMemory Usage:")); |
| |
| // PANIC does not include FATAL |
| Logger::setLevel(Logger::PANIC); |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), "message"); |
| ASSERT_EQ(gtestLogOutput.str(), ""); |
| |
| Logger::setLevel(Logger::NUM_LOG_LEVELS); |
| } |
| |
| /** Test printing with the panic logger, which cannot be disabled. */ |
| TEST_F(LoggingFixture, PanicLoggerPrint) |
| { |
| // The actual value of memory usage is not relevant |
| Logger::setLevel(Logger::PANIC); |
| Logger &logger = Logger::getPanic(); |
| gtestLogOutput.str(""); |
| logger.print(Logger::Loc("File", 10), "message"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("File:10: panic: message\nMemory Usage:")); |
| |
| Logger::setLevel(Logger::NUM_LOG_LEVELS); |
| } |
| |
| /** Test macro base_message. */ |
| TEST_F(LoggingFixture, BaseMessage) |
| { |
| Logger logger("test: "); |
| |
| // The logger will automatically add '\n' to the end of the message |
| // if it does not already have at least one. |
| gtestLogOutput.str(""); |
| base_message(logger, "message"); |
| ASSERT_THAT(gtestLogOutput.str(), ::testing::HasSubstr("test: message\n")); |
| |
| gtestLogOutput.str(""); |
| base_message(logger, "message\n"); |
| ASSERT_THAT(gtestLogOutput.str(), ::testing::HasSubstr("test: message\n")); |
| |
| gtestLogOutput.str(""); |
| base_message(logger, "sample message\n\n"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("test: sample message\n\n")); |
| |
| gtestLogOutput.str(""); |
| base_message(logger, "sample message\nwith \n3 lines"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("test: sample message\nwith \n3 lines\n")); |
| |
| gtestLogOutput.str(""); |
| base_message(logger, "sample %s with %d arguments\n", "message", 2); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("test: sample message with 2 arguments\n")); |
| } |
| |
| /** Test that base_message_once only prints the message once in a loop. */ |
| TEST_F(LoggingFixture, BaseMessageOnce) |
| { |
| Logger logger("test: "); |
| |
| for (int i = 0; i < 10; i++) { |
| gtestLogOutput.str(""); |
| base_message_once(logger, "message\n"); |
| if (i == 0) { |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("test: message\n")); |
| } else { |
| ASSERT_EQ(gtestLogOutput.str(), ""); |
| } |
| } |
| } |
| |
| /** Test macro warn. */ |
| TEST_F(LoggingFixture, Warn) |
| { |
| // The logger will automatically add '\n' to the end of the message |
| // if it does not already have at least one. |
| gtestLogOutput.str(""); |
| warn("message"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("warn: message\n")); |
| |
| gtestLogOutput.str(""); |
| warn("message\n"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("warn: message\n")); |
| |
| gtestLogOutput.str(""); |
| warn("sample message\n\n"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("warn: sample message\n\n")); |
| |
| gtestLogOutput.str(""); |
| warn("sample message\nwith \n3 lines"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("warn: sample message\nwith \n3 lines\n")); |
| |
| gtestLogOutput.str(""); |
| warn("sample %s with %d arguments\n", "message", 2); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("warn: sample message with 2 arguments\n")); |
| } |
| |
| /** Test macro inform. */ |
| TEST_F(LoggingFixture, Inform) |
| { |
| // The logger will automatically add '\n' to the end of the message |
| // if it does not already have at least one. |
| gtestLogOutput.str(""); |
| inform("message"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("info: message\n")); |
| |
| gtestLogOutput.str(""); |
| inform("message\n"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("info: message\n")); |
| |
| gtestLogOutput.str(""); |
| inform("sample message\n\n"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("info: sample message\n\n")); |
| |
| gtestLogOutput.str(""); |
| inform("sample message\nwith \n3 lines"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("info: sample message\nwith \n3 lines\n")); |
| |
| gtestLogOutput.str(""); |
| inform("sample %s with %d arguments\n", "message", 2); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("info: sample message with 2 arguments\n")); |
| } |
| |
| /** Test macro hack. */ |
| TEST_F(LoggingFixture, Hack) |
| { |
| // The logger will automatically add '\n' to the end of the message |
| // if it does not already have at least one. |
| gtestLogOutput.str(""); |
| hack("message"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("hack: message\n")); |
| |
| gtestLogOutput.str(""); |
| hack("message\n"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("hack: message\n")); |
| |
| gtestLogOutput.str(""); |
| hack("sample message\n\n"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("hack: sample message\n\n")); |
| |
| gtestLogOutput.str(""); |
| hack("sample message\nwith \n3 lines"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("hack: sample message\nwith \n3 lines\n")); |
| |
| gtestLogOutput.str(""); |
| hack("sample %s with %d arguments\n", "message", 2); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("hack: sample message with 2 arguments\n")); |
| } |
| |
| /** Test that warn_once only prints the message once in a loop. */ |
| TEST_F(LoggingFixture, WarnOnce) |
| { |
| for (int i = 0; i < 10; i++) { |
| gtestLogOutput.str(""); |
| warn_once("message\n"); |
| if (i == 0) { |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("warn: message\n")); |
| } else { |
| ASSERT_EQ(gtestLogOutput.str(), ""); |
| } |
| } |
| } |
| |
| /** Test that inform_once only prints the message once in a loop. */ |
| TEST_F(LoggingFixture, InformOnce) |
| { |
| for (int i = 0; i < 10; i++) { |
| gtestLogOutput.str(""); |
| inform_once("message\n"); |
| if (i == 0) { |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("info: message\n")); |
| } else { |
| ASSERT_EQ(gtestLogOutput.str(), ""); |
| } |
| } |
| } |
| |
| /** Test that hack_once only prints the message once in a loop. */ |
| TEST_F(LoggingFixture, HackOnce) |
| { |
| for (int i = 0; i < 10; i++) { |
| gtestLogOutput.str(""); |
| hack_once("message\n"); |
| if (i == 0) { |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("hack: message\n")); |
| } else { |
| ASSERT_EQ(gtestLogOutput.str(), ""); |
| } |
| } |
| } |
| |
| /** Test that warn_if only prints the message when the condition is true. */ |
| TEST_F(LoggingFixture, WarnIf) |
| { |
| gtestLogOutput.str(""); |
| warn_if(true, "message\n"); |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("warn: message\n")); |
| |
| gtestLogOutput.str(""); |
| warn_if(false, "message\n"); |
| ASSERT_EQ(gtestLogOutput.str(), ""); |
| } |
| |
| /** Test that warn_if_once only prints the message once in a loop. */ |
| TEST_F(LoggingFixture, WarnIfOnce) |
| { |
| for (int i = 0; i < 10; i++) { |
| gtestLogOutput.str(""); |
| warn_if_once(i == 3, "message\n"); |
| if (i == 3) { |
| ASSERT_THAT(gtestLogOutput.str(), |
| ::testing::HasSubstr("warn: message\n")); |
| } else { |
| ASSERT_EQ(gtestLogOutput.str(), ""); |
| } |
| } |
| } |
| |
| /** Test that a logger cannot be created with an empty prefix. */ |
| TEST(LoggingDeathTest, EmptyPrefix) |
| { |
| #ifdef NDEBUG |
| GTEST_SKIP() << "Skipping as assertions are " |
| "stripped out of fast builds"; |
| #endif |
| ASSERT_DEATH(Logger(nullptr), ""); |
| } |
| |
| /** Test that the test logger's exit helper will end execution gracefully. */ |
| TEST(LoggingDeathTest, ExitHelper) |
| { |
| ASSERT_DEATH(Logger("test: ").exit_helper(), ""); |
| } |
| |
| /** Test that the warn logger's exit helper will end execution gracefully. */ |
| TEST(LoggingDeathTest, WarnLoggerExitHelper) |
| { |
| ASSERT_DEATH(Logger::getWarn().exit_helper(), ""); |
| } |
| |
| /** Test that the info logger's exit helper will end execution gracefully. */ |
| TEST(LoggingDeathTest, InfoLoggerExitHelper) |
| { |
| ASSERT_DEATH(Logger::getInfo().exit_helper(), ""); |
| } |
| |
| /** Test that the hack logger's exit helper will end execution gracefully. */ |
| TEST(LoggingDeathTest, HackLoggerExitHelper) |
| { |
| ASSERT_DEATH(Logger::getHack().exit_helper(), ""); |
| } |
| |
| /** Test that the fatal logger's exit helper will end execution with error. */ |
| TEST(LoggingDeathTest, FatalLoggerExitHelper) |
| { |
| ASSERT_DEATH(Logger::getFatal().exit_helper(), ""); |
| } |
| |
| /** Test that the panic logger's exit helper will end execution with error. */ |
| TEST(LoggingDeathTest, PanicLoggerExitHelper) |
| { |
| ASSERT_DEATH(Logger::getPanic().exit_helper(), ""); |
| } |
| |
| /** Test that exit_message prints a message and exits. */ |
| TEST(LoggingDeathTest, ExitMessage) |
| { |
| Logger logger("test: "); |
| ASSERT_DEATH(exit_message(logger, "message\n"), "test: message\n"); |
| } |
| |
| /** Test macro panic. */ |
| TEST(LoggingDeathTest, Panic) |
| { |
| ASSERT_DEATH(panic("message\n"), |
| ::testing::HasSubstr("panic: message\nMemory Usage:")); |
| } |
| |
| /** Test macro fatal. */ |
| TEST(LoggingDeathTest, Fatal) |
| { |
| ASSERT_DEATH(fatal("message\n"), |
| ::testing::HasSubstr("fatal: message\nMemory Usage:")); |
| } |
| |
| /** Test that panic_if only prints the message when the condition is true. */ |
| TEST(LoggingDeathTest, PanicIf) |
| { |
| panic_if(false, "No death"); |
| ASSERT_DEATH(panic_if(true, "message\n"), ::testing::HasSubstr( |
| "panic: panic condition true occurred: message\nMemory Usage:")); |
| } |
| |
| /** Test that fatal_if only prints the message when the condition is true. */ |
| TEST(LoggingDeathTest, FatalIf) |
| { |
| fatal_if(false, "No death"); |
| ASSERT_DEATH(fatal_if(true, "message\n"), ::testing::HasSubstr( |
| "fatal: fatal condition true occurred: message\nMemory Usage:")); |
| } |
| |
| /** Test macro gem5_assert. */ |
| TEST(LoggingDeathTest, gem5Assert) |
| { |
| #ifdef NDEBUG |
| GTEST_SKIP() << "Skipping as assertions are " |
| "stripped out of fast builds"; |
| #endif |
| gem5_assert(true, "message\n"); |
| ASSERT_DEATH(gem5_assert(false, "message\n"), ::testing::HasSubstr( |
| "panic: assert(false) failed: message\nMemory Usage:")); |
| ASSERT_DEATH(gem5_assert(false, "%s, %s!\n", "Hello", "World"), |
| ::testing::HasSubstr( |
| "panic: assert(false) failed: Hello, World!\nMemory Usage:")); |
| gem5_assert(true); |
| ASSERT_DEATH(gem5_assert(false), ::testing::HasSubstr( |
| "panic: assert(false) failed\nMemory Usage:")); |
| } |