Files
ptprnt/tests/usb_device_test/usb_device_test.cpp
Moritz Martinius 34b4e10c62
All checks were successful
Build ptprnt / build (push) Successful in 3m0s
Rename occurences Libusb -> LibUsb
2025-10-21 20:29:33 +02:00

277 lines
9.0 KiB
C++

/*
ptrnt - print labels on linux
Copyright (C) 2025 Moritz Martinius
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <memory>
#include "libusb.h"
#include "libusbwrap/LibUsbTypes.hpp"
#include "libusbwrap/UsbDevice.hpp"
#include "mocks/MockLibUsbWrapper.hpp"
using ::testing::_;
using ::testing::DoAll;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::SetArgPointee;
namespace libusbwrap {
// Test fixture for UsbDevice tests
class UsbDeviceTest : public ::testing::Test {
protected:
void SetUp() override {
mockLibUsb = std::make_shared<NiceMock<MockLibUsbWrapper>>();
// Create mock device pointer
mockDevice = reinterpret_cast<libusb_device*>(0x1000);
// Create mock device handle
mockHandle = reinterpret_cast<libusb_device_handle*>(0x2000);
// Setup device descriptor
desc.idVendor = 0x04f9; // Brother vendor ID
desc.idProduct = 0x2042; // P700 product ID
// Default behaviors
ON_CALL(*mockLibUsb, open(_, _)).WillByDefault(DoAll(SetArgPointee<1>(mockHandle), Return(0)));
ON_CALL(*mockLibUsb, getSpeed(_)).WillByDefault(Return(LIBUSB_SPEED_FULL));
ON_CALL(*mockLibUsb, getBusNumber(_)).WillByDefault(Return(1));
ON_CALL(*mockLibUsb, getPortNumber(_)).WillByDefault(Return(2));
ON_CALL(*mockLibUsb, errorName(_)).WillByDefault(Return("LIBUSB_SUCCESS"));
}
std::shared_ptr<MockLibUsbWrapper> mockLibUsb;
libusb_device* mockDevice;
libusb_device_handle* mockHandle;
libusb_device_descriptor desc{};
};
// Constructor tests
TEST_F(UsbDeviceTest, ConstructorWithValidDevice) {
EXPECT_NO_THROW({
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
EXPECT_NE(device, nullptr);
});
}
TEST_F(UsbDeviceTest, ConstructorWithNullptrThrows) {
EXPECT_THROW({ auto device = std::make_unique<UsbDevice>(nullptr, desc, mockLibUsb); }, std::invalid_argument);
}
// Open/Close tests
TEST_F(UsbDeviceTest, OpenSuccess) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
EXPECT_CALL(*mockLibUsb, open(mockDevice, _)).WillOnce(DoAll(SetArgPointee<1>(mockHandle), Return(0)));
EXPECT_TRUE(device->open());
}
TEST_F(UsbDeviceTest, OpenFailure) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
EXPECT_CALL(*mockLibUsb, open(mockDevice, _)).WillOnce(Return(LIBUSB_ERROR_ACCESS));
EXPECT_FALSE(device->open());
EXPECT_EQ(device->getLastError(), Error::ACCESS);
}
TEST_F(UsbDeviceTest, CloseWithOpenDevice) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
device->open();
EXPECT_CALL(*mockLibUsb, close(mockHandle)).Times(1);
device->close();
}
TEST_F(UsbDeviceTest, CloseWithoutOpenDevice) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
// Should not call close if device was never opened
EXPECT_CALL(*mockLibUsb, close(_)).Times(0);
device->close();
}
TEST_F(UsbDeviceTest, DestructorClosesOpenDevice) {
EXPECT_CALL(*mockLibUsb, close(mockHandle)).Times(1);
{
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
device->open();
// Device goes out of scope, destructor should call close
}
}
// Kernel driver tests
TEST_F(UsbDeviceTest, DetachKernelDriverWhenActive) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
device->open();
EXPECT_CALL(*mockLibUsb, kernelDriverActive(mockHandle, 0)).WillOnce(Return(1)); // Active
EXPECT_CALL(*mockLibUsb, detachKernelDriver(mockHandle, 0)).WillOnce(Return(0)); // Success
EXPECT_TRUE(device->detachKernelDriver(0));
}
TEST_F(UsbDeviceTest, DetachKernelDriverWhenNotActive) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
device->open();
EXPECT_CALL(*mockLibUsb, kernelDriverActive(mockHandle, 0)).WillOnce(Return(0)); // Not active
EXPECT_CALL(*mockLibUsb, detachKernelDriver(_, _)).Times(0); // Should not call detach
EXPECT_TRUE(device->detachKernelDriver(0));
}
TEST_F(UsbDeviceTest, DetachKernelDriverFailure) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
device->open();
EXPECT_CALL(*mockLibUsb, kernelDriverActive(mockHandle, 0)).WillOnce(Return(1)); // Active
EXPECT_CALL(*mockLibUsb, detachKernelDriver(mockHandle, 0)).WillOnce(Return(LIBUSB_ERROR_NOT_FOUND));
EXPECT_FALSE(device->detachKernelDriver(0));
EXPECT_EQ(device->getLastError(), Error::NOT_FOUND);
}
// Interface tests
TEST_F(UsbDeviceTest, ClaimInterfaceSuccess) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
device->open();
EXPECT_CALL(*mockLibUsb, claimInterface(mockHandle, 0)).WillOnce(Return(0));
EXPECT_TRUE(device->claimInterface(0));
}
TEST_F(UsbDeviceTest, ClaimInterfaceFailure) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
device->open();
EXPECT_CALL(*mockLibUsb, claimInterface(mockHandle, 0)).WillOnce(Return(LIBUSB_ERROR_BUSY));
EXPECT_FALSE(device->claimInterface(0));
EXPECT_EQ(device->getLastError(), Error::BUSY);
}
TEST_F(UsbDeviceTest, ReleaseInterfaceSuccess) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
device->open();
EXPECT_CALL(*mockLibUsb, releaseInterface(mockHandle, 0)).WillOnce(Return(0));
EXPECT_TRUE(device->releaseInterface(0));
}
TEST_F(UsbDeviceTest, ReleaseInterfaceFailure) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
device->open();
EXPECT_CALL(*mockLibUsb, releaseInterface(mockHandle, 0)).WillOnce(Return(LIBUSB_ERROR_NOT_FOUND));
EXPECT_FALSE(device->releaseInterface(0));
EXPECT_EQ(device->getLastError(), Error::NOT_FOUND);
}
// Bulk transfer tests
TEST_F(UsbDeviceTest, BulkTransferSuccess) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
device->open();
std::vector<uint8_t> data = {0x01, 0x02, 0x03};
int transferred = 0;
EXPECT_CALL(*mockLibUsb, bulkTransfer(mockHandle, 0x02, _, 3, _, 1000))
.WillOnce(DoAll(SetArgPointee<4>(3), Return(0)));
EXPECT_TRUE(device->bulkTransfer(0x02, data, &transferred, 1000));
}
TEST_F(UsbDeviceTest, BulkTransferFailure) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
device->open();
std::vector<uint8_t> data = {0x01, 0x02, 0x03};
int transferred = 0;
EXPECT_CALL(*mockLibUsb, bulkTransfer(mockHandle, 0x02, _, 3, _, 1000)).WillOnce(Return(LIBUSB_ERROR_TIMEOUT));
EXPECT_FALSE(device->bulkTransfer(0x02, data, &transferred, 1000));
EXPECT_EQ(device->getLastError(), Error::TIMEOUT);
}
// Getter tests
TEST_F(UsbDeviceTest, GetUsbId) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
auto usbId = device->getUsbId();
EXPECT_EQ(usbId.first, 0x04f9); // vid
EXPECT_EQ(usbId.second, 0x2042); // pid
}
TEST_F(UsbDeviceTest, GetSpeed) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
EXPECT_CALL(*mockLibUsb, getSpeed(mockDevice)).WillOnce(Return(LIBUSB_SPEED_HIGH));
EXPECT_EQ(device->getSpeed(), device::Speed::HIGH);
}
TEST_F(UsbDeviceTest, GetBusNumber) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
EXPECT_CALL(*mockLibUsb, getBusNumber(mockDevice)).WillOnce(Return(5));
EXPECT_EQ(device->getBusNumber(), 5);
}
TEST_F(UsbDeviceTest, GetPortNumber) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
EXPECT_CALL(*mockLibUsb, getPortNumber(mockDevice)).WillOnce(Return(3));
EXPECT_EQ(device->getPortNumber(), 3);
}
TEST_F(UsbDeviceTest, GetLastError) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
// Initially no error
EXPECT_EQ(device->getLastError(), Error::SUCCESS);
// After a failed operation
EXPECT_CALL(*mockLibUsb, open(_, _)).WillOnce(Return(LIBUSB_ERROR_NO_DEVICE));
device->open();
EXPECT_EQ(device->getLastError(), Error::NO_DEVICE);
}
TEST_F(UsbDeviceTest, GetLastErrorString) {
auto device = std::make_unique<UsbDevice>(mockDevice, desc, mockLibUsb);
EXPECT_CALL(*mockLibUsb, errorName(static_cast<int>(Error::SUCCESS))).WillOnce(Return("LIBUSB_SUCCESS"));
EXPECT_EQ(device->getLastErrorString(), "LIBUSB_SUCCESS");
}
} // namespace libusbwrap