|  | #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 |