The C++ versions of those functions are technically in the std namespace, and while they may work without it (the C version leaking through from somewhere?), they should still use it. Change-Id: Ib53a7f0c41d7f5776221e7661c616ea51e8ed528 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/31834 Tested-by: kokoro <noreply+kokoro@google.com> Maintainer: Bobby R. Bruce <bbruce@ucdavis.edu> Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br>
210 lines
6.1 KiB
C++
210 lines
6.1 KiB
C++
/*
|
|
* 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 <cstring>
|
|
#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.
|
|
std::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");
|
|
}
|