| #!/usr/bin/python |
| # Copyright 2014 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import unittest |
| import uuid |
| |
| import mock |
| |
| import gadget |
| import usb_constants |
| import usb_descriptors |
| |
| |
| device_desc = usb_descriptors.DeviceDescriptor( |
| idVendor=0x18D1, # Google Inc. |
| idProduct=0xFF00, |
| bcdUSB=0x0200, |
| iManufacturer=1, |
| iProduct=2, |
| iSerialNumber=3, |
| bNumConfigurations=1, |
| bcdDevice=0x0100) |
| |
| fs_config_desc = usb_descriptors.ConfigurationDescriptor( |
| bmAttributes=0xC0, |
| MaxPower=50) |
| |
| fs_interface_desc = usb_descriptors.InterfaceDescriptor( |
| bInterfaceNumber=0 |
| ) |
| fs_config_desc.AddInterface(fs_interface_desc) |
| |
| fs_bulk_in_endpoint_desc = usb_descriptors.EndpointDescriptor( |
| bEndpointAddress=0x01, |
| bmAttributes=usb_constants.TransferType.BULK, |
| wMaxPacketSize=64, |
| bInterval=0 |
| ) |
| fs_interface_desc.AddEndpoint(fs_bulk_in_endpoint_desc) |
| |
| fs_bulk_out_endpoint_desc = usb_descriptors.EndpointDescriptor( |
| bEndpointAddress=0x81, |
| bmAttributes=usb_constants.TransferType.BULK, |
| wMaxPacketSize=64, |
| bInterval=0 |
| ) |
| fs_interface_desc.AddEndpoint(fs_bulk_out_endpoint_desc) |
| |
| fs_alt_interface_desc = usb_descriptors.InterfaceDescriptor( |
| bInterfaceNumber=0, |
| bAlternateSetting=1 |
| ) |
| fs_config_desc.AddInterface(fs_alt_interface_desc) |
| |
| fs_interrupt_in_endpoint_desc = usb_descriptors.EndpointDescriptor( |
| bEndpointAddress=0x01, |
| bmAttributes=usb_constants.TransferType.INTERRUPT, |
| wMaxPacketSize=64, |
| bInterval=1 |
| ) |
| fs_alt_interface_desc.AddEndpoint(fs_interrupt_in_endpoint_desc) |
| |
| fs_interrupt_out_endpoint_desc = usb_descriptors.EndpointDescriptor( |
| bEndpointAddress=0x81, |
| bmAttributes=usb_constants.TransferType.INTERRUPT, |
| wMaxPacketSize=64, |
| bInterval=1 |
| ) |
| fs_alt_interface_desc.AddEndpoint(fs_interrupt_out_endpoint_desc) |
| |
| hs_config_desc = usb_descriptors.ConfigurationDescriptor( |
| bmAttributes=0xC0, |
| MaxPower=50) |
| |
| hs_interface_desc = usb_descriptors.InterfaceDescriptor( |
| bInterfaceNumber=0 |
| ) |
| hs_config_desc.AddInterface(hs_interface_desc) |
| |
| hs_bulk_in_endpoint_desc = usb_descriptors.EndpointDescriptor( |
| bEndpointAddress=0x01, |
| bmAttributes=usb_constants.TransferType.BULK, |
| wMaxPacketSize=512, |
| bInterval=0 |
| ) |
| hs_interface_desc.AddEndpoint(hs_bulk_in_endpoint_desc) |
| |
| hs_bulk_out_endpoint_desc = usb_descriptors.EndpointDescriptor( |
| bEndpointAddress=0x81, |
| bmAttributes=usb_constants.TransferType.BULK, |
| wMaxPacketSize=512, |
| bInterval=0 |
| ) |
| hs_interface_desc.AddEndpoint(hs_bulk_out_endpoint_desc) |
| |
| hs_alt_interface_desc = usb_descriptors.InterfaceDescriptor( |
| bInterfaceNumber=0, |
| bAlternateSetting=1 |
| ) |
| hs_config_desc.AddInterface(hs_alt_interface_desc) |
| |
| hs_interrupt_in_endpoint_desc = usb_descriptors.EndpointDescriptor( |
| bEndpointAddress=0x01, |
| bmAttributes=usb_constants.TransferType.INTERRUPT, |
| wMaxPacketSize=256, |
| bInterval=1 |
| ) |
| hs_alt_interface_desc.AddEndpoint(hs_interrupt_in_endpoint_desc) |
| |
| hs_interrupt_out_endpoint_desc = usb_descriptors.EndpointDescriptor( |
| bEndpointAddress=0x81, |
| bmAttributes=usb_constants.TransferType.INTERRUPT, |
| wMaxPacketSize=256, |
| bInterval=1 |
| ) |
| hs_alt_interface_desc.AddEndpoint(hs_interrupt_out_endpoint_desc) |
| |
| |
| class GadgetTest(unittest.TestCase): |
| |
| def test_get_descriptors(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| self.assertEquals(g.GetDeviceDescriptor(), device_desc) |
| self.assertEquals(g.GetFullSpeedConfigurationDescriptor(), fs_config_desc) |
| self.assertEquals(g.GetHighSpeedConfigurationDescriptor(), hs_config_desc) |
| with self.assertRaisesRegexp(RuntimeError, 'not connected'): |
| g.GetConfigurationDescriptor() |
| |
| def test_connect_full_speed(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| g.Connected(mock.Mock(), usb_constants.Speed.FULL) |
| self.assertTrue(g.IsConnected()) |
| self.assertEquals(g.GetSpeed(), usb_constants.Speed.FULL) |
| self.assertEquals(g.GetConfigurationDescriptor(), fs_config_desc) |
| g.Disconnected() |
| self.assertFalse(g.IsConnected()) |
| |
| def test_connect_high_speed(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| g.Connected(mock.Mock(), usb_constants.Speed.HIGH) |
| self.assertTrue(g.IsConnected()) |
| self.assertEquals(g.GetSpeed(), usb_constants.Speed.HIGH) |
| self.assertEquals(g.GetConfigurationDescriptor(), hs_config_desc) |
| g.Disconnected() |
| self.assertFalse(g.IsConnected()) |
| |
| def test_string_index_out_of_range(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| with self.assertRaisesRegexp(ValueError, 'index out of range'): |
| g.AddStringDescriptor(0, 'Hello world!') |
| |
| def test_language_id_out_of_range(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| with self.assertRaisesRegexp(ValueError, 'language code out of range'): |
| g.AddStringDescriptor(1, 'Hello world!', lang=-1) |
| |
| def test_get_languages(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| g.AddStringDescriptor(1, 'Hello world!') |
| desc = g.ControlRead(0x80, 6, 0x0300, 0, 255) |
| self.assertEquals(desc, '\x04\x03\x09\x04') |
| |
| def test_get_string_descriptor(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| g.AddStringDescriptor(1, 'Hello world!') |
| desc = g.ControlRead(0x80, 6, 0x0301, 0x0409, 255) |
| self.assertEquals(desc, '\x1A\x03H\0e\0l\0l\0o\0 \0w\0o\0r\0l\0d\0!\0') |
| |
| def test_get_missing_string_descriptor(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| g.AddStringDescriptor(1, 'Hello world!') |
| desc = g.ControlRead(0x80, 6, 0x0302, 0x0409, 255) |
| self.assertEquals(desc, None) |
| |
| def test_get_missing_string_language(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| g.AddStringDescriptor(1, 'Hello world!') |
| desc = g.ControlRead(0x80, 6, 0x0301, 0x040C, 255) |
| self.assertEquals(desc, None) |
| |
| def test_class_and_vendor_transfers(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| self.assertIsNone(g.ControlRead(0xA0, 0, 0, 0, 0)) |
| self.assertIsNone(g.ControlRead(0xC0, 0, 0, 0, 0)) |
| self.assertIsNone(g.ControlWrite(0x20, 0, 0, 0, '')) |
| self.assertIsNone(g.ControlWrite(0x40, 0, 0, 0, '')) |
| |
| def test_set_configuration(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| chip = mock.Mock() |
| g.Connected(chip, usb_constants.Speed.HIGH) |
| g.ControlWrite(0, 9, 1, 0, 0) |
| chip.StartEndpoint.assert_has_calls([ |
| mock.call(hs_bulk_in_endpoint_desc), |
| mock.call(hs_bulk_out_endpoint_desc) |
| ]) |
| |
| def test_set_configuration_zero(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| chip = mock.Mock() |
| g.Connected(chip, usb_constants.Speed.HIGH) |
| g.ControlWrite(0, 9, 1, 0, 0) |
| chip.StartEndpoint.reset_mock() |
| g.ControlWrite(0, 9, 0, 0, 0) |
| chip.StopEndpoint.assert_has_calls([ |
| mock.call(0x01), |
| mock.call(0x81) |
| ]) |
| |
| def test_set_bad_configuration(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| g.Connected(mock.Mock(), usb_constants.Speed.HIGH) |
| self.assertIsNone(g.ControlWrite(0, 9, 2, 0, 0)) |
| |
| def test_set_interface(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| chip = mock.Mock() |
| g.Connected(chip, usb_constants.Speed.HIGH) |
| self.assertTrue(g.ControlWrite(0, 9, 1, 0, 0)) |
| chip.reset_mock() |
| self.assertTrue(g.ControlWrite(1, 11, 1, 0, 0)) |
| chip.StopEndpoint.assert_has_calls([ |
| mock.call(0x01), |
| mock.call(0x81) |
| ]) |
| chip.StartEndpoint.assert_has_calls([ |
| mock.call(hs_interrupt_in_endpoint_desc), |
| mock.call(hs_interrupt_out_endpoint_desc) |
| ]) |
| chip.reset_mock() |
| self.assertTrue(g.ControlWrite(1, 11, 0, 0, 0)) |
| chip.StopEndpoint.assert_has_calls([ |
| mock.call(0x01), |
| mock.call(0x81) |
| ]) |
| chip.StartEndpoint.assert_has_calls([ |
| mock.call(hs_bulk_in_endpoint_desc), |
| mock.call(hs_bulk_out_endpoint_desc) |
| ]) |
| |
| def test_set_bad_interface(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| g.Connected(mock.Mock(), usb_constants.Speed.HIGH) |
| self.assertTrue(g.ControlWrite(0, 9, 1, 0, 0)) |
| self.assertIsNone(g.ControlWrite(1, 11, 0, 1, 0)) |
| |
| def test_send_packet(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| chip = mock.Mock() |
| g.Connected(chip, usb_constants.Speed.HIGH) |
| g.SendPacket(0x81, 'Hello world!') |
| chip.SendPacket.assert_called_once_with(0x81, 'Hello world!') |
| |
| def test_send_packet_disconnected(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| with self.assertRaisesRegexp(RuntimeError, 'not connected'): |
| g.SendPacket(0x81, 'Hello world!') |
| g.Connected(mock.Mock(), usb_constants.Speed.HIGH) |
| g.SendPacket(0x81, 'Hello world!') |
| g.Disconnected() |
| with self.assertRaisesRegexp(RuntimeError, 'not connected'): |
| g.SendPacket(0x81, 'Hello world!') |
| |
| def test_send_invalid_endpoint(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| chip = mock.Mock() |
| g.Connected(chip, usb_constants.Speed.HIGH) |
| with self.assertRaisesRegexp(ValueError, 'non-input endpoint'): |
| g.SendPacket(0x01, 'Hello world!') |
| |
| def test_receive_packet(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| self.assertIsNone(g.ReceivePacket(0x01, 'Hello world!')) |
| |
| def test_halt_endpoint(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| chip = mock.Mock() |
| g.Connected(chip, usb_constants.Speed.HIGH) |
| g.HaltEndpoint(0x01) |
| chip.HaltEndpoint.assert_called_once_with(0x01) |
| |
| def test_get_microsoft_os_string_descriptor(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| g.EnableMicrosoftOSDescriptorsV1(vendor_code=0x42) |
| os_string_descriptor = g.ControlRead(0x80, |
| usb_constants.Request.GET_DESCRIPTOR, |
| 0x03EE, |
| 0x0000, |
| 0x12) |
| self.assertEqual(os_string_descriptor, |
| "\x12\x03M\x00S\x00F\x00T\x001\x000\x000\x00\x42\x00") |
| |
| def test_get_microsoft_os_compat_id_descriptor(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| g.EnableMicrosoftOSDescriptorsV1(vendor_code=0x42) |
| g.SetMicrosoftCompatId(0, 'WINUSB') |
| chip = mock.Mock() |
| g.Connected(chip, usb_constants.Speed.HIGH) |
| |
| expected_compatid_header = \ |
| "\x28\x00\x00\x00\x00\x01\x04\x00\x01\0\0\0\0\0\0\0" |
| compatid_header = g.ControlRead(0xC0, 0x42, 0x0000, 0x0004, 0x0010) |
| self.assertEqual(compatid_header, expected_compatid_header) |
| |
| compatid_descriptor = g.ControlRead(0xC0, 0x42, 0x0000, 0x0004, 0x0028) |
| self.assertEqual(compatid_descriptor, |
| expected_compatid_header + |
| "\x00\x01WINUSB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0") |
| |
| def test_get_bos_descriptor(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| self.assertIsNone(g.ControlRead(0x80, 0x06, 0x0F00, 0x0000, 5)) |
| |
| container_id = uuid.uuid4() |
| g.AddDeviceCapabilityDescriptor(usb_descriptors.ContainerIdDescriptor( |
| ContainerID=container_id.bytes_le)) |
| bos_descriptor_header = g.ControlRead(0x80, 0x06, 0x0F00, 0x0000, 5) |
| self.assertEquals('\x05\x0F\x19\x00\x01', bos_descriptor_header) |
| |
| bos_descriptor = g.ControlRead(0x80, 0x06, 0x0F00, 0x0000, 25) |
| self.assertEquals( |
| '\x05\x0F\x19\x00\x01\x14\x10\x04\x00' + container_id.bytes_le, |
| bos_descriptor) |
| |
| def test_get_microsoft_os_20_descriptor_set(self): |
| g = gadget.Gadget(device_desc, fs_config_desc, hs_config_desc) |
| g.EnableMicrosoftOSDescriptorsV2(vendor_code=0x42) |
| g.SetMicrosoftCompatId(0, 'WINUSB') |
| chip = mock.Mock() |
| g.Connected(chip, usb_constants.Speed.HIGH) |
| |
| bos_descriptor = g.ControlRead(0x80, 0x06, 0x0F00, 0x0000, 33) |
| self.assertEquals( |
| '\x05\x0F\x21\x00\x01' + |
| '\x1C\x10\x05\x00' + |
| uuid.UUID('{D8DD60DF-4589-4CC7-9CD2-659D9E648A9F}').bytes_le + |
| '\x00\x00\x03\x06\x2E\x00\x42\x00', |
| bos_descriptor) |
| |
| descriptor_set = g.ControlRead(0xC0, 0x42, 0x0000, 0x0007, 48) |
| self.assertEquals( |
| '\x0A\x00\x00\x00\x00\x00\x03\x06\x2E\x00' + |
| '\x08\x00\x01\x00\x00\x00\x24\x00' + |
| '\x08\x00\x02\x00\x00\x00\x1C\x00' + |
| '\x14\x00\x03\x00WINUSB\0\0\0\0\0\0\0\0\0\0', |
| descriptor_set) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |