1 #include <linux/gpio.h>
2
3 #include <gpioplus/handle.hpp>
4 #include <gpioplus/test/sys.hpp>
5
6 #include <cerrno>
7 #include <cstdint>
8 #include <memory>
9 #include <stdexcept>
10 #include <string>
11 #include <system_error>
12 #include <vector>
13
14 #include <gmock/gmock.h>
15 #include <gtest/gtest.h>
16
17 namespace gpioplus
18 {
19 namespace
20 {
21
22 using testing::DoAll;
23 using testing::Return;
24 using testing::SaveArgPointee;
25 using testing::SetArgPointee;
26
TEST(HandleFlags,HandleFlagsFromLineFlags)27 TEST(HandleFlags, HandleFlagsFromLineFlags)
28 {
29 LineFlags line_flags(GPIOLINE_FLAG_KERNEL | GPIOLINE_FLAG_OPEN_DRAIN);
30 HandleFlags handle_flags(line_flags);
31 EXPECT_FALSE(handle_flags.output);
32 EXPECT_FALSE(handle_flags.active_low);
33 EXPECT_TRUE(handle_flags.open_drain);
34 EXPECT_FALSE(handle_flags.open_source);
35 }
36
TEST(HandleFlags,HandleFlagsToInt)37 TEST(HandleFlags, HandleFlagsToInt)
38 {
39 HandleFlags handle_flags;
40 handle_flags.output = false;
41 handle_flags.active_low = true;
42 handle_flags.open_drain = false;
43 handle_flags.open_source = false;
44 EXPECT_EQ(GPIOHANDLE_REQUEST_INPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
45 handle_flags.toInt());
46
47 handle_flags.output = true;
48 handle_flags.active_low = false;
49 handle_flags.open_drain = true;
50 handle_flags.open_source = true;
51 EXPECT_EQ(GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_OPEN_DRAIN |
52 GPIOHANDLE_REQUEST_OPEN_SOURCE,
53 handle_flags.toInt());
54 }
55
56 class HandleTest : public testing::Test
57 {
58 protected:
59 const int chip_fd = 1234;
60 const int handle_fd = 2345;
61 testing::StrictMock<test::SysMock> mock;
62 std::unique_ptr<Chip> chip;
63
SetUp()64 void SetUp()
65 {
66 EXPECT_CALL(mock, open(testing::_, testing::_))
67 .WillOnce(Return(chip_fd));
68 chip = std::make_unique<Chip>(0, &mock);
69 }
70
TearDown()71 void TearDown()
72 {
73 EXPECT_CALL(mock, close(chip_fd)).WillOnce(Return(0));
74 chip.reset();
75 }
76 };
77
TEST_F(HandleTest,ConstructSuccess)78 TEST_F(HandleTest, ConstructSuccess)
79 {
80 const std::string label{"test"};
81 std::vector<Handle::Line> lines;
82 for (uint32_t i = 0; i < 7; ++i)
83 {
84 lines.push_back({i, 1});
85 }
86
87 struct gpiohandle_request req, ret;
88 ret.fd = handle_fd;
89 EXPECT_CALL(mock, gpio_get_linehandle(chip_fd, testing::_))
90 .WillOnce(
91 DoAll(SaveArgPointee<1>(&req), SetArgPointee<1>(ret), Return(0)));
92 Handle handle(*chip, lines,
93 HandleFlags(LineFlags(GPIOLINE_FLAG_ACTIVE_LOW)),
94 label.c_str());
95
96 EXPECT_EQ(handle_fd, *handle.getFd());
97 EXPECT_EQ(GPIOHANDLE_REQUEST_INPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
98 req.flags);
99 EXPECT_EQ(label, req.consumer_label);
100 EXPECT_EQ(lines.size(), req.lines);
101 for (uint32_t i = 0; i < lines.size(); ++i)
102 {
103 EXPECT_EQ(i, req.lineoffsets[i]);
104 EXPECT_EQ(1, req.default_values[i]);
105 }
106
107 EXPECT_CALL(mock, close(handle_fd)).WillOnce(Return(0));
108 }
109
TEST_F(HandleTest,ConstructTooMany)110 TEST_F(HandleTest, ConstructTooMany)
111 {
112 const std::vector<Handle::Line> lines(GPIOHANDLES_MAX + 1);
113 EXPECT_THROW(Handle(*chip, lines, HandleFlags(), "too_many"),
114 std::runtime_error);
115 }
116
TEST_F(HandleTest,ConstructLabelTooLong)117 TEST_F(HandleTest, ConstructLabelTooLong)
118 {
119 const size_t large_size = sizeof(
120 reinterpret_cast<struct gpiohandle_request*>(NULL)->consumer_label);
121 EXPECT_THROW(Handle(*chip, {}, HandleFlags(), std::string(large_size, '1')),
122 std::invalid_argument);
123 }
124
TEST_F(HandleTest,ConstructError)125 TEST_F(HandleTest, ConstructError)
126 {
127 const std::string label{"error"};
128 std::vector<Handle::Line> lines;
129 for (uint32_t i = 0; i < 5; ++i)
130 {
131 lines.push_back({i, 0});
132 }
133
134 struct gpiohandle_request req;
135 EXPECT_CALL(mock, gpio_get_linehandle(chip_fd, testing::_))
136 .WillOnce(DoAll(SaveArgPointee<1>(&req), Return(-EINVAL)));
137 EXPECT_THROW(Handle(*chip, lines,
138 HandleFlags(LineFlags(GPIOLINE_FLAG_IS_OUT)),
139 label.c_str()),
140 std::runtime_error);
141
142 EXPECT_EQ(GPIOHANDLE_REQUEST_OUTPUT, req.flags);
143 EXPECT_EQ(label, req.consumer_label);
144 EXPECT_EQ(lines.size(), req.lines);
145 for (uint32_t i = 0; i < lines.size(); ++i)
146 {
147 EXPECT_EQ(i, req.lineoffsets[i]);
148 EXPECT_EQ(0, req.default_values[i]);
149 }
150 }
151
152 class HandleMethodTest : public HandleTest
153 {
154 protected:
155 std::unique_ptr<Handle> handle;
156 const std::vector<Handle::Line> lines{{1, 1}, {4, 0}};
157
SetUp()158 void SetUp()
159 {
160 HandleTest::SetUp();
161 struct gpiohandle_request ret;
162 ret.fd = handle_fd;
163 EXPECT_CALL(mock, gpio_get_linehandle(chip_fd, testing::_))
164 .WillOnce(DoAll(SetArgPointee<1>(ret), Return(0)));
165 handle = std::make_unique<Handle>(
166 *chip, lines, HandleFlags(LineFlags(GPIOLINE_FLAG_IS_OUT)),
167 "method");
168 }
169
TearDown()170 void TearDown()
171 {
172 EXPECT_CALL(mock, close(handle_fd)).WillOnce(Return(0));
173 handle.reset();
174 HandleTest::TearDown();
175 }
176 };
177
TEST_F(HandleMethodTest,GetValuesRet)178 TEST_F(HandleMethodTest, GetValuesRet)
179 {
180 const std::vector<uint8_t> expected{0, 0};
181 struct gpiohandle_data ret;
182 ret.values[0] = 0;
183 ret.values[1] = 0;
184
185 EXPECT_CALL(mock, gpiohandle_get_line_values(handle_fd, testing::_))
186 .WillOnce(DoAll(SetArgPointee<1>(ret), Return(0)));
187 EXPECT_EQ(expected, handle->getValues());
188 }
189
TEST_F(HandleMethodTest,GetValuesSuccess)190 TEST_F(HandleMethodTest, GetValuesSuccess)
191 {
192 const std::vector<uint8_t> expected{1, 1};
193 struct gpiohandle_data ret;
194 ret.values[0] = 1;
195 ret.values[1] = 1;
196
197 EXPECT_CALL(mock, gpiohandle_get_line_values(handle_fd, testing::_))
198 .WillOnce(DoAll(SetArgPointee<1>(ret), Return(0)));
199 std::vector<uint8_t> output;
200 handle->getValues(output);
201 EXPECT_EQ(expected, output);
202 }
203
TEST_F(HandleMethodTest,GetValuesFailure)204 TEST_F(HandleMethodTest, GetValuesFailure)
205 {
206 EXPECT_CALL(mock, gpiohandle_get_line_values(handle_fd, testing::_))
207 .WillOnce(Return(-EINVAL));
208 EXPECT_THROW(handle->getValues(), std::system_error);
209 }
210
TEST_F(HandleMethodTest,SetValuesSuccess)211 TEST_F(HandleMethodTest, SetValuesSuccess)
212 {
213 struct gpiohandle_data req;
214 EXPECT_CALL(mock, gpiohandle_set_line_values(handle_fd, testing::_))
215 .WillOnce(DoAll(SaveArgPointee<1>(&req), Return(0)));
216 handle->setValues({0, 1});
217 EXPECT_EQ(0, req.values[0]);
218 EXPECT_EQ(1, req.values[1]);
219 }
220
TEST_F(HandleMethodTest,SetValuesInvalid)221 TEST_F(HandleMethodTest, SetValuesInvalid)
222 {
223 EXPECT_THROW(handle->setValues({1}), std::runtime_error);
224 EXPECT_THROW(handle->setValues({1, 0, 1}), std::runtime_error);
225 }
226
TEST_F(HandleMethodTest,SetValuesFailure)227 TEST_F(HandleMethodTest, SetValuesFailure)
228 {
229 struct gpiohandle_data req;
230 EXPECT_CALL(mock, gpiohandle_set_line_values(handle_fd, testing::_))
231 .WillOnce(DoAll(SaveArgPointee<1>(&req), Return(-EINVAL)));
232 EXPECT_THROW(handle->setValues({1, 1}), std::system_error);
233 EXPECT_EQ(1, req.values[0]);
234 EXPECT_EQ(1, req.values[1]);
235 }
236
237 } // namespace
238 } // namespace gpioplus
239