tools: add missing io handler unittests

Signed-off-by: Patrick Venture <venture@google.com>
Change-Id: I78dfb794969fc8b34bdd9093745bc625581069dd
diff --git a/tools/test/io_unittest.cpp b/tools/test/io_unittest.cpp
new file mode 100644
index 0000000..492c699
--- /dev/null
+++ b/tools/test/io_unittest.cpp
@@ -0,0 +1,178 @@
+#include "internal_sys_mock.hpp"
+#include "io.hpp"
+
+#include <sys/mman.h>
+
+#include <memory>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace host_tool
+{
+namespace
+{
+
+using ::testing::_;
+using ::testing::Eq;
+using ::testing::Return;
+using ::testing::StrEq;
+
+class DevMemTest : public ::testing::Test
+{
+  protected:
+    DevMemTest() : devmem(std::make_unique<DevMemDevice>(&sys_mock))
+    {}
+
+    internal::InternalSysMock sys_mock;
+    std::unique_ptr<DevMemDevice> devmem;
+};
+
+TEST_F(DevMemTest, OpenFromReadFails)
+{
+    EXPECT_CALL(sys_mock, open(_, _)).WillOnce(Return(-1));
+
+    char destination;
+    EXPECT_FALSE(devmem->read(/*offset*/ 0, /*length*/ 1, &destination));
+}
+
+TEST_F(DevMemTest, MmapFromReadFails)
+{
+    int fd = 1;
+    EXPECT_CALL(sys_mock, open(_, _)).WillOnce(Return(fd));
+    EXPECT_CALL(sys_mock, getpagesize()).WillOnce(Return(4096));
+    EXPECT_CALL(sys_mock, mmap(0, _, _, _, fd, _)).WillOnce(Return(MAP_FAILED));
+    EXPECT_CALL(sys_mock, close(fd));
+
+    char destination;
+    EXPECT_FALSE(devmem->read(/*offset*/ 0, /*length*/ 1, &destination));
+}
+
+TEST_F(DevMemTest, CopiesOutOfMmap)
+{
+    int fd = 1;
+    char source = 'a';
+    EXPECT_CALL(sys_mock, open(_, _)).WillOnce(Return(fd));
+    EXPECT_CALL(sys_mock, getpagesize()).WillOnce(Return(4096));
+    EXPECT_CALL(sys_mock, mmap(0, _, _, _, fd, _)).WillOnce(Return(&source));
+    EXPECT_CALL(sys_mock, munmap(_, _));
+    EXPECT_CALL(sys_mock, close(fd));
+
+    char destination = 'b';
+    EXPECT_TRUE(devmem->read(/*offset*/ 0, /*length*/ 1, &destination));
+    EXPECT_THAT(destination, Eq('a'));
+}
+
+TEST_F(DevMemTest, OpenFromWriteFails)
+{
+    EXPECT_CALL(sys_mock, open(_, _)).WillOnce(Return(-1));
+
+    char source;
+    EXPECT_FALSE(devmem->write(/*offset*/ 0, /*length*/ 1, &source));
+}
+
+TEST_F(DevMemTest, MmapFromWriteFails)
+{
+    int fd = 1;
+    EXPECT_CALL(sys_mock, open(_, _)).WillOnce(Return(fd));
+    EXPECT_CALL(sys_mock, getpagesize()).WillOnce(Return(4096));
+    EXPECT_CALL(sys_mock, mmap(0, _, _, _, fd, _)).WillOnce(Return(MAP_FAILED));
+    EXPECT_CALL(sys_mock, close(fd));
+
+    char source;
+    EXPECT_FALSE(devmem->write(/*offset*/ 0, /*length*/ 1, &source));
+}
+
+TEST_F(DevMemTest, CopiesIntoMmap)
+{
+    int fd = 1;
+    char destination = 'b';
+    EXPECT_CALL(sys_mock, open(_, _)).WillOnce(Return(fd));
+    EXPECT_CALL(sys_mock, getpagesize()).WillOnce(Return(4096));
+    EXPECT_CALL(sys_mock, mmap(0, _, _, _, fd, _))
+        .WillOnce(Return(&destination));
+    EXPECT_CALL(sys_mock, munmap(_, _));
+    EXPECT_CALL(sys_mock, close(fd));
+
+    char source = 'a';
+    EXPECT_TRUE(devmem->write(/*offset*/ 0, /*length*/ 1, &source));
+    EXPECT_THAT(destination, Eq('a'));
+}
+
+class PpcMemTest : public ::testing::Test
+{
+  protected:
+    static constexpr char path[] = "/dev/fun";
+
+    PpcMemTest() : devmem(std::make_unique<PpcMemDevice>(path, &sys_mock))
+    {}
+
+    internal::InternalSysMock sys_mock;
+    std::unique_ptr<PpcMemDevice> devmem;
+};
+
+TEST_F(PpcMemTest, OpenFromReadFails)
+{
+    EXPECT_CALL(sys_mock, open(StrEq(path), _)).WillOnce(Return(-1));
+
+    char destination = 'b';
+    EXPECT_FALSE(devmem->read(/*offset*/ 0, /*length*/ 1, &destination));
+}
+
+TEST_F(PpcMemTest, PreadFails)
+{
+    int fd = 1;
+    EXPECT_CALL(sys_mock, open(StrEq(path), _)).WillOnce(Return(fd));
+    EXPECT_CALL(sys_mock, pread(fd, _, 1, 0)).WillOnce(Return(-1));
+
+    char destination = 'b';
+    EXPECT_FALSE(devmem->read(/*offset*/ 0, /*length*/ 1, &destination));
+}
+
+TEST_F(PpcMemTest, PreadReadWorks)
+{
+    int fd = 1;
+    EXPECT_CALL(sys_mock, open(StrEq(path), _)).WillOnce(Return(fd));
+    EXPECT_CALL(sys_mock, pread(fd, _, 1, 0)).WillOnce(Return(0));
+    EXPECT_CALL(sys_mock, close(fd));
+
+    /* Test does not validate byte is copied because that's part of pread and
+     * not the code.
+     */
+    char destination = 'b';
+    EXPECT_TRUE(devmem->read(/*offset*/ 0, /*length*/ 1, &destination));
+}
+
+TEST_F(PpcMemTest, OpenFromWriteFails)
+{
+    EXPECT_CALL(sys_mock, open(StrEq(path), _)).WillOnce(Return(-1));
+
+    char source = 'a';
+    EXPECT_FALSE(devmem->write(/*offset*/ 0, /*length*/ 1, &source));
+}
+
+TEST_F(PpcMemTest, PwriteFails)
+{
+    int fd = 1;
+    EXPECT_CALL(sys_mock, open(StrEq(path), _)).WillOnce(Return(fd));
+    EXPECT_CALL(sys_mock, pwrite(fd, _, 1, 0)).WillOnce(Return(-1));
+
+    char source = 'a';
+    EXPECT_FALSE(devmem->write(/*offset*/ 0, /*length*/ 1, &source));
+}
+
+TEST_F(PpcMemTest, PwriteWorks)
+{
+    int fd = 1;
+    EXPECT_CALL(sys_mock, open(StrEq(path), _)).WillOnce(Return(fd));
+    EXPECT_CALL(sys_mock, pwrite(fd, _, 1, 0)).WillOnce(Return(0));
+
+    /* Test does not validate byte is copied because that's part of pwrite and
+     * not the code.
+     */
+    char source = 'a';
+    EXPECT_TRUE(devmem->write(/*offset*/ 0, /*length*/ 1, &source));
+}
+
+} // namespace
+} // namespace host_tool