chromium/extensions/test/data/api_test/hid/api/background.js

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var kInvalidDeviceId = -1;
var kInvalidConnectionId = -1;

var kReportDescriptor = [0x06, 0x00, 0xFF, 0x08, 0xA1, 0x01, 0x15,
                         0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95,
                         0x08, 0x08, 0x81, 0x02, 0x08, 0x91, 0x02,
                         0x08, 0xB1, 0x02, 0xC0];
var kReportDescriptorWithIDs = [
    0x06, 0x01, 0xFF, 0x08, 0xA1, 0x01, 0x15, 0x00, 0x26,
    0xFF, 0x00, 0x85, 0x01, 0x75, 0x08, 0x95, 0x08, 0x08,
    0x81, 0x02, 0x08, 0x91, 0x02, 0x08, 0xB1, 0x02, 0xC0];

function getDevice(wantReportIds, callback) {
  chrome.hid.getDevices({}, function (devices) {
    chrome.test.assertNoLastError();
    for (var device of devices) {
      chrome.test.assertTrue(device.collections.length > 0);
      var foundReportId = false;
      for (var collection of device.collections) {
        if (collection.reportIds.length > 0) {
          foundReportId = true;
        }
      }
      if (wantReportIds == foundReportId) {
        callback(device);
        return;
      }
    }
    chrome.test.fail("No appropriate device found.");
  });
}

function openDevice(wantReportIds, callback) {
  getDevice(wantReportIds, function (device) {
    chrome.hid.connect(device.deviceId, function (connection) {
      chrome.test.assertNoLastError();
      callback(connection.connectionId);
    });
  });
}

function openDeviceWithReportId(callback) {
  return openDevice(true, callback);
}

function openDeviceWithoutReportId(callback) {
  return openDevice(false, callback);
}

function arrayBufferToString(buffer) {
  return String.fromCharCode.apply(null, new Uint8Array(buffer));
}

function stringToArrayBuffer(string) {
  var buffer = new ArrayBuffer(string.length);
  var view = new Uint8Array(buffer);
  for (var i = 0; i < string.length; i++) {
    view[i] = string.charCodeAt(i);
  }
  return buffer;
}

function assertArrayBufferEqualsListOfBytes(expected, actual) {
  chrome.test.assertEq(expected.length, actual.byteLength);
  var byteView = new Uint8Array(actual);
  for (var i = 0; i < expected.length; i++) {
    chrome.test.assertEq(expected[i], byteView[i], 'index ' + i);
  }
}

function testGetDevicesWithNoOptions() {
  chrome.hid.getDevices({}, function (devices) {
    chrome.test.assertNoLastError();
    chrome.test.assertEq(2, devices.length, "Expected two enumerated devices.");
    chrome.test.succeed("Device enumeration successful.");
  });
};

function testGetDevicesWithLegacyVidAndPid() {
  chrome.hid.getDevices({
      'vendorId': 0x18D1,
      'productId': 0x58F0
    }, function (devices) {
    chrome.test.assertNoLastError();
    chrome.test.assertEq(2, devices.length, "Expected two enumerated devices.");
    chrome.test.succeed("Device enumeration successful.");
  });
};

function testGetDevicesWithNoFilters() {
  chrome.hid.getDevices({ 'filters': [] }, function (devices) {
    chrome.test.assertNoLastError();
    chrome.test.assertEq(2, devices.length, "Expected two enumerated devices.");
    chrome.test.succeed("Device enumeration successful.");
  });
};

function testGetDevicesWithVidPidFilter() {
  chrome.hid.getDevices({ 'filters': [
      { 'vendorId': 0x18D1, 'productId': 0x58F0}
    ] }, function (devices) {
    chrome.test.assertNoLastError();
    chrome.test.assertEq(2, devices.length, "Expected two enumerated devices.");
    chrome.test.succeed("Device enumeration successful.");
  });
};

function testGetDevicesWithUsageFilter() {
  chrome.hid.getDevices({ 'filters': [
      { 'usagePage': 0xFF00 }  /* vendor-specified usage page */
    ] }, function (devices) {
    chrome.test.assertNoLastError();
    chrome.test.assertEq(1, devices.length, "Expected one enumerated device.");
    var device = devices[0];
    chrome.test.assertEq(1, device.collections.length,
                         "Expected one collection.");
    var collection = device.collections[0];
    chrome.test.assertEq(0xFF00, collection.usagePage);
    chrome.test.succeed("Device enumeration successful.");
  });
}

function testGetDevicesWithUnauthorizedDevice() {
  chrome.hid.getDevices({ 'filters': [
      { 'vendorId': 0x18D1, 'productId': 0x58F1}
    ] }, function (devices) {
    chrome.test.assertNoLastError();
    chrome.test.assertEq(0, devices.length, "Expected no enumerated devices.");
    chrome.test.succeed("Device enumeration successful.");
  });
};

function testDeviceInfo() {
  var expectedDevices = 2;
  getDevice(false, function (deviceInfo) {
    chrome.test.assertEq(0x18D1, deviceInfo.vendorId);
    chrome.test.assertEq(0x58F0, deviceInfo.productId);
    chrome.test.assertEq("Test Device", deviceInfo.productName);
    chrome.test.assertEq("A", deviceInfo.serialNumber);
    chrome.test.assertEq(1, deviceInfo.collections.length);
    chrome.test.assertEq(0xFF00, deviceInfo.collections[0].usagePage);
    chrome.test.assertEq(0, deviceInfo.collections[0].usage);
    chrome.test.assertEq(0, deviceInfo.collections[0].reportIds.length);
    assertArrayBufferEqualsListOfBytes(kReportDescriptor,
                                       deviceInfo.reportDescriptor);
    if (--expectedDevices == 0) {
      chrome.test.succeed();
    }
  });

  getDevice(true, function (deviceInfo) {
    chrome.test.assertEq(0x18D1, deviceInfo.vendorId);
    chrome.test.assertEq(0x58F0, deviceInfo.productId);
    chrome.test.assertEq(1, deviceInfo.collections.length);
    chrome.test.assertEq(0xFF01, deviceInfo.collections[0].usagePage);
    chrome.test.assertEq(0, deviceInfo.collections[0].usage);
    chrome.test.assertEq(1, deviceInfo.collections[0].reportIds.length);
    chrome.test.assertEq(1, deviceInfo.collections[0].reportIds[0]);
    assertArrayBufferEqualsListOfBytes(kReportDescriptorWithIDs,
                                       deviceInfo.reportDescriptor);
    if (--expectedDevices == 0) {
      chrome.test.succeed();
    }
  });
};

function testConnectWithInvalidDeviceId() {
  chrome.hid.connect(kInvalidDeviceId, function (connection) {
    chrome.test.assertLastError("Invalid HID device ID.");
    chrome.test.succeed("Rejected invalid device ID.");
  });
};

function testConnectAndDisconnect() {
  chrome.hid.getDevices({ 'filters': [
      { 'vendorId': 0x18D1, 'productId': 0x58F0 }
    ] }, function (devices) {
    chrome.test.assertNoLastError();
    chrome.test.assertTrue(devices.length >= 1, "Expected connectable device.");
    chrome.hid.connect(devices[0].deviceId, function (connection) {
      chrome.test.assertNoLastError();
      chrome.hid.disconnect(connection.connectionId, function () {
        chrome.test.assertNoLastError();
        chrome.test.succeed("Opened and closed device.");
      });
    });
  });
};

function testDisconnectWithInvalidConnectionId() {
  chrome.hid.disconnect(kInvalidConnectionId, function () {
    chrome.test.assertLastError("Connection not established.");
    chrome.test.succeed("Rejected invalid connection ID.");
  });
}

function testReceiveWithInvalidConnectionId() {
  chrome.hid.receive(kInvalidConnectionId, function (reportId, data) {
    chrome.test.assertLastError("Connection not established.");
    chrome.test.succeed("Rejected invalid connection ID.");
  });
}

function testReceiveWithReportId() {
  openDeviceWithReportId(function (connection) {
    chrome.hid.receive(connection, function (reportId, data) {
      chrome.test.assertEq(1, reportId, "Expected report_id == 1.");
      var expected = "This is a HID input report.";
      chrome.test.assertEq(expected, arrayBufferToString(data));
      chrome.test.succeed("Receive successful.");
    });
  });
}

function testReceiveWithoutReportId() {
  openDeviceWithoutReportId(function (connection) {
    chrome.hid.receive(connection, function (reportId, data) {
      chrome.test.assertNoLastError();
      chrome.test.assertEq(0, reportId, "Expected report_id == 0.");
      var expected = "This is a HID input report.";
      chrome.test.assertEq(expected, arrayBufferToString(data));
      chrome.test.succeed("Receive successful.");
    });
  });
}

function testSendWithInvalidConnectionId() {
  var buffer = new ArrayBuffer();
  chrome.hid.send(kInvalidConnectionId, 0, buffer, function () {
    chrome.test.assertLastError("Connection not established.");
    chrome.test.succeed("Rejected invalid connection ID.");
  });
}

function testSendOversizeReport() {
  openDeviceWithReportId(function (connection) {
    var buffer = stringToArrayBuffer("oversize report");
    chrome.hid.send(connection, 1, buffer, function () {
      chrome.test.assertLastError("Transfer failed.");
      chrome.hid.disconnect(connection);
      chrome.test.succeed("Caught oversize report.");
    });
  });
}

function testSendWithReportId() {
  openDeviceWithReportId(function (connection) {
    var buffer = stringToArrayBuffer("o-report");
    chrome.hid.send(connection, 1, buffer, function () {
      chrome.test.assertNoLastError();
      chrome.hid.disconnect(connection);
      chrome.test.succeed("Send successful.");
    });
  });
}

function testSendWithoutReportId() {
  openDeviceWithoutReportId(function (connection) {
    var buffer = stringToArrayBuffer("o-report");
    chrome.hid.send(connection, 0, buffer, function () {
      chrome.test.assertNoLastError();
      chrome.hid.disconnect(connection);
      chrome.test.succeed("Send successful.");
    });
  });
}

function testSendWithInvalidReportId() {
  openDeviceWithReportId(function (connection) {
    var buffer = stringToArrayBuffer("o-report");
    chrome.hid.send(connection, 0, buffer, function () {
      chrome.test.assertLastError("Transfer failed.");
      chrome.hid.disconnect(connection);
      chrome.test.succeed("Caught invalid report ID.");
    });
  });
}

function testSendWithUnexpectedReportId() {
  openDeviceWithoutReportId(function (connection) {
    var buffer = stringToArrayBuffer("o-report");
    chrome.hid.send(connection, 1, buffer, function () {
      chrome.test.assertLastError("Transfer failed.");
      chrome.hid.disconnect(connection);
      chrome.test.succeed("Caught unexpected report ID.");
    });
  });
}

function testReceiveFeatureReportWithInvalidConnectionId() {
  chrome.hid.receiveFeatureReport(kInvalidConnectionId, 0, function (data) {
    chrome.test.assertLastError("Connection not established.");
    chrome.test.succeed("Rejected invalid connection ID.");
  });
}

function testReceiveFeatureReportWithReportId() {
  openDeviceWithReportId(function (connection) {
    chrome.hid.receiveFeatureReport(connection, 1, function (data) {
      chrome.test.assertNoLastError();
      var expected = "\1This is a HID feature report.";
      chrome.test.assertEq(expected, arrayBufferToString(data));
      chrome.test.succeed("Received feature report.");
    });
  });
}

function testReceiveFeatureReportWithoutReportId() {
  openDeviceWithoutReportId(function (connection) {
    chrome.hid.receiveFeatureReport(connection, 0, function (data) {
      chrome.test.assertNoLastError();
      var expected = "This is a HID feature report.";
      chrome.test.assertEq(expected, arrayBufferToString(data));
      chrome.test.succeed("Received feature report.");
    });
  });
}

function testReceiveFeatureReportWithInvalidReportId() {
  openDeviceWithReportId(function (connection) {
    chrome.hid.receiveFeatureReport(connection, 0, function (data) {
      chrome.test.assertLastError("Transfer failed.");
      chrome.test.succeed("Caught invalid report ID.");
    });
  });
}

function testReceiveFeatureReportWithUnexpectedReportId() {
  openDeviceWithoutReportId(function (connection) {
    chrome.hid.receiveFeatureReport(connection, 1, function (data) {
      chrome.test.assertLastError("Transfer failed.");
      chrome.test.succeed("Caught unexpected report ID.");
    });
  });
}

function testSendFeatureReportWithInvalidConnectionId() {
  var buffer = new ArrayBuffer();
  chrome.hid.sendFeatureReport(kInvalidConnectionId, 0, buffer, function () {
    chrome.test.assertLastError("Connection not established.");
    chrome.test.succeed("Rejected invalid connection ID.");
  });
}

function testSendFeatureReportWithReportId() {
  openDeviceWithReportId(function (connection) {
    var buffer =
        stringToArrayBuffer("The app is setting this HID feature report.");
    chrome.hid.sendFeatureReport(connection, 1, buffer, function () {
      chrome.test.assertNoLastError();
      chrome.hid.disconnect(connection);
      chrome.test.succeed("Send successful.");
    });
  });
}

function testSendFeatureReportWithoutReportId() {
  openDeviceWithoutReportId(function (connection) {
    var buffer =
        stringToArrayBuffer("The app is setting this HID feature report.");
    chrome.hid.sendFeatureReport(connection, 0, buffer, function () {
      chrome.test.assertNoLastError();
      chrome.hid.disconnect(connection);
      chrome.test.succeed("Send successful.");
    });
  });
}

function testSendFeatureReportWithInvalidReportId() {
  openDeviceWithReportId(function (connection) {
    var buffer =
        stringToArrayBuffer("The app is setting this HID feature report.");
    chrome.hid.sendFeatureReport(connection, 0, buffer, function () {
      chrome.test.assertLastError("Transfer failed.");
      chrome.hid.disconnect(connection);
      chrome.test.succeed("Caught invalid report ID.");
    });
  });
}

function testSendFeatureReportWithUnexpectedReportId() {
  openDeviceWithoutReportId(function (connection) {
    var buffer =
        stringToArrayBuffer("The app is setting this HID feature report.");
    chrome.hid.sendFeatureReport(connection, 1, buffer, function () {
      chrome.test.assertLastError("Transfer failed.");
      chrome.hid.disconnect(connection);
      chrome.test.succeed("Caught unexpected report ID.");
    });
  });
}

chrome.test.runTests([
  testGetDevicesWithNoOptions,
  testGetDevicesWithLegacyVidAndPid,
  testGetDevicesWithNoFilters,
  testGetDevicesWithVidPidFilter,
  testGetDevicesWithUsageFilter,
  testGetDevicesWithUnauthorizedDevice,
  testDeviceInfo,
  testConnectWithInvalidDeviceId,
  testConnectAndDisconnect,
  testDisconnectWithInvalidConnectionId,
  testReceiveWithInvalidConnectionId,
  testReceiveWithReportId,
  testReceiveWithoutReportId,
  testSendWithInvalidConnectionId,
  testSendOversizeReport,
  testSendWithReportId,
  testSendWithoutReportId,
  testSendWithInvalidReportId,
  testSendWithUnexpectedReportId,
  testReceiveFeatureReportWithInvalidConnectionId,
  testReceiveFeatureReportWithReportId,
  testReceiveFeatureReportWithoutReportId,
  testReceiveFeatureReportWithInvalidReportId,
  testReceiveFeatureReportWithUnexpectedReportId,
  testSendFeatureReportWithInvalidConnectionId,
  testSendFeatureReportWithReportId,
  testSendFeatureReportWithoutReportId,
  testSendFeatureReportWithInvalidReportId,
  testSendFeatureReportWithUnexpectedReportId,
]);