blob: e524ad64963928cadea6d2cdc62cdd5c6b94f109 [file] [log] [blame]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <libusb-1.0/libusb.h>
#include "libec/ec_usb_endpoint.h"
using ::testing::_;
using ::testing::AtLeast;
using ::testing::DoAll;
using ::testing::InvokeWithoutArgs;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
using ::testing::SetArgReferee;
namespace ec {
namespace {
class MockLibusb : public LibusbWrapper {
public:
MockLibusb() {}
~MockLibusb() {}
MOCK_METHOD(int, init, (libusb_context * *ctx), (override));
MOCK_METHOD(void, exit, (libusb_context * ctx), (override));
MOCK_METHOD(ssize_t,
get_device_list,
(libusb_context * ctx, libusb_device*** list),
(override));
MOCK_METHOD(int,
get_device_descriptor,
(libusb_device * dev, struct libusb_device_descriptor* desc),
(override));
MOCK_METHOD(void,
free_device_list,
(libusb_device * *list, int unref_devices),
(override));
MOCK_METHOD(int,
open,
(libusb_device * dev, libusb_device_handle** dev_handle),
(override));
MOCK_METHOD(void, close, (libusb_device_handle * dev_handle), (override));
MOCK_METHOD(int,
get_active_config_descriptor,
(libusb_device * dev, struct libusb_config_descriptor** config),
(override));
MOCK_METHOD(void,
free_config_descriptor,
(struct libusb_config_descriptor * config),
(override));
MOCK_METHOD(int,
claim_interface,
(libusb_device_handle * dev_handle, int interface_number),
(override));
MOCK_METHOD(int,
release_interface,
(libusb_device_handle * dev_handle, int interface_number),
(override));
};
class EcUsbEndpointTest : public ::testing::Test {
protected:
std::unique_ptr<MockLibusb> mock = std::make_unique<MockLibusb>();
libusb_device* devs[2] = {
reinterpret_cast<libusb_device*>(1),
nullptr,
};
struct libusb_device_descriptor desc = {
.idVendor = 0x18d1,
.idProduct = 0x5022,
};
libusb_device_handle* handle = reinterpret_cast<libusb_device_handle*>(3);
struct libusb_endpoint_descriptor ep = {
.bEndpointAddress = 2,
.wMaxPacketSize = 64,
};
struct libusb_interface_descriptor iface = {
.bInterfaceNumber = 1,
.bNumEndpoints = 1,
.endpoint = &ep,
};
struct libusb_interface interface = {
.altsetting = &iface,
.num_altsetting = 1,
};
struct libusb_config_descriptor conf = {
.bNumInterfaces = 1,
.interface = &interface,
};
};
TEST_F(EcUsbEndpointTest, Init_FailInInit) {
EXPECT_CALL(*mock, init).WillOnce(Return(LIBUSB_ERROR_IO));
EXPECT_CALL(*mock, exit).Times(0);
EcUsbEndpoint uep(std::move(mock), /*max_retries=*/0);
EXPECT_FALSE(uep.Init(0x18d1, 0x5022));
}
TEST_F(EcUsbEndpointTest, Init_FailInGetDeviceList) {
EXPECT_CALL(*mock, init).WillOnce(Return(LIBUSB_SUCCESS));
EXPECT_CALL(*mock, get_device_list).WillOnce(Return(LIBUSB_ERROR_IO));
EXPECT_CALL(*mock, exit);
EcUsbEndpoint uep(std::move(mock), /*max_retries=*/0);
EXPECT_FALSE(uep.Init(0x18d1, 0x5022));
}
TEST_F(EcUsbEndpointTest, Init_CantFindDevice) {
EXPECT_CALL(*mock, init).WillOnce(Return(LIBUSB_SUCCESS));
EXPECT_CALL(*mock, get_device_list)
.WillOnce(DoAll(SetArgPointee<1>(devs), Return(LIBUSB_SUCCESS)));
EXPECT_CALL(*mock, get_device_descriptor).WillOnce(Return(LIBUSB_ERROR_IO));
EXPECT_CALL(*mock, free_device_list).WillOnce(Return());
EXPECT_CALL(*mock, exit).WillOnce(Return());
EcUsbEndpoint uep(std::move(mock), /*max_retries=*/0);
EXPECT_FALSE(uep.Init(0x18d1, 0x5022));
}
TEST_F(EcUsbEndpointTest, Init_FailInVid) {
desc.idVendor = 0;
EXPECT_CALL(*mock, init).WillOnce(Return(LIBUSB_SUCCESS));
EXPECT_CALL(*mock, get_device_list)
.WillOnce(DoAll(SetArgPointee<1>(devs), Return(LIBUSB_SUCCESS)));
EXPECT_CALL(*mock, get_device_descriptor)
.WillOnce(DoAll(SetArgPointee<1>(desc), Return(LIBUSB_SUCCESS)));
EXPECT_CALL(*mock, free_device_list).WillOnce(Return());
EXPECT_CALL(*mock, exit).WillOnce(Return());
EcUsbEndpoint uep(std::move(mock), /*max_retries=*/0);
EXPECT_FALSE(uep.Init(0x18d1, 0x5022));
}
TEST_F(EcUsbEndpointTest, Init_FailInPid) {
desc.idProduct = 0;
EXPECT_CALL(*mock, init).WillOnce(Return(LIBUSB_SUCCESS));
EXPECT_CALL(*mock, get_device_list)
.WillOnce(DoAll(SetArgPointee<1>(devs), Return(LIBUSB_SUCCESS)));
EXPECT_CALL(*mock, get_device_descriptor)
.WillOnce(DoAll(SetArgPointee<1>(desc), Return(LIBUSB_SUCCESS)));
EXPECT_CALL(*mock, free_device_list).WillOnce(Return());
EXPECT_CALL(*mock, exit).WillOnce(Return());
EcUsbEndpoint uep(std::move(mock), /*max_retries=*/0);
EXPECT_FALSE(uep.Init(0x18d1, 0x5022));
}
TEST_F(EcUsbEndpointTest, Init_FailInGetConfigDescriptor) {
EXPECT_CALL(*mock, init).WillOnce(Return(LIBUSB_SUCCESS));
EXPECT_CALL(*mock, get_device_list)
.WillOnce(DoAll(SetArgPointee<1>(devs), Return(LIBUSB_SUCCESS)));
EXPECT_CALL(*mock, get_device_descriptor)
.WillOnce(DoAll(SetArgPointee<1>(desc), Return(LIBUSB_SUCCESS)));
EXPECT_CALL(*mock, get_active_config_descriptor)
.WillOnce(Return(LIBUSB_ERROR_IO));
EXPECT_CALL(*mock, free_device_list).WillOnce(Return());
EXPECT_CALL(*mock, exit).WillOnce(Return());
EcUsbEndpoint uep(std::move(mock), /*max_retries=*/0);
EXPECT_FALSE(uep.Init(0x18d1, 0x5022));
}
TEST_F(EcUsbEndpointTest, Init_BadMaxPacketSize) {
ep.wMaxPacketSize = 0;
EXPECT_CALL(*mock, init).WillOnce(Return(LIBUSB_SUCCESS));
EXPECT_CALL(*mock, get_device_list)
.WillOnce(DoAll(SetArgPointee<1>(devs), Return(LIBUSB_SUCCESS)));
EXPECT_CALL(*mock, get_device_descriptor)
.WillOnce(DoAll(SetArgPointee<1>(desc), Return(LIBUSB_SUCCESS)));
EXPECT_CALL(*mock, get_active_config_descriptor)
.WillOnce(DoAll(SetArgPointee<1>(&conf), Return(LIBUSB_SUCCESS)));
EXPECT_CALL(*mock, free_config_descriptor).WillOnce(Return());
EXPECT_CALL(*mock, free_device_list).WillOnce(Return());
EXPECT_CALL(*mock, exit).WillOnce(Return());
EcUsbEndpoint uep(std::move(mock), /*max_retries=*/0);
EXPECT_FALSE(uep.Init(0x18d1, 0x5022));
}
TEST_F(EcUsbEndpointTest, Init_Success) {
EXPECT_CALL(*mock, init).WillOnce(Return(LIBUSB_SUCCESS));
EXPECT_CALL(*mock, get_device_list)
.WillOnce(DoAll(SetArgPointee<1>(devs), Return(LIBUSB_SUCCESS)));
EXPECT_CALL(*mock, get_device_descriptor)
.WillOnce(DoAll(SetArgPointee<1>(desc), Return(LIBUSB_SUCCESS)));
EXPECT_CALL(*mock, get_active_config_descriptor)
.WillOnce(DoAll(SetArgPointee<1>(&conf), Return(LIBUSB_SUCCESS)));
EXPECT_CALL(*mock, free_config_descriptor).WillOnce(Return());
EXPECT_CALL(*mock, free_device_list).WillOnce(Return());
EXPECT_CALL(*mock, exit).WillOnce(Return());
EcUsbEndpoint uep(std::move(mock), /*max_retries=*/0);
EXPECT_TRUE(uep.Init(0x18d1, 0x5022));
}
TEST_F(EcUsbEndpointTest, ClaimInterface_NotInitialized) {
EcUsbEndpoint uep(std::move(mock), /*max_retries=*/0);
EXPECT_FALSE(uep.ClaimInterface());
}
TEST_F(EcUsbEndpointTest, ClaimInterface_FailInOpen) {
EXPECT_CALL(*mock, init).WillOnce(Return(LIBUSB_SUCCESS));
EXPECT_CALL(*mock, get_device_list)
.WillOnce(DoAll(SetArgPointee<1>(devs), Return(LIBUSB_SUCCESS)));
EXPECT_CALL(*mock, get_device_descriptor)
.WillOnce(DoAll(SetArgPointee<1>(desc), Return(LIBUSB_SUCCESS)));
EXPECT_CALL(*mock, get_active_config_descriptor)
.WillOnce(DoAll(SetArgPointee<1>(&conf), Return(LIBUSB_SUCCESS)));
EXPECT_CALL(*mock, open).WillOnce(Return(LIBUSB_ERROR_IO));
EXPECT_CALL(*mock, claim_interface).Times(0);
EcUsbEndpoint uep(std::move(mock), /*max_retries=*/0);
EXPECT_TRUE(uep.Init(0x18d1, 0x5022));
EXPECT_FALSE(uep.ClaimInterface());
}
TEST_F(EcUsbEndpointTest, ReleaseInterface_NotInitialized) {
EcUsbEndpoint uep(std::move(mock), /*max_retries=*/0);
EXPECT_TRUE(uep.ReleaseInterface());
}
} // namespace
} // namespace ec