tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

usbDevice.https.any.js (47817B)


      1 // META: timeout=long
      2 // META: script=/resources/test-only-api.js
      3 // META: script=/webusb/resources/fake-devices.js
      4 // META: script=/webusb/resources/usb-helpers.js
      5 'use strict';
      6 
      7 function detachBuffer(buffer) {
      8  if (self.GLOBAL.isWindow())
      9    window.postMessage('', '*', [buffer]);
     10  else
     11    self.postMessage('', [buffer]);
     12 }
     13 
     14 usb_test((t) => {
     15  return getFakeDevice().then(({device, fakeDevice}) => {
     16    return waitForDisconnect(fakeDevice)
     17        .then(() => promise_rejects_dom(t, 'NotFoundError', device.open()));
     18  });
     19 }, 'open rejects when called on a disconnected device');
     20 
     21 usb_test(() => {
     22  return getFakeDevice().then(({ device, fakeDevice }) => {
     23    return device.open()
     24      .then(() => waitForDisconnect(fakeDevice))
     25      .then(() => {
     26        assert_false(device.opened);
     27      });
     28  });
     29 }, 'disconnection closes the device');
     30 
     31 usb_test(() => {
     32  return getFakeDevice().then(({ device }) => {
     33    assert_false(device.opened);
     34    return device.open().then(() => {
     35      assert_true(device.opened);
     36      return device.close().then(() => {
     37        assert_false(device.opened);
     38      });
     39    });
     40  });
     41 }, 'a device can be opened and closed');
     42 
     43 usb_test(() => {
     44  return getFakeDevice().then(({ device }) => {
     45    return device.open()
     46      .then(() => device.open())
     47      .then(() => device.open())
     48      .then(() => device.open())
     49      .then(() => device.close())
     50      .then(() => device.close())
     51      .then(() => device.close())
     52      .then(() => device.close());
     53  });
     54 }, 'open and close can be called multiple times');
     55 
     56 usb_test(async (t) => {
     57  let { device } = await getFakeDevice();
     58  await Promise.all([
     59    device.open(),
     60    promise_rejects_dom(t, 'InvalidStateError', device.open()),
     61    promise_rejects_dom(t, 'InvalidStateError', device.close()),
     62  ]);
     63  await Promise.all([
     64    device.close(),
     65    promise_rejects_dom(t, 'InvalidStateError', device.open()),
     66    promise_rejects_dom(t, 'InvalidStateError', device.close()),
     67  ]);
     68 }, 'open and close cannot be called again while open or close are in progress');
     69 
     70 usb_test(async (t) => {
     71  let { device } = await getFakeDevice();
     72  await device.open();
     73  return Promise.all([
     74    device.selectConfiguration(1),
     75    promise_rejects_dom(t, 'InvalidStateError', device.claimInterface(0)),
     76    promise_rejects_dom(t, 'InvalidStateError', device.releaseInterface(0)),
     77    promise_rejects_dom(t, 'InvalidStateError', device.open()),
     78    promise_rejects_dom(t, 'InvalidStateError', device.selectConfiguration(1)),
     79    promise_rejects_dom(t, 'InvalidStateError', device.reset()),
     80    promise_rejects_dom(
     81        t, 'InvalidStateError', device.selectAlternateInterface(0, 0)),
     82    promise_rejects_dom(t, 'InvalidStateError', device.controlTransferOut({
     83      requestType: 'standard',
     84      recipient: 'interface',
     85      request: 0x42,
     86      value: 0x1234,
     87      index: 0x0000,
     88    })),
     89    promise_rejects_dom(
     90        t, 'InvalidStateError',
     91        device.controlTransferOut(
     92            {
     93              requestType: 'standard',
     94              recipient: 'interface',
     95              request: 0x42,
     96              value: 0x1234,
     97              index: 0x0000,
     98            },
     99            new Uint8Array([1, 2, 3]))),
    100    promise_rejects_dom(
    101        t, 'InvalidStateError',
    102        device.controlTransferIn(
    103            {
    104              requestType: 'standard',
    105              recipient: 'interface',
    106              request: 0x42,
    107              value: 0x1234,
    108              index: 0x0000
    109            },
    110            0)),
    111    promise_rejects_dom(t, 'InvalidStateError', device.close()),
    112  ]);
    113 }, 'device operations reject if an device state change is in progress');
    114 
    115 usb_test((t) => {
    116  return getFakeDevice().then(({device, fakeDevice}) => {
    117    return device.open()
    118        .then(() => waitForDisconnect(fakeDevice))
    119        .then(() => promise_rejects_dom(t, 'NotFoundError', device.close()));
    120  });
    121 }, 'close rejects when called on a disconnected device');
    122 
    123 usb_test((t) => {
    124  return getFakeDevice().then(({device, fakeDevice}) => {
    125    return device.open()
    126        .then(() => waitForDisconnect(fakeDevice))
    127        .then(
    128            () => promise_rejects_dom(
    129                t, 'NotFoundError', device.selectConfiguration(1)));
    130  });
    131 }, 'selectConfiguration rejects when called on a disconnected device');
    132 
    133 usb_test((t) => {
    134  return getFakeDevice().then(({device}) => Promise.all([
    135    promise_rejects_dom(t, 'InvalidStateError', device.selectConfiguration(1)),
    136    promise_rejects_dom(t, 'InvalidStateError', device.claimInterface(0)),
    137    promise_rejects_dom(t, 'InvalidStateError', device.releaseInterface(0)),
    138    promise_rejects_dom(
    139        t, 'InvalidStateError', device.selectAlternateInterface(0, 1)),
    140    promise_rejects_dom(
    141        t, 'InvalidStateError',
    142        device.controlTransferIn(
    143            {
    144              requestType: 'vendor',
    145              recipient: 'device',
    146              request: 0x42,
    147              value: 0x1234,
    148              index: 0x5678
    149            },
    150            7)),
    151    promise_rejects_dom(
    152        t, 'InvalidStateError',
    153        device.controlTransferOut(
    154            {
    155              requestType: 'vendor',
    156              recipient: 'device',
    157              request: 0x42,
    158              value: 0x1234,
    159              index: 0x5678
    160            },
    161            new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]))),
    162    promise_rejects_dom(t, 'InvalidStateError', device.clearHalt('in', 1)),
    163    promise_rejects_dom(t, 'InvalidStateError', device.transferIn(1, 8)),
    164    promise_rejects_dom(
    165        t, 'InvalidStateError', device.transferOut(1, new ArrayBuffer(8))),
    166    promise_rejects_dom(
    167        t, 'InvalidStateError', device.isochronousTransferIn(1, [8])),
    168    promise_rejects_dom(
    169        t, 'InvalidStateError',
    170        device.isochronousTransferOut(1, new ArrayBuffer(8), [8])),
    171    promise_rejects_dom(t, 'InvalidStateError', device.reset())
    172  ]));
    173 }, 'methods requiring it reject when the device is not open');
    174 
    175 usb_test(() => {
    176  return getFakeDevice().then(({ device }) => {
    177    assert_equals(device.configuration, null);
    178    return device.open()
    179      .then(() => {
    180        assert_equals(device.configuration, null);
    181        return device.selectConfiguration(1);
    182      })
    183      .then(() => {
    184        assertDeviceInfoEquals(
    185            device.configuration, fakeDeviceInit.configurations[0]);
    186      })
    187      .then(() => device.close());
    188  });
    189 }, 'device configuration can be set and queried');
    190 
    191 usb_test(async () => {
    192  let { device } = await getFakeDevice();
    193  assert_equals(device.configuration, null);
    194  await device.open();
    195  assert_equals(device.configuration, null);
    196  await device.selectConfiguration(1);
    197  await device.selectConfiguration(1);
    198  assertDeviceInfoEquals(
    199      device.configuration, fakeDeviceInit.configurations[0]);
    200  await device.selectConfiguration(2);
    201  assertDeviceInfoEquals(
    202      device.configuration, fakeDeviceInit.configurations[1]);
    203  await device.close();
    204 }, 'a device configuration value can be set again');
    205 
    206 usb_test((t) => {
    207  return getFakeDevice().then(({ device }) => {
    208    assert_equals(device.configuration, null);
    209    return device.open()
    210        .then(
    211            () => promise_rejects_dom(
    212                t, 'NotFoundError', device.selectConfiguration(10)))
    213        .then(() => device.close());
    214  });
    215 }, 'selectConfiguration rejects on invalid configurations');
    216 
    217 usb_test((t) => {
    218  return getFakeDevice().then(({ device }) => {
    219    assert_equals(device.configuration, null);
    220    return device.open()
    221        .then(() => Promise.all([
    222          promise_rejects_dom(t, 'InvalidStateError', device.claimInterface(0)),
    223          promise_rejects_dom(
    224              t, 'InvalidStateError', device.releaseInterface(0)),
    225          promise_rejects_dom(
    226              t, 'InvalidStateError', device.selectAlternateInterface(0, 1)),
    227          promise_rejects_dom(
    228              t, 'InvalidStateError', device.clearHalt('in', 1)),
    229          promise_rejects_dom(t, 'InvalidStateError', device.transferIn(1, 8)),
    230          promise_rejects_dom(
    231              t, 'InvalidStateError',
    232              device.transferOut(1, new ArrayBuffer(8))),
    233          promise_rejects_dom(
    234              t, 'InvalidStateError', device.isochronousTransferIn(1, [8])),
    235          promise_rejects_dom(
    236              t, 'InvalidStateError',
    237              device.isochronousTransferOut(1, new ArrayBuffer(8), [8])),
    238        ]))
    239        .then(() => device.close());
    240  });
    241 }, 'methods requiring it reject when the device is unconfigured');
    242 
    243 usb_test(async () => {
    244  let { device } = await getFakeDevice();
    245  await device.open();
    246  await device.selectConfiguration(1);
    247  assert_false(device.configuration.interfaces[0].claimed);
    248  assert_false(device.configuration.interfaces[1].claimed);
    249 
    250  await device.claimInterface(0);
    251  assert_true(device.configuration.interfaces[0].claimed);
    252  assert_false(device.configuration.interfaces[1].claimed);
    253 
    254  await device.claimInterface(1);
    255  assert_true(device.configuration.interfaces[0].claimed);
    256  assert_true(device.configuration.interfaces[1].claimed);
    257 
    258  await device.releaseInterface(0);
    259  assert_false(device.configuration.interfaces[0].claimed);
    260  assert_true(device.configuration.interfaces[1].claimed);
    261 
    262  await device.releaseInterface(1);
    263  assert_false(device.configuration.interfaces[0].claimed);
    264  assert_false(device.configuration.interfaces[1].claimed);
    265 
    266  await device.close();
    267 }, 'interfaces can be claimed and released');
    268 
    269 usb_test(async () => {
    270  let { device } = await getFakeDevice();
    271  await device.open();
    272  await device.selectConfiguration(1);
    273  assert_false(device.configuration.interfaces[0].claimed);
    274  assert_false(device.configuration.interfaces[1].claimed);
    275 
    276  await Promise.all([device.claimInterface(0),
    277                     device.claimInterface(1)]);
    278  assert_true(device.configuration.interfaces[0].claimed);
    279  assert_true(device.configuration.interfaces[1].claimed);
    280 
    281  await Promise.all([device.releaseInterface(0),
    282                     device.releaseInterface(1)]);
    283  assert_false(device.configuration.interfaces[0].claimed);
    284  assert_false(device.configuration.interfaces[1].claimed);
    285 
    286  await device.close();
    287 }, 'interfaces can be claimed and released in parallel');
    288 
    289 usb_test(async () => {
    290  let { device } = await getFakeDevice()
    291  await device.open();
    292  await device.selectConfiguration(1);
    293  await device.claimInterface(0);
    294  assert_true(device.configuration.interfaces[0].claimed);
    295  await device.claimInterface(0);
    296  assert_true(device.configuration.interfaces[0].claimed);
    297  await device.close();
    298 }, 'an interface can be claimed multiple times');
    299 
    300 usb_test(async () => {
    301  let { device } = await getFakeDevice();
    302  await device.open();
    303  await device.selectConfiguration(1);
    304  await device.claimInterface(0);
    305  assert_true(device.configuration.interfaces[0].claimed);
    306  await device.releaseInterface(0);
    307  assert_false(device.configuration.interfaces[0].claimed);
    308  await device.releaseInterface(0);
    309  assert_false(device.configuration.interfaces[0].claimed);
    310  await device.close();
    311 }, 'an interface can be released multiple times');
    312 
    313 usb_test(async (t) => {
    314  let { device } = await getFakeDevice();
    315  await device.open();
    316  await device.selectConfiguration(1);
    317  return Promise.all([
    318    device.claimInterface(0),
    319    promise_rejects_dom(t, 'InvalidStateError', device.claimInterface(0)),
    320    promise_rejects_dom(t, 'InvalidStateError', device.releaseInterface(0)),
    321    promise_rejects_dom(t, 'InvalidStateError', device.open()),
    322    promise_rejects_dom(t, 'InvalidStateError', device.selectConfiguration(1)),
    323    promise_rejects_dom(t, 'InvalidStateError', device.reset()),
    324    promise_rejects_dom(
    325        t, 'InvalidStateError', device.selectAlternateInterface(0, 0)),
    326    promise_rejects_dom(t, 'InvalidStateError', device.controlTransferOut({
    327      requestType: 'standard',
    328      recipient: 'interface',
    329      request: 0x42,
    330      value: 0x1234,
    331      index: 0x0000,
    332    })),
    333    promise_rejects_dom(
    334        t, 'InvalidStateError',
    335        device.controlTransferOut(
    336            {
    337              requestType: 'standard',
    338              recipient: 'interface',
    339              request: 0x42,
    340              value: 0x1234,
    341              index: 0x0000,
    342            },
    343            new Uint8Array([1, 2, 3]))),
    344    promise_rejects_dom(
    345        t, 'InvalidStateError',
    346        device.controlTransferIn(
    347            {
    348              requestType: 'standard',
    349              recipient: 'interface',
    350              request: 0x42,
    351              value: 0x1234,
    352              index: 0x0000
    353            },
    354            0)),
    355    promise_rejects_dom(t, 'InvalidStateError', device.close()),
    356  ]);
    357 }, 'device operations reject if an interface state change is in progress');
    358 
    359 usb_test(async () => {
    360  let { device } = await getFakeDevice();
    361  await device.open();
    362  await device.selectConfiguration(1);
    363  await device.claimInterface(0);
    364  assert_true(device.configuration.interfaces[0].claimed);
    365  await device.close(0);
    366  assert_false(device.configuration.interfaces[0].claimed);
    367 }, 'interfaces are released on close');
    368 
    369 usb_test((t) => {
    370  return getFakeDevice().then(({device}) => {
    371    return device.open()
    372        .then(() => device.selectConfiguration(1))
    373        .then(() => Promise.all([
    374          promise_rejects_dom(t, 'NotFoundError', device.claimInterface(2)),
    375          promise_rejects_dom(t, 'NotFoundError', device.releaseInterface(2)),
    376        ]))
    377        .then(() => device.close());
    378  });
    379 }, 'a non-existent interface cannot be claimed or released');
    380 
    381 usb_test((t) => {
    382  return getFakeDevice().then(({device, fakeDevice}) => {
    383    return device.open()
    384        .then(() => device.selectConfiguration(1))
    385        .then(() => waitForDisconnect(fakeDevice))
    386        .then(
    387            () => promise_rejects_dom(
    388                t, 'NotFoundError', device.claimInterface(0)));
    389  });
    390 }, 'claimInterface rejects when called on a disconnected device');
    391 
    392 usb_test((t) => {
    393  return getFakeDevice().then(({device, fakeDevice}) => {
    394    return device.open()
    395        .then(() => device.selectConfiguration(1))
    396        .then(() => device.claimInterface(0))
    397        .then(() => waitForDisconnect(fakeDevice))
    398        .then(
    399            () => promise_rejects_dom(
    400                t, 'NotFoundError', device.releaseInterface(0)));
    401  });
    402 }, 'releaseInterface rejects when called on a disconnected device');
    403 
    404 usb_test(() => {
    405  return getFakeDevice().then(({ device }) => {
    406    return device.open()
    407      .then(() => device.selectConfiguration(2))
    408      .then(() => device.claimInterface(0))
    409      .then(() => device.selectAlternateInterface(0, 1))
    410      .then(() => device.close());
    411  });
    412 }, 'can select an alternate interface');
    413 
    414 usb_test(
    415    async () => {
    416      const {device} = await getFakeDevice();
    417      await device.open();
    418      await device.selectConfiguration(3);
    419      await device.claimInterface(2);
    420      await device.selectAlternateInterface(2, 0);
    421      await device.close();
    422    },
    423    'can select an alternate interface on a setting with non-sequential ' +
    424        'interface number');
    425 
    426 usb_test(
    427    async () => {
    428      const {device} = await getFakeDevice();
    429      await device.open();
    430      await device.selectConfiguration(3);
    431      await device.claimInterface(0);
    432      await device.selectAlternateInterface(0, 2);
    433      await device.close();
    434    },
    435    'can select an alternate interface on a setting with non-sequential ' +
    436        'alternative setting value');
    437 
    438 usb_test((t) => {
    439  return getFakeDevice().then(({device}) => {
    440    return device.open()
    441        .then(() => device.selectConfiguration(2))
    442        .then(() => device.claimInterface(0))
    443        .then(
    444            () => promise_rejects_dom(
    445                t, 'NotFoundError', device.selectAlternateInterface(0, 2)))
    446        .then(() => device.close());
    447  });
    448 }, 'cannot select a non-existent alternate interface');
    449 
    450 usb_test((t) => {
    451  return getFakeDevice().then(({device, fakeDevice}) => {
    452    return device.open()
    453        .then(() => device.selectConfiguration(2))
    454        .then(() => device.claimInterface(0))
    455        .then(() => waitForDisconnect(fakeDevice))
    456        .then(
    457            () => promise_rejects_dom(
    458                t, 'NotFoundError', device.selectAlternateInterface(0, 1)));
    459  });
    460 }, 'selectAlternateInterface rejects when called on a disconnected device');
    461 
    462 usb_test(async () => {
    463  let { device } = await getFakeDevice();
    464  let usbRequestTypes = ['standard', 'class', 'vendor'];
    465  let usbRecipients = ['device', 'interface', 'endpoint', 'other'];
    466  await device.open();
    467  await device.selectConfiguration(1);
    468  await device.claimInterface(0);
    469  await device.selectAlternateInterface(0, 0);
    470  for (const requestType of usbRequestTypes) {
    471    for (const recipient of usbRecipients) {
    472      let index = recipient === 'interface' ? 0x5600 : 0x5681;
    473      let result = await device.controlTransferIn({
    474        requestType: requestType,
    475        recipient: recipient,
    476        request: 0x42,
    477        value: 0x1234,
    478        index: index
    479      }, 7);
    480      assert_true(result instanceof USBInTransferResult);
    481      assert_equals(result.status, 'ok');
    482      assert_equals(result.data.byteLength, 7);
    483      assert_equals(result.data.getUint16(0), 0x07);
    484      assert_equals(result.data.getUint8(2), 0x42);
    485      assert_equals(result.data.getUint16(3), 0x1234);
    486      assert_equals(result.data.getUint16(5), index);
    487    }
    488  }
    489  await device.close();
    490 }, 'can issue all types of IN control transfers');
    491 
    492 usb_test(async () => {
    493  let { device } = await getFakeDevice();
    494  let usbRequestTypes = ['standard', 'class', 'vendor'];
    495  let usbRecipients = ['device', 'other'];
    496  await device.open();
    497  await Promise.all(usbRequestTypes.flatMap(requestType => {
    498    return usbRecipients.map(async recipient => {
    499      let result = await device.controlTransferIn({
    500        requestType: requestType,
    501        recipient: recipient,
    502        request: 0x42,
    503        value: 0x1234,
    504        index: 0x5678
    505      }, 7);
    506      assert_true(result instanceof USBInTransferResult);
    507      assert_equals(result.status, 'ok');
    508      assert_equals(result.data.byteLength, 7);
    509      assert_equals(result.data.getUint16(0), 0x07);
    510      assert_equals(result.data.getUint8(2), 0x42);
    511      assert_equals(result.data.getUint16(3), 0x1234);
    512      assert_equals(result.data.getUint16(5), 0x5678);
    513    });
    514  }));
    515  await device.close();
    516 }, 'device-scope IN control transfers don\'t require configuration');
    517 
    518 usb_test(async (t) => {
    519  let { device } = await getFakeDevice();
    520  let usbRequestTypes = ['standard', 'class', 'vendor'];
    521  let usbRecipients = ['interface', 'endpoint'];
    522  await device.open();
    523  await Promise.all(usbRequestTypes.flatMap(requestType => {
    524    return usbRecipients.map(recipient => {
    525      let index = recipient === 'interface' ? 0x5600 : 0x5681;
    526      return promise_rejects_dom(
    527          t, 'InvalidStateError',
    528          device.controlTransferIn(
    529              {
    530                requestType: requestType,
    531                recipient: recipient,
    532                request: 0x42,
    533                value: 0x1234,
    534                index: index
    535              },
    536              7));
    537    });
    538  }));
    539  await device.close();
    540 }, 'interface-scope IN control transfers require configuration');
    541 
    542 usb_test(async (t) => {
    543  let { device } = await getFakeDevice();
    544  let usbRequestTypes = ['standard', 'class', 'vendor'];
    545  let usbRecipients = ['interface', 'endpoint'];
    546  await device.open();
    547  await device.selectConfiguration(1);
    548  await Promise.all(usbRequestTypes.flatMap(requestType => {
    549    return [
    550      promise_rejects_dom(
    551          t, 'InvalidStateError',
    552          device.controlTransferIn(
    553              {
    554                requestType: requestType,
    555                recipient: 'interface',
    556                request: 0x42,
    557                value: 0x1234,
    558                index: 0x5600
    559              },
    560              7)),
    561      promise_rejects_dom(
    562          t, 'NotFoundError',
    563          device.controlTransferIn(
    564              {
    565                requestType: requestType,
    566                recipient: 'endpoint',
    567                request: 0x42,
    568                value: 0x1234,
    569                index: 0x5681
    570              },
    571              7))
    572    ];
    573  }));
    574  await device.close();
    575 }, 'interface-scope IN control transfers require claiming the interface');
    576 
    577 usb_test((t) => {
    578  return getFakeDevice().then(({device, fakeDevice}) => {
    579    return device.open()
    580        .then(() => device.selectConfiguration(1))
    581        .then(() => waitForDisconnect(fakeDevice))
    582        .then(
    583            () => promise_rejects_dom(
    584                t, 'NotFoundError',
    585                device.controlTransferIn(
    586                    {
    587                      requestType: 'vendor',
    588                      recipient: 'device',
    589                      request: 0x42,
    590                      value: 0x1234,
    591                      index: 0x5678
    592                    },
    593                    7)));
    594  });
    595 }, 'controlTransferIn rejects when called on a disconnected device');
    596 
    597 usb_test(async () => {
    598  let { device } = await getFakeDevice();
    599  let usbRequestTypes = ['standard', 'class', 'vendor'];
    600  let usbRecipients = ['device', 'interface', 'endpoint', 'other'];
    601  let dataArray = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
    602  let dataTypes = [dataArray, dataArray.buffer];
    603  await device.open();
    604  await device.selectConfiguration(1);
    605  await device.claimInterface(0);
    606  await device.selectAlternateInterface(0, 0);
    607  for (const requestType of usbRequestTypes) {
    608    for (const recipient of usbRecipients) {
    609      let index = recipient === 'interface' ? 0x5600 : 0x5681;
    610      let transferParams = {
    611        requestType: requestType,
    612        recipient: recipient,
    613        request: 0x42,
    614        value: 0x1234,
    615        index: index
    616      };
    617      for (const data of dataTypes) {
    618        let result = await device.controlTransferOut(transferParams, data);
    619        assert_true(result instanceof USBOutTransferResult);
    620        assert_equals(result.status, 'ok');
    621        assert_equals(result.bytesWritten, 8);
    622      }
    623      let result = await device.controlTransferOut(transferParams);
    624      assert_true(result instanceof USBOutTransferResult);
    625      assert_equals(result.status, 'ok');
    626    }
    627  }
    628  await device.close();
    629 }, 'can issue all types of OUT control transfers');
    630 
    631 usb_test(async () => {
    632  let { device } = await getFakeDevice();
    633  let usbRequestTypes = ['standard', 'class', 'vendor'];
    634  let usbRecipients = ['device', 'other'];
    635  let dataArray = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
    636  let dataTypes = [dataArray, dataArray.buffer];
    637  await device.open();
    638  await Promise.all(usbRequestTypes.flatMap(requestType => {
    639    return usbRecipients.flatMap(recipient => {
    640      let transferParams = {
    641        requestType: requestType,
    642        recipient: recipient,
    643        request: 0x42,
    644        value: 0x1234,
    645        index: 0x5678
    646      };
    647      return dataTypes.map(async data => {
    648        let result = await device.controlTransferOut(transferParams, data);
    649        assert_true(result instanceof USBOutTransferResult);
    650        assert_equals(result.status, 'ok');
    651        assert_equals(result.bytesWritten, 8);
    652      }).push((async () => {
    653        let result = await device.controlTransferOut(transferParams);
    654        assert_true(result instanceof USBOutTransferResult);
    655        assert_equals(result.status, 'ok');
    656      })());
    657    });
    658  }));
    659  await device.close();
    660 }, 'device-scope OUT control transfers don\'t require configuration');
    661 
    662 usb_test(async (t) => {
    663  let { device } = await getFakeDevice();
    664  let usbRequestTypes = ['standard', 'class', 'vendor'];
    665  let usbRecipients = ['interface', 'endpoint'];
    666  let dataArray = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
    667  let dataTypes = [dataArray, dataArray.buffer];
    668  await device.open();
    669  await Promise.all(usbRequestTypes.flatMap(requestType => {
    670    return usbRecipients.flatMap(recipient => {
    671      let index = recipient === 'interface' ? 0x5600 : 0x5681;
    672      let transferParams = {
    673        requestType: requestType,
    674        recipient: recipient,
    675        request: 0x42,
    676        value: 0x1234,
    677        index: index
    678      };
    679      return dataTypes
    680          .map(data => {
    681            return promise_rejects_dom(
    682                t, 'InvalidStateError',
    683                device.controlTransferOut(transferParams, data));
    684          })
    685          .push(promise_rejects_dom(
    686              t, 'InvalidStateError',
    687              device.controlTransferOut(transferParams)));
    688    });
    689  }));
    690  await device.close();
    691 }, 'interface-scope OUT control transfers require configuration');
    692 
    693 usb_test(async (t) => {
    694  let { device } = await getFakeDevice();
    695  let usbRequestTypes = ['standard', 'class', 'vendor'];
    696  let usbRecipients = ['interface', 'endpoint'];
    697  let dataArray = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
    698  let dataTypes = [dataArray, dataArray.buffer];
    699  await device.open();
    700  await device.selectConfiguration(1);
    701  await Promise.all(usbRequestTypes.flatMap(requestType => {
    702    return usbRecipients.flatMap(recipient => {
    703      let index = recipient === 'interface' ? 0x5600 : 0x5681;
    704      let error =
    705          recipient === 'interface' ? 'InvalidStateError' : 'NotFoundError';
    706      let transferParams = {
    707        requestType: requestType,
    708        recipient: recipient,
    709        request: 0x42,
    710        value: 0x1234,
    711        index: index
    712      };
    713      return dataTypes
    714          .map(data => {
    715            return promise_rejects_dom(
    716                t, error, device.controlTransferOut(transferParams, data));
    717          })
    718          .push(promise_rejects_dom(
    719              t, error, device.controlTransferOut(transferParams)));
    720    });
    721  }));
    722  await device.close();
    723 }, 'interface-scope OUT control transfers an interface claim');
    724 
    725 usb_test((t) => {
    726  return getFakeDevice().then(({device, fakeDevice}) => {
    727    return device.open()
    728        .then(() => device.selectConfiguration(1))
    729        .then(() => waitForDisconnect(fakeDevice))
    730        .then(
    731            () => promise_rejects_dom(
    732                t, 'NotFoundError',
    733                device.controlTransferOut(
    734                    {
    735                      requestType: 'vendor',
    736                      recipient: 'device',
    737                      request: 0x42,
    738                      value: 0x1234,
    739                      index: 0x5678
    740                    },
    741                    new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]))));
    742  });
    743 }, 'controlTransferOut rejects when called on a disconnected device');
    744 
    745 usb_test(async (t) => {
    746  let { device } = await getFakeDevice();
    747  await device.open();
    748  await device.selectConfiguration(1);
    749  await device.claimInterface(0);
    750  await Promise.all([
    751    promise_rejects_js(
    752        t, TypeError,
    753        device.controlTransferOut(
    754            {
    755              requestType: 'invalid',
    756              recipient: 'device',
    757              request: 0x42,
    758              value: 0x1234,
    759              index: 0x5678
    760            },
    761            new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]))),
    762    promise_rejects_js(
    763        t, TypeError,
    764        device.controlTransferIn(
    765            {
    766              requestType: 'invalid',
    767              recipient: 'device',
    768              request: 0x42,
    769              value: 0x1234,
    770              index: 0x5678
    771            },
    772            0)),
    773  ]);
    774  await device.close();
    775 }, 'control transfers with a invalid request type reject');
    776 
    777 usb_test(async (t) => {
    778  let { device } = await getFakeDevice();
    779  await device.open();
    780  await device.selectConfiguration(1);
    781  await device.claimInterface(0);
    782  await Promise.all([
    783    promise_rejects_js(
    784        t, TypeError,
    785        device.controlTransferOut(
    786            {
    787              requestType: 'vendor',
    788              recipient: 'invalid',
    789              request: 0x42,
    790              value: 0x1234,
    791              index: 0x5678
    792            },
    793            new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]))),
    794    promise_rejects_js(
    795        t, TypeError,
    796        device.controlTransferIn(
    797            {
    798              requestType: 'vendor',
    799              recipient: 'invalid',
    800              request: 0x42,
    801              value: 0x1234,
    802              index: 0x5678
    803            },
    804            0)),
    805  ]);
    806 }, 'control transfers with a invalid recipient type reject');
    807 
    808 usb_test(async (t) => {
    809  let { device } = await getFakeDevice();
    810  await device.open();
    811  await device.selectConfiguration(1);
    812  await device.claimInterface(0);
    813  await Promise.all([
    814    promise_rejects_dom(
    815        t, 'NotFoundError',
    816        device.controlTransferOut(
    817            {
    818              requestType: 'vendor',
    819              recipient: 'interface',
    820              request: 0x42,
    821              value: 0x1234,
    822              index: 0x0002  // Last byte of index is interface number.
    823            },
    824            new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]))),
    825    promise_rejects_dom(
    826        t, 'NotFoundError',
    827        device.controlTransferIn(
    828            {
    829              requestType: 'vendor',
    830              recipient: 'interface',
    831              request: 0x42,
    832              value: 0x1234,
    833              index: 0x0002  // Last byte of index is interface number.
    834            },
    835            0)),
    836  ]);
    837 }, 'control transfers to a non-existant interface reject');
    838 
    839 usb_test((t) => {
    840  return getFakeDevice().then(({ device }) => {
    841    let interfaceRequest = {
    842        requestType: 'vendor',
    843        recipient: 'interface',
    844        request: 0x42,
    845        value: 0x1234,
    846        index: 0x5600  // Last byte of index is interface number.
    847    };
    848    let endpointRequest = {
    849        requestType: 'vendor',
    850        recipient: 'endpoint',
    851        request: 0x42,
    852        value: 0x1234,
    853        index: 0x5681  // Last byte of index is endpoint address.
    854    };
    855    let data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
    856    return device.open()
    857        .then(() => device.selectConfiguration(1))
    858        .then(() => Promise.all([
    859          promise_rejects_dom(
    860              t, 'InvalidStateError',
    861              device.controlTransferIn(interfaceRequest, 7)),
    862          promise_rejects_dom(
    863              t, 'NotFoundError', device.controlTransferIn(endpointRequest, 7)),
    864          promise_rejects_dom(
    865              t, 'InvalidStateError',
    866              device.controlTransferOut(interfaceRequest, data)),
    867          promise_rejects_dom(
    868              t, 'NotFoundError',
    869              device.controlTransferOut(endpointRequest, data)),
    870        ]))
    871        .then(() => device.claimInterface(0))
    872        .then(() => Promise.all([
    873          device.controlTransferIn(interfaceRequest, 7).then(result => {
    874            assert_true(result instanceof USBInTransferResult);
    875            assert_equals(result.status, 'ok');
    876            assert_equals(result.data.byteLength, 7);
    877            assert_equals(result.data.getUint16(0), 0x07);
    878            assert_equals(result.data.getUint8(2), 0x42);
    879            assert_equals(result.data.getUint16(3), 0x1234);
    880            assert_equals(result.data.getUint16(5), 0x5600);
    881          }),
    882          device.controlTransferIn(endpointRequest, 7).then(result => {
    883            assert_true(result instanceof USBInTransferResult);
    884            assert_equals(result.status, 'ok');
    885            assert_equals(result.data.byteLength, 7);
    886            assert_equals(result.data.getUint16(0), 0x07);
    887            assert_equals(result.data.getUint8(2), 0x42);
    888            assert_equals(result.data.getUint16(3), 0x1234);
    889            assert_equals(result.data.getUint16(5), 0x5681);
    890          }),
    891          device.controlTransferOut(interfaceRequest, data),
    892          device.controlTransferOut(endpointRequest, data),
    893        ]))
    894        .then(() => device.close());
    895  });
    896 }, 'requests to interfaces and endpoint require an interface claim');
    897 
    898 usb_test(async () => {
    899  const { device } = await getFakeDevice();
    900  await device.open();
    901  await device.selectConfiguration(1);
    902  await device.claimInterface(0);
    903 
    904  const transfer_params = {
    905      requestType: 'vendor',
    906      recipient: 'device',
    907      request: 0,
    908      value: 0,
    909      index: 0
    910  };
    911 
    912  const array_buffer = new ArrayBuffer(64 * 8);
    913  let result = await device.controlTransferOut(transfer_params, array_buffer);
    914  assert_equals(result.status, 'ok');
    915  assert_equals(result.bytesWritten, 64 * 8);
    916 
    917  detachBuffer(array_buffer);
    918  result = await device.controlTransferOut(transfer_params, array_buffer);
    919  assert_true(result instanceof USBOutTransferResult);
    920  assert_equals(result.status, 'ok');
    921  // A detached buffer is treated as if it had zero length.
    922  assert_equals(result.bytesWritten, 0);
    923 
    924  const typed_array = new Uint8Array(64 * 8);
    925  result = await device.controlTransferOut(transfer_params, typed_array);
    926  assert_equals(result.status, 'ok');
    927  assert_equals(result.bytesWritten, 64 * 8);
    928 
    929  detachBuffer(typed_array.buffer);
    930  result = await device.controlTransferOut(transfer_params, typed_array);
    931  // A detached buffer is treated as if it had zero length.
    932  assert_equals(result.bytesWritten, 0);
    933 }, 'controlTransferOut can safely be called with a detached buffer');
    934 
    935 usb_test(() => {
    936  return getFakeDevice().then(({ device }) => {
    937    return device.open()
    938      .then(() => device.selectConfiguration(1))
    939      .then(() => device.claimInterface(0))
    940      .then(() => device.clearHalt('in', 1))
    941      .then(() => device.close());
    942  });
    943 }, 'can clear a halt condition');
    944 
    945 usb_test((t) => {
    946  return getFakeDevice(t).then(({device, fakeDevice}) => {
    947    return device.open()
    948        .then(() => device.selectConfiguration(1))
    949        .then(() => device.claimInterface(0))
    950        .then(() => waitForDisconnect(fakeDevice))
    951        .then(
    952            () => promise_rejects_dom(
    953                t, 'NotFoundError', device.clearHalt('in', 1)));
    954  });
    955 }, 'clearHalt rejects when called on a disconnected device');
    956 
    957 usb_test((t) => {
    958  return getFakeDevice().then(({ device }) => {
    959    let data = new DataView(new ArrayBuffer(1024));
    960    for (let i = 0; i < 1024; ++i)
    961      data.setUint8(i, i & 0xff);
    962    return device.open()
    963        .then(() => device.selectConfiguration(1))
    964        .then(() => device.claimInterface(0))
    965        .then(() => Promise.all([
    966          promise_rejects_dom(
    967              t, 'NotFoundError', device.transferIn(2, 8)),  // Unclaimed
    968          promise_rejects_dom(
    969              t, 'NotFoundError', device.transferIn(3, 8)),  // Non-existent
    970          promise_rejects_dom(t, 'IndexSizeError', device.transferIn(16, 8)),
    971          promise_rejects_dom(
    972              t, 'NotFoundError', device.transferOut(2, data)),  // Unclaimed
    973          promise_rejects_dom(
    974              t, 'NotFoundError', device.transferOut(3, data)),  // Non-existent
    975          promise_rejects_dom(
    976              t, 'IndexSizeError', device.transferOut(16, data)),
    977        ]));
    978  });
    979 }, 'transfers to unavailable endpoints are rejected');
    980 
    981 usb_test(() => {
    982  return getFakeDevice().then(({ device }) => {
    983    return device.open()
    984      .then(() => device.selectConfiguration(1))
    985      .then(() => device.claimInterface(0))
    986      .then(() => device.transferIn(1, 8))
    987      .then(result => {
    988        assert_true(result instanceof USBInTransferResult);
    989        assert_equals(result.status, 'ok');
    990        assert_equals(result.data.byteLength, 8);
    991        for (let i = 0; i < 8; ++i)
    992          assert_equals(result.data.getUint8(i), i, 'mismatch at byte ' + i);
    993        return device.close();
    994      });
    995  });
    996 }, 'can issue IN interrupt transfer');
    997 
    998 usb_test(() => {
    999  return getFakeDevice().then(({ device }) => {
   1000    return device.open()
   1001      .then(() => device.selectConfiguration(1))
   1002      .then(() => device.claimInterface(1))
   1003      .then(() => device.transferIn(2, 1024))
   1004      .then(result => {
   1005        assert_true(result instanceof USBInTransferResult);
   1006        assert_equals(result.status, 'ok');
   1007        assert_equals(result.data.byteLength, 1024);
   1008        for (let i = 0; i < 1024; ++i)
   1009          assert_equals(result.data.getUint8(i), i & 0xff,
   1010                        'mismatch at byte ' + i);
   1011        return device.close();
   1012      });
   1013  });
   1014 }, 'can issue IN bulk transfer');
   1015 
   1016 usb_test((t) => {
   1017  return getFakeDevice().then(({device, fakeDevice}) => {
   1018    return device.open()
   1019        .then(() => device.selectConfiguration(1))
   1020        .then(() => device.claimInterface(1))
   1021        .then(() => waitForDisconnect(fakeDevice))
   1022        .then(
   1023            () => promise_rejects_dom(
   1024                t, 'NotFoundError', device.transferIn(2, 1024)));
   1025  });
   1026 }, 'transferIn rejects if called on a disconnected device');
   1027 
   1028 usb_test(() => {
   1029  return getFakeDevice().then(({ device }) => {
   1030    return device.open()
   1031      .then(() => device.selectConfiguration(1))
   1032      .then(() => device.claimInterface(1))
   1033      .then(() => {
   1034        let data = new DataView(new ArrayBuffer(1024));
   1035        for (let i = 0; i < 1024; ++i)
   1036          data.setUint8(i, i & 0xff);
   1037        return device.transferOut(2, data);
   1038      })
   1039      .then(result => {
   1040        assert_true(result instanceof USBOutTransferResult);
   1041        assert_equals(result.status, 'ok');
   1042        assert_equals(result.bytesWritten, 1024);
   1043        return device.close();
   1044      });
   1045  });
   1046 }, 'can issue OUT bulk transfer');
   1047 
   1048 usb_test((t) => {
   1049  return getFakeDevice().then(({ device, fakeDevice }) => {
   1050    return device.open()
   1051      .then(() => device.selectConfiguration(1))
   1052      .then(() => device.claimInterface(1))
   1053      .then(() => {
   1054        let data = new DataView(new ArrayBuffer(1024));
   1055        for (let i = 0; i < 1024; ++i)
   1056          data.setUint8(i, i & 0xff);
   1057        return waitForDisconnect(fakeDevice)
   1058            .then(
   1059                () => promise_rejects_dom(
   1060                    t, 'NotFoundError', device.transferOut(2, data)));
   1061      });
   1062  });
   1063 }, 'transferOut rejects if called on a disconnected device');
   1064 
   1065 usb_test(async () => {
   1066  const { device } = await getFakeDevice();
   1067  await device.open();
   1068  await device.selectConfiguration(1);
   1069  await device.claimInterface(1);
   1070 
   1071  const array_buffer = new ArrayBuffer(64 * 8);
   1072  let result = await device.transferOut(2, array_buffer);
   1073  assert_equals(result.status, 'ok');
   1074  assert_equals(result.bytesWritten, 64 * 8);
   1075 
   1076  detachBuffer(array_buffer);
   1077  result = await device.transferOut(2, array_buffer);
   1078  // A detached buffer is treated as if it had zero length.
   1079  assert_equals(result.bytesWritten, 0);
   1080 
   1081  const typed_array = new Uint8Array(64 * 8);
   1082  result = await device.transferOut(2, typed_array);
   1083  assert_equals(result.status, 'ok');
   1084  assert_equals(result.bytesWritten, 64 * 8);
   1085 
   1086  detachBuffer(typed_array.buffer);
   1087  result = await device.transferOut(2, typed_array);
   1088  // A detached buffer is treated as if it had zero length.
   1089  assert_equals(result.bytesWritten, 0);
   1090 }, 'transferOut can safely be called with a detached buffer');
   1091 
   1092 usb_test(() => {
   1093  return getFakeDevice().then(({ device }) => {
   1094    return device.open()
   1095      .then(() => device.selectConfiguration(2))
   1096      .then(() => device.claimInterface(0))
   1097      .then(() => device.selectAlternateInterface(0, 1))
   1098      .then(() => device.isochronousTransferIn(
   1099          1, [64, 64, 64, 64, 64, 64, 64, 64]))
   1100      .then(result => {
   1101        assert_true(result instanceof USBIsochronousInTransferResult);
   1102        assert_equals(result.data.byteLength, 64 * 8, 'buffer size');
   1103        assert_equals(result.packets.length, 8, 'number of packets');
   1104        let byteOffset = 0;
   1105        for (let i = 0; i < result.packets.length; ++i) {
   1106          assert_true(
   1107              result.packets[i] instanceof USBIsochronousInTransferPacket);
   1108          assert_equals(result.packets[i].status, 'ok');
   1109          assert_equals(result.packets[i].data.byteLength, 64);
   1110          assert_equals(result.packets[i].data.buffer, result.data.buffer);
   1111          assert_equals(result.packets[i].data.byteOffset, byteOffset);
   1112          for (let j = 0; j < 64; ++j)
   1113            assert_equals(result.packets[i].data.getUint8(j), j & 0xff,
   1114                          'mismatch at byte ' + j + ' of packet ' + i);
   1115          byteOffset += result.packets[i].data.byteLength;
   1116        }
   1117        return device.close();
   1118      });
   1119  });
   1120 }, 'can issue IN isochronous transfer');
   1121 
   1122 usb_test((t) => {
   1123  return getFakeDevice().then(({device, fakeDevice}) => {
   1124    return device.open()
   1125        .then(() => device.selectConfiguration(2))
   1126        .then(() => device.claimInterface(0))
   1127        .then(() => device.selectAlternateInterface(0, 1))
   1128        .then(() => waitForDisconnect(fakeDevice))
   1129        .then(
   1130            () => promise_rejects_dom(
   1131                t, 'NotFoundError',
   1132                device.isochronousTransferIn(
   1133                    1, [64, 64, 64, 64, 64, 64, 64, 64])));
   1134  });
   1135 }, 'isochronousTransferIn rejects when called on a disconnected device');
   1136 
   1137 usb_test(() => {
   1138  return getFakeDevice().then(({ device }) => {
   1139    return device.open()
   1140      .then(() => device.selectConfiguration(2))
   1141      .then(() => device.claimInterface(0))
   1142      .then(() => device.selectAlternateInterface(0, 1))
   1143      .then(() => {
   1144        let data = new DataView(new ArrayBuffer(64 * 8));
   1145        for (let i = 0; i < 8; ++i) {
   1146          for (let j = 0; j < 64; ++j)
   1147            data.setUint8(i * j, j & 0xff);
   1148        }
   1149        return device.isochronousTransferOut(
   1150            1, data, [64, 64, 64, 64, 64, 64, 64, 64]);
   1151      })
   1152      .then(result => {
   1153        assert_true(result instanceof USBIsochronousOutTransferResult);
   1154        assert_equals(result.packets.length, 8, 'number of packets');
   1155        let byteOffset = 0;
   1156        for (let i = 0; i < result.packets.length; ++i) {
   1157          assert_true(
   1158              result.packets[i] instanceof USBIsochronousOutTransferPacket);
   1159          assert_equals(result.packets[i].status, 'ok');
   1160          assert_equals(result.packets[i].bytesWritten, 64);
   1161        }
   1162        return device.close();
   1163      });
   1164  });
   1165 }, 'can issue OUT isochronous transfer');
   1166 
   1167 usb_test((t) => {
   1168  return getFakeDevice().then(({ device, fakeDevice }) => {
   1169    return device.open()
   1170      .then(() => device.selectConfiguration(2))
   1171      .then(() => device.claimInterface(0))
   1172      .then(() => device.selectAlternateInterface(0, 1))
   1173      .then(() => {
   1174        let data = new DataView(new ArrayBuffer(64 * 8));
   1175        for (let i = 0; i < 8; ++i) {
   1176          for (let j = 0; j < 64; ++j)
   1177            data.setUint8(i * j, j & 0xff);
   1178        }
   1179        return waitForDisconnect(fakeDevice)
   1180            .then(
   1181                () => promise_rejects_dom(
   1182                    t, 'NotFoundError',
   1183                    device.isochronousTransferOut(
   1184                        1, data, [64, 64, 64, 64, 64, 64, 64, 64])));
   1185      });
   1186  });
   1187 }, 'isochronousTransferOut rejects when called on a disconnected device');
   1188 
   1189 usb_test(async (t) => {
   1190  const { device } = await getFakeDevice();
   1191  await device.open();
   1192  await device.selectConfiguration(2);
   1193  await device.claimInterface(0);
   1194  await device.selectAlternateInterface(0, 1);
   1195 
   1196  const array_buffer = new ArrayBuffer(64 * 8);
   1197  let result = await device.isochronousTransferOut(
   1198      1, array_buffer, [64, 64, 64, 64, 64, 64, 64, 64]);
   1199  for (let i = 0; i < result.packets.length; ++i) {
   1200    assert_equals(result.packets[i].status, 'ok');
   1201    assert_equals(result.packets[i].bytesWritten, 64);
   1202  }
   1203 
   1204  detachBuffer(array_buffer);
   1205  // A detached buffer has zero length, so it doesn't match the packet sizes.
   1206  await promise_rejects_dom(
   1207      t, 'DataError',
   1208      device.isochronousTransferOut(
   1209          1, array_buffer, [64, 64, 64, 64, 64, 64, 64, 64]));
   1210 
   1211  const typed_array = new Uint8Array(64 * 8);
   1212  result = await device.isochronousTransferOut(
   1213      1, typed_array, [64, 64, 64, 64, 64, 64, 64, 64]);
   1214  for (let i = 0; i < result.packets.length; ++i) {
   1215    assert_equals(result.packets[i].status, 'ok');
   1216    assert_equals(result.packets[i].bytesWritten, 64);
   1217  }
   1218 
   1219  detachBuffer(typed_array.buffer);
   1220  // A detached buffer has zero length, so it doesn't match the packet sizes.
   1221  await promise_rejects_dom(
   1222      t, 'DataError',
   1223      device.isochronousTransferOut(
   1224          1, typed_array, [64, 64, 64, 64, 64, 64, 64, 64]));
   1225 }, 'isochronousTransferOut rejects when called with a detached buffer');
   1226 
   1227 usb_test(() => {
   1228  return getFakeDevice().then(({ device }) => {
   1229    return device.open().then(() => device.reset()).then(() => device.close());
   1230  });
   1231 }, 'can reset the device');
   1232 
   1233 usb_test((t) => {
   1234  return getFakeDevice().then(({device, fakeDevice}) => {
   1235    return device.open()
   1236        .then(() => waitForDisconnect(fakeDevice))
   1237        .then(() => promise_rejects_dom(t, 'NotFoundError', device.reset()));
   1238  });
   1239 }, 'resetDevice rejects when called on a disconnected device');
   1240 
   1241 usb_test(async (t) => {
   1242  const PACKET_COUNT = 4;
   1243  const PACKET_LENGTH = 8;
   1244  const {device, fakeDevice} = await getFakeDevice();
   1245  await device.open();
   1246  await device.selectConfiguration(2);
   1247  await device.claimInterface(0);
   1248  await device.selectAlternateInterface(0, 1);
   1249  const buffer = new Uint8Array(PACKET_COUNT * PACKET_LENGTH);
   1250  const packetLengths = new Array(PACKET_COUNT).fill(PACKET_LENGTH);
   1251  packetLengths[0] = PACKET_LENGTH - 1;
   1252  await promise_rejects_dom(
   1253      t, 'DataError', device.isochronousTransferOut(1, buffer, packetLengths));
   1254 }, 'isochronousTransferOut rejects when buffer size exceeds packet lengths');
   1255 
   1256 usb_test(async (t) => {
   1257  const PACKET_COUNT = 4;
   1258  const PACKET_LENGTH = 8;
   1259  const {device, fakeDevice} = await getFakeDevice();
   1260  await device.open();
   1261  await device.selectConfiguration(2);
   1262  await device.claimInterface(0);
   1263  await device.selectAlternateInterface(0, 1);
   1264  const buffer = new Uint8Array(PACKET_COUNT * PACKET_LENGTH);
   1265  const packetLengths = new Array(PACKET_COUNT).fill(PACKET_LENGTH);
   1266  packetLengths[0] = PACKET_LENGTH + 1;
   1267  await promise_rejects_dom(
   1268      t, 'DataError', device.isochronousTransferOut(1, buffer, packetLengths));
   1269 }, 'isochronousTransferOut rejects when packet lengths exceed buffer size');
   1270 
   1271 usb_test(async (t) => {
   1272  const {device} = await getFakeDevice();
   1273  await device.open();
   1274  await device.selectConfiguration(2);
   1275  await device.claimInterface(0);
   1276  await device.selectAlternateInterface(0, 1);
   1277  const packetLengths = [33554432, 1];
   1278  await promise_rejects_dom(
   1279      t, 'DataError', device.isochronousTransferIn(1, packetLengths));
   1280 }, 'isochronousTransferIn rejects when packet lengths exceed maximum size');
   1281 
   1282 usb_test(async (t) => {
   1283  const {device} = await getFakeDevice();
   1284  await device.open();
   1285  await device.selectConfiguration(2);
   1286  await device.claimInterface(0);
   1287  await device.selectAlternateInterface(0, 1);
   1288  const buffer = new Uint8Array(33554432 + 1);
   1289  const packetLengths = [33554432, 1];
   1290  await promise_rejects_dom(
   1291      t, 'DataError', device.isochronousTransferOut(1, buffer, packetLengths));
   1292 }, 'isochronousTransferOut rejects when packet lengths exceed maximum size');
   1293 
   1294 usb_test(async (t) => {
   1295  const {device} = await getFakeDevice();
   1296  await device.open();
   1297  await device.selectConfiguration(2);
   1298  await device.claimInterface(0);
   1299  await device.selectAlternateInterface(0, 1);
   1300  await promise_rejects_dom(
   1301      t, 'DataError', device.transferIn(1, 33554433));
   1302 }, 'transferIn rejects when packet lengths exceed maximum size');
   1303 
   1304 usb_test(async (t) => {
   1305  const {device} = await getFakeDevice();
   1306  await device.open();
   1307  await device.selectConfiguration(2);
   1308  await device.claimInterface(0);
   1309  await device.selectAlternateInterface(0, 1);
   1310  await promise_rejects_dom(
   1311      t, 'DataError', device.transferOut(1, new ArrayBuffer(33554433)));
   1312 }, 'transferOut rejects when packet lengths exceed maximum size');
   1313 
   1314 usb_test(async (t) => {
   1315  const {device} = await getFakeDevice();
   1316  await device.open();
   1317  await device.selectConfiguration(2);
   1318  await device.claimInterface(0);
   1319  await device.selectAlternateInterface(0, 1);
   1320  await promise_rejects_dom(
   1321      t, 'DataError', device.controlTransferOut({
   1322        requestType: 'vendor',
   1323        recipient: 'device',
   1324        request: 0x42,
   1325        value: 0x1234,
   1326        index: 0x5678
   1327      }, new ArrayBuffer(33554433)));
   1328 }, 'controlTransferOut rejects when packet lengths exceed maximum size');