blob: 87324d228035d19ac7b5700c1a737b3b7af85654 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/devices_app/usb/device_impl.h"
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <queue>
#include <set>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "device/devices_app/usb/fake_permission_provider.h"
#include "device/usb/mock_usb_device.h"
#include "device/usb/mock_usb_device_handle.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "net/base/io_buffer.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::Invoke;
using ::testing::_;
namespace device {
namespace usb {
namespace {
class ConfigBuilder {
public:
ConfigBuilder(uint8_t value) { config_.configuration_value = value; }
ConfigBuilder& AddInterface(uint8_t interface_number,
uint8_t alternate_setting,
uint8_t class_code,
uint8_t subclass_code,
uint8_t protocol_code) {
UsbInterfaceDescriptor interface;
interface.interface_number = interface_number;
interface.alternate_setting = alternate_setting;
interface.interface_class = class_code;
interface.interface_subclass = subclass_code;
interface.interface_protocol = protocol_code;
config_.interfaces.push_back(interface);
return *this;
}
const UsbConfigDescriptor& config() const { return config_; }
private:
UsbConfigDescriptor config_;
};
void ExpectOpenAndThen(OpenDeviceError expected,
const base::Closure& continuation,
OpenDeviceError error) {
EXPECT_EQ(expected, error);
continuation.Run();
}
void ExpectDeviceInfoAndThen(const std::string& guid,
uint16_t vendor_id,
uint16_t product_id,
const std::string& manufacturer_name,
const std::string& product_name,
const std::string& serial_number,
const base::Closure& continuation,
DeviceInfoPtr device_info) {
EXPECT_EQ(guid, device_info->guid);
EXPECT_EQ(vendor_id, device_info->vendor_id);
EXPECT_EQ(product_id, device_info->product_id);
EXPECT_EQ(manufacturer_name, device_info->manufacturer_name);
EXPECT_EQ(product_name, device_info->product_name);
EXPECT_EQ(serial_number, device_info->serial_number);
continuation.Run();
}
void ExpectResultAndThen(bool expected_result,
const base::Closure& continuation,
bool actual_result) {
EXPECT_EQ(expected_result, actual_result);
continuation.Run();
}
void ExpectTransferInAndThen(TransferStatus expected_status,
const std::vector<uint8_t>& expected_bytes,
const base::Closure& continuation,
TransferStatus actual_status,
mojo::Array<uint8_t> actual_bytes) {
EXPECT_EQ(expected_status, actual_status);
ASSERT_EQ(expected_bytes.size(), actual_bytes.size());
for (size_t i = 0; i < actual_bytes.size(); ++i) {
EXPECT_EQ(expected_bytes[i], actual_bytes[i])
<< "Contents differ at index: " << i;
}
continuation.Run();
}
void ExpectPacketsAndThen(
TransferStatus expected_status,
const std::vector<std::vector<uint8_t>>& expected_packets,
const base::Closure& continuation,
TransferStatus actual_status,
mojo::Array<mojo::Array<uint8_t>> actual_packets) {
EXPECT_EQ(expected_status, actual_status);
ASSERT_EQ(expected_packets.size(), actual_packets.size());
for (size_t i = 0; i < expected_packets.size(); ++i) {
EXPECT_EQ(expected_packets[i].size(), actual_packets[i].size())
<< "Packet sizes differ at index: " << i;
for (size_t j = 0; j < expected_packets[i].size(); ++j) {
EXPECT_EQ(expected_packets[i][j], actual_packets[i][j])
<< "Contents of packet " << i << " differ at index " << j;
}
}
continuation.Run();
}
void ExpectTransferStatusAndThen(TransferStatus expected_status,
const base::Closure& continuation,
TransferStatus actual_status) {
EXPECT_EQ(expected_status, actual_status);
continuation.Run();
}
class USBDeviceImplTest : public testing::Test {
public:
USBDeviceImplTest()
: message_loop_(new base::MessageLoop),
is_device_open_(false),
allow_reset_(false),
current_config_(0) {}
~USBDeviceImplTest() override {}
protected:
MockUsbDevice& mock_device() { return *mock_device_.get(); }
bool is_device_open() const { return is_device_open_; }
MockUsbDeviceHandle& mock_handle() { return *mock_handle_.get(); }
void set_allow_reset(bool allow_reset) { allow_reset_ = allow_reset; }
// Creates a mock device and binds a Device proxy to a Device service impl
// wrapping the mock device.
DevicePtr GetMockDeviceProxy(uint16_t vendor_id,
uint16_t product_id,
const std::string& manufacturer,
const std::string& product,
const std::string& serial) {
mock_device_ =
new MockUsbDevice(vendor_id, product_id, manufacturer, product, serial);
mock_handle_ = new MockUsbDeviceHandle(mock_device_.get());
PermissionProviderPtr permission_provider;
permission_provider_.Bind(mojo::GetProxy(&permission_provider));
DevicePtr proxy;
new DeviceImpl(mock_device_, std::move(permission_provider),
mojo::GetProxy(&proxy));
// Set up mock handle calls to respond based on mock device configs
// established by the test.
ON_CALL(mock_device(), Open(_))
.WillByDefault(Invoke(this, &USBDeviceImplTest::OpenMockHandle));
ON_CALL(mock_device(), GetActiveConfiguration())
.WillByDefault(
Invoke(this, &USBDeviceImplTest::GetActiveConfiguration));
ON_CALL(mock_handle(), Close())
.WillByDefault(Invoke(this, &USBDeviceImplTest::CloseMockHandle));
ON_CALL(mock_handle(), SetConfiguration(_, _))
.WillByDefault(Invoke(this, &USBDeviceImplTest::SetConfiguration));
ON_CALL(mock_handle(), ClaimInterface(_, _))
.WillByDefault(Invoke(this, &USBDeviceImplTest::ClaimInterface));
ON_CALL(mock_handle(), ReleaseInterface(_))
.WillByDefault(Invoke(this, &USBDeviceImplTest::ReleaseInterface));
ON_CALL(mock_handle(), SetInterfaceAlternateSetting(_, _, _))
.WillByDefault(
Invoke(this, &USBDeviceImplTest::SetInterfaceAlternateSetting));
ON_CALL(mock_handle(), ResetDevice(_))
.WillByDefault(Invoke(this, &USBDeviceImplTest::ResetDevice));
ON_CALL(mock_handle(), ControlTransfer(_, _, _, _, _, _, _, _, _, _))
.WillByDefault(Invoke(this, &USBDeviceImplTest::ControlTransfer));
ON_CALL(mock_handle(), GenericTransfer(_, _, _, _, _, _))
.WillByDefault(Invoke(this, &USBDeviceImplTest::GenericTransfer));
ON_CALL(mock_handle(), IsochronousTransfer(_, _, _, _, _, _, _, _))
.WillByDefault(Invoke(this, &USBDeviceImplTest::IsochronousTransfer));
return proxy;
}
DevicePtr GetMockDeviceProxy() {
return GetMockDeviceProxy(0x1234, 0x5678, "ACME", "Frobinator", "ABCDEF");
}
void AddMockConfig(const ConfigBuilder& builder) {
const UsbConfigDescriptor& config = builder.config();
DCHECK(!ContainsKey(mock_configs_, config.configuration_value));
mock_configs_[config.configuration_value] = config;
}
void AddMockInboundData(const std::vector<uint8_t>& data) {
mock_inbound_data_.push(data);
}
void AddMockOutboundData(const std::vector<uint8_t>& data) {
mock_outbound_data_.push(data);
}
private:
void OpenMockHandle(const UsbDevice::OpenCallback& callback) {
EXPECT_FALSE(is_device_open_);
is_device_open_ = true;
callback.Run(mock_handle_);
}
void CloseMockHandle() {
EXPECT_TRUE(is_device_open_);
is_device_open_ = false;
}
const UsbConfigDescriptor* GetActiveConfiguration() {
if (current_config_ == 0) {
return nullptr;
} else {
const auto it = mock_configs_.find(current_config_);
EXPECT_TRUE(it != mock_configs_.end());
return &it->second;
}
}
void SetConfiguration(uint8_t value,
const UsbDeviceHandle::ResultCallback& callback) {
if (mock_configs_.find(value) != mock_configs_.end()) {
current_config_ = value;
callback.Run(true);
} else {
callback.Run(false);
}
}
void ClaimInterface(uint8_t interface_number,
const UsbDeviceHandle::ResultCallback& callback) {
for (const auto& config : mock_configs_) {
for (const auto& interface : config.second.interfaces) {
if (interface.interface_number == interface_number) {
claimed_interfaces_.insert(interface_number);
callback.Run(true);
return;
}
}
}
callback.Run(false);
}
bool ReleaseInterface(uint8_t interface_number) {
if (ContainsKey(claimed_interfaces_, interface_number)) {
claimed_interfaces_.erase(interface_number);
return true;
}
return false;
}
void SetInterfaceAlternateSetting(
uint8_t interface_number,
uint8_t alternate_setting,
const UsbDeviceHandle::ResultCallback& callback) {
for (const auto& config : mock_configs_) {
for (const auto& interface : config.second.interfaces) {
if (interface.interface_number == interface_number &&
interface.alternate_setting == alternate_setting) {
callback.Run(true);
return;
}
}
}
callback.Run(false);
}
void ResetDevice(const UsbDeviceHandle::ResultCallback& callback) {
callback.Run(allow_reset_);
}
void InboundTransfer(const UsbDeviceHandle::TransferCallback& callback) {
ASSERT_GE(mock_inbound_data_.size(), 1u);
const std::vector<uint8_t>& bytes = mock_inbound_data_.front();
size_t length = bytes.size();
scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(length);
std::copy(bytes.begin(), bytes.end(), buffer->data());
mock_inbound_data_.pop();
callback.Run(USB_TRANSFER_COMPLETED, buffer, length);
}
void OutboundTransfer(scoped_refptr<net::IOBuffer> buffer,
size_t length,
const UsbDeviceHandle::TransferCallback& callback) {
ASSERT_GE(mock_outbound_data_.size(), 1u);
const std::vector<uint8_t>& bytes = mock_outbound_data_.front();
ASSERT_EQ(bytes.size(), length);
for (size_t i = 0; i < length; ++i) {
EXPECT_EQ(bytes[i], buffer->data()[i])
<< "Contents differ at index: " << i;
}
mock_outbound_data_.pop();
callback.Run(USB_TRANSFER_COMPLETED, buffer, length);
}
void ControlTransfer(UsbEndpointDirection direction,
UsbDeviceHandle::TransferRequestType request_type,
UsbDeviceHandle::TransferRecipient recipient,
uint8_t request,
uint16_t value,
uint16_t index,
scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int timeout,
const UsbDeviceHandle::TransferCallback& callback) {
if (direction == USB_DIRECTION_INBOUND)
InboundTransfer(callback);
else
OutboundTransfer(buffer, length, callback);
}
void GenericTransfer(UsbEndpointDirection direction,
uint8_t endpoint,
scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int timeout,
const UsbDeviceHandle::TransferCallback& callback) {
if (direction == USB_DIRECTION_INBOUND)
InboundTransfer(callback);
else
OutboundTransfer(buffer, length, callback);
}
void IsochronousTransfer(UsbEndpointDirection direction,
uint8_t endpoint,
scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int packets,
unsigned int packet_length,
unsigned int timeout,
const UsbDeviceHandle::TransferCallback& callback) {
if (direction == USB_DIRECTION_INBOUND)
InboundTransfer(callback);
else
OutboundTransfer(buffer, length, callback);
}
scoped_ptr<base::MessageLoop> message_loop_;
scoped_refptr<MockUsbDevice> mock_device_;
scoped_refptr<MockUsbDeviceHandle> mock_handle_;
bool is_device_open_;
bool allow_reset_;
std::map<uint8_t, UsbConfigDescriptor> mock_configs_;
uint8_t current_config_;
std::queue<std::vector<uint8_t>> mock_inbound_data_;
std::queue<std::vector<uint8_t>> mock_outbound_data_;
std::set<uint8_t> claimed_interfaces_;
FakePermissionProvider permission_provider_;
DISALLOW_COPY_AND_ASSIGN(USBDeviceImplTest);
};
} // namespace
TEST_F(USBDeviceImplTest, Open) {
DevicePtr device = GetMockDeviceProxy();
EXPECT_FALSE(is_device_open());
EXPECT_CALL(mock_device(), Open(_));
base::RunLoop loop;
device->Open(
base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK, loop.QuitClosure()));
loop.Run();
EXPECT_CALL(mock_handle(), Close());
}
TEST_F(USBDeviceImplTest, Close) {
DevicePtr device = GetMockDeviceProxy();
EXPECT_FALSE(is_device_open());
EXPECT_CALL(mock_device(), Open(_));
{
base::RunLoop loop;
device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK,
loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), Close());
{
base::RunLoop loop;
device->Close(loop.QuitClosure());
loop.Run();
}
EXPECT_FALSE(is_device_open());
}
// Test that the information returned via the Device::GetDeviceInfo matches that
// of the underlying device.
TEST_F(USBDeviceImplTest, GetDeviceInfo) {
DevicePtr device =
GetMockDeviceProxy(0x1234, 0x5678, "ACME", "Frobinator", "ABCDEF");
base::RunLoop loop;
device->GetDeviceInfo(base::Bind(&ExpectDeviceInfoAndThen,
mock_device().guid(), 0x1234, 0x5678, "ACME",
"Frobinator", "ABCDEF", loop.QuitClosure()));
loop.Run();
}
TEST_F(USBDeviceImplTest, SetInvalidConfiguration) {
DevicePtr device = GetMockDeviceProxy();
EXPECT_CALL(mock_device(), Open(_));
{
base::RunLoop loop;
device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK,
loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), SetConfiguration(42, _));
{
// SetConfiguration should fail because 42 is not a valid mock
// configuration.
base::RunLoop loop;
device->SetConfiguration(
42, base::Bind(&ExpectResultAndThen, false, loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), Close());
}
TEST_F(USBDeviceImplTest, SetValidConfiguration) {
DevicePtr device = GetMockDeviceProxy();
EXPECT_CALL(mock_device(), Open(_));
{
base::RunLoop loop;
device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK,
loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), SetConfiguration(42, _));
AddMockConfig(ConfigBuilder(42));
{
// SetConfiguration should succeed because 42 is a valid mock configuration.
base::RunLoop loop;
device->SetConfiguration(
42, base::Bind(&ExpectResultAndThen, true, loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), Close());
}
// Verify that the result of Reset() reflects the underlying UsbDeviceHandle's
// ResetDevice() result.
TEST_F(USBDeviceImplTest, Reset) {
DevicePtr device = GetMockDeviceProxy();
EXPECT_CALL(mock_device(), Open(_));
{
base::RunLoop loop;
device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK,
loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), ResetDevice(_));
set_allow_reset(true);
{
base::RunLoop loop;
device->Reset(base::Bind(&ExpectResultAndThen, true, loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), ResetDevice(_));
set_allow_reset(false);
{
base::RunLoop loop;
device->Reset(base::Bind(&ExpectResultAndThen, false, loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), Close());
}
TEST_F(USBDeviceImplTest, ClaimAndReleaseInterface) {
DevicePtr device = GetMockDeviceProxy();
EXPECT_CALL(mock_device(), Open(_));
{
base::RunLoop loop;
device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK,
loop.QuitClosure()));
loop.Run();
}
// Now add a mock interface #1.
AddMockConfig(ConfigBuilder(1).AddInterface(1, 0, 1, 2, 3));
EXPECT_CALL(mock_handle(), SetConfiguration(1, _));
{
base::RunLoop loop;
device->SetConfiguration(
1, base::Bind(&ExpectResultAndThen, true, loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_device(), GetActiveConfiguration());
EXPECT_CALL(mock_handle(), ClaimInterface(2, _));
{
// Try to claim an invalid interface and expect failure.
base::RunLoop loop;
device->ClaimInterface(
2, base::Bind(&ExpectResultAndThen, false, loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_device(), GetActiveConfiguration());
EXPECT_CALL(mock_handle(), ClaimInterface(1, _));
{
base::RunLoop loop;
device->ClaimInterface(
1, base::Bind(&ExpectResultAndThen, true, loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), ReleaseInterface(2));
{
// Releasing a non-existent interface should fail.
base::RunLoop loop;
device->ReleaseInterface(
2, base::Bind(&ExpectResultAndThen, false, loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), ReleaseInterface(1));
{
// Now this should release the claimed interface and close the handle.
base::RunLoop loop;
device->ReleaseInterface(
1, base::Bind(&ExpectResultAndThen, true, loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), Close());
}
TEST_F(USBDeviceImplTest, SetInterfaceAlternateSetting) {
DevicePtr device = GetMockDeviceProxy();
EXPECT_CALL(mock_device(), Open(_));
{
base::RunLoop loop;
device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK,
loop.QuitClosure()));
loop.Run();
}
AddMockConfig(ConfigBuilder(1)
.AddInterface(1, 0, 1, 2, 3)
.AddInterface(1, 42, 1, 2, 3)
.AddInterface(2, 0, 1, 2, 3));
EXPECT_CALL(mock_handle(), SetInterfaceAlternateSetting(1, 42, _));
{
base::RunLoop loop;
device->SetInterfaceAlternateSetting(
1, 42, base::Bind(&ExpectResultAndThen, true, loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), SetInterfaceAlternateSetting(1, 100, _));
{
base::RunLoop loop;
device->SetInterfaceAlternateSetting(
1, 100, base::Bind(&ExpectResultAndThen, false, loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), Close());
}
TEST_F(USBDeviceImplTest, ControlTransfer) {
DevicePtr device = GetMockDeviceProxy();
EXPECT_CALL(mock_device(), Open(_));
{
base::RunLoop loop;
device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK,
loop.QuitClosure()));
loop.Run();
}
AddMockConfig(ConfigBuilder(1).AddInterface(7, 0, 1, 2, 3));
EXPECT_CALL(mock_device(), GetActiveConfiguration());
EXPECT_CALL(mock_handle(), SetConfiguration(1, _));
{
base::RunLoop loop;
device->SetConfiguration(
1, base::Bind(&ExpectResultAndThen, true, loop.QuitClosure()));
loop.Run();
}
std::vector<uint8_t> fake_data;
fake_data.push_back(41);
fake_data.push_back(42);
fake_data.push_back(43);
AddMockInboundData(fake_data);
EXPECT_CALL(mock_handle(),
ControlTransfer(USB_DIRECTION_INBOUND, UsbDeviceHandle::STANDARD,
UsbDeviceHandle::DEVICE, 5, 6, 7, _, _, 0, _));
{
auto params = ControlTransferParams::New();
params->type = ControlTransferType::STANDARD;
params->recipient = ControlTransferRecipient::DEVICE;
params->request = 5;
params->value = 6;
params->index = 7;
base::RunLoop loop;
device->ControlTransferIn(
std::move(params), static_cast<uint32_t>(fake_data.size()), 0,
base::Bind(&ExpectTransferInAndThen, TransferStatus::COMPLETED,
fake_data, loop.QuitClosure()));
loop.Run();
}
AddMockOutboundData(fake_data);
EXPECT_CALL(mock_device(), GetActiveConfiguration());
EXPECT_CALL(mock_handle(),
ControlTransfer(USB_DIRECTION_OUTBOUND, UsbDeviceHandle::STANDARD,
UsbDeviceHandle::INTERFACE, 5, 6, 7, _, _, 0, _));
{
auto params = ControlTransferParams::New();
params->type = ControlTransferType::STANDARD;
params->recipient = ControlTransferRecipient::INTERFACE;
params->request = 5;
params->value = 6;
params->index = 7;
base::RunLoop loop;
device->ControlTransferOut(
std::move(params), mojo::Array<uint8_t>::From(fake_data), 0,
base::Bind(&ExpectTransferStatusAndThen, TransferStatus::COMPLETED,
loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), Close());
}
TEST_F(USBDeviceImplTest, GenericTransfer) {
DevicePtr device = GetMockDeviceProxy();
EXPECT_CALL(mock_device(), Open(_));
{
base::RunLoop loop;
device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK,
loop.QuitClosure()));
loop.Run();
}
std::string message1 = "say hello please";
std::vector<uint8_t> fake_outbound_data(message1.size());
std::copy(message1.begin(), message1.end(), fake_outbound_data.begin());
std::string message2 = "hello world!";
std::vector<uint8_t> fake_inbound_data(message2.size());
std::copy(message2.begin(), message2.end(), fake_inbound_data.begin());
AddMockConfig(ConfigBuilder(1).AddInterface(7, 0, 1, 2, 3));
AddMockOutboundData(fake_outbound_data);
AddMockInboundData(fake_inbound_data);
EXPECT_CALL(mock_handle(), GenericTransfer(USB_DIRECTION_OUTBOUND, 0x01, _,
fake_outbound_data.size(), 0, _));
{
base::RunLoop loop;
device->GenericTransferOut(
1, mojo::Array<uint8_t>::From(fake_outbound_data), 0,
base::Bind(&ExpectTransferStatusAndThen, TransferStatus::COMPLETED,
loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), GenericTransfer(USB_DIRECTION_INBOUND, 0x81, _,
fake_inbound_data.size(), 0, _));
{
base::RunLoop loop;
device->GenericTransferIn(
1, static_cast<uint32_t>(fake_inbound_data.size()), 0,
base::Bind(&ExpectTransferInAndThen, TransferStatus::COMPLETED,
fake_inbound_data, loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), Close());
}
TEST_F(USBDeviceImplTest, IsochronousTransfer) {
DevicePtr device = GetMockDeviceProxy();
EXPECT_CALL(mock_device(), Open(_));
{
base::RunLoop loop;
device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK,
loop.QuitClosure()));
loop.Run();
}
std::string outbound_packet_data = "aaaaaaaabbbbbbbbccccccccdddddddd";
std::vector<uint8_t> fake_outbound_packets(outbound_packet_data.size());
std::copy(outbound_packet_data.begin(), outbound_packet_data.end(),
fake_outbound_packets.begin());
std::string inbound_packet_data = "ddddddddccccccccbbbbbbbbaaaaaaaa";
std::vector<uint8_t> fake_inbound_packets(inbound_packet_data.size());
std::copy(inbound_packet_data.begin(), inbound_packet_data.end(),
fake_inbound_packets.begin());
AddMockConfig(ConfigBuilder(1).AddInterface(7, 0, 1, 2, 3));
AddMockOutboundData(fake_outbound_packets);
AddMockInboundData(fake_inbound_packets);
EXPECT_CALL(mock_handle(),
IsochronousTransfer(USB_DIRECTION_OUTBOUND, 0x01, _,
fake_outbound_packets.size(), 4, 8, 0, _));
{
base::RunLoop loop;
mojo::Array<mojo::Array<uint8_t>> packets =
mojo::Array<mojo::Array<uint8_t>>::New(4);
for (size_t i = 0; i < 4; ++i) {
std::vector<uint8_t> bytes(8);
std::copy(outbound_packet_data.begin() + i * 8,
outbound_packet_data.begin() + i * 8 + 8, bytes.begin());
packets[i].Swap(&bytes);
}
device->IsochronousTransferOut(
1, std::move(packets), 0,
base::Bind(&ExpectTransferStatusAndThen, TransferStatus::COMPLETED,
loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(),
IsochronousTransfer(USB_DIRECTION_INBOUND, 0x81, _,
fake_inbound_packets.size(), 4, 8, 0, _));
{
base::RunLoop loop;
std::vector<std::vector<uint8_t>> packets(4);
for (size_t i = 0; i < 4; ++i) {
packets[i].resize(8);
std::copy(inbound_packet_data.begin() + i * 8,
inbound_packet_data.begin() + i * 8 + 8, packets[i].begin());
}
device->IsochronousTransferIn(
1, 4, 8, 0, base::Bind(&ExpectPacketsAndThen, TransferStatus::COMPLETED,
packets, loop.QuitClosure()));
loop.Run();
}
EXPECT_CALL(mock_handle(), Close());
}
} // namespace usb
} // namespace device