1 // Copyright 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.
5 #include "base/run_loop.h"
6 #include "base/thread_task_runner_handle.h"
7 #include "content/public/browser/browser_thread.h"
8 #include "device/hid/hid_collection_info.h"
9 #include "device/hid/hid_connection.h"
10 #include "device/hid/hid_device_info.h"
11 #include "device/hid/hid_service.h"
12 #include "device/hid/hid_usage_and_page.h"
13 #include "extensions/shell/test/shell_apitest.h"
14 #include "net/base/io_buffer.h"
16 namespace extensions
{
20 using base::ThreadTaskRunnerHandle
;
21 using content::BrowserThread
;
22 using device::HidCollectionInfo
;
23 using device::HidConnection
;
24 using device::HidDeviceId
;
25 using device::HidDeviceInfo
;
26 using device::HidService
;
27 using device::HidUsageAndPage
;
30 class MockHidConnection
: public HidConnection
{
32 MockHidConnection(const HidDeviceInfo
& device_info
)
33 : HidConnection(device_info
) {}
35 void PlatformClose() override
{}
37 void PlatformRead(const ReadCallback
& callback
) override
{
38 const char kResult
[] = "This is a HID input report.";
39 uint8_t report_id
= device_info().has_report_id
? 1 : 0;
40 scoped_refptr
<IOBuffer
> buffer(new IOBuffer(sizeof(kResult
)));
41 buffer
->data()[0] = report_id
;
42 memcpy(buffer
->data() + 1, kResult
, sizeof(kResult
) - 1);
43 ThreadTaskRunnerHandle::Get()->PostTask(
44 FROM_HERE
, base::Bind(callback
, true, buffer
, sizeof(kResult
)));
47 void PlatformWrite(scoped_refptr
<net::IOBuffer
> buffer
,
49 const WriteCallback
& callback
) override
{
50 const char kExpected
[] = "This is a HID output report.";
52 if (size
== sizeof(kExpected
)) {
53 uint8_t report_id
= buffer
->data()[0];
54 uint8_t expected_report_id
= device_info().has_report_id
? 1 : 0;
55 if (report_id
== expected_report_id
) {
56 if (memcmp(buffer
->data() + 1, kExpected
, sizeof(kExpected
) - 1) == 0) {
61 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
62 base::Bind(callback
, result
));
65 void PlatformGetFeatureReport(uint8_t report_id
,
66 const ReadCallback
& callback
) override
{
67 const char kResult
[] = "This is a HID feature report.";
68 scoped_refptr
<IOBuffer
> buffer(new IOBuffer(sizeof(kResult
)));
70 if (device_info().has_report_id
) {
71 buffer
->data()[offset
++] = report_id
;
73 memcpy(buffer
->data() + offset
, kResult
, sizeof(kResult
) - 1);
74 ThreadTaskRunnerHandle::Get()->PostTask(
76 base::Bind(callback
, true, buffer
, sizeof(kResult
) - 1 + offset
));
79 void PlatformSendFeatureReport(scoped_refptr
<net::IOBuffer
> buffer
,
81 const WriteCallback
& callback
) override
{
82 const char kExpected
[] = "The app is setting this HID feature report.";
84 if (size
== sizeof(kExpected
)) {
85 uint8_t report_id
= buffer
->data()[0];
86 uint8_t expected_report_id
= device_info().has_report_id
? 1 : 0;
87 if (report_id
== expected_report_id
&&
88 memcmp(buffer
->data() + 1, kExpected
, sizeof(kExpected
) - 1) == 0) {
92 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
93 base::Bind(callback
, result
));
97 ~MockHidConnection() {}
100 class MockHidService
: public HidService
{
102 MockHidService() : HidService() {
104 HidDeviceInfo device_info
;
105 device_info
.device_id
= "Device A";
106 device_info
.vendor_id
= 0x18D1;
107 device_info
.product_id
= 0x58F0;
108 device_info
.max_input_report_size
= 128;
109 device_info
.max_output_report_size
= 128;
110 device_info
.max_feature_report_size
= 128;
112 HidCollectionInfo collection_info
;
113 device_info
.collections
.push_back(collection_info
);
115 AddDevice(device_info
);
119 HidDeviceInfo device_info
;
120 device_info
.device_id
= "Device B";
121 device_info
.vendor_id
= 0x18D1;
122 device_info
.product_id
= 0x58F0;
123 device_info
.max_input_report_size
= 128;
124 device_info
.max_output_report_size
= 128;
125 device_info
.max_feature_report_size
= 128;
127 HidCollectionInfo collection_info
;
128 collection_info
.usage
=
129 HidUsageAndPage(0, HidUsageAndPage::kPageVendor
);
130 collection_info
.report_ids
.insert(1);
131 device_info
.has_report_id
= true;
132 device_info
.collections
.push_back(collection_info
);
134 AddDevice(device_info
);
138 HidDeviceInfo device_info
;
139 device_info
.device_id
= "Device C";
140 device_info
.vendor_id
= 0x18D1;
141 device_info
.product_id
= 0x58F1;
142 device_info
.max_input_report_size
= 128;
143 device_info
.max_output_report_size
= 128;
144 device_info
.max_feature_report_size
= 128;
146 HidCollectionInfo collection_info
;
147 device_info
.collections
.push_back(collection_info
);
149 AddDevice(device_info
);
153 void Connect(const HidDeviceId
& device_id
,
154 const ConnectCallback
& callback
) override
{
155 const auto& device_entry
= devices().find(device_id
);
156 scoped_refptr
<HidConnection
> connection
;
157 if (device_entry
!= devices().end()) {
158 connection
= new MockHidConnection(device_entry
->second
);
161 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
162 base::Bind(callback
, connection
));
168 class HidApiTest
: public ShellApiTest
{
170 void SetUpOnMainThread() override
{
171 ShellApiTest::SetUpOnMainThread();
172 base::RunLoop run_loop
;
173 BrowserThread::PostTaskAndReply(BrowserThread::FILE,
175 base::Bind(&HidApiTest::SetUpService
, this),
176 run_loop
.QuitClosure());
180 void SetUpService() { HidService::SetInstanceForTest(new MockHidService()); }
183 IN_PROC_BROWSER_TEST_F(HidApiTest
, HidApp
) {
184 ASSERT_TRUE(RunAppTest("api_test/hid/api")) << message_
;
187 } // namespace extensions