From 8096f628fa72cd4177ab38f880ba65e2a1917ffe Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Mon, 6 Apr 2020 22:10:25 -0700 Subject: [PATCH] util: Add a "call_type" unit test to the m5 utility. Change-Id: I6ffdf1242a063e776dbb7c18664755773a591b8b Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/27561 Maintainer: Gabe Black Tested-by: kokoro Reviewed-by: Jason Lowe-Power --- util/m5/src/SConscript.native | 1 + util/m5/src/call_type.hh | 4 +- util/m5/src/call_type.test.cc | 247 ++++++++++++++++++++++++++++++++++ util/m5/src/call_type/addr.cc | 2 + util/m5/src/call_type/inst.cc | 2 + util/m5/src/call_type/semi.cc | 2 + 6 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 util/m5/src/call_type.test.cc diff --git a/util/m5/src/SConscript.native b/util/m5/src/SConscript.native index c7cacdd0e..2ce94d421 100644 --- a/util/m5/src/SConscript.native +++ b/util/m5/src/SConscript.native @@ -26,3 +26,4 @@ Import('*') env.GTest('args') +env.GTest('call_type') diff --git a/util/m5/src/call_type.hh b/util/m5/src/call_type.hh index 6ee536d2d..4b2b3d120 100644 --- a/util/m5/src/call_type.hh +++ b/util/m5/src/call_type.hh @@ -32,8 +32,8 @@ #include #include -#include "args.hh" -#include "dispatch_table.hh" +class Args; +class DispatchTable; class CallType { diff --git a/util/m5/src/call_type.test.cc b/util/m5/src/call_type.test.cc new file mode 100644 index 000000000..0aad8439b --- /dev/null +++ b/util/m5/src/call_type.test.cc @@ -0,0 +1,247 @@ +/* + * Copyright 2020 Google Inc. + * + * 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 + +// For EXPECT_THAT and HasSubstr +#include + +#include "call_type.hh" + +// Simple substitute definitions for Args and DispatchTable, with an int so +// we can tell instances apart. +class Args { public: int i; }; +class DispatchTable { public: int i; }; + +class TestCallType : public CallType +{ + protected: + bool isDefault() const override { return testIsDefault; } + bool checkArgs(Args &args) override { return args.i == testAcceptArgs; } + void + init() override + { + testInitHappened = true; + CallType::init(); + } + + void printBrief(std::ostream &os) const override { os << testBrief; } + void printDesc(std::ostream &os) const override { os << testDesc; } + public: + static std::vector &testGetAllTypes() { return allTypes(); } + + // Usage strings to return. + std::string testBrief; + std::string testDesc; + + // Return this dispatch table when requested. + DispatchTable testDt = { 0 }; + const DispatchTable &getDispatch() const override { return testDt; } + + // If an Args has this value, accept it. + int testAcceptArgs = 0; + + // Whether this call type should be considered default. + bool testIsDefault = false; + + // Whether init has been called. + bool testInitHappened = false; +}; + +TEST(CallTypeTest, Constructor) +{ + auto &all_types = TestCallType::testGetAllTypes(); + + // There should be no call types yet. + EXPECT_EQ(all_types.size(), 0); + + // Create one. + TestCallType test_ct; + + // Set the dispatch table to something we'll recognize. + test_ct.testDt.i = 0xaa55; + + // Verify that the list of all call types has one in it now. + EXPECT_EQ(all_types.size(), 1); + + // Verify that that was our call type by verifying that the dispatch table + // has our signature. + EXPECT_EQ(all_types[0]->getDispatch().i, 0xaa55); + + // Clear all_types, since call types don't clean up after themselves as + // they go away. + all_types.clear(); +} + +TEST(CallTypeTest, DetectOne) +{ + auto &all_types = TestCallType::testGetAllTypes(); + + // One option selected. + TestCallType option1; + option1.testAcceptArgs = 1; + option1.testIsDefault = true; + option1.testDt.i = 1; + + EXPECT_EQ(all_types.size(), 1); + + Args args; + args.i = 1; + + EXPECT_FALSE(option1.testInitHappened); + + auto &ct = CallType::detect(args); + + // Verify that we selected the only option. + EXPECT_TRUE(option1.testInitHappened); + EXPECT_EQ(ct.getDispatch().i, 1); + + // One option, selecting the default. + option1.testInitHappened = false; + + // Args will not match. + args.i = 2; + + auto &def_ct = CallType::detect(args); + + // Verify that the one option was defaulted to. + EXPECT_TRUE(option1.testInitHappened); + EXPECT_EQ(def_ct.getDispatch().i, 1); + + // Reset all_types. + all_types.clear(); +} + +TEST(CallTypeTest, DetectTwo) +{ + auto &all_types = TestCallType::testGetAllTypes(); + + // One of two options selected. + TestCallType option1; + option1.testAcceptArgs = 1; + option1.testIsDefault = true; + option1.testDt.i = 1; + + TestCallType option2; + option2.testAcceptArgs = 2; + option2.testIsDefault = false; + option2.testDt.i = 2; + + EXPECT_EQ(all_types.size(), 2); + + // Select the first option. + Args args; + args.i = 1; + + EXPECT_FALSE(option1.testInitHappened); + EXPECT_FALSE(option2.testInitHappened); + + auto &ct1 = CallType::detect(args); + + // Verify that we selected the first option. + EXPECT_TRUE(option1.testInitHappened); + EXPECT_FALSE(option2.testInitHappened); + EXPECT_EQ(ct1.getDispatch().i, 1); + + option1.testInitHappened = false; + option2.testInitHappened = false; + + // Select the second option. + args.i = 2; + + auto &ct2 = CallType::detect(args); + + // Verify that we selected the second option. + EXPECT_FALSE(option1.testInitHappened); + EXPECT_TRUE(option2.testInitHappened); + EXPECT_EQ(ct2.getDispatch().i, 2); + + option1.testInitHappened = false; + option2.testInitHappened = false; + + // Default to the first option. + args.i = 3; + + auto &def_ct1 = CallType::detect(args); + + // Verify that we selected the first option. + EXPECT_TRUE(option1.testInitHappened); + EXPECT_FALSE(option2.testInitHappened); + EXPECT_EQ(ct1.getDispatch().i, 1); + + option1.testInitHappened = false; + option2.testInitHappened = false; + + // Default to the second option. + option1.testIsDefault = false; + option2.testIsDefault = true; + + auto &def_ct2 = CallType::detect(args); + + // Verify that we selected the second option. + EXPECT_FALSE(option1.testInitHappened); + EXPECT_TRUE(option2.testInitHappened); + EXPECT_EQ(ct2.getDispatch().i, 2); + + option1.testInitHappened = false; + option2.testInitHappened = false; + + // Reset all_types. + all_types.clear(); +} + +TEST(CallTypeTest, Usage) +{ + auto &all_types = TestCallType::testGetAllTypes(); + + TestCallType ct1; + ct1.testBrief = "brief 1"; + ct1.testDesc = "A longer description of call type 1, which is long."; + + TestCallType ct2; + ct2.testBrief = "short 2"; + ct2.testDesc = "Very verbose text saying what call type 2 is, " + "and is different from 1."; + + EXPECT_EQ(all_types.size(), 2); + + auto summary = CallType::usageSummary(); + + // For now, just expect that the brief and full descriptive text shows up + // in the summary somewhere. + // + // More strict checks might test that things were placed in the right + // order, were on their own lines when appropriate, etc. + EXPECT_THAT(summary, testing::HasSubstr(ct1.testBrief)); + EXPECT_THAT(summary, testing::HasSubstr(ct1.testDesc)); + EXPECT_THAT(summary, testing::HasSubstr(ct2.testBrief)); + EXPECT_THAT(summary, testing::HasSubstr(ct2.testDesc)); + EXPECT_THAT(summary, testing::HasSubstr(ct2.testDesc)); + + // Reset all_types. + all_types.clear(); +} diff --git a/util/m5/src/call_type/addr.cc b/util/m5/src/call_type/addr.cc index f8e39c9f5..ab26db73f 100644 --- a/util/m5/src/call_type/addr.cc +++ b/util/m5/src/call_type/addr.cc @@ -27,7 +27,9 @@ #include +#include "args.hh" #include "call_type.hh" +#include "dispatch_table.hh" #include "m5_mmap.h" #include "usage.hh" diff --git a/util/m5/src/call_type/inst.cc b/util/m5/src/call_type/inst.cc index e19f6018b..a6af59550 100644 --- a/util/m5/src/call_type/inst.cc +++ b/util/m5/src/call_type/inst.cc @@ -27,7 +27,9 @@ #include +#include "args.hh" #include "call_type.hh" +#include "dispatch_table.hh" namespace { diff --git a/util/m5/src/call_type/semi.cc b/util/m5/src/call_type/semi.cc index 25b830c2d..ddc192565 100644 --- a/util/m5/src/call_type/semi.cc +++ b/util/m5/src/call_type/semi.cc @@ -27,7 +27,9 @@ #include +#include "args.hh" #include "call_type.hh" +#include "dispatch_table.hh" extern "C" { -- 2.30.2