xref: /openbmc/gpioplus/test/handle.cpp (revision 7ba248ad)
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