Gabe Black has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/27608 )

Change subject: util: Add a unit test for the m5 utility's "readfile" command.
......................................................................

util: Add a unit test for the m5 utility's "readfile" command.

This feeds a fake file to the readfile command which is just a sequence
of incrementing 32 bit values. The incrementing values make sure that
the right region of the input file is being read at the right position,
and the relatively small size means there shouldn't be tons of zeroes
everywhere which can't be distinguished from each other.

Change-Id: I4286b1f92684f127c4885c29192c6c5244a61855
---
M util/m5/src/command/SConscript.native
A util/m5/src/command/readfile.test.cc
2 files changed, 209 insertions(+), 0 deletions(-)



diff --git a/util/m5/src/command/SConscript.native b/util/m5/src/command/SConscript.native
index 10e45d2..7d23b2a 100644
--- a/util/m5/src/command/SConscript.native
+++ b/util/m5/src/command/SConscript.native
@@ -34,6 +34,7 @@
     'fail',
     'initparam',
     'loadsymbol',
+    'readfile',
     'resetstats',
     'sum',
 )
diff --git a/util/m5/src/command/readfile.test.cc b/util/m5/src/command/readfile.test.cc
new file mode 100644
index 0000000..d5ffe1d
--- /dev/null
+++ b/util/m5/src/command/readfile.test.cc
@@ -0,0 +1,208 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <sstream>
+
+#include "args.hh"
+#include "command.hh"
+#include "dispatch_table.hh"
+
+uint64_t test_read_file_size;
+uint64_t test_max_buf_size;
+
+uint64_t test_total_read;
+
+uint64_t
+test_m5_read_file(void *buffer, uint64_t len, uint64_t offset)
+{
+    // The "file" we're reading is just a series of incrementing 32 bit
+    // integers.
+
+    // If the buffer is entirely past the end of our "file", return 0.
+    if (offset >= test_read_file_size)
+        return 0;
+
+    // If the buffer extends beyond our "file" truncate it.
+    if (offset + len > test_read_file_size)
+        len = test_read_file_size - offset;
+
+ // If more data was requested than we want to send at once, truncate len.
+    if (test_max_buf_size && len > test_max_buf_size)
+        len = test_max_buf_size;
+
+    int chunk_size = sizeof(uint32_t);
+
+    // How much of len is still unaccounted for.
+    uint64_t remaining = len;
+
+    // How much overlaps with the preceeding chunk?
+    int at_start = chunk_size - (offset % chunk_size);
+    // If we don't even cover the entire previous chunk...
+    if (at_start > len)
+        at_start = len;
+    remaining -= at_start;
+
+    // How much overlaps with the following chunk?
+    int at_end = remaining % chunk_size;
+    remaining -= at_end;
+
+ // The number of chunks are the number we cover fully, plus one for each
+    // end were we partially overlap.
+    uint64_t num_chunks = remaining / chunk_size +
+        (at_start ? 1 : 0) + (at_end ? 1 : 0);
+
+    // Build this part of the file.
+    uint32_t *chunks = new uint32_t [num_chunks];
+
+    uint32_t chunk_idx = offset / chunk_size;
+    for (uint64_t i = 0; i < num_chunks; i++)
+        chunks[i] = chunk_idx++;
+
+    // Copy out to the requested buffer.
+    memcpy(buffer, ((uint8_t *)chunks) + (chunk_size - at_start), len);
+
+    // Clean up.
+    delete [] chunks;
+
+    test_total_read += len;
+    return len;
+}
+
+DispatchTable dt = { .m5_read_file = &test_m5_read_file };
+
+std::string cout_output;
+
+bool
+run(std::initializer_list<std::string> arg_args, bool bad_file=false)
+{
+    test_total_read = 0;
+
+    Args args(arg_args);
+
+    // Redirect cout into a stringstream.
+    std::stringstream buffer;
+    std::streambuf *orig = std::cout.rdbuf(buffer.rdbuf());
+
+    // Simulate a problem writing to cout.
+    if (bad_file)
+        std::cout.setstate(std::cout.badbit);
+
+    bool res = Command::run(dt, args);
+
+    if (bad_file)
+        std::cout.clear();
+
+    // Capture the contents of the stringstream and restore cout.
+    cout_output = buffer.str();
+    std::cout.rdbuf(orig);
+
+    return res;
+}
+
+void
+test_verify_data()
+{
+    EXPECT_EQ(test_total_read, test_read_file_size);
+    EXPECT_EQ(cout_output.size(), test_read_file_size);
+
+    auto *data32 = (const uint32_t *)cout_output.data();
+    uint64_t len = cout_output.size();
+
+    int chunk_size = sizeof(uint32_t);
+
+    uint64_t num_chunks = len / chunk_size;
+    int leftovers = len % chunk_size;
+
+    uint32_t chunk_idx;
+    for (chunk_idx = 0; chunk_idx < num_chunks; chunk_idx++)
+        EXPECT_EQ(*data32++, chunk_idx);
+
+    if (leftovers)
+        EXPECT_EQ(memcmp(&chunk_idx, data32, leftovers), 0);
+}
+
+TEST(Readfile, OneArgument)
+{
+    // Call with an argument.
+    EXPECT_FALSE(run({"readfile", "foo"}));
+    EXPECT_EQ(test_total_read, 0);
+}
+
+TEST(Readfile, SmallFile)
+{
+    // Read a small "file".
+    test_read_file_size = 16;
+    test_max_buf_size = 0;
+    EXPECT_TRUE(run({"readfile"}));
+    test_verify_data();
+}
+
+TEST(Readfile, MultipleChunks)
+{
+ // Read a "file" which will need to be split into multiple whole chunks.
+    test_read_file_size = 256 * 1024 * 4;
+    test_max_buf_size = 0;
+    EXPECT_TRUE(run({"readfile"}));
+    test_verify_data();
+}
+
+TEST(Readfile, MultipleAndPartialChunks)
+{
+ // Read a "file" which will be split into some whole and one partial chunk.
+    test_read_file_size = 256 * 1024 * 2 + 256;
+    test_max_buf_size = 0;
+    EXPECT_TRUE(run({"readfile"}));
+    test_verify_data();
+}
+
+TEST(Readfile, OddSizedChunks)
+{
+    // Read a "file" in chunks that aren't nicely aligned.
+    test_read_file_size = 256 * 1024;
+    test_max_buf_size = 13;
+    EXPECT_TRUE(run({"readfile"}));
+    test_verify_data();
+}
+
+TEST(Readfile, CappedReadSize)
+{
+    // Read a "file", returning less than the requested amount of data.
+    test_read_file_size = 256 * 1024 * 2 + 256;
+    test_max_buf_size = 256;
+    EXPECT_TRUE(run({"readfile"}));
+    test_verify_data();
+}
+
+TEST(ReadfileDeathTest, BadFile)
+{
+    test_read_file_size = 16;
+    test_max_buf_size = 0;
+    EXPECT_EXIT(run({"readfile"}, true), ::testing::ExitedWithCode(2),
+            "Failed to write file");
+}

--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/27608
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I4286b1f92684f127c4885c29192c6c5244a61855
Gerrit-Change-Number: 27608
Gerrit-PatchSet: 1
Gerrit-Owner: Gabe Black <gabebl...@google.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
gem5-dev@gem5.org
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to