OLD | NEW |
| (Empty) |
1 // Copyright 2015 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. | |
4 | |
5 #include "device/devices_app/usb/device_impl.h" | |
6 | |
7 #include <stddef.h> | |
8 #include <stdint.h> | |
9 | |
10 #include <map> | |
11 #include <numeric> | |
12 #include <queue> | |
13 #include <set> | |
14 #include <string> | |
15 #include <utility> | |
16 #include <vector> | |
17 | |
18 #include "base/bind.h" | |
19 #include "base/macros.h" | |
20 #include "base/message_loop/message_loop.h" | |
21 #include "base/run_loop.h" | |
22 #include "base/stl_util.h" | |
23 #include "device/devices_app/usb/fake_permission_provider.h" | |
24 #include "device/usb/mock_usb_device.h" | |
25 #include "device/usb/mock_usb_device_handle.h" | |
26 #include "mojo/public/cpp/bindings/interface_request.h" | |
27 #include "net/base/io_buffer.h" | |
28 #include "testing/gtest/include/gtest/gtest.h" | |
29 | |
30 using ::testing::Invoke; | |
31 using ::testing::_; | |
32 | |
33 namespace device { | |
34 namespace usb { | |
35 | |
36 namespace { | |
37 | |
38 class ConfigBuilder { | |
39 public: | |
40 explicit ConfigBuilder(uint8_t value) { config_.configuration_value = value; } | |
41 | |
42 ConfigBuilder& AddInterface(uint8_t interface_number, | |
43 uint8_t alternate_setting, | |
44 uint8_t class_code, | |
45 uint8_t subclass_code, | |
46 uint8_t protocol_code) { | |
47 UsbInterfaceDescriptor interface; | |
48 interface.interface_number = interface_number; | |
49 interface.alternate_setting = alternate_setting; | |
50 interface.interface_class = class_code; | |
51 interface.interface_subclass = subclass_code; | |
52 interface.interface_protocol = protocol_code; | |
53 config_.interfaces.push_back(interface); | |
54 return *this; | |
55 } | |
56 | |
57 const UsbConfigDescriptor& config() const { return config_; } | |
58 | |
59 private: | |
60 UsbConfigDescriptor config_; | |
61 }; | |
62 | |
63 void ExpectOpenAndThen(OpenDeviceError expected, | |
64 const base::Closure& continuation, | |
65 OpenDeviceError error) { | |
66 EXPECT_EQ(expected, error); | |
67 continuation.Run(); | |
68 } | |
69 | |
70 void ExpectDeviceInfoAndThen(const std::string& guid, | |
71 uint16_t vendor_id, | |
72 uint16_t product_id, | |
73 const std::string& manufacturer_name, | |
74 const std::string& product_name, | |
75 const std::string& serial_number, | |
76 const base::Closure& continuation, | |
77 DeviceInfoPtr device_info) { | |
78 EXPECT_EQ(guid, device_info->guid); | |
79 EXPECT_EQ(vendor_id, device_info->vendor_id); | |
80 EXPECT_EQ(product_id, device_info->product_id); | |
81 EXPECT_EQ(manufacturer_name, device_info->manufacturer_name); | |
82 EXPECT_EQ(product_name, device_info->product_name); | |
83 EXPECT_EQ(serial_number, device_info->serial_number); | |
84 continuation.Run(); | |
85 } | |
86 | |
87 void ExpectResultAndThen(bool expected_result, | |
88 const base::Closure& continuation, | |
89 bool actual_result) { | |
90 EXPECT_EQ(expected_result, actual_result); | |
91 continuation.Run(); | |
92 } | |
93 | |
94 void ExpectTransferInAndThen(TransferStatus expected_status, | |
95 const std::vector<uint8_t>& expected_bytes, | |
96 const base::Closure& continuation, | |
97 TransferStatus actual_status, | |
98 mojo::Array<uint8_t> actual_bytes) { | |
99 EXPECT_EQ(expected_status, actual_status); | |
100 ASSERT_EQ(expected_bytes.size(), actual_bytes.size()); | |
101 for (size_t i = 0; i < actual_bytes.size(); ++i) { | |
102 EXPECT_EQ(expected_bytes[i], actual_bytes[i]) | |
103 << "Contents differ at index: " << i; | |
104 } | |
105 continuation.Run(); | |
106 } | |
107 | |
108 void ExpectPacketsOutAndThen(const std::vector<uint32_t>& expected_packets, | |
109 const base::Closure& continuation, | |
110 mojo::Array<IsochronousPacketPtr> actual_packets) { | |
111 ASSERT_EQ(expected_packets.size(), actual_packets.size()); | |
112 for (size_t i = 0; i < expected_packets.size(); ++i) { | |
113 EXPECT_EQ(expected_packets[i], actual_packets[i]->transferred_length) | |
114 << "Packet lengths differ at index: " << i; | |
115 EXPECT_EQ(TransferStatus::COMPLETED, actual_packets[i]->status) | |
116 << "Packet at index " << i << " not completed."; | |
117 } | |
118 continuation.Run(); | |
119 } | |
120 | |
121 void ExpectPacketsInAndThen(const std::vector<uint8_t>& expected_bytes, | |
122 const std::vector<uint32_t>& expected_packets, | |
123 const base::Closure& continuation, | |
124 mojo::Array<uint8_t> actual_bytes, | |
125 mojo::Array<IsochronousPacketPtr> actual_packets) { | |
126 ASSERT_EQ(expected_packets.size(), actual_packets.size()); | |
127 for (size_t i = 0; i < expected_packets.size(); ++i) { | |
128 EXPECT_EQ(expected_packets[i], actual_packets[i]->transferred_length) | |
129 << "Packet lengths differ at index: " << i; | |
130 EXPECT_EQ(TransferStatus::COMPLETED, actual_packets[i]->status) | |
131 << "Packet at index " << i << " not completed."; | |
132 } | |
133 ASSERT_EQ(expected_bytes.size(), actual_bytes.size()); | |
134 for (size_t i = 0; i < expected_bytes.size(); ++i) { | |
135 EXPECT_EQ(expected_bytes[i], actual_bytes[i]) | |
136 << "Contents differ at index: " << i; | |
137 } | |
138 continuation.Run(); | |
139 } | |
140 | |
141 void ExpectTransferStatusAndThen(TransferStatus expected_status, | |
142 const base::Closure& continuation, | |
143 TransferStatus actual_status) { | |
144 EXPECT_EQ(expected_status, actual_status); | |
145 continuation.Run(); | |
146 } | |
147 | |
148 class USBDeviceImplTest : public testing::Test { | |
149 public: | |
150 USBDeviceImplTest() | |
151 : message_loop_(new base::MessageLoop), | |
152 is_device_open_(false), | |
153 allow_reset_(false), | |
154 current_config_(0) {} | |
155 | |
156 ~USBDeviceImplTest() override {} | |
157 | |
158 protected: | |
159 MockUsbDevice& mock_device() { return *mock_device_.get(); } | |
160 bool is_device_open() const { return is_device_open_; } | |
161 MockUsbDeviceHandle& mock_handle() { return *mock_handle_.get(); } | |
162 | |
163 void set_allow_reset(bool allow_reset) { allow_reset_ = allow_reset; } | |
164 | |
165 // Creates a mock device and binds a Device proxy to a Device service impl | |
166 // wrapping the mock device. | |
167 DevicePtr GetMockDeviceProxy(uint16_t vendor_id, | |
168 uint16_t product_id, | |
169 const std::string& manufacturer, | |
170 const std::string& product, | |
171 const std::string& serial) { | |
172 mock_device_ = | |
173 new MockUsbDevice(vendor_id, product_id, manufacturer, product, serial); | |
174 mock_handle_ = new MockUsbDeviceHandle(mock_device_.get()); | |
175 | |
176 PermissionProviderPtr permission_provider; | |
177 permission_provider_.Bind(mojo::GetProxy(&permission_provider)); | |
178 DevicePtr proxy; | |
179 new DeviceImpl(mock_device_, std::move(permission_provider), | |
180 mojo::GetProxy(&proxy)); | |
181 | |
182 // Set up mock handle calls to respond based on mock device configs | |
183 // established by the test. | |
184 ON_CALL(mock_device(), Open(_)) | |
185 .WillByDefault(Invoke(this, &USBDeviceImplTest::OpenMockHandle)); | |
186 ON_CALL(mock_device(), GetActiveConfiguration()) | |
187 .WillByDefault( | |
188 Invoke(this, &USBDeviceImplTest::GetActiveConfiguration)); | |
189 ON_CALL(mock_handle(), Close()) | |
190 .WillByDefault(Invoke(this, &USBDeviceImplTest::CloseMockHandle)); | |
191 ON_CALL(mock_handle(), SetConfiguration(_, _)) | |
192 .WillByDefault(Invoke(this, &USBDeviceImplTest::SetConfiguration)); | |
193 ON_CALL(mock_handle(), ClaimInterface(_, _)) | |
194 .WillByDefault(Invoke(this, &USBDeviceImplTest::ClaimInterface)); | |
195 ON_CALL(mock_handle(), ReleaseInterface(_, _)) | |
196 .WillByDefault(Invoke(this, &USBDeviceImplTest::ReleaseInterface)); | |
197 ON_CALL(mock_handle(), SetInterfaceAlternateSetting(_, _, _)) | |
198 .WillByDefault( | |
199 Invoke(this, &USBDeviceImplTest::SetInterfaceAlternateSetting)); | |
200 ON_CALL(mock_handle(), ResetDevice(_)) | |
201 .WillByDefault(Invoke(this, &USBDeviceImplTest::ResetDevice)); | |
202 ON_CALL(mock_handle(), ControlTransfer(_, _, _, _, _, _, _, _, _, _)) | |
203 .WillByDefault(Invoke(this, &USBDeviceImplTest::ControlTransfer)); | |
204 ON_CALL(mock_handle(), GenericTransfer(_, _, _, _, _, _)) | |
205 .WillByDefault(Invoke(this, &USBDeviceImplTest::GenericTransfer)); | |
206 ON_CALL(mock_handle(), IsochronousTransferIn(_, _, _, _)) | |
207 .WillByDefault(Invoke(this, &USBDeviceImplTest::IsochronousTransferIn)); | |
208 ON_CALL(mock_handle(), IsochronousTransferOut(_, _, _, _, _)) | |
209 .WillByDefault( | |
210 Invoke(this, &USBDeviceImplTest::IsochronousTransferOut)); | |
211 | |
212 return proxy; | |
213 } | |
214 | |
215 DevicePtr GetMockDeviceProxy() { | |
216 return GetMockDeviceProxy(0x1234, 0x5678, "ACME", "Frobinator", "ABCDEF"); | |
217 } | |
218 | |
219 void AddMockConfig(const ConfigBuilder& builder) { | |
220 const UsbConfigDescriptor& config = builder.config(); | |
221 DCHECK(!ContainsKey(mock_configs_, config.configuration_value)); | |
222 mock_configs_[config.configuration_value] = config; | |
223 } | |
224 | |
225 void AddMockInboundData(const std::vector<uint8_t>& data) { | |
226 mock_inbound_data_.push(data); | |
227 } | |
228 | |
229 void AddMockInboundPackets( | |
230 const std::vector<uint8_t>& data, | |
231 const std::vector<UsbDeviceHandle::IsochronousPacket>& packets) { | |
232 mock_inbound_data_.push(data); | |
233 mock_inbound_packets_.push(packets); | |
234 } | |
235 | |
236 void AddMockOutboundData(const std::vector<uint8_t>& data) { | |
237 mock_outbound_data_.push(data); | |
238 } | |
239 | |
240 void AddMockOutboundPackets( | |
241 const std::vector<uint8_t>& data, | |
242 const std::vector<UsbDeviceHandle::IsochronousPacket>& packets) { | |
243 mock_outbound_data_.push(data); | |
244 mock_outbound_packets_.push(packets); | |
245 } | |
246 | |
247 private: | |
248 void OpenMockHandle(const UsbDevice::OpenCallback& callback) { | |
249 EXPECT_FALSE(is_device_open_); | |
250 is_device_open_ = true; | |
251 callback.Run(mock_handle_); | |
252 } | |
253 | |
254 void CloseMockHandle() { | |
255 EXPECT_TRUE(is_device_open_); | |
256 is_device_open_ = false; | |
257 } | |
258 | |
259 const UsbConfigDescriptor* GetActiveConfiguration() { | |
260 if (current_config_ == 0) { | |
261 return nullptr; | |
262 } else { | |
263 const auto it = mock_configs_.find(current_config_); | |
264 EXPECT_TRUE(it != mock_configs_.end()); | |
265 return &it->second; | |
266 } | |
267 } | |
268 | |
269 void SetConfiguration(uint8_t value, | |
270 const UsbDeviceHandle::ResultCallback& callback) { | |
271 if (mock_configs_.find(value) != mock_configs_.end()) { | |
272 current_config_ = value; | |
273 callback.Run(true); | |
274 } else { | |
275 callback.Run(false); | |
276 } | |
277 } | |
278 | |
279 void ClaimInterface(uint8_t interface_number, | |
280 const UsbDeviceHandle::ResultCallback& callback) { | |
281 for (const auto& config : mock_configs_) { | |
282 for (const auto& interface : config.second.interfaces) { | |
283 if (interface.interface_number == interface_number) { | |
284 claimed_interfaces_.insert(interface_number); | |
285 callback.Run(true); | |
286 return; | |
287 } | |
288 } | |
289 } | |
290 callback.Run(false); | |
291 } | |
292 | |
293 void ReleaseInterface(uint8_t interface_number, | |
294 const UsbDeviceHandle::ResultCallback& callback) { | |
295 if (ContainsKey(claimed_interfaces_, interface_number)) { | |
296 claimed_interfaces_.erase(interface_number); | |
297 callback.Run(true); | |
298 } else { | |
299 callback.Run(false); | |
300 } | |
301 } | |
302 | |
303 void SetInterfaceAlternateSetting( | |
304 uint8_t interface_number, | |
305 uint8_t alternate_setting, | |
306 const UsbDeviceHandle::ResultCallback& callback) { | |
307 for (const auto& config : mock_configs_) { | |
308 for (const auto& interface : config.second.interfaces) { | |
309 if (interface.interface_number == interface_number && | |
310 interface.alternate_setting == alternate_setting) { | |
311 callback.Run(true); | |
312 return; | |
313 } | |
314 } | |
315 } | |
316 callback.Run(false); | |
317 } | |
318 | |
319 void ResetDevice(const UsbDeviceHandle::ResultCallback& callback) { | |
320 callback.Run(allow_reset_); | |
321 } | |
322 | |
323 void InboundTransfer(const UsbDeviceHandle::TransferCallback& callback) { | |
324 ASSERT_GE(mock_inbound_data_.size(), 1u); | |
325 const std::vector<uint8_t>& bytes = mock_inbound_data_.front(); | |
326 size_t length = bytes.size(); | |
327 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(length); | |
328 std::copy(bytes.begin(), bytes.end(), buffer->data()); | |
329 mock_inbound_data_.pop(); | |
330 callback.Run(USB_TRANSFER_COMPLETED, buffer, length); | |
331 } | |
332 | |
333 void OutboundTransfer(scoped_refptr<net::IOBuffer> buffer, | |
334 size_t length, | |
335 const UsbDeviceHandle::TransferCallback& callback) { | |
336 ASSERT_GE(mock_outbound_data_.size(), 1u); | |
337 const std::vector<uint8_t>& bytes = mock_outbound_data_.front(); | |
338 ASSERT_EQ(bytes.size(), length); | |
339 for (size_t i = 0; i < length; ++i) { | |
340 EXPECT_EQ(bytes[i], buffer->data()[i]) | |
341 << "Contents differ at index: " << i; | |
342 } | |
343 mock_outbound_data_.pop(); | |
344 callback.Run(USB_TRANSFER_COMPLETED, buffer, length); | |
345 } | |
346 | |
347 void ControlTransfer(UsbEndpointDirection direction, | |
348 UsbDeviceHandle::TransferRequestType request_type, | |
349 UsbDeviceHandle::TransferRecipient recipient, | |
350 uint8_t request, | |
351 uint16_t value, | |
352 uint16_t index, | |
353 scoped_refptr<net::IOBuffer> buffer, | |
354 size_t length, | |
355 unsigned int timeout, | |
356 const UsbDeviceHandle::TransferCallback& callback) { | |
357 if (direction == USB_DIRECTION_INBOUND) | |
358 InboundTransfer(callback); | |
359 else | |
360 OutboundTransfer(buffer, length, callback); | |
361 } | |
362 | |
363 void GenericTransfer(UsbEndpointDirection direction, | |
364 uint8_t endpoint, | |
365 scoped_refptr<net::IOBuffer> buffer, | |
366 size_t length, | |
367 unsigned int timeout, | |
368 const UsbDeviceHandle::TransferCallback& callback) { | |
369 if (direction == USB_DIRECTION_INBOUND) | |
370 InboundTransfer(callback); | |
371 else | |
372 OutboundTransfer(buffer, length, callback); | |
373 } | |
374 | |
375 void IsochronousTransferIn( | |
376 uint8_t endpoint_number, | |
377 const std::vector<uint32_t>& packet_lengths, | |
378 unsigned int timeout, | |
379 const UsbDeviceHandle::IsochronousTransferCallback& callback) { | |
380 ASSERT_FALSE(mock_inbound_data_.empty()); | |
381 const std::vector<uint8_t>& bytes = mock_inbound_data_.front(); | |
382 size_t length = bytes.size(); | |
383 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(length); | |
384 std::copy(bytes.begin(), bytes.end(), buffer->data()); | |
385 mock_inbound_data_.pop(); | |
386 | |
387 ASSERT_FALSE(mock_inbound_packets_.empty()); | |
388 std::vector<UsbDeviceHandle::IsochronousPacket> packets = | |
389 mock_inbound_packets_.front(); | |
390 ASSERT_EQ(packets.size(), packet_lengths.size()); | |
391 for (size_t i = 0; i < packets.size(); ++i) { | |
392 EXPECT_EQ(packets[i].length, packet_lengths[i]) | |
393 << "Packet lengths differ at index: " << i; | |
394 } | |
395 mock_inbound_packets_.pop(); | |
396 | |
397 callback.Run(buffer, packets); | |
398 } | |
399 | |
400 void IsochronousTransferOut( | |
401 uint8_t endpoint_number, | |
402 scoped_refptr<net::IOBuffer> buffer, | |
403 const std::vector<uint32_t>& packet_lengths, | |
404 unsigned int timeout, | |
405 const UsbDeviceHandle::IsochronousTransferCallback& callback) { | |
406 ASSERT_FALSE(mock_outbound_data_.empty()); | |
407 const std::vector<uint8_t>& bytes = mock_outbound_data_.front(); | |
408 size_t length = | |
409 std::accumulate(packet_lengths.begin(), packet_lengths.end(), 0u); | |
410 ASSERT_EQ(bytes.size(), length); | |
411 for (size_t i = 0; i < length; ++i) { | |
412 EXPECT_EQ(bytes[i], buffer->data()[i]) << "Contents differ at index: " | |
413 << i; | |
414 } | |
415 mock_outbound_data_.pop(); | |
416 | |
417 ASSERT_FALSE(mock_outbound_packets_.empty()); | |
418 std::vector<UsbDeviceHandle::IsochronousPacket> packets = | |
419 mock_outbound_packets_.front(); | |
420 ASSERT_EQ(packets.size(), packet_lengths.size()); | |
421 for (size_t i = 0; i < packets.size(); ++i) { | |
422 EXPECT_EQ(packets[i].length, packet_lengths[i]) | |
423 << "Packet lengths differ at index: " << i; | |
424 } | |
425 mock_outbound_packets_.pop(); | |
426 | |
427 callback.Run(buffer, packets); | |
428 } | |
429 | |
430 scoped_ptr<base::MessageLoop> message_loop_; | |
431 scoped_refptr<MockUsbDevice> mock_device_; | |
432 scoped_refptr<MockUsbDeviceHandle> mock_handle_; | |
433 bool is_device_open_; | |
434 bool allow_reset_; | |
435 | |
436 std::map<uint8_t, UsbConfigDescriptor> mock_configs_; | |
437 uint8_t current_config_; | |
438 | |
439 std::queue<std::vector<uint8_t>> mock_inbound_data_; | |
440 std::queue<std::vector<uint8_t>> mock_outbound_data_; | |
441 std::queue<std::vector<UsbDeviceHandle::IsochronousPacket>> | |
442 mock_inbound_packets_; | |
443 std::queue<std::vector<UsbDeviceHandle::IsochronousPacket>> | |
444 mock_outbound_packets_; | |
445 | |
446 std::set<uint8_t> claimed_interfaces_; | |
447 | |
448 FakePermissionProvider permission_provider_; | |
449 | |
450 DISALLOW_COPY_AND_ASSIGN(USBDeviceImplTest); | |
451 }; | |
452 | |
453 } // namespace | |
454 | |
455 TEST_F(USBDeviceImplTest, Open) { | |
456 DevicePtr device = GetMockDeviceProxy(); | |
457 | |
458 EXPECT_FALSE(is_device_open()); | |
459 | |
460 EXPECT_CALL(mock_device(), Open(_)); | |
461 | |
462 base::RunLoop loop; | |
463 device->Open( | |
464 base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK, loop.QuitClosure())); | |
465 loop.Run(); | |
466 | |
467 EXPECT_CALL(mock_handle(), Close()); | |
468 } | |
469 | |
470 TEST_F(USBDeviceImplTest, Close) { | |
471 DevicePtr device = GetMockDeviceProxy(); | |
472 | |
473 EXPECT_FALSE(is_device_open()); | |
474 | |
475 EXPECT_CALL(mock_device(), Open(_)); | |
476 | |
477 { | |
478 base::RunLoop loop; | |
479 device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK, | |
480 loop.QuitClosure())); | |
481 loop.Run(); | |
482 } | |
483 | |
484 EXPECT_CALL(mock_handle(), Close()); | |
485 | |
486 { | |
487 base::RunLoop loop; | |
488 device->Close(loop.QuitClosure()); | |
489 loop.Run(); | |
490 } | |
491 | |
492 EXPECT_FALSE(is_device_open()); | |
493 } | |
494 | |
495 // Test that the information returned via the Device::GetDeviceInfo matches that | |
496 // of the underlying device. | |
497 TEST_F(USBDeviceImplTest, GetDeviceInfo) { | |
498 DevicePtr device = | |
499 GetMockDeviceProxy(0x1234, 0x5678, "ACME", "Frobinator", "ABCDEF"); | |
500 | |
501 base::RunLoop loop; | |
502 device->GetDeviceInfo(base::Bind(&ExpectDeviceInfoAndThen, | |
503 mock_device().guid(), 0x1234, 0x5678, "ACME", | |
504 "Frobinator", "ABCDEF", loop.QuitClosure())); | |
505 loop.Run(); | |
506 } | |
507 | |
508 TEST_F(USBDeviceImplTest, SetInvalidConfiguration) { | |
509 DevicePtr device = GetMockDeviceProxy(); | |
510 | |
511 EXPECT_CALL(mock_device(), Open(_)); | |
512 | |
513 { | |
514 base::RunLoop loop; | |
515 device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK, | |
516 loop.QuitClosure())); | |
517 loop.Run(); | |
518 } | |
519 | |
520 EXPECT_CALL(mock_handle(), SetConfiguration(42, _)); | |
521 | |
522 { | |
523 // SetConfiguration should fail because 42 is not a valid mock | |
524 // configuration. | |
525 base::RunLoop loop; | |
526 device->SetConfiguration( | |
527 42, base::Bind(&ExpectResultAndThen, false, loop.QuitClosure())); | |
528 loop.Run(); | |
529 } | |
530 | |
531 EXPECT_CALL(mock_handle(), Close()); | |
532 } | |
533 | |
534 TEST_F(USBDeviceImplTest, SetValidConfiguration) { | |
535 DevicePtr device = GetMockDeviceProxy(); | |
536 | |
537 EXPECT_CALL(mock_device(), Open(_)); | |
538 | |
539 { | |
540 base::RunLoop loop; | |
541 device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK, | |
542 loop.QuitClosure())); | |
543 loop.Run(); | |
544 } | |
545 | |
546 EXPECT_CALL(mock_handle(), SetConfiguration(42, _)); | |
547 | |
548 AddMockConfig(ConfigBuilder(42)); | |
549 | |
550 { | |
551 // SetConfiguration should succeed because 42 is a valid mock configuration. | |
552 base::RunLoop loop; | |
553 device->SetConfiguration( | |
554 42, base::Bind(&ExpectResultAndThen, true, loop.QuitClosure())); | |
555 loop.Run(); | |
556 } | |
557 | |
558 EXPECT_CALL(mock_handle(), Close()); | |
559 } | |
560 | |
561 // Verify that the result of Reset() reflects the underlying UsbDeviceHandle's | |
562 // ResetDevice() result. | |
563 TEST_F(USBDeviceImplTest, Reset) { | |
564 DevicePtr device = GetMockDeviceProxy(); | |
565 | |
566 EXPECT_CALL(mock_device(), Open(_)); | |
567 | |
568 { | |
569 base::RunLoop loop; | |
570 device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK, | |
571 loop.QuitClosure())); | |
572 loop.Run(); | |
573 } | |
574 | |
575 EXPECT_CALL(mock_handle(), ResetDevice(_)); | |
576 | |
577 set_allow_reset(true); | |
578 | |
579 { | |
580 base::RunLoop loop; | |
581 device->Reset(base::Bind(&ExpectResultAndThen, true, loop.QuitClosure())); | |
582 loop.Run(); | |
583 } | |
584 | |
585 EXPECT_CALL(mock_handle(), ResetDevice(_)); | |
586 | |
587 set_allow_reset(false); | |
588 | |
589 { | |
590 base::RunLoop loop; | |
591 device->Reset(base::Bind(&ExpectResultAndThen, false, loop.QuitClosure())); | |
592 loop.Run(); | |
593 } | |
594 | |
595 EXPECT_CALL(mock_handle(), Close()); | |
596 } | |
597 | |
598 TEST_F(USBDeviceImplTest, ClaimAndReleaseInterface) { | |
599 DevicePtr device = GetMockDeviceProxy(); | |
600 | |
601 EXPECT_CALL(mock_device(), Open(_)); | |
602 | |
603 { | |
604 base::RunLoop loop; | |
605 device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK, | |
606 loop.QuitClosure())); | |
607 loop.Run(); | |
608 } | |
609 | |
610 // Now add a mock interface #1. | |
611 AddMockConfig(ConfigBuilder(1).AddInterface(1, 0, 1, 2, 3)); | |
612 | |
613 EXPECT_CALL(mock_handle(), SetConfiguration(1, _)); | |
614 | |
615 { | |
616 base::RunLoop loop; | |
617 device->SetConfiguration( | |
618 1, base::Bind(&ExpectResultAndThen, true, loop.QuitClosure())); | |
619 loop.Run(); | |
620 } | |
621 | |
622 EXPECT_CALL(mock_device(), GetActiveConfiguration()); | |
623 EXPECT_CALL(mock_handle(), ClaimInterface(2, _)); | |
624 | |
625 { | |
626 // Try to claim an invalid interface and expect failure. | |
627 base::RunLoop loop; | |
628 device->ClaimInterface( | |
629 2, base::Bind(&ExpectResultAndThen, false, loop.QuitClosure())); | |
630 loop.Run(); | |
631 } | |
632 | |
633 EXPECT_CALL(mock_device(), GetActiveConfiguration()); | |
634 EXPECT_CALL(mock_handle(), ClaimInterface(1, _)); | |
635 | |
636 { | |
637 base::RunLoop loop; | |
638 device->ClaimInterface( | |
639 1, base::Bind(&ExpectResultAndThen, true, loop.QuitClosure())); | |
640 loop.Run(); | |
641 } | |
642 | |
643 EXPECT_CALL(mock_handle(), ReleaseInterface(2, _)); | |
644 | |
645 { | |
646 // Releasing a non-existent interface should fail. | |
647 base::RunLoop loop; | |
648 device->ReleaseInterface( | |
649 2, base::Bind(&ExpectResultAndThen, false, loop.QuitClosure())); | |
650 loop.Run(); | |
651 } | |
652 | |
653 EXPECT_CALL(mock_handle(), ReleaseInterface(1, _)); | |
654 | |
655 { | |
656 // Now this should release the claimed interface and close the handle. | |
657 base::RunLoop loop; | |
658 device->ReleaseInterface( | |
659 1, base::Bind(&ExpectResultAndThen, true, loop.QuitClosure())); | |
660 loop.Run(); | |
661 } | |
662 | |
663 EXPECT_CALL(mock_handle(), Close()); | |
664 } | |
665 | |
666 TEST_F(USBDeviceImplTest, SetInterfaceAlternateSetting) { | |
667 DevicePtr device = GetMockDeviceProxy(); | |
668 | |
669 EXPECT_CALL(mock_device(), Open(_)); | |
670 | |
671 { | |
672 base::RunLoop loop; | |
673 device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK, | |
674 loop.QuitClosure())); | |
675 loop.Run(); | |
676 } | |
677 | |
678 AddMockConfig(ConfigBuilder(1) | |
679 .AddInterface(1, 0, 1, 2, 3) | |
680 .AddInterface(1, 42, 1, 2, 3) | |
681 .AddInterface(2, 0, 1, 2, 3)); | |
682 | |
683 EXPECT_CALL(mock_handle(), SetInterfaceAlternateSetting(1, 42, _)); | |
684 | |
685 { | |
686 base::RunLoop loop; | |
687 device->SetInterfaceAlternateSetting( | |
688 1, 42, base::Bind(&ExpectResultAndThen, true, loop.QuitClosure())); | |
689 loop.Run(); | |
690 } | |
691 | |
692 EXPECT_CALL(mock_handle(), SetInterfaceAlternateSetting(1, 100, _)); | |
693 | |
694 { | |
695 base::RunLoop loop; | |
696 device->SetInterfaceAlternateSetting( | |
697 1, 100, base::Bind(&ExpectResultAndThen, false, loop.QuitClosure())); | |
698 loop.Run(); | |
699 } | |
700 | |
701 EXPECT_CALL(mock_handle(), Close()); | |
702 } | |
703 | |
704 TEST_F(USBDeviceImplTest, ControlTransfer) { | |
705 DevicePtr device = GetMockDeviceProxy(); | |
706 | |
707 EXPECT_CALL(mock_device(), Open(_)); | |
708 | |
709 { | |
710 base::RunLoop loop; | |
711 device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK, | |
712 loop.QuitClosure())); | |
713 loop.Run(); | |
714 } | |
715 | |
716 AddMockConfig(ConfigBuilder(1).AddInterface(7, 0, 1, 2, 3)); | |
717 | |
718 EXPECT_CALL(mock_device(), GetActiveConfiguration()); | |
719 EXPECT_CALL(mock_handle(), SetConfiguration(1, _)); | |
720 | |
721 { | |
722 base::RunLoop loop; | |
723 device->SetConfiguration( | |
724 1, base::Bind(&ExpectResultAndThen, true, loop.QuitClosure())); | |
725 loop.Run(); | |
726 } | |
727 | |
728 std::vector<uint8_t> fake_data; | |
729 fake_data.push_back(41); | |
730 fake_data.push_back(42); | |
731 fake_data.push_back(43); | |
732 | |
733 AddMockInboundData(fake_data); | |
734 | |
735 EXPECT_CALL(mock_handle(), | |
736 ControlTransfer(USB_DIRECTION_INBOUND, UsbDeviceHandle::STANDARD, | |
737 UsbDeviceHandle::DEVICE, 5, 6, 7, _, _, 0, _)); | |
738 | |
739 { | |
740 auto params = ControlTransferParams::New(); | |
741 params->type = ControlTransferType::STANDARD; | |
742 params->recipient = ControlTransferRecipient::DEVICE; | |
743 params->request = 5; | |
744 params->value = 6; | |
745 params->index = 7; | |
746 base::RunLoop loop; | |
747 device->ControlTransferIn( | |
748 std::move(params), static_cast<uint32_t>(fake_data.size()), 0, | |
749 base::Bind(&ExpectTransferInAndThen, TransferStatus::COMPLETED, | |
750 fake_data, loop.QuitClosure())); | |
751 loop.Run(); | |
752 } | |
753 | |
754 AddMockOutboundData(fake_data); | |
755 | |
756 EXPECT_CALL(mock_device(), GetActiveConfiguration()); | |
757 EXPECT_CALL(mock_handle(), | |
758 ControlTransfer(USB_DIRECTION_OUTBOUND, UsbDeviceHandle::STANDARD, | |
759 UsbDeviceHandle::INTERFACE, 5, 6, 7, _, _, 0, _)); | |
760 | |
761 { | |
762 auto params = ControlTransferParams::New(); | |
763 params->type = ControlTransferType::STANDARD; | |
764 params->recipient = ControlTransferRecipient::INTERFACE; | |
765 params->request = 5; | |
766 params->value = 6; | |
767 params->index = 7; | |
768 base::RunLoop loop; | |
769 device->ControlTransferOut( | |
770 std::move(params), mojo::Array<uint8_t>::From(fake_data), 0, | |
771 base::Bind(&ExpectTransferStatusAndThen, TransferStatus::COMPLETED, | |
772 loop.QuitClosure())); | |
773 loop.Run(); | |
774 } | |
775 | |
776 EXPECT_CALL(mock_handle(), Close()); | |
777 } | |
778 | |
779 TEST_F(USBDeviceImplTest, GenericTransfer) { | |
780 DevicePtr device = GetMockDeviceProxy(); | |
781 | |
782 EXPECT_CALL(mock_device(), Open(_)); | |
783 | |
784 { | |
785 base::RunLoop loop; | |
786 device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK, | |
787 loop.QuitClosure())); | |
788 loop.Run(); | |
789 } | |
790 | |
791 std::string message1 = "say hello please"; | |
792 std::vector<uint8_t> fake_outbound_data(message1.size()); | |
793 std::copy(message1.begin(), message1.end(), fake_outbound_data.begin()); | |
794 | |
795 std::string message2 = "hello world!"; | |
796 std::vector<uint8_t> fake_inbound_data(message2.size()); | |
797 std::copy(message2.begin(), message2.end(), fake_inbound_data.begin()); | |
798 | |
799 AddMockConfig(ConfigBuilder(1).AddInterface(7, 0, 1, 2, 3)); | |
800 AddMockOutboundData(fake_outbound_data); | |
801 AddMockInboundData(fake_inbound_data); | |
802 | |
803 EXPECT_CALL(mock_handle(), GenericTransfer(USB_DIRECTION_OUTBOUND, 0x01, _, | |
804 fake_outbound_data.size(), 0, _)); | |
805 | |
806 { | |
807 base::RunLoop loop; | |
808 device->GenericTransferOut( | |
809 1, mojo::Array<uint8_t>::From(fake_outbound_data), 0, | |
810 base::Bind(&ExpectTransferStatusAndThen, TransferStatus::COMPLETED, | |
811 loop.QuitClosure())); | |
812 loop.Run(); | |
813 } | |
814 | |
815 EXPECT_CALL(mock_handle(), GenericTransfer(USB_DIRECTION_INBOUND, 0x81, _, | |
816 fake_inbound_data.size(), 0, _)); | |
817 | |
818 { | |
819 base::RunLoop loop; | |
820 device->GenericTransferIn( | |
821 1, static_cast<uint32_t>(fake_inbound_data.size()), 0, | |
822 base::Bind(&ExpectTransferInAndThen, TransferStatus::COMPLETED, | |
823 fake_inbound_data, loop.QuitClosure())); | |
824 loop.Run(); | |
825 } | |
826 | |
827 EXPECT_CALL(mock_handle(), Close()); | |
828 } | |
829 | |
830 TEST_F(USBDeviceImplTest, IsochronousTransfer) { | |
831 DevicePtr device = GetMockDeviceProxy(); | |
832 | |
833 EXPECT_CALL(mock_device(), Open(_)); | |
834 | |
835 { | |
836 base::RunLoop loop; | |
837 device->Open(base::Bind(&ExpectOpenAndThen, OpenDeviceError::OK, | |
838 loop.QuitClosure())); | |
839 loop.Run(); | |
840 } | |
841 | |
842 std::vector<UsbDeviceHandle::IsochronousPacket> fake_packets(4); | |
843 for (size_t i = 0; i < fake_packets.size(); ++i) { | |
844 fake_packets[i].length = 8; | |
845 fake_packets[i].transferred_length = 8; | |
846 fake_packets[i].status = USB_TRANSFER_COMPLETED; | |
847 } | |
848 std::vector<uint32_t> fake_packet_lengths(4, 8); | |
849 | |
850 std::vector<uint32_t> expected_transferred_lengths(4, 8); | |
851 | |
852 std::string outbound_data = "aaaaaaaabbbbbbbbccccccccdddddddd"; | |
853 std::vector<uint8_t> fake_outbound_data(outbound_data.size()); | |
854 std::copy(outbound_data.begin(), outbound_data.end(), | |
855 fake_outbound_data.begin()); | |
856 | |
857 std::string inbound_data = "ddddddddccccccccbbbbbbbbaaaaaaaa"; | |
858 std::vector<uint8_t> fake_inbound_data(inbound_data.size()); | |
859 std::copy(inbound_data.begin(), inbound_data.end(), | |
860 fake_inbound_data.begin()); | |
861 | |
862 AddMockConfig(ConfigBuilder(1).AddInterface(7, 0, 1, 2, 3)); | |
863 AddMockOutboundPackets(fake_outbound_data, fake_packets); | |
864 AddMockInboundPackets(fake_inbound_data, fake_packets); | |
865 | |
866 EXPECT_CALL(mock_handle(), | |
867 IsochronousTransferOut(0x01, _, fake_packet_lengths, 0, _)); | |
868 | |
869 { | |
870 base::RunLoop loop; | |
871 device->IsochronousTransferOut( | |
872 1, mojo::Array<uint8_t>::From(fake_outbound_data), | |
873 mojo::Array<uint32_t>::From(fake_packet_lengths), 0, | |
874 base::Bind(&ExpectPacketsOutAndThen, expected_transferred_lengths, | |
875 loop.QuitClosure())); | |
876 loop.Run(); | |
877 } | |
878 | |
879 EXPECT_CALL(mock_handle(), | |
880 IsochronousTransferIn(0x81, fake_packet_lengths, 0, _)); | |
881 | |
882 { | |
883 base::RunLoop loop; | |
884 device->IsochronousTransferIn( | |
885 1, mojo::Array<uint32_t>::From(fake_packet_lengths), 0, | |
886 base::Bind(&ExpectPacketsInAndThen, fake_inbound_data, | |
887 expected_transferred_lengths, loop.QuitClosure())); | |
888 loop.Run(); | |
889 } | |
890 | |
891 EXPECT_CALL(mock_handle(), Close()); | |
892 } | |
893 | |
894 } // namespace usb | |
895 } // namespace device | |
OLD | NEW |