2 * Copyright 2020 Google Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met: redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer;
8 * redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution;
11 * neither the name of the copyright holders nor the names of its
12 * contributors may be used to endorse or promote products derived from
13 * this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <gtest/gtest.h>
34 #include "dispatch_table.hh"
36 uint64_t test_read_file_size
;
37 uint64_t test_max_buf_size
;
39 uint64_t test_total_read
;
42 test_m5_read_file(void *buffer
, uint64_t len
, uint64_t offset
)
44 // The "file" we're reading is just a series of incrementing 32 bit
47 // If the buffer is entirely past the end of our "file", return 0.
48 if (offset
>= test_read_file_size
)
51 // If the buffer extends beyond our "file" truncate it.
52 if (offset
+ len
> test_read_file_size
)
53 len
= test_read_file_size
- offset
;
55 // If more data was requested than we want to send at once, truncate len.
56 if (test_max_buf_size
&& len
> test_max_buf_size
)
57 len
= test_max_buf_size
;
59 int chunk_size
= sizeof(uint32_t);
61 // How much of len is still unaccounted for.
62 uint64_t remaining
= len
;
64 // How much overlaps with the preceeding chunk?
65 int at_start
= chunk_size
- (offset
% chunk_size
);
66 // If we don't even cover the entire previous chunk...
69 remaining
-= at_start
;
71 // How much overlaps with the following chunk?
72 int at_end
= remaining
% chunk_size
;
75 // The number of chunks are the number we cover fully, plus one for each
76 // end were we partially overlap.
77 uint64_t num_chunks
= remaining
/ chunk_size
+
78 (at_start
? 1 : 0) + (at_end
? 1 : 0);
80 // Build this part of the file.
81 uint32_t *chunks
= new uint32_t [num_chunks
];
83 uint32_t chunk_idx
= offset
/ chunk_size
;
84 for (uint64_t i
= 0; i
< num_chunks
; i
++)
85 chunks
[i
] = chunk_idx
++;
87 // Copy out to the requested buffer.
88 memcpy(buffer
, ((uint8_t *)chunks
) + (chunk_size
- at_start
), len
);
93 test_total_read
+= len
;
97 DispatchTable dt
= { .m5_read_file
= &test_m5_read_file
};
99 std::string cout_output
;
102 run(std::initializer_list
<std::string
> arg_args
, bool bad_file
=false)
108 // Redirect cout into a stringstream.
109 std::stringstream buffer
;
110 std::streambuf
*orig
= std::cout
.rdbuf(buffer
.rdbuf());
112 // Simulate a problem writing to cout.
114 std::cout
.setstate(std::cout
.badbit
);
116 bool res
= Command::run(dt
, args
);
121 // Capture the contents of the stringstream and restore cout.
122 cout_output
= buffer
.str();
123 std::cout
.rdbuf(orig
);
131 EXPECT_EQ(test_total_read
, test_read_file_size
);
132 EXPECT_EQ(cout_output
.size(), test_read_file_size
);
134 auto *data32
= (const uint32_t *)cout_output
.data();
135 uint64_t len
= cout_output
.size();
137 int chunk_size
= sizeof(uint32_t);
139 uint64_t num_chunks
= len
/ chunk_size
;
140 int leftovers
= len
% chunk_size
;
143 for (chunk_idx
= 0; chunk_idx
< num_chunks
; chunk_idx
++)
144 EXPECT_EQ(*data32
++, chunk_idx
);
147 EXPECT_EQ(memcmp(&chunk_idx
, data32
, leftovers
), 0);
150 TEST(Readfile
, OneArgument
)
152 // Call with an argument.
153 EXPECT_FALSE(run({"readfile", "foo"}));
154 EXPECT_EQ(test_total_read
, 0);
157 TEST(Readfile
, SmallFile
)
159 // Read a small "file".
160 test_read_file_size
= 16;
161 test_max_buf_size
= 0;
162 EXPECT_TRUE(run({"readfile"}));
166 TEST(Readfile
, MultipleChunks
)
168 // Read a "file" which will need to be split into multiple whole chunks.
169 test_read_file_size
= 256 * 1024 * 4;
170 test_max_buf_size
= 0;
171 EXPECT_TRUE(run({"readfile"}));
175 TEST(Readfile
, MultipleAndPartialChunks
)
177 // Read a "file" which will be split into some whole and one partial chunk.
178 test_read_file_size
= 256 * 1024 * 2 + 256;
179 test_max_buf_size
= 0;
180 EXPECT_TRUE(run({"readfile"}));
184 TEST(Readfile
, OddSizedChunks
)
186 // Read a "file" in chunks that aren't nicely aligned.
187 test_read_file_size
= 256 * 1024;
188 test_max_buf_size
= 13;
189 EXPECT_TRUE(run({"readfile"}));
193 TEST(Readfile
, CappedReadSize
)
195 // Read a "file", returning less than the requested amount of data.
196 test_read_file_size
= 256 * 1024 * 2 + 256;
197 test_max_buf_size
= 256;
198 EXPECT_TRUE(run({"readfile"}));
202 TEST(ReadfileDeathTest
, BadFile
)
204 test_read_file_size
= 16;
205 test_max_buf_size
= 0;
206 EXPECT_EXIT(run({"readfile"}, true), ::testing::ExitedWithCode(2),
207 "Failed to write file");