fd/ops: Add readAllFixed()
This is similar to readAll in that it guarantees to read the file all
the way to EOF, but it allows you to provide a fixed buffer space to
store the file contents. This is useful if you know the bounds of the
file and don't mind preallocating space for them.
This is generally the preferred candidate for reading all of a file, as
you should know the bounds of the data you would like to read if you are
reading the entire thing.
Change-Id: I72a9e2fb7ee84d4e37963c8dcdff3e9e351e2339
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/test/fd/ops.cpp b/test/fd/ops.cpp
index 2855edd..708a0ff 100644
--- a/test/fd/ops.cpp
+++ b/test/fd/ops.cpp
@@ -248,4 +248,108 @@
stdplus::hton(int32_t{0x05060708})}));
}
+TEST(ReadAllFixed, SuccessEmpty)
+{
+ testing::StrictMock<FdMock> fd;
+ {
+ testing::InSequence seq;
+ EXPECT_CALL(fd, read(_))
+ .WillRepeatedly(testing::Throw(exception::Eof("test")));
+ }
+ std::array<char, 16> buf;
+ auto ret = readAllFixed(fd, buf);
+ EXPECT_EQ(std::string_view(ret.begin(), ret.end()), "");
+}
+
+TEST(ReadAllFixed, Success)
+{
+ testing::StrictMock<FdMock> fd;
+ {
+ testing::InSequence seq;
+ EXPECT_CALL(fd, read(SizeIs(Ge(4)))).WillOnce(readSv("alph"));
+ EXPECT_CALL(fd, read(SizeIs(Ge(2)))).WillOnce(readSv("a "));
+ EXPECT_CALL(fd, read(SizeIs(Ge(3)))).WillOnce(readSv("one"));
+ EXPECT_CALL(fd, read(_))
+ .WillRepeatedly(testing::Throw(exception::Eof("test")));
+ }
+ std::array<char, 16> buf;
+ auto ret = readAllFixed(fd, buf);
+ EXPECT_EQ(std::string_view(ret.begin(), ret.end()), "alpha one");
+}
+
+TEST(ReadAllFixed, Block)
+{
+ testing::StrictMock<FdMock> fd;
+ {
+ testing::InSequence seq;
+ EXPECT_CALL(fd, read(SizeIs(Ge(4)))).WillOnce(readSv("alph"));
+ EXPECT_CALL(fd, read(SizeIs(Ge(2)))).WillOnce(readSv("a "));
+ EXPECT_CALL(fd, read(_)).WillRepeatedly(readSv(""));
+ }
+ std::array<char, 16> buf;
+ EXPECT_THROW(readAllFixed(fd, buf), exception::WouldBlock);
+}
+
+TEST(ReadAllFixed, NotEnough)
+{
+ testing::StrictMock<FdMock> fd;
+ {
+ testing::InSequence seq;
+ EXPECT_CALL(fd, read(SizeIs(Ge(5))))
+ .WillOnce(readSv("\x01\x02\x03\x04\x05"));
+ EXPECT_CALL(fd, read(SizeIs(Ge(1)))).WillOnce(readSv("\x06"));
+ EXPECT_CALL(fd, read(_)).WillRepeatedly(readSv(""));
+ }
+ std::array<int32_t, 2> buf;
+ EXPECT_THROW(readAllFixed(fd, buf), exception::Incomplete);
+}
+
+TEST(ReadAllFixed, NotEnoughEof)
+{
+ testing::StrictMock<FdMock> fd;
+ {
+ testing::InSequence seq;
+ EXPECT_CALL(fd, read(SizeIs(Ge(5))))
+ .WillOnce(readSv("\x01\x02\x03\x04\x05"));
+ EXPECT_CALL(fd, read(SizeIs(Ge(1)))).WillOnce(readSv("\x06"));
+ EXPECT_CALL(fd, read(_))
+ .WillRepeatedly(testing::Throw(exception::Eof("test")));
+ }
+ std::array<int32_t, 2> buf;
+ EXPECT_THROW(readAllFixed(fd, buf), exception::Incomplete);
+}
+
+TEST(ReadAllFixed, EnoughInt)
+{
+ testing::StrictMock<FdMock> fd;
+ {
+ testing::InSequence seq;
+ EXPECT_CALL(fd, read(SizeIs(Ge(5))))
+ .WillOnce(readSv("\x01\x02\x03\x04\x05"));
+ EXPECT_CALL(fd, read(SizeIs(Ge(1)))).WillOnce(readSv("\x06"));
+ EXPECT_CALL(fd, read(SizeIs(Ge(2)))).WillOnce(readSv("\x07\x08"));
+ EXPECT_CALL(fd, read(_))
+ .WillRepeatedly(testing::Throw(exception::Eof("test")));
+ }
+ std::array<int32_t, 2> buf;
+ EXPECT_THAT(readAllFixed(fd, buf),
+ testing::ElementsAre(stdplus::hton(int32_t{0x01020304}),
+ stdplus::hton(int32_t{0x05060708})));
+}
+
+TEST(ReadAllFixed, TooMuch)
+{
+ testing::StrictMock<FdMock> fd;
+ {
+ testing::InSequence seq;
+ EXPECT_CALL(fd, read(SizeIs(Ge(5))))
+ .WillOnce(readSv("\x01\x02\x03\x04\x05"));
+ EXPECT_CALL(fd, read(SizeIs(Ge(1)))).WillOnce(readSv("\x06"));
+ EXPECT_CALL(fd, read(SizeIs(Ge(2)))).WillOnce(readSv("\x07\x08"));
+ EXPECT_CALL(fd, read(SizeIs(Ge(1)))).WillOnce(readSv("\x09"));
+ }
+ std::array<int32_t, 2> buf;
+ EXPECT_THROW(readAllFixed(fd, buf), std::system_error);
+}
+
} // namespace stdplus::fd