Reland the ULONG -> SIZE_T change from 317177
[chromium-blink-merge.git] / extensions / browser / api / hid / hid_apitest.cc
blob63012a10663c01d282df1dd9b4fa00678bc371e5
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/bind.h"
6 #include "base/run_loop.h"
7 #include "base/thread_task_runner_handle.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 "extensions/test/extension_test_message_listener.h"
15 #include "net/base/io_buffer.h"
17 using base::ThreadTaskRunnerHandle;
18 using device::HidCollectionInfo;
19 using device::HidConnection;
20 using device::HidDeviceId;
21 using device::HidDeviceInfo;
22 using device::HidService;
23 using device::HidUsageAndPage;
24 using net::IOBuffer;
26 namespace device {
28 // These report descriptors define two devices with 8-byte input, output and
29 // feature reports. The first implements usage page 0xFF00 and has a single
30 // report without and ID. The second implements usage page 0xFF01 and has a
31 // single report with ID 1.
32 const uint8 kReportDescriptor[] = {0x06, 0x00, 0xFF, 0x08, 0xA1, 0x01, 0x15,
33 0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95,
34 0x08, 0x08, 0x81, 0x02, 0x08, 0x91, 0x02,
35 0x08, 0xB1, 0x02, 0xC0};
36 const uint8 kReportDescriptorWithIDs[] = {
37 0x06, 0x01, 0xFF, 0x08, 0xA1, 0x01, 0x15, 0x00, 0x26,
38 0xFF, 0x00, 0x85, 0x01, 0x75, 0x08, 0x95, 0x08, 0x08,
39 0x81, 0x02, 0x08, 0x91, 0x02, 0x08, 0xB1, 0x02, 0xC0};
41 class MockHidConnection : public HidConnection {
42 public:
43 MockHidConnection(scoped_refptr<HidDeviceInfo> device_info)
44 : HidConnection(device_info) {}
46 void PlatformClose() override {}
48 void PlatformRead(const ReadCallback& callback) override {
49 const char kResult[] = "This is a HID input report.";
50 uint8_t report_id = device_info()->has_report_id() ? 1 : 0;
51 scoped_refptr<IOBuffer> buffer(new IOBuffer(sizeof(kResult)));
52 buffer->data()[0] = report_id;
53 memcpy(buffer->data() + 1, kResult, sizeof(kResult) - 1);
54 ThreadTaskRunnerHandle::Get()->PostTask(
55 FROM_HERE, base::Bind(callback, true, buffer, sizeof(kResult)));
58 void PlatformWrite(scoped_refptr<net::IOBuffer> buffer,
59 size_t size,
60 const WriteCallback& callback) override {
61 const char kExpected[] = "o-report"; // 8 bytes
62 bool result = false;
63 if (size == sizeof(kExpected)) {
64 uint8_t report_id = buffer->data()[0];
65 uint8_t expected_report_id = device_info()->has_report_id() ? 1 : 0;
66 if (report_id == expected_report_id) {
67 if (memcmp(buffer->data() + 1, kExpected, sizeof(kExpected) - 1) == 0) {
68 result = true;
72 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
73 base::Bind(callback, result));
76 void PlatformGetFeatureReport(uint8_t report_id,
77 const ReadCallback& callback) override {
78 const char kResult[] = "This is a HID feature report.";
79 scoped_refptr<IOBuffer> buffer(new IOBuffer(sizeof(kResult)));
80 size_t offset = 0;
81 if (device_info()->has_report_id()) {
82 buffer->data()[offset++] = report_id;
84 memcpy(buffer->data() + offset, kResult, sizeof(kResult) - 1);
85 ThreadTaskRunnerHandle::Get()->PostTask(
86 FROM_HERE,
87 base::Bind(callback, true, buffer, sizeof(kResult) - 1 + offset));
90 void PlatformSendFeatureReport(scoped_refptr<net::IOBuffer> buffer,
91 size_t size,
92 const WriteCallback& callback) override {
93 const char kExpected[] = "The app is setting this HID feature report.";
94 bool result = false;
95 if (size == sizeof(kExpected)) {
96 uint8_t report_id = buffer->data()[0];
97 uint8_t expected_report_id = device_info()->has_report_id() ? 1 : 0;
98 if (report_id == expected_report_id &&
99 memcmp(buffer->data() + 1, kExpected, sizeof(kExpected) - 1) == 0) {
100 result = true;
103 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
104 base::Bind(callback, result));
107 private:
108 ~MockHidConnection() override {}
111 class MockHidService : public HidService {
112 public:
113 MockHidService() : HidService() {
114 // Verify that devices are enumerated properly even when the first
115 // enumeration happens asynchronously.
116 ThreadTaskRunnerHandle::Get()->PostTask(
117 FROM_HERE, base::Bind(&MockHidService::LazyFirstEnumeration,
118 base::Unretained(this)));
121 void Connect(const HidDeviceId& device_id,
122 const ConnectCallback& callback) override {
123 const auto& device_entry = devices().find(device_id);
124 scoped_refptr<HidConnection> connection;
125 if (device_entry != devices().end()) {
126 connection = new MockHidConnection(device_entry->second);
129 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
130 base::Bind(callback, connection));
133 void LazyFirstEnumeration() {
134 AddDevice("A", 0x18D1, 0x58F0, false);
135 AddDevice("B", 0x18D1, 0x58F0, true);
136 AddDevice("C", 0x18D1, 0x58F1, false);
137 FirstEnumerationComplete();
140 void AddDevice(const std::string& device_id,
141 int vendor_id,
142 int product_id,
143 bool report_id) {
144 std::vector<uint8> report_descriptor;
145 if (report_id) {
146 report_descriptor.insert(
147 report_descriptor.begin(), kReportDescriptorWithIDs,
148 kReportDescriptorWithIDs + sizeof(kReportDescriptorWithIDs));
149 } else {
150 report_descriptor.insert(report_descriptor.begin(), kReportDescriptor,
151 kReportDescriptor + sizeof(kReportDescriptor));
153 HidService::AddDevice(new HidDeviceInfo(device_id, vendor_id, product_id,
154 "", "", kHIDBusTypeUSB,
155 report_descriptor));
158 void RemoveDevice(const std::string& device_id) {
159 HidService::RemoveDevice(device_id);
163 } // namespace device
165 namespace extensions {
167 class HidApiTest : public ShellApiTest {
168 public:
169 void SetUpOnMainThread() override {
170 ShellApiTest::SetUpOnMainThread();
171 hid_service_ = new device::MockHidService();
172 HidService::SetInstanceForTest(hid_service_);
175 protected:
176 device::MockHidService* hid_service_;
179 IN_PROC_BROWSER_TEST_F(HidApiTest, HidApp) {
180 ASSERT_TRUE(RunAppTest("api_test/hid/api")) << message_;
183 IN_PROC_BROWSER_TEST_F(HidApiTest, OnDeviceAdded) {
184 ExtensionTestMessageListener load_listener("loaded", false);
185 ExtensionTestMessageListener result_listener("success", false);
186 result_listener.set_failure_message("failure");
188 ASSERT_TRUE(LoadApp("api_test/hid/add_event"));
189 ASSERT_TRUE(load_listener.WaitUntilSatisfied());
191 // Add a blocked device first so that the test will fail if a notification is
192 // received.
193 hid_service_->AddDevice("D", 0x18D1, 0x58F1, false);
194 hid_service_->AddDevice("E", 0x18D1, 0x58F0, false);
195 ASSERT_TRUE(result_listener.WaitUntilSatisfied());
196 EXPECT_EQ("success", result_listener.message());
199 IN_PROC_BROWSER_TEST_F(HidApiTest, OnDeviceRemoved) {
200 ExtensionTestMessageListener load_listener("loaded", false);
201 ExtensionTestMessageListener result_listener("success", false);
202 result_listener.set_failure_message("failure");
204 ASSERT_TRUE(LoadApp("api_test/hid/remove_event"));
205 ASSERT_TRUE(load_listener.WaitUntilSatisfied());
207 // Device C was not returned by chrome.hid.getDevices, the app will not get
208 // a notification.
209 hid_service_->RemoveDevice("C");
210 // Device A was returned, the app will get a notification.
211 hid_service_->RemoveDevice("A");
212 ASSERT_TRUE(result_listener.WaitUntilSatisfied());
213 EXPECT_EQ("success", result_listener.message());
216 } // namespace extensions