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/test_device_client.h"
18 #include "device/test/usb_test_gadget.h"
19 #include "device/usb/usb_device.h"
20 #include "net/base/io_buffer.h"
21 #include "testing/gtest/include/gtest/gtest.h"
27 using net::IOBufferWithSize
;
29 // Helper class that can be used to block until a HID device with a particular
30 // serial number is available. Example usage:
32 // DeviceCatcher device_catcher("ABC123");
33 // HidDeviceId device_id = device_catcher.WaitForDevice();
34 // /* Call HidService::Connect(device_id) to open the device. */
36 class DeviceCatcher
: HidService::Observer
{
38 DeviceCatcher(HidService
* hid_service
, const base::string16
& serial_number
)
39 : serial_number_(base::UTF16ToUTF8(serial_number
)), observer_(this) {
40 observer_
.Add(hid_service
);
41 hid_service
->GetDevices(base::Bind(&DeviceCatcher::OnEnumerationComplete
,
42 base::Unretained(this)));
45 const HidDeviceId
& WaitForDevice() {
47 observer_
.RemoveAll();
52 void OnEnumerationComplete(
53 const std::vector
<scoped_refptr
<HidDeviceInfo
>>& devices
) {
54 for (const scoped_refptr
<HidDeviceInfo
>& device_info
: devices
) {
55 if (device_info
->serial_number() == serial_number_
) {
56 device_id_
= device_info
->device_id();
63 void OnDeviceAdded(scoped_refptr
<HidDeviceInfo
> device_info
) override
{
64 if (device_info
->serial_number() == serial_number_
) {
65 device_id_
= device_info
->device_id();
70 std::string serial_number_
;
71 ScopedObserver
<device::HidService
, device::HidService::Observer
> observer_
;
72 base::RunLoop run_loop_
;
73 HidDeviceId device_id_
;
76 class TestConnectCallback
{
79 : callback_(base::Bind(&TestConnectCallback::SetConnection
,
80 base::Unretained(this))) {}
81 ~TestConnectCallback() {}
83 void SetConnection(scoped_refptr
<HidConnection
> connection
) {
84 connection_
= connection
;
88 scoped_refptr
<HidConnection
> WaitForConnection() {
93 const HidService::ConnectCallback
& callback() { return callback_
; }
96 HidService::ConnectCallback callback_
;
97 base::RunLoop run_loop_
;
98 scoped_refptr
<HidConnection
> connection_
;
101 class TestIoCallback
{
105 base::Bind(&TestIoCallback::SetReadResult
, base::Unretained(this))),
106 write_callback_(base::Bind(&TestIoCallback::SetWriteResult
,
107 base::Unretained(this))) {}
110 void SetReadResult(bool success
,
111 scoped_refptr
<net::IOBuffer
> buffer
,
119 void SetWriteResult(bool success
) {
124 bool WaitForResult() {
129 const HidConnection::ReadCallback
& read_callback() { return read_callback_
; }
130 const HidConnection::WriteCallback
write_callback() {
131 return write_callback_
;
133 scoped_refptr
<net::IOBuffer
> buffer() const { return buffer_
; }
134 size_t size() const { return size_
; }
137 base::RunLoop run_loop_
;
140 scoped_refptr
<net::IOBuffer
> buffer_
;
141 HidConnection::ReadCallback read_callback_
;
142 HidConnection::WriteCallback write_callback_
;
147 class HidConnectionTest
: public testing::Test
{
149 void SetUp() override
{
150 if (!UsbTestGadget::IsTestEnabled()) return;
152 message_loop_
.reset(new base::MessageLoopForUI());
153 io_thread_
.reset(new base::TestIOThread(base::TestIOThread::kAutoStart
));
154 device_client_
.reset(new TestDeviceClient(io_thread_
->task_runner()));
156 service_
= DeviceClient::Get()->GetHidService();
157 ASSERT_TRUE(service_
);
159 test_gadget_
= UsbTestGadget::Claim(io_thread_
->task_runner());
160 ASSERT_TRUE(test_gadget_
);
161 ASSERT_TRUE(test_gadget_
->SetType(UsbTestGadget::HID_ECHO
));
163 DeviceCatcher
device_catcher(service_
,
164 test_gadget_
->GetDevice()->serial_number());
165 device_id_
= device_catcher
.WaitForDevice();
166 ASSERT_NE(device_id_
, kInvalidHidDeviceId
);
169 scoped_ptr
<base::MessageLoopForUI
> message_loop_
;
170 scoped_ptr
<base::TestIOThread
> io_thread_
;
171 scoped_ptr
<TestDeviceClient
> device_client_
;
172 HidService
* service_
;
173 scoped_ptr
<UsbTestGadget
> test_gadget_
;
174 HidDeviceId device_id_
;
177 TEST_F(HidConnectionTest
, ReadWrite
) {
178 if (!UsbTestGadget::IsTestEnabled()) return;
180 TestConnectCallback connect_callback
;
181 service_
->Connect(device_id_
, connect_callback
.callback());
182 scoped_refptr
<HidConnection
> conn
= connect_callback
.WaitForConnection();
183 ASSERT_TRUE(conn
.get());
185 const char kBufferSize
= 9;
186 for (char i
= 0; i
< 8; ++i
) {
187 scoped_refptr
<IOBufferWithSize
> buffer(new IOBufferWithSize(kBufferSize
));
188 buffer
->data()[0] = 0;
189 for (unsigned char j
= 1; j
< kBufferSize
; ++j
) {
190 buffer
->data()[j
] = i
+ j
- 1;
193 TestIoCallback write_callback
;
194 conn
->Write(buffer
, buffer
->size(), write_callback
.write_callback());
195 ASSERT_TRUE(write_callback
.WaitForResult());
197 TestIoCallback read_callback
;
198 conn
->Read(read_callback
.read_callback());
199 ASSERT_TRUE(read_callback
.WaitForResult());
200 ASSERT_EQ(9UL, read_callback
.size());
201 ASSERT_EQ(0, read_callback
.buffer()->data()[0]);
202 for (unsigned char j
= 1; j
< kBufferSize
; ++j
) {
203 ASSERT_EQ(i
+ j
- 1, read_callback
.buffer()->data()[j
]);
210 } // namespace device