1 #include "internal_sys_mock.hpp"
2 #include "io.hpp"
3 
4 #include <sys/mman.h>
5 
6 #include <memory>
7 
8 #include <gmock/gmock.h>
9 #include <gtest/gtest.h>
10 
11 namespace host_tool
12 {
13 namespace
14 {
15 
16 using ::testing::_;
17 using ::testing::Eq;
18 using ::testing::Return;
19 using ::testing::StrEq;
20 
21 class DevMemTest : public ::testing::Test
22 {
23   protected:
24     DevMemTest() : devmem(std::make_unique<DevMemDevice>(&sys_mock)) {}
25 
26     internal::InternalSysMock sys_mock;
27     std::unique_ptr<DevMemDevice> devmem;
28 };
29 
30 TEST_F(DevMemTest, OpenFromReadFails)
31 {
32     EXPECT_CALL(sys_mock, open(_, _)).WillOnce(Return(-1));
33 
34     char destination;
35     EXPECT_FALSE(devmem->read(/*offset*/ 0, /*length*/ 1, &destination));
36 }
37 
38 TEST_F(DevMemTest, MmapFromReadFails)
39 {
40     int fd = 1;
41     EXPECT_CALL(sys_mock, open(_, _)).WillOnce(Return(fd));
42     EXPECT_CALL(sys_mock, getpagesize()).WillOnce(Return(4096));
43     EXPECT_CALL(sys_mock, mmap(0, _, _, _, fd, _)).WillOnce(Return(MAP_FAILED));
44     EXPECT_CALL(sys_mock, close(fd));
45 
46     char destination;
47     EXPECT_FALSE(devmem->read(/*offset*/ 0, /*length*/ 1, &destination));
48 }
49 
50 TEST_F(DevMemTest, CopiesOutOfMmap)
51 {
52     int fd = 1;
53     char source = 'a';
54     EXPECT_CALL(sys_mock, open(_, _)).WillOnce(Return(fd));
55     EXPECT_CALL(sys_mock, getpagesize()).WillOnce(Return(4096));
56     EXPECT_CALL(sys_mock, mmap(0, _, _, _, fd, _)).WillOnce(Return(&source));
57     EXPECT_CALL(sys_mock, munmap(_, _));
58     EXPECT_CALL(sys_mock, close(fd));
59 
60     char destination = 'b';
61     EXPECT_TRUE(devmem->read(/*offset*/ 0, /*length*/ 1, &destination));
62     EXPECT_THAT(destination, Eq('a'));
63 }
64 
65 TEST_F(DevMemTest, OpenFromWriteFails)
66 {
67     EXPECT_CALL(sys_mock, open(_, _)).WillOnce(Return(-1));
68 
69     char source;
70     EXPECT_FALSE(devmem->write(/*offset*/ 0, /*length*/ 1, &source));
71 }
72 
73 TEST_F(DevMemTest, MmapFromWriteFails)
74 {
75     int fd = 1;
76     EXPECT_CALL(sys_mock, open(_, _)).WillOnce(Return(fd));
77     EXPECT_CALL(sys_mock, getpagesize()).WillOnce(Return(4096));
78     EXPECT_CALL(sys_mock, mmap(0, _, _, _, fd, _)).WillOnce(Return(MAP_FAILED));
79     EXPECT_CALL(sys_mock, close(fd));
80 
81     char source;
82     EXPECT_FALSE(devmem->write(/*offset*/ 0, /*length*/ 1, &source));
83 }
84 
85 TEST_F(DevMemTest, CopiesIntoMmap)
86 {
87     int fd = 1;
88     char destination = 'b';
89     EXPECT_CALL(sys_mock, open(_, _)).WillOnce(Return(fd));
90     EXPECT_CALL(sys_mock, getpagesize()).WillOnce(Return(4096));
91     EXPECT_CALL(sys_mock, mmap(0, _, _, _, fd, _))
92         .WillOnce(Return(&destination));
93     EXPECT_CALL(sys_mock, munmap(_, _));
94     EXPECT_CALL(sys_mock, close(fd));
95 
96     char source = 'a';
97     EXPECT_TRUE(devmem->write(/*offset*/ 0, /*length*/ 1, &source));
98     EXPECT_THAT(destination, Eq('a'));
99 }
100 
101 class PpcMemTest : public ::testing::Test
102 {
103   protected:
104     static constexpr char path[] = "/dev/fun";
105 
106     PpcMemTest() : devmem(std::make_unique<PpcMemDevice>(path, &sys_mock)) {}
107 
108     internal::InternalSysMock sys_mock;
109     std::unique_ptr<PpcMemDevice> devmem;
110 };
111 
112 TEST_F(PpcMemTest, OpenFromReadFails)
113 {
114     EXPECT_CALL(sys_mock, open(StrEq(path), _)).WillOnce(Return(-1));
115 
116     char destination = 'b';
117     EXPECT_FALSE(devmem->read(/*offset*/ 0, /*length*/ 1, &destination));
118 }
119 
120 TEST_F(PpcMemTest, PreadFails)
121 {
122     int fd = 1;
123     EXPECT_CALL(sys_mock, open(StrEq(path), _)).WillOnce(Return(fd));
124     EXPECT_CALL(sys_mock, pread(fd, _, 1, 0)).WillOnce(Return(-1));
125 
126     char destination = 'b';
127     EXPECT_FALSE(devmem->read(/*offset*/ 0, /*length*/ 1, &destination));
128 }
129 
130 TEST_F(PpcMemTest, PreadReadWorks)
131 {
132     int fd = 1;
133     EXPECT_CALL(sys_mock, open(StrEq(path), _)).WillOnce(Return(fd));
134     EXPECT_CALL(sys_mock, pread(fd, _, 1, 0)).WillOnce(Return(0));
135     EXPECT_CALL(sys_mock, close(fd));
136 
137     /* Test does not validate byte is copied because that's part of pread and
138      * not the code.
139      */
140     char destination = 'b';
141     EXPECT_TRUE(devmem->read(/*offset*/ 0, /*length*/ 1, &destination));
142 }
143 
144 TEST_F(PpcMemTest, OpenFromWriteFails)
145 {
146     EXPECT_CALL(sys_mock, open(StrEq(path), _)).WillOnce(Return(-1));
147 
148     char source = 'a';
149     EXPECT_FALSE(devmem->write(/*offset*/ 0, /*length*/ 1, &source));
150 }
151 
152 TEST_F(PpcMemTest, PwriteFails)
153 {
154     int fd = 1;
155     EXPECT_CALL(sys_mock, open(StrEq(path), _)).WillOnce(Return(fd));
156     EXPECT_CALL(sys_mock, pwrite(fd, _, 1, 0)).WillOnce(Return(-1));
157 
158     char source = 'a';
159     EXPECT_FALSE(devmem->write(/*offset*/ 0, /*length*/ 1, &source));
160 }
161 
162 TEST_F(PpcMemTest, PwriteWorks)
163 {
164     int fd = 1;
165     EXPECT_CALL(sys_mock, open(StrEq(path), _)).WillOnce(Return(fd));
166     EXPECT_CALL(sys_mock, pwrite(fd, _, 1, 0)).WillOnce(Return(0));
167 
168     /* Test does not validate byte is copied because that's part of pwrite and
169      * not the code.
170      */
171     char source = 'a';
172     EXPECT_TRUE(devmem->write(/*offset*/ 0, /*length*/ 1, &source));
173 }
174 
175 } // namespace
176 } // namespace host_tool
177