Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
429 changes: 304 additions & 125 deletions tests/unit/device/deviceManager.spec.ts

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions tests/unit/device/deviceOfferRejectedError.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { describe, it, expect } from 'vitest';
import DeviceOfferRejectedError from '../../../src/device/deviceOfferRejectedError.js';

describe('DeviceOfferRejectedError', () => {
it('is an instance of Error', () => {
const error = new DeviceOfferRejectedError('some reason');

expect(error).toBeInstanceOf(Error);
expect(error).toBeInstanceOf(DeviceOfferRejectedError);
});

it('carries the given message', () => {
const error = new DeviceOfferRejectedError('Device with id \'foo\' has disappeared');

expect(error.message).toBe('Device with id \'foo\' has disappeared');
});

it('is distinguishable from a plain Error via instanceof, as relied upon by DeviceProvider', () => {
const rejection: unknown = new DeviceOfferRejectedError('claimed by another provider');
const genuineFailure: unknown = new Error('connect failed');

expect(rejection instanceof DeviceOfferRejectedError).toBe(true);
expect(genuineFailure instanceof DeviceOfferRejectedError).toBe(false);
});
});
38 changes: 38 additions & 0 deletions tests/unit/device/protocol/airotic/airoticDeviceProvider.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { describe, it, expect } from 'vitest';
import { mock } from 'vitest-mock-extended';
import AiroticDeviceProvider from '../../../../../src/device/protocol/airotic/airoticDeviceProvider.js';
import AiroticDeviceFactory from '../../../../../src/device/protocol/airotic/airoticDeviceFactory.js';
import DeviceManager from '../../../../../src/device/deviceManager.js';
import BleObserver from '../../../../../src/device/transport/bleObserver.js';
import Logger from '../../../../../src/logging/Logger.js';

describe('AiroticDeviceProvider', () => {
it('constructs with the reduced constructor signature and names its child logger after the class', () => {
const deviceManager = mock<DeviceManager>();
const bleObserver = mock<BleObserver>();
const deviceFactory = mock<AiroticDeviceFactory>();
const logger = mock<Logger>();
logger.child.mockReturnValue(logger);

const provider = new AiroticDeviceProvider(deviceManager, bleObserver, deviceFactory, logger);

expect(provider).toBeInstanceOf(AiroticDeviceProvider);
expect(logger.child).toHaveBeenCalledWith({ name: AiroticDeviceProvider.name });
});

it('delegates doStart()/doStop() to the injected BleObserver', async () => {
const deviceManager = mock<DeviceManager>();
const bleObserver = mock<BleObserver>();
const deviceFactory = mock<AiroticDeviceFactory>();
const logger = mock<Logger>();
logger.child.mockReturnValue(logger);

const provider = new AiroticDeviceProvider(deviceManager, bleObserver, deviceFactory, logger);

await provider.start();
expect(bleObserver.start).toHaveBeenCalledTimes(1);

await provider.stop();
expect(bleObserver.stop).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { describe, it, expect } from 'vitest';
import { mock } from 'vitest-mock-extended';
import ButtplugIoWebsocketDeviceProvider from '../../../../../src/device/protocol/buttplugIo/buttplugIoWebsocketDeviceProvider.js';
import ButtplugIoDeviceFactory from '../../../../../src/device/protocol/buttplugIo/buttplugIoDeviceFactory.js';
import DeviceManager from '../../../../../src/device/deviceManager.js';
import Logger from '../../../../../src/logging/Logger.js';

describe('ButtplugIoWebsocketDeviceProvider', () => {
it('constructs with the reduced constructor signature and names its child logger after the class', () => {
const deviceManager = mock<DeviceManager>();
const deviceFactory = mock<ButtplugIoDeviceFactory>();
const logger = mock<Logger>();
logger.child.mockReturnValue(logger);

const provider = new ButtplugIoWebsocketDeviceProvider(
deviceManager,
deviceFactory,
'localhost:12345',
true,
false,
logger
);

expect(provider).toBeInstanceOf(ButtplugIoWebsocketDeviceProvider);
expect(logger.child).toHaveBeenCalledWith({ name: ButtplugIoWebsocketDeviceProvider.name });
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { describe, it, expect } from 'vitest';
import { mock } from 'vitest-mock-extended';
import ButtplugIoWebsocketDeviceProviderFactory from '../../../../../src/device/protocol/buttplugIo/buttplugIoWebsocketDeviceProviderFactory.js';
import ButtplugIoWebsocketDeviceProvider from '../../../../../src/device/protocol/buttplugIo/buttplugIoWebsocketDeviceProvider.js';
import ButtplugIoDeviceFactory from '../../../../../src/device/protocol/buttplugIo/buttplugIoDeviceFactory.js';
import DeviceManager from '../../../../../src/device/deviceManager.js';
import Logger from '../../../../../src/logging/Logger.js';

describe('ButtplugIoWebsocketDeviceProviderFactory', () => {
it('creates a provider wired with the given config, without requiring an eventEmitter', () => {
const deviceManager = mock<DeviceManager>();
const deviceFactory = mock<ButtplugIoDeviceFactory>();
const logger = mock<Logger>();
logger.child.mockReturnValue(logger);

const factory = new ButtplugIoWebsocketDeviceProviderFactory(deviceManager, deviceFactory, logger);

const provider = factory.create({ address: '127.0.0.1:12345', autoScan: true, useDeviceNameAsId: false });

expect(provider).toBeInstanceOf(ButtplugIoWebsocketDeviceProvider);
expect(logger.child).toHaveBeenCalledWith({ name: ButtplugIoWebsocketDeviceProvider.name });
});

it('creates a fresh provider instance on every call', () => {
const deviceManager = mock<DeviceManager>();
const deviceFactory = mock<ButtplugIoDeviceFactory>();
const logger = mock<Logger>();
logger.child.mockReturnValue(logger);

const factory = new ButtplugIoWebsocketDeviceProviderFactory(deviceManager, deviceFactory, logger);

const providerA = factory.create({ address: 'localhost:1', autoScan: false, useDeviceNameAsId: false });
const providerB = factory.create({ address: 'localhost:2', autoScan: false, useDeviceNameAsId: false });

expect(providerA).not.toBe(providerB);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { describe, it, expect } from 'vitest';
import { mock } from 'vitest-mock-extended';
import EStim2bSerialDeviceProvider from '../../../../../src/device/protocol/estim2b/estim2bSerialDeviceProvider.js';
import EStim2bDeviceFactory from '../../../../../src/device/protocol/estim2b/estim2bDeviceFactory.js';
import SerialDeviceTransportFactory from '../../../../../src/device/transport/serialDeviceTransportFactory.js';
import SerialPortFactory from '../../../../../src/factory/serialPortFactory.js';
import SerialPortObserver from '../../../../../src/device/transport/serialPortObserver.js';
import DeviceManager from '../../../../../src/device/deviceManager.js';
import Logger from '../../../../../src/logging/Logger.js';

describe('EStim2bSerialDeviceProvider', () => {
const create = (
deviceManager = mock<DeviceManager>(),
serialPortFactory = mock<SerialPortFactory>(),
serialPortObserver = mock<SerialPortObserver>(),
transportFactory = mock<SerialDeviceTransportFactory>(),
deviceFactory = mock<EStim2bDeviceFactory>(),
logger = (() => { const l = mock<Logger>(); l.child.mockReturnValue(l); return l; })()
) => ({
provider: new EStim2bSerialDeviceProvider(
deviceManager,
serialPortFactory,
serialPortObserver,
transportFactory,
deviceFactory,
logger
),
serialPortObserver,
logger,
});

it('constructs with the reduced constructor signature and names its child logger after the class', () => {
const { provider, logger } = create();

expect(provider).toBeInstanceOf(EStim2bSerialDeviceProvider);
expect(logger.child).toHaveBeenCalledWith({ name: EStim2bSerialDeviceProvider.name });
});

it('delegates doStart()/doStop() to the injected SerialPortObserver', async () => {
const { provider, serialPortObserver } = create();

await provider.start();
expect(serialPortObserver.start).toHaveBeenCalledTimes(1);

await provider.stop();
expect(serialPortObserver.stop).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { describe, it, expect } from 'vitest';
import { mock } from 'vitest-mock-extended';
import SlvCtrlPlusSerialDeviceProvider from '../../../../../src/device/protocol/slvCtrlPlus/slvCtrlPlusSerialDeviceProvider.js';
import SlvCtrlPlusDeviceFactory from '../../../../../src/device/protocol/slvCtrlPlus/slvCtrlPlusDeviceFactory.js';
import SerialDeviceTransportFactory from '../../../../../src/device/transport/serialDeviceTransportFactory.js';
import SerialPortFactory from '../../../../../src/factory/serialPortFactory.js';
import SerialPortObserver from '../../../../../src/device/transport/serialPortObserver.js';
import DeviceManager from '../../../../../src/device/deviceManager.js';
import Logger from '../../../../../src/logging/Logger.js';

describe('SlvCtrlPlusSerialDeviceProvider', () => {
const create = (
deviceManager = mock<DeviceManager>(),
serialPortFactory = mock<SerialPortFactory>(),
serialPortObserver = mock<SerialPortObserver>(),
deviceFactory = mock<SlvCtrlPlusDeviceFactory>(),
deviceTransportFactory = mock<SerialDeviceTransportFactory>(),
logger = (() => { const l = mock<Logger>(); l.child.mockReturnValue(l); return l; })()
) => ({
provider: new SlvCtrlPlusSerialDeviceProvider(
deviceManager,
serialPortFactory,
serialPortObserver,
deviceFactory,
deviceTransportFactory,
logger
),
serialPortObserver,
logger,
});

it('constructs with the reduced constructor signature and names its child logger after the class', () => {
const { provider, logger } = create();

expect(provider).toBeInstanceOf(SlvCtrlPlusSerialDeviceProvider);
expect(logger.child).toHaveBeenCalledWith({ name: SlvCtrlPlusSerialDeviceProvider.name });
});

it('delegates doStart()/doStop() to the injected SerialPortObserver', async () => {
const { provider, serialPortObserver } = create();

await provider.start();
expect(serialPortObserver.start).toHaveBeenCalledTimes(1);

await provider.stop();
expect(serialPortObserver.stop).toHaveBeenCalledTimes(1);
});
});
46 changes: 46 additions & 0 deletions tests/unit/device/protocol/virtual/virtualDeviceProvider.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { describe, it, expect } from 'vitest';
import { mock } from 'vitest-mock-extended';
import VirtualDeviceProvider from '../../../../../src/device/protocol/virtual/virtualDeviceProvider.js';
import VirtualDeviceFactory from '../../../../../src/device/protocol/virtual/virtualDeviceFactory.js';
import SettingsManager from '../../../../../src/settings/settingsManager.js';
import SettingsEventType from '../../../../../src/settings/settingsEventType.js';
import DeviceManager from '../../../../../src/device/deviceManager.js';
import Logger from '../../../../../src/logging/Logger.js';

describe('VirtualDeviceProvider', () => {
const create = (
deviceManager = mock<DeviceManager>(),
deviceFactory = mock<VirtualDeviceFactory>(),
settingsManager = mock<SettingsManager>(),
logger = (() => { const l = mock<Logger>(); l.child.mockReturnValue(l); return l; })()
) => ({ provider: new VirtualDeviceProvider(deviceManager, deviceFactory, settingsManager, logger), settingsManager, logger });

it('constructs with the reduced constructor signature and names its child logger after the class', () => {
const { provider, logger } = create();

expect(provider).toBeInstanceOf(VirtualDeviceProvider);
expect(logger.child).toHaveBeenCalledWith({ name: VirtualDeviceProvider.name });
});

it('subscribes to settings changes on start() and unsubscribes on stop()', async () => {
const settingsManager = mock<SettingsManager>();
settingsManager.getSettings.mockReturnValue(undefined);
const { provider } = create(undefined, undefined, settingsManager);

await provider.start();
expect(settingsManager.on).toHaveBeenCalledWith(SettingsEventType.changed, expect.any(Function));

await provider.stop();
expect(settingsManager.off).toHaveBeenCalledWith(SettingsEventType.changed, expect.any(Function));
});

it('scans for configured virtual devices via the injected SettingsManager on start()', async () => {
const settingsManager = mock<SettingsManager>();
settingsManager.getSettings.mockReturnValue(undefined);
const { provider } = create(undefined, undefined, settingsManager);

await provider.start();

expect(settingsManager.getSettings).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { describe, it, expect } from 'vitest';
import { mock } from 'vitest-mock-extended';
import VirtualDeviceProviderFactory from '../../../../../src/device/protocol/virtual/virtualDeviceProviderFactory.js';
import VirtualDeviceProvider from '../../../../../src/device/protocol/virtual/virtualDeviceProvider.js';
import VirtualDeviceFactory from '../../../../../src/device/protocol/virtual/virtualDeviceFactory.js';
import DeviceManager from '../../../../../src/device/deviceManager.js';
import SettingsManager from '../../../../../src/settings/settingsManager.js';
import Logger from '../../../../../src/logging/Logger.js';

describe('VirtualDeviceProviderFactory', () => {
it('creates a provider wired with its dependencies, without requiring an eventEmitterFactory', () => {
const deviceManager = mock<DeviceManager>();
const deviceFactory = mock<VirtualDeviceFactory>();
const settingsManager = mock<SettingsManager>();
const logger = mock<Logger>();
logger.child.mockReturnValue(logger);

const factory = new VirtualDeviceProviderFactory(deviceManager, deviceFactory, settingsManager, logger);

const provider = factory.create();

expect(provider).toBeInstanceOf(VirtualDeviceProvider);
expect(logger.child).toHaveBeenCalledWith({ name: VirtualDeviceProvider.name });
});

it('creates a fresh provider instance on every call', () => {
const deviceManager = mock<DeviceManager>();
const deviceFactory = mock<VirtualDeviceFactory>();
const settingsManager = mock<SettingsManager>();
const logger = mock<Logger>();
logger.child.mockReturnValue(logger);

const factory = new VirtualDeviceProviderFactory(deviceManager, deviceFactory, settingsManager, logger);

expect(factory.create()).not.toBe(factory.create());
});
});
48 changes: 48 additions & 0 deletions tests/unit/device/protocol/zc95/zc95SerialDeviceProvider.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { describe, it, expect } from 'vitest';
import { mock } from 'vitest-mock-extended';
import Zc95SerialDeviceProvider from '../../../../../src/device/protocol/zc95/zc95SerialDeviceProvider.js';
import Zc95DeviceFactory from '../../../../../src/device/protocol/zc95/zc95DeviceFactory.js';
import SerialDeviceTransportFactory from '../../../../../src/device/transport/serialDeviceTransportFactory.js';
import SerialPortFactory from '../../../../../src/factory/serialPortFactory.js';
import SerialPortObserver from '../../../../../src/device/transport/serialPortObserver.js';
import DeviceManager from '../../../../../src/device/deviceManager.js';
import Logger from '../../../../../src/logging/Logger.js';

describe('Zc95SerialDeviceProvider', () => {
const create = (
deviceManager = mock<DeviceManager>(),
serialPortFactory = mock<SerialPortFactory>(),
serialPortObserver = mock<SerialPortObserver>(),
transportFactory = mock<SerialDeviceTransportFactory>(),
deviceFactory = mock<Zc95DeviceFactory>(),
logger = (() => { const l = mock<Logger>(); l.child.mockReturnValue(l); return l; })()
) => ({
provider: new Zc95SerialDeviceProvider(
deviceManager,
serialPortFactory,
serialPortObserver,
transportFactory,
deviceFactory,
logger
),
serialPortObserver,
logger,
});

it('constructs with the reduced constructor signature and names its child logger after the class', () => {
const { provider, logger } = create();

expect(provider).toBeInstanceOf(Zc95SerialDeviceProvider);
expect(logger.child).toHaveBeenCalledWith({ name: Zc95SerialDeviceProvider.name });
});

it('delegates doStart()/doStop() to the injected SerialPortObserver', async () => {
const { provider, serialPortObserver } = create();

await provider.start();
expect(serialPortObserver.start).toHaveBeenCalledTimes(1);

await provider.stop();
expect(serialPortObserver.stop).toHaveBeenCalledTimes(1);
});
});
Loading
Loading