/* * Copyright (c) 2020 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 #include "base/debug.hh" #include "base/gtest/logging.hh" using namespace gem5; /** Test assignment of names and descriptions. */ TEST(DebugFlagTest, NameDesc) { debug::SimpleFlag flag_a("FlagNameDescTestKidA", "Kid A"); EXPECT_EQ("FlagNameDescTestKidA", flag_a.name()); EXPECT_EQ("Kid A", flag_a.desc()); debug::SimpleFlag flag_b("FlagNameDescTestKidB", "Kid B"); EXPECT_EQ("FlagNameDescTestKidB", flag_b.name()); EXPECT_EQ("Kid B", flag_b.desc()); debug::CompoundFlag compound_flag("FlagNameDescTest", "Compound Flag", {&flag_a, &flag_b}); EXPECT_EQ("FlagNameDescTest", compound_flag.name()); EXPECT_EQ("Compound Flag", compound_flag.desc()); } /** Test that names are unique. */ TEST(DebugFlagDeathTest, UniqueNames) { debug::SimpleFlag flag("FlagUniqueNamesTest", "A"); gtestLogOutput.str(""); EXPECT_ANY_THROW(debug::SimpleFlag("FlagUniqueNamesTest", "B")); const std::string expected = "panic: panic condition !result.second " "occurred: Flag FlagUniqueNamesTest already defined!\n"; std::string actual = gtestLogOutput.str(); EXPECT_EQ(expected, actual); } /** Test format attribute. */ TEST(DebugFlagTest, IsFormat) { debug::SimpleFlag flag_a("FlagIsFormatTestA", "", true); EXPECT_TRUE(flag_a.isFormat()); debug::SimpleFlag flag_b("FlagIsFormatTestB", "", false); EXPECT_FALSE(flag_b.isFormat()); debug::SimpleFlag flag_c("FlagIsFormatTestC", ""); EXPECT_FALSE(flag_c.isFormat()); } /** Test enabling and disabling simple flags, as well as the global enabler. */ TEST(DebugSimpleFlagTest, Enabled) { debug::Flag::globalDisable(); debug::SimpleFlag flag("SimpleFlagEnabledTest", ""); // By default flags are initialized disabled ASSERT_FALSE(flag.tracing()); // Flags must be globally enabled before individual flags are enabled flag.enable(); ASSERT_FALSE(flag.tracing()); debug::Flag::globalEnable(); ASSERT_TRUE(!TRACING_ON || flag.tracing()); // Verify that the global enabler works debug::Flag::globalDisable(); ASSERT_FALSE(flag.tracing()); debug::Flag::globalEnable(); ASSERT_TRUE(!TRACING_ON || flag.tracing()); // Test disabling the flag with global enabled flag.disable(); ASSERT_FALSE(flag.tracing()); } /** * Tests that manipulate the enablement status of the compound flag to change * the corresponding status of the kids. */ TEST(DebugCompoundFlagTest, Enabled) { debug::Flag::globalDisable(); debug::SimpleFlag flag_a("CompoundFlagEnabledTestKidA", ""); debug::SimpleFlag flag_b("CompoundFlagEnabledTestKidB", ""); debug::CompoundFlag flag("CompoundFlagEnabledTest", "", {&flag_a, &flag_b}); // By default flags are initialized disabled ASSERT_FALSE(flag.tracing()); // Flags must be globally enabled before individual flags are enabled flag.enable(); ASSERT_FALSE(flag_a.tracing()); ASSERT_FALSE(flag_b.tracing()); ASSERT_FALSE(flag.tracing()); debug::Flag::globalEnable(); for (auto &kid : flag.kids()) { ASSERT_TRUE(!TRACING_ON || kid->tracing()); } ASSERT_TRUE(!TRACING_ON || flag_a.tracing()); ASSERT_TRUE(!TRACING_ON || flag_b.tracing()); // Test disabling the flag with global enabled flag.disable(); for (auto &kid : flag.kids()) { ASSERT_FALSE(kid->tracing()); } ASSERT_FALSE(flag_a.tracing()); ASSERT_FALSE(flag_b.tracing()); ASSERT_FALSE(flag.tracing()); } /** Test that the conversion operator matches the enablement status. */ TEST(DebugFlagTest, ConversionOperator) { debug::Flag::globalEnable(); debug::SimpleFlag flag("FlagConversionOperatorTest", ""); ASSERT_EQ(flag, flag.tracing()); flag.enable(); ASSERT_EQ(flag, flag.tracing()); flag.disable(); } /** * Tests that manipulate the kids to change the enablement status of the * compound flag. */ TEST(DebugCompoundFlagTest, EnabledKids) { debug::Flag::globalEnable(); debug::SimpleFlag flag_a("CompoundFlagEnabledKidsTestKidA", ""); debug::SimpleFlag flag_b("CompoundFlagEnabledKidsTestKidB", ""); debug::CompoundFlag flag("CompoundFlagEnabledKidsTest", "", {&flag_a, &flag_b}); // Test enabling only flag A ASSERT_FALSE(flag_a.tracing()); ASSERT_FALSE(flag_b.tracing()); ASSERT_FALSE(flag.tracing()); flag_a.enable(); ASSERT_TRUE(!TRACING_ON || flag_a.tracing()); ASSERT_FALSE(flag_b.tracing()); ASSERT_FALSE(flag.tracing()); // Test that enabling both flags enables the compound flag ASSERT_TRUE(!TRACING_ON || flag_a.tracing()); ASSERT_FALSE(flag_b.tracing()); ASSERT_FALSE(flag.tracing()); flag_b.enable(); ASSERT_TRUE(!TRACING_ON || flag_a.tracing()); ASSERT_TRUE(!TRACING_ON || flag_b.tracing()); // Test that disabling one of the flags disables the compound flag flag_a.disable(); ASSERT_FALSE(flag_a.tracing()); ASSERT_TRUE(!TRACING_ON || flag_b.tracing()); ASSERT_FALSE(flag.tracing()); } /** Search for existent and non-existent flags. */ TEST(DebugFlagTest, FindFlag) { debug::Flag::globalEnable(); debug::SimpleFlag flag_a("FlagFindFlagTestA", ""); debug::SimpleFlag flag_b("FlagFindFlagTestB", ""); // Enable the found flags and verify that the original flags are // enabled too debug::Flag *flag; EXPECT_TRUE(flag = debug::findFlag("FlagFindFlagTestA")); ASSERT_FALSE(flag_a.tracing()); flag->enable(); ASSERT_TRUE(!TRACING_ON || flag_a.tracing()); EXPECT_TRUE(flag = debug::findFlag("FlagFindFlagTestB")); ASSERT_FALSE(flag_b.tracing()); flag->enable(); ASSERT_TRUE(!TRACING_ON || flag_b.tracing()); // Search for a non-existent flag EXPECT_FALSE(debug::findFlag("FlagFindFlagTestC")); } /** Test changing flag enabled. */ TEST(DebugFlagTest, ChangeFlag) { debug::Flag::globalEnable(); debug::SimpleFlag flag_a("FlagChangeFlagTestA", ""); debug::SimpleFlag flag_b("FlagChangeFlagTestB", ""); // Enable the found flags and verify that the original flags are // enabled too ASSERT_FALSE(flag_a.tracing()); EXPECT_TRUE(debug::changeFlag("FlagChangeFlagTestA", true)); ASSERT_TRUE(!TRACING_ON || flag_a.tracing()); EXPECT_TRUE(debug::changeFlag("FlagChangeFlagTestA", false)); ASSERT_FALSE(flag_a.tracing()); // Disable and enable a flag ASSERT_FALSE(flag_b.tracing()); EXPECT_TRUE(debug::changeFlag("FlagChangeFlagTestB", false)); ASSERT_FALSE(flag_b.tracing()); EXPECT_TRUE(debug::changeFlag("FlagChangeFlagTestB", true)); ASSERT_TRUE(!TRACING_ON || flag_b.tracing()); // Change a non-existent flag ASSERT_FALSE(debug::changeFlag("FlagChangeFlagTestC", true)); } /** Test changing flag enabled with aux functions. */ TEST(DebugFlagTest, SetClearDebugFlag) { debug::Flag::globalEnable(); debug::SimpleFlag flag_a("FlagSetClearDebugFlagTestA", ""); debug::SimpleFlag flag_b("FlagSetClearDebugFlagTestB", ""); // Enable and disable a flag ASSERT_FALSE(flag_a.tracing()); setDebugFlag("FlagSetClearDebugFlagTestA"); ASSERT_TRUE(!TRACING_ON || flag_a.tracing()); clearDebugFlag("FlagSetClearDebugFlagTestA"); ASSERT_FALSE(flag_a.tracing()); // Disable and enable a flag ASSERT_FALSE(flag_b.tracing()); clearDebugFlag("FlagSetClearDebugFlagTestB"); ASSERT_FALSE(flag_b.tracing()); setDebugFlag("FlagSetClearDebugFlagTestB"); ASSERT_TRUE(!TRACING_ON || flag_b.tracing()); // Change a non-existent flag setDebugFlag("FlagSetClearDebugFlagTestC"); clearDebugFlag("FlagSetClearDebugFlagTestC"); } /** Test dumping no enabled debug flags. */ TEST(DebugFlagTest, NoDumpDebugFlags) { debug::Flag::globalEnable(); debug::SimpleFlag flag("FlagDumpDebugFlagTest", ""); // Verify that the names of the enabled flags are printed gtestLogOutput.str(""); dumpDebugFlags(); std::string output = gtestLogOutput.str(); EXPECT_EQ(output, ""); ASSERT_FALSE(flag.tracing()); } /** Test dumping enabled debug flags with a larger set of flags. */ TEST(DebugFlagTest, DumpDebugFlags) { debug::Flag::globalEnable(); debug::SimpleFlag flag_a("FlagDumpDebugFlagTestA", ""); debug::SimpleFlag flag_b("FlagDumpDebugFlagTestB", ""); debug::SimpleFlag flag_c("FlagDumpDebugFlagTestC", ""); debug::SimpleFlag flag_d("FlagDumpDebugFlagTestD", ""); debug::SimpleFlag flag_e("FlagDumpDebugFlagTestE", ""); debug::CompoundFlag compound_flag_a("CompoundFlagDumpDebugFlagTestA", "", {&flag_d}); debug::CompoundFlag compound_flag_b("CompoundFlagDumpDebugFlagTestB", "", {&flag_e}); // Enable a few flags ASSERT_FALSE(flag_a.tracing()); ASSERT_FALSE(flag_b.tracing()); ASSERT_FALSE(flag_c.tracing()); ASSERT_FALSE(flag_d.tracing()); ASSERT_FALSE(flag_e.tracing()); flag_a.enable(); flag_c.enable(); compound_flag_b.enable(); // Verify that the names of the enabled flags are printed if TRACING_ON. if (TRACING_ON) { std::ostringstream os; dumpDebugFlags(os); std::string output = os.str(); EXPECT_EQ(output, "FlagDumpDebugFlagTestA\nFlagDumpDebugFlagTestC\n" \ "FlagDumpDebugFlagTestE\n"); } }