1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
9 #include "base/callback.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/run_loop.h"
12 #include "base/scoped_observer.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/test/test_io_thread.h"
15 #include "device/hid/hid_connection.h"
16 #include "device/hid/hid_service.h"
17 #include "device/test/usb_test_gadget.h"
18 #include "device/usb/usb_device.h"
19 #include "net/base/io_buffer.h"
20 #include "testing/gtest/include/gtest/gtest.h"
26 using net::IOBufferWithSize
;
28 // Helper class that can be used to block until a HID device with a particular
29 // serial number is available. Example usage:
31 // DeviceCatcher device_catcher("ABC123");
32 // HidDeviceId device_id = device_catcher.WaitForDevice();
33 // /* Call HidService::Connect(device_id) to open the device. */
35 class DeviceCatcher
: HidService::Observer
{
37 DeviceCatcher(HidService
* hid_service
, const base::string16
& serial_number
)
38 : serial_number_(base::UTF16ToUTF8(serial_number
)), observer_(this) {
39 observer_
.Add(hid_service
);
40 hid_service
->GetDevices(base::Bind(&DeviceCatcher::OnEnumerationComplete
,
41 base::Unretained(this)));
44 const HidDeviceId
& WaitForDevice() {
46 observer_
.RemoveAll();
51 void OnEnumerationComplete(
52 const std::vector
<scoped_refptr
<HidDeviceInfo
>>& devices
) {
53 for (const scoped_refptr
<HidDeviceInfo
>& device_info
: devices
) {
54 if (device_info
->serial_number() == serial_number_
) {
55 device_id_
= device_info
->device_id();
62 void OnDeviceAdded(scoped_refptr
<HidDeviceInfo
> device_info
) override
{
63 if (device_info
->serial_number() == serial_number_
) {
64 device_id_
= device_info
->device_id();
69 std::string serial_number_
;
70 ScopedObserver
<device::HidService
, device::HidService::Observer
> observer_
;
71 base::RunLoop run_loop_
;
72 HidDeviceId device_id_
;
75 class TestConnectCallback
{
78 : callback_(base::Bind(&TestConnectCallback::SetConnection
,
79 base::Unretained(this))) {}
80 ~TestConnectCallback() {}
82 void SetConnection(scoped_refptr
<HidConnection
> connection
) {
83 connection_
= connection
;
87 scoped_refptr
<HidConnection
> WaitForConnection() {
92 const HidService::ConnectCallback
& callback() { return callback_
; }
95 HidService::ConnectCallback callback_
;
96 base::RunLoop run_loop_
;
97 scoped_refptr
<HidConnection
> connection_
;
100 class TestIoCallback
{
104 base::Bind(&TestIoCallback::SetReadResult
, base::Unretained(this))),
105 write_callback_(base::Bind(&TestIoCallback::SetWriteResult
,
106 base::Unretained(this))) {}
109 void SetReadResult(bool success
,
110 scoped_refptr
<net::IOBuffer
> buffer
,
118 void SetWriteResult(bool success
) {
123 bool WaitForResult() {
128 const HidConnection::ReadCallback
& read_callback() { return read_callback_
; }
129 const HidConnection::WriteCallback
write_callback() {
130 return write_callback_
;
132 scoped_refptr
<net::IOBuffer
> buffer() const { return buffer_
; }
133 size_t size() const { return size_
; }
136 base::RunLoop run_loop_
;
139 scoped_refptr
<net::IOBuffer
> buffer_
;
140 HidConnection::ReadCallback read_callback_
;
141 HidConnection::WriteCallback write_callback_
;
146 class HidConnectionTest
: public testing::Test
{
148 void SetUp() override
{
149 if (!UsbTestGadget::IsTestEnabled()) return;
151 message_loop_
.reset(new base::MessageLoopForUI());
152 io_thread_
.reset(new base::TestIOThread(base::TestIOThread::kAutoStart
));
154 service_
= HidService::GetInstance(io_thread_
->task_runner());
155 ASSERT_TRUE(service_
);
157 test_gadget_
= UsbTestGadget::Claim(io_thread_
->task_runner());
158 ASSERT_TRUE(test_gadget_
);
159 ASSERT_TRUE(test_gadget_
->SetType(UsbTestGadget::HID_ECHO
));
161 DeviceCatcher
device_catcher(service_
,
162 test_gadget_
->GetDevice()->serial_number());
163 device_id_
= device_catcher
.WaitForDevice();
164 ASSERT_NE(device_id_
, kInvalidHidDeviceId
);
167 scoped_ptr
<base::MessageLoopForUI
> message_loop_
;
168 scoped_ptr
<base::TestIOThread
> io_thread_
;
169 HidService
* service_
;
170 scoped_ptr
<UsbTestGadget
> test_gadget_
;
171 HidDeviceId device_id_
;
174 TEST_F(HidConnectionTest
, ReadWrite
) {
175 if (!UsbTestGadget::IsTestEnabled()) return;
177 TestConnectCallback connect_callback
;
178 service_
->Connect(device_id_
, connect_callback
.callback());
179 scoped_refptr
<HidConnection
> conn
= connect_callback
.WaitForConnection();
180 ASSERT_TRUE(conn
.get());
182 const char kBufferSize
= 9;
183 for (char i
= 0; i
< 8; ++i
) {
184 scoped_refptr
<IOBufferWithSize
> buffer(new IOBufferWithSize(kBufferSize
));
185 buffer
->data()[0] = 0;
186 for (unsigned char j
= 1; j
< kBufferSize
; ++j
) {
187 buffer
->data()[j
] = i
+ j
- 1;
190 TestIoCallback write_callback
;
191 conn
->Write(buffer
, buffer
->size(), write_callback
.write_callback());
192 ASSERT_TRUE(write_callback
.WaitForResult());
194 TestIoCallback read_callback
;
195 conn
->Read(read_callback
.read_callback());
196 ASSERT_TRUE(read_callback
.WaitForResult());
197 ASSERT_EQ(9UL, read_callback
.size());
198 ASSERT_EQ(0, read_callback
.buffer()->data()[0]);
199 for (unsigned char j
= 1; j
< kBufferSize
; ++j
) {
200 ASSERT_EQ(i
+ j
- 1, read_callback
.buffer()->data()[j
]);
207 } // namespace device