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