xref: /openbmc/gpioplus/test/handle.cpp (revision 8ff58122)
1 #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 
14 namespace gpioplus
15 {
16 namespace
17 {
18 
19 using testing::DoAll;
20 using testing::Return;
21 using testing::SaveArgPointee;
22 using testing::SetArgPointee;
23 
24 TEST(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 
34 TEST(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 
53 class 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 
75 TEST_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 
107 TEST_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 
114 TEST_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 
122 TEST_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 
149 class 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 
175 TEST_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 
187 TEST_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 
201 TEST_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 
208 TEST_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 
218 TEST_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 
224 TEST_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
236