1# Copyright (C) 2009-2014 Wander Lairson Costa
2#
3# The following terms apply to all files associated
4# with the software unless explicitly disclaimed in individual files.
5#
6# The authors hereby grant permission to use, copy, modify, distribute,
7# and license this software and its documentation for any purpose, provided
8# that existing copyright notices are retained in all copies and that this
9# notice is included verbatim in any distributions. No written agreement,
10# license, or royalty fee is required for any of the authorized uses.
11# Modifications to this software may be copyrighted by their authors
12# and need not follow the licensing terms described here, provided that
13# the new terms are clearly indicated on the first page of each file where
14# they apply.
15#
16# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
17# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
18# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
19# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
20# POSSIBILITY OF SUCH DAMAGE.
21#
22# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
23# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
24# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
25# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
26# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
27# MODIFICATIONS.
28
29# Integration tests
30
31import utils
32import unittest
33import usb.core
34import devinfo
35import usb._interop
36from usb._debug import methodtrace
37import usb.util
38import usb.backend.libusb0 as libusb0
39import usb.backend.libusb1 as libusb1
40import usb.backend.openusb as openusb
41import time
42import sys
43
44def make_data_list(length = 8):
45    return (utils.get_array_data1(length),
46            utils.get_array_data2(length),
47            utils.get_list_data1(length),
48            utils.get_list_data2(length),
49            utils.get_str_data1(length),
50            utils.get_str_data1(length))
51
52class DeviceTest(unittest.TestCase):
53    @methodtrace(utils.logger)
54    def __init__(self, dev):
55        unittest.TestCase.__init__(self)
56        self.dev = dev
57
58    @methodtrace(utils.logger)
59    def runTest(self):
60        try:
61            self.test_attributes()
62            self.test_timeout()
63            self.test_set_configuration()
64            self.test_set_interface_altsetting()
65            self.test_write_read()
66            self.test_write_array()
67            self.test_ctrl_transfer()
68            self.test_clear_halt()
69            #self.test_reset()
70        finally:
71            usb.util.dispose_resources(self.dev)
72
73    @methodtrace(utils.logger)
74    def test_attributes(self):
75        self.assertEqual(self.dev.bLength, 18)
76        self.assertEqual(self.dev.bDescriptorType, usb.util.DESC_TYPE_DEVICE)
77        self.assertEqual(self.dev.bcdUSB, 0x0200)
78        self.assertEqual(self.dev.idVendor, devinfo.ID_VENDOR)
79        self.assertEqual(self.dev.idProduct, devinfo.ID_PRODUCT)
80        self.assertEqual(self.dev.bcdDevice, 0x0001)
81        self.assertEqual(self.dev.iManufacturer, 0x01)
82        self.assertEqual(self.dev.iProduct, 0x02)
83        self.assertEqual(self.dev.iSerialNumber, 0x03)
84        self.assertEqual(self.dev.bNumConfigurations, 0x01)
85        self.assertEqual(self.dev.bMaxPacketSize0, 8)
86        self.assertEqual(self.dev.bDeviceClass, 0x00)
87        self.assertEqual(self.dev.bDeviceSubClass, 0x00)
88        self.assertEqual(self.dev.bDeviceProtocol, 0x00)
89
90    @methodtrace(utils.logger)
91    def test_timeout(self):
92        def set_invalid_timeout():
93            self.dev.default_timeout = -1
94        tmo = self.dev.default_timeout
95        self.dev.default_timeout = 1
96        self.assertEqual(self.dev.default_timeout, 1)
97        self.dev.default_timeout = tmo
98        self.assertEqual(self.dev.default_timeout, tmo)
99        self.assertRaises(ValueError, set_invalid_timeout)
100        self.assertEqual(self.dev.default_timeout, tmo)
101
102    @methodtrace(utils.logger)
103    def test_set_configuration(self):
104        cfg = self.dev[0].bConfigurationValue
105        self.dev.set_configuration(cfg)
106        self.dev.set_configuration()
107        self.assertEqual(cfg, self.dev.get_active_configuration().bConfigurationValue)
108
109    @methodtrace(utils.logger)
110    def test_set_interface_altsetting(self):
111        intf = self.dev.get_active_configuration()[(0,0)]
112        self.dev.set_interface_altsetting(intf.bInterfaceNumber, intf.bAlternateSetting)
113        self.dev.set_interface_altsetting()
114
115    @methodtrace(utils.logger)
116    def test_reset(self):
117        self.dev.reset()
118        utils.delay_after_reset()
119
120    @methodtrace(utils.logger)
121    def test_write_read(self):
122        altsettings = [devinfo.INTF_BULK, devinfo.INTF_INTR]
123        eps = [devinfo.EP_BULK, devinfo.EP_INTR]
124        data_len = [8, 8]
125
126        if utils.is_iso_test_allowed():
127            altsettings.append(devinfo.INTF_ISO)
128            eps.append(devinfo.EP_ISO)
129            data_len.append(64)
130
131        def delay(alt):
132            # Hack to avoid two consecutive isochronous transfers to fail
133            if alt == devinfo.INTF_ISO and utils.is_windows():
134                time.sleep(0.5)
135
136        for alt, length in zip(altsettings, data_len):
137            self.dev.set_interface_altsetting(0, alt)
138            for data in make_data_list(length):
139                adata = utils.to_array(data)
140                length = utils.data_len(data)
141                buff = usb.util.create_buffer(length)
142
143                try:
144                    ret = self.dev.write(eps[alt], data)
145                except NotImplementedError:
146                    continue
147
148                self.assertEqual(ret, length)
149
150                self.assertEqual(
151                    ret,
152                    length,
153                    'Failed to write data: ' + \
154                        str(data) + ', in interface = ' + \
155                        str(alt))
156
157                try:
158                    ret = self.dev.read(eps[alt] | usb.util.ENDPOINT_IN, length)
159                except NotImplementedError:
160                    continue
161
162                self.assertTrue(
163                    utils.array_equals(ret, adata),
164                    str(ret) + ' != ' + \
165                        str(adata) + ', in interface = ' + \
166                        str(alt))
167
168                delay(alt)
169
170                try:
171                    ret = self.dev.write(eps[alt], data)
172                except NotImplementedError:
173                    continue
174
175                self.assertEqual(ret, length)
176
177                self.assertEqual(
178                    ret,
179                    length,
180                    'Failed to write data: ' + \
181                        str(data) + ', in interface = ' + \
182                        str(alt))
183
184                try:
185                    ret = self.dev.read(eps[alt] | usb.util.ENDPOINT_IN, buff)
186                except NotImplementedError:
187                    continue
188
189                self.assertEqual(ret, length)
190
191                self.assertTrue(
192                    utils.array_equals(buff, adata),
193                     str(buff) + ' != ' + \
194                        str(adata) + ', in interface = ' + \
195                        str(alt))
196
197                delay(alt)
198
199    @methodtrace(utils.logger)
200    def test_write_array(self):
201        a = usb._interop.as_array('test')
202        self.dev.set_interface_altsetting(0, devinfo.INTF_BULK)
203
204        self.assertEquals(self.dev.write(devinfo.EP_BULK, a), len(a))
205
206        self.assertTrue(utils.array_equals(
207            self.dev.read(devinfo.EP_BULK | usb.util.ENDPOINT_IN, len(a)),
208            a))
209
210    @methodtrace(utils.logger)
211    def test_ctrl_transfer(self):
212        for data in make_data_list():
213            length = utils.data_len(data)
214            adata = utils.to_array(data)
215
216            ret = self.dev.ctrl_transfer(
217                    0x40,
218                    devinfo.PICFW_SET_VENDOR_BUFFER,
219                    0,
220                    0,
221                    data)
222
223            self.assertEqual(ret,
224                             length,
225                             'Failed to write data: ' + str(data))
226
227            ret = utils.to_array(self.dev.ctrl_transfer(
228                        0xC0,
229                        devinfo.PICFW_GET_VENDOR_BUFFER,
230                        0,
231                        0,
232                        length))
233
234            self.assertTrue(utils.array_equals(ret, adata),
235                             str(ret) + ' != ' + str(adata))
236
237            buff = usb.util.create_buffer(length)
238
239            ret = self.dev.ctrl_transfer(
240                    0x40,
241                    devinfo.PICFW_SET_VENDOR_BUFFER,
242                    0,
243                    0,
244                    data)
245
246            self.assertEqual(ret,
247                             length,
248                             'Failed to write data: ' + str(data))
249
250            ret = self.dev.ctrl_transfer(
251                        0xC0,
252                        devinfo.PICFW_GET_VENDOR_BUFFER,
253                        0,
254                        0,
255                        buff)
256
257            self.assertEqual(ret, length)
258
259            self.assertTrue(utils.array_equals(buff, adata),
260                             str(buff) + ' != ' + str(adata))
261
262    @methodtrace(utils.logger)
263    def test_clear_halt(self):
264        self.dev.set_interface_altsetting(0, 0)
265        self.dev.clear_halt(0x01)
266        self.dev.clear_halt(0x81)
267
268class ConfigurationTest(unittest.TestCase):
269    @methodtrace(utils.logger)
270    def __init__(self, dev):
271        unittest.TestCase.__init__(self)
272        self.cfg = dev[0]
273
274    @methodtrace(utils.logger)
275    def runTest(self):
276        try:
277            self.test_attributes()
278            self.test_set()
279        finally:
280            usb.util.dispose_resources(self.cfg.device)
281
282    @methodtrace(utils.logger)
283    def test_attributes(self):
284        self.assertEqual(self.cfg.bLength, 9)
285        self.assertEqual(self.cfg.bDescriptorType, usb.util.DESC_TYPE_CONFIG)
286        self.assertEqual(self.cfg.wTotalLength, 78)
287        self.assertEqual(self.cfg.bNumInterfaces, 0x01)
288        self.assertEqual(self.cfg.bConfigurationValue, 0x01)
289        self.assertEqual(self.cfg.iConfiguration, 0x00)
290        self.assertEqual(self.cfg.bmAttributes, 0xC0)
291        self.assertEqual(self.cfg.bMaxPower, 50)
292
293    @methodtrace(utils.logger)
294    def test_set(self):
295        self.cfg.set()
296
297class InterfaceTest(unittest.TestCase):
298    @methodtrace(utils.logger)
299    def __init__(self, dev):
300        unittest.TestCase.__init__(self)
301        self.dev = dev
302        self.intf = dev[0][(0,0)]
303
304    @methodtrace(utils.logger)
305    def runTest(self):
306        try:
307            self.dev.set_configuration()
308            self.test_attributes()
309            self.test_set_altsetting()
310        finally:
311            usb.util.dispose_resources(self.intf.device)
312
313    @methodtrace(utils.logger)
314    def test_attributes(self):
315        self.assertEqual(self.intf.bLength, 9)
316        self.assertEqual(self.intf.bDescriptorType, usb.util.DESC_TYPE_INTERFACE)
317        self.assertEqual(self.intf.bInterfaceNumber, 0)
318        self.assertEqual(self.intf.bAlternateSetting, 0)
319        self.assertEqual(self.intf.bNumEndpoints, 2)
320        self.assertEqual(self.intf.bInterfaceClass, 0x00)
321        self.assertEqual(self.intf.bInterfaceSubClass, 0x00)
322        self.assertEqual(self.intf.bInterfaceProtocol, 0x00)
323        self.assertEqual(self.intf.iInterface, 0x00)
324
325    @methodtrace(utils.logger)
326    def test_set_altsetting(self):
327        self.intf.set_altsetting()
328
329class EndpointTest(unittest.TestCase):
330    @methodtrace(utils.logger)
331    def __init__(self, dev):
332        unittest.TestCase.__init__(self)
333        self.dev = dev
334        intf = dev[0][(0,0)]
335        self.ep_out = usb.util.find_descriptor(intf, bEndpointAddress=0x01)
336        self.ep_in = usb.util.find_descriptor(intf, bEndpointAddress=0x81)
337
338    @methodtrace(utils.logger)
339    def runTest(self):
340        try:
341            self.dev.set_configuration()
342            self.test_attributes()
343            self.test_write_read()
344        finally:
345            usb.util.dispose_resources(self.dev)
346
347    @methodtrace(utils.logger)
348    def test_attributes(self):
349        self.assertEqual(self.ep_out.bLength, 7)
350        self.assertEqual(self.ep_out.bDescriptorType, usb.util.DESC_TYPE_ENDPOINT)
351        self.assertEqual(self.ep_out.bEndpointAddress, 0x01)
352        self.assertEqual(self.ep_out.bmAttributes, 0x02)
353        self.assertEqual(self.ep_out.wMaxPacketSize, 16)
354        self.assertEqual(self.ep_out.bInterval, 0)
355
356    @methodtrace(utils.logger)
357    def test_write_read(self):
358        self.dev.set_interface_altsetting(0, 0)
359        for data in make_data_list():
360            adata = utils.to_array(data)
361            length = utils.data_len(data)
362            buff = usb.util.create_buffer(length)
363
364            ret = self.ep_out.write(data)
365            self.assertEqual(ret, length, 'Failed to write data: ' + str(data))
366            ret = self.ep_in.read(length)
367            self.assertTrue(utils.array_equals(ret, adata), str(ret) + ' != ' + str(adata))
368
369            ret = self.ep_out.write(data)
370            self.assertEqual(ret, length, 'Failed to write data: ' + str(data))
371            ret = self.ep_in.read(buff)
372            self.assertEqual(ret, length)
373            self.assertTrue(utils.array_equals(buff, adata), str(buff) + ' != ' + str(adata))
374
375def get_suite():
376    suite = unittest.TestSuite()
377    test_cases = (DeviceTest, ConfigurationTest, InterfaceTest, EndpointTest)
378    for m in (libusb1, libusb0, openusb):
379        b = m.get_backend()
380        if b is None:
381            continue
382        dev = utils.find_my_device(b)
383        if dev is None:
384            utils.logger.warning('Test hardware not found for backend %s', m.__name__)
385            continue
386
387        for ObjectTestCase in test_cases:
388            utils.logger.info('Adding %s(%s) to test suite...', ObjectTestCase.__name__, m.__name__)
389            suite.addTest(ObjectTestCase(dev))
390
391    return suite
392
393if __name__ == '__main__':
394    utils.run_tests(get_suite())
395