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