summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/resources/chromium/fake-hid.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/resources/chromium/fake-hid.js
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/resources/chromium/fake-hid.js')
-rw-r--r--testing/web-platform/tests/resources/chromium/fake-hid.js297
1 files changed, 297 insertions, 0 deletions
diff --git a/testing/web-platform/tests/resources/chromium/fake-hid.js b/testing/web-platform/tests/resources/chromium/fake-hid.js
new file mode 100644
index 0000000000..70a01490d8
--- /dev/null
+++ b/testing/web-platform/tests/resources/chromium/fake-hid.js
@@ -0,0 +1,297 @@
+import {HidConnectionReceiver, HidDeviceInfo} from '/gen/services/device/public/mojom/hid.mojom.m.js';
+import {HidService, HidServiceReceiver} from '/gen/third_party/blink/public/mojom/hid/hid.mojom.m.js';
+
+// Fake implementation of device.mojom.HidConnection. HidConnection represents
+// an open connection to a HID device and can be used to send and receive
+// reports.
+class FakeHidConnection {
+ constructor(client) {
+ this.client_ = client;
+ this.receiver_ = new HidConnectionReceiver(this);
+ this.expectedWrites_ = [];
+ this.expectedGetFeatureReports_ = [];
+ this.expectedSendFeatureReports_ = [];
+ }
+
+ bindNewPipeAndPassRemote() {
+ return this.receiver_.$.bindNewPipeAndPassRemote();
+ }
+
+ // Simulate an input report sent from the device to the host. The connection
+ // client's onInputReport method will be called with the provided |reportId|
+ // and |buffer|.
+ simulateInputReport(reportId, reportData) {
+ if (this.client_) {
+ this.client_.onInputReport(reportId, reportData);
+ }
+ }
+
+ // Specify the result for an expected call to write. If |success| is true the
+ // write will be successful, otherwise it will simulate a failure. The
+ // parameters of the next write call must match |reportId| and |buffer|.
+ queueExpectedWrite(success, reportId, reportData) {
+ this.expectedWrites_.push({
+ params: {reportId, data: reportData},
+ result: {success},
+ });
+ }
+
+ // Specify the result for an expected call to getFeatureReport. If |success|
+ // is true the operation is successful, otherwise it will simulate a failure.
+ // The parameter of the next getFeatureReport call must match |reportId|.
+ queueExpectedGetFeatureReport(success, reportId, reportData) {
+ this.expectedGetFeatureReports_.push({
+ params: {reportId},
+ result: {success, buffer: reportData},
+ });
+ }
+
+ // Specify the result for an expected call to sendFeatureReport. If |success|
+ // is true the operation is successful, otherwise it will simulate a failure.
+ // The parameters of the next sendFeatureReport call must match |reportId| and
+ // |buffer|.
+ queueExpectedSendFeatureReport(success, reportId, reportData) {
+ this.expectedSendFeatureReports_.push({
+ params: {reportId, data: reportData},
+ result: {success},
+ });
+ }
+
+ // Asserts that there are no more expected operations.
+ assertExpectationsMet() {
+ assert_equals(this.expectedWrites_.length, 0);
+ assert_equals(this.expectedGetFeatureReports_.length, 0);
+ assert_equals(this.expectedSendFeatureReports_.length, 0);
+ }
+
+ read() {}
+
+ // Implementation of HidConnection::Write. Causes an assertion failure if
+ // there are no expected write operations, or if the parameters do not match
+ // the expected call.
+ async write(reportId, buffer) {
+ let expectedWrite = this.expectedWrites_.shift();
+ assert_not_equals(expectedWrite, undefined);
+ assert_equals(reportId, expectedWrite.params.reportId);
+ let actual = new Uint8Array(buffer);
+ compareDataViews(
+ new DataView(actual.buffer, actual.byteOffset),
+ new DataView(
+ expectedWrite.params.data.buffer,
+ expectedWrite.params.data.byteOffset));
+ return expectedWrite.result;
+ }
+
+ // Implementation of HidConnection::GetFeatureReport. Causes an assertion
+ // failure if there are no expected write operations, or if the parameters do
+ // not match the expected call.
+ async getFeatureReport(reportId) {
+ let expectedGetFeatureReport = this.expectedGetFeatureReports_.shift();
+ assert_not_equals(expectedGetFeatureReport, undefined);
+ assert_equals(reportId, expectedGetFeatureReport.params.reportId);
+ return expectedGetFeatureReport.result;
+ }
+
+ // Implementation of HidConnection::SendFeatureReport. Causes an assertion
+ // failure if there are no expected write operations, or if the parameters do
+ // not match the expected call.
+ async sendFeatureReport(reportId, buffer) {
+ let expectedSendFeatureReport = this.expectedSendFeatureReports_.shift();
+ assert_not_equals(expectedSendFeatureReport, undefined);
+ assert_equals(reportId, expectedSendFeatureReport.params.reportId);
+ let actual = new Uint8Array(buffer);
+ compareDataViews(
+ new DataView(actual.buffer, actual.byteOffset),
+ new DataView(
+ expectedSendFeatureReport.params.data.buffer,
+ expectedSendFeatureReport.params.data.byteOffset));
+ return expectedSendFeatureReport.result;
+ }
+}
+
+
+// A fake implementation of the HidService mojo interface. HidService manages
+// HID device access for clients in the render process. Typically, when a client
+// requests access to a HID device a chooser dialog is shown with a list of
+// available HID devices. Selecting a device from the chooser also grants
+// permission for the client to access that device.
+//
+// The fake implementation allows tests to simulate connected devices. It also
+// skips the chooser dialog and instead allows tests to specify which device
+// should be selected. All devices are treated as if the user had already
+// granted permission. It is possible to revoke permission with forget() later.
+class FakeHidService {
+ constructor() {
+ this.interceptor_ = new MojoInterfaceInterceptor(HidService.$interfaceName);
+ this.interceptor_.oninterfacerequest = e => this.bind(e.handle);
+ this.receiver_ = new HidServiceReceiver(this);
+ this.nextGuidValue_ = 0;
+ this.simulateConnectFailure_ = false;
+ this.reset();
+ }
+
+ start() {
+ this.interceptor_.start();
+ }
+
+ stop() {
+ this.interceptor_.stop();
+ }
+
+ reset() {
+ this.devices_ = new Map();
+ this.allowedDevices_ = new Map();
+ this.fakeConnections_ = new Map();
+ this.selectedDevices_ = [];
+ }
+
+ // Creates and returns a HidDeviceInfo with the specified device IDs.
+ makeDevice(vendorId, productId) {
+ let guidValue = ++this.nextGuidValue_;
+ let info = new HidDeviceInfo();
+ info.guid = 'guid-' + guidValue.toString();
+ info.physicalDeviceId = 'physical-device-id-' + guidValue.toString();
+ info.vendorId = vendorId;
+ info.productId = productId;
+ info.productName = 'product name';
+ info.serialNumber = '0';
+ info.reportDescriptor = new Uint8Array();
+ info.collections = [];
+ info.deviceNode = 'device node';
+ return info;
+ }
+
+ // Simulates a connected device the client has already been granted permission
+ // to. Returns the key used to store the device in the map. The key is either
+ // the physical device ID, or the device GUID if it has no physical device ID.
+ addDevice(deviceInfo, grantPermission = true) {
+ let key = deviceInfo.physicalDeviceId;
+ if (key.length === 0)
+ key = deviceInfo.guid;
+
+ let devices = this.devices_.get(key) || [];
+ devices.push(deviceInfo);
+ this.devices_.set(key, devices);
+
+ if (grantPermission) {
+ let allowedDevices = this.allowedDevices_.get(key) || [];
+ allowedDevices.push(deviceInfo);
+ this.allowedDevices_.set(key, allowedDevices);
+ }
+
+ if (this.client_)
+ this.client_.deviceAdded(deviceInfo);
+ return key;
+ }
+
+ // Simulates disconnecting a connected device.
+ removeDevice(key) {
+ let devices = this.devices_.get(key);
+ this.devices_.delete(key);
+ if (this.client_ && devices) {
+ devices.forEach(deviceInfo => {
+ this.client_.deviceRemoved(deviceInfo);
+ });
+ }
+ }
+
+ // Simulates updating the device information for a connected device.
+ changeDevice(deviceInfo) {
+ let key = deviceInfo.physicalDeviceId;
+ if (key.length === 0)
+ key = deviceInfo.guid;
+
+ let devices = this.devices_.get(key) || [];
+ let i = devices.length;
+ while (i--) {
+ if (devices[i].guid == deviceInfo.guid)
+ devices.splice(i, 1);
+ }
+ devices.push(deviceInfo);
+ this.devices_.set(key, devices);
+
+ let allowedDevices = this.allowedDevices_.get(key) || [];
+ let j = allowedDevices.length;
+ while (j--) {
+ if (allowedDevices[j].guid == deviceInfo.guid)
+ allowedDevices.splice(j, 1);
+ }
+ allowedDevices.push(deviceInfo);
+ this.allowedDevices_.set(key, allowedDevices);
+
+ if (this.client_)
+ this.client_.deviceChanged(deviceInfo);
+ return key;
+ }
+
+ // Sets a flag that causes the next call to connect() to fail.
+ simulateConnectFailure() {
+ this.simulateConnectFailure_ = true;
+ }
+
+ // Sets the key of the device that will be returned as the selected item the
+ // next time requestDevice is called. The device with this key must have been
+ // previously added with addDevice.
+ setSelectedDevice(key) {
+ this.selectedDevices_ = this.devices_.get(key);
+ }
+
+ // Returns the fake HidConnection object for this device, if there is one. A
+ // connection is created once the device is opened.
+ getFakeConnection(guid) {
+ return this.fakeConnections_.get(guid);
+ }
+
+ bind(handle) {
+ this.receiver_.$.bindHandle(handle);
+ }
+
+ registerClient(client) {
+ this.client_ = client;
+ }
+
+ // Returns an array of connected devices the client has already been granted
+ // permission to access.
+ async getDevices() {
+ let devices = [];
+ this.allowedDevices_.forEach((value) => {
+ devices = devices.concat(value);
+ });
+ return {devices};
+ }
+
+ // Simulates a device chooser prompt, returning |selectedDevices_| as the
+ // simulated selection. |options| is ignored.
+ async requestDevice(options) {
+ return {devices: this.selectedDevices_};
+ }
+
+ // Returns a fake connection to the device with the specified GUID. If
+ // |connectionClient| is not null, its onInputReport method will be called
+ // when input reports are received. If simulateConnectFailure() was called
+ // then a null connection is returned instead, indicating failure.
+ async connect(guid, connectionClient) {
+ if (this.simulateConnectFailure_) {
+ this.simulateConnectFailure_ = false;
+ return {connection: null};
+ }
+ const fakeConnection = new FakeHidConnection(connectionClient);
+ this.fakeConnections_.set(guid, fakeConnection);
+ return {connection: fakeConnection.bindNewPipeAndPassRemote()};
+ }
+
+ // Removes the allowed device.
+ async forget(deviceInfo) {
+ for (const [key, value] of this.allowedDevices_) {
+ for (const device of value) {
+ if (device.guid == deviceInfo.guid) {
+ this.allowedDevices_.delete(key);
+ break;
+ }
+ }
+ }
+ return {success: true};
+ }
+}
+
+export const fakeHidService = new FakeHidService();