| #include <cerrno> |
| #include <cstdint> |
| #include <gmock/gmock.h> |
| #include <gpioplus/handle.hpp> |
| #include <gpioplus/test/sys.hpp> |
| #include <gtest/gtest.h> |
| #include <linux/gpio.h> |
| #include <memory> |
| #include <stdexcept> |
| #include <string> |
| #include <system_error> |
| #include <vector> |
| |
| namespace gpioplus |
| { |
| namespace |
| { |
| |
| using testing::DoAll; |
| using testing::Return; |
| using testing::SaveArgPointee; |
| using testing::SetArgPointee; |
| |
| TEST(HandleFlags, HandleFlagsFromLineFlags) |
| { |
| LineFlags line_flags(GPIOLINE_FLAG_KERNEL | GPIOLINE_FLAG_OPEN_DRAIN); |
| HandleFlags handle_flags(line_flags); |
| EXPECT_FALSE(handle_flags.output); |
| EXPECT_FALSE(handle_flags.active_low); |
| EXPECT_TRUE(handle_flags.open_drain); |
| EXPECT_FALSE(handle_flags.open_source); |
| } |
| |
| TEST(HandleFlags, HandleFlagsToInt) |
| { |
| HandleFlags handle_flags; |
| handle_flags.output = false; |
| handle_flags.active_low = true; |
| handle_flags.open_drain = false; |
| handle_flags.open_source = false; |
| EXPECT_EQ(GPIOHANDLE_REQUEST_INPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW, |
| handle_flags.toInt()); |
| |
| handle_flags.output = true; |
| handle_flags.active_low = false; |
| handle_flags.open_drain = true; |
| handle_flags.open_source = true; |
| EXPECT_EQ(GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_OPEN_DRAIN | |
| GPIOHANDLE_REQUEST_OPEN_SOURCE, |
| handle_flags.toInt()); |
| } |
| |
| class HandleTest : public testing::Test |
| { |
| protected: |
| const int chip_fd = 1234; |
| const int handle_fd = 2345; |
| testing::StrictMock<test::SysMock> mock; |
| std::unique_ptr<Chip> chip; |
| |
| void SetUp() |
| { |
| EXPECT_CALL(mock, open(testing::_, testing::_)) |
| .WillOnce(Return(chip_fd)); |
| chip = std::make_unique<Chip>(0, &mock); |
| } |
| |
| void TearDown() |
| { |
| EXPECT_CALL(mock, close(chip_fd)).WillOnce(Return(0)); |
| chip.reset(); |
| } |
| }; |
| |
| TEST_F(HandleTest, ConstructSuccess) |
| { |
| const std::string label{"test"}; |
| std::vector<Handle::Line> lines; |
| for (uint32_t i = 0; i < 7; ++i) |
| { |
| lines.push_back({i, 1}); |
| } |
| |
| struct gpiohandle_request req, ret; |
| ret.fd = handle_fd; |
| EXPECT_CALL(mock, gpio_get_linehandle(chip_fd, testing::_)) |
| .WillOnce( |
| DoAll(SaveArgPointee<1>(&req), SetArgPointee<1>(ret), Return(0))); |
| Handle handle(*chip, lines, |
| HandleFlags(LineFlags(GPIOLINE_FLAG_ACTIVE_LOW)), |
| label.c_str()); |
| |
| EXPECT_EQ(handle_fd, *handle.getFd()); |
| EXPECT_EQ(GPIOHANDLE_REQUEST_INPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW, |
| req.flags); |
| EXPECT_EQ(label, req.consumer_label); |
| EXPECT_EQ(lines.size(), req.lines); |
| for (uint32_t i = 0; i < lines.size(); ++i) |
| { |
| EXPECT_EQ(i, req.lineoffsets[i]); |
| EXPECT_EQ(1, req.default_values[i]); |
| } |
| |
| EXPECT_CALL(mock, close(handle_fd)).WillOnce(Return(0)); |
| } |
| |
| TEST_F(HandleTest, ConstructTooMany) |
| { |
| const std::vector<Handle::Line> lines(GPIOHANDLES_MAX + 1); |
| EXPECT_THROW(Handle(*chip, lines, HandleFlags(), "too_many"), |
| std::runtime_error); |
| } |
| |
| TEST_F(HandleTest, ConstructLabelTooLong) |
| { |
| const size_t large_size = sizeof( |
| reinterpret_cast<struct gpiohandle_request*>(NULL)->consumer_label); |
| EXPECT_THROW(Handle(*chip, {}, HandleFlags(), std::string(large_size, '1')), |
| std::invalid_argument); |
| } |
| |
| TEST_F(HandleTest, ConstructError) |
| { |
| const std::string label{"error"}; |
| std::vector<Handle::Line> lines; |
| for (uint32_t i = 0; i < 5; ++i) |
| { |
| lines.push_back({i, 0}); |
| } |
| |
| struct gpiohandle_request req; |
| EXPECT_CALL(mock, gpio_get_linehandle(chip_fd, testing::_)) |
| .WillOnce(DoAll(SaveArgPointee<1>(&req), Return(-EINVAL))); |
| EXPECT_THROW(Handle(*chip, lines, |
| HandleFlags(LineFlags(GPIOLINE_FLAG_IS_OUT)), |
| label.c_str()), |
| std::runtime_error); |
| |
| EXPECT_EQ(GPIOHANDLE_REQUEST_OUTPUT, req.flags); |
| EXPECT_EQ(label, req.consumer_label); |
| EXPECT_EQ(lines.size(), req.lines); |
| for (uint32_t i = 0; i < lines.size(); ++i) |
| { |
| EXPECT_EQ(i, req.lineoffsets[i]); |
| EXPECT_EQ(0, req.default_values[i]); |
| } |
| } |
| |
| class HandleMethodTest : public HandleTest |
| { |
| protected: |
| std::unique_ptr<Handle> handle; |
| const std::vector<Handle::Line> lines{{1, 1}, {4, 0}}; |
| |
| void SetUp() |
| { |
| HandleTest::SetUp(); |
| struct gpiohandle_request ret; |
| ret.fd = handle_fd; |
| EXPECT_CALL(mock, gpio_get_linehandle(chip_fd, testing::_)) |
| .WillOnce(DoAll(SetArgPointee<1>(ret), Return(0))); |
| handle = std::make_unique<Handle>( |
| *chip, lines, HandleFlags(LineFlags(GPIOLINE_FLAG_IS_OUT)), |
| "method"); |
| } |
| |
| void TearDown() |
| { |
| EXPECT_CALL(mock, close(handle_fd)).WillOnce(Return(0)); |
| handle.reset(); |
| HandleTest::TearDown(); |
| } |
| }; |
| |
| TEST_F(HandleMethodTest, GetValuesRet) |
| { |
| const std::vector<uint8_t> expected{0, 0}; |
| struct gpiohandle_data ret; |
| ret.values[0] = 0; |
| ret.values[1] = 0; |
| |
| EXPECT_CALL(mock, gpiohandle_get_line_values(handle_fd, testing::_)) |
| .WillOnce(DoAll(SetArgPointee<1>(ret), Return(0))); |
| EXPECT_EQ(expected, handle->getValues()); |
| } |
| |
| TEST_F(HandleMethodTest, GetValuesSuccess) |
| { |
| const std::vector<uint8_t> expected{1, 1}; |
| struct gpiohandle_data ret; |
| ret.values[0] = 1; |
| ret.values[1] = 1; |
| |
| EXPECT_CALL(mock, gpiohandle_get_line_values(handle_fd, testing::_)) |
| .WillOnce(DoAll(SetArgPointee<1>(ret), Return(0))); |
| std::vector<uint8_t> output; |
| handle->getValues(output); |
| EXPECT_EQ(expected, output); |
| } |
| |
| TEST_F(HandleMethodTest, GetValuesFailure) |
| { |
| EXPECT_CALL(mock, gpiohandle_get_line_values(handle_fd, testing::_)) |
| .WillOnce(Return(-EINVAL)); |
| EXPECT_THROW(handle->getValues(), std::system_error); |
| } |
| |
| TEST_F(HandleMethodTest, SetValuesSuccess) |
| { |
| struct gpiohandle_data req; |
| EXPECT_CALL(mock, gpiohandle_set_line_values(handle_fd, testing::_)) |
| .WillOnce(DoAll(SaveArgPointee<1>(&req), Return(0))); |
| handle->setValues({0, 1}); |
| EXPECT_EQ(0, req.values[0]); |
| EXPECT_EQ(1, req.values[1]); |
| } |
| |
| TEST_F(HandleMethodTest, SetValuesInvalid) |
| { |
| EXPECT_THROW(handle->setValues({1}), std::runtime_error); |
| EXPECT_THROW(handle->setValues({1, 0, 1}), std::runtime_error); |
| } |
| |
| TEST_F(HandleMethodTest, SetValuesFailure) |
| { |
| struct gpiohandle_data req; |
| EXPECT_CALL(mock, gpiohandle_set_line_values(handle_fd, testing::_)) |
| .WillOnce(DoAll(SaveArgPointee<1>(&req), Return(-EINVAL))); |
| EXPECT_THROW(handle->setValues({1, 1}), std::system_error); |
| EXPECT_EQ(1, req.values[0]); |
| EXPECT_EQ(1, req.values[1]); |
| } |
| |
| } // namespace |
| } // namespace gpioplus |