Skip to content

Commit

Permalink
Merge pull request #993 from lbrooks/find-device-tests
Browse files Browse the repository at this point in the history
coverage: Refactor and add tests to findDevice.ts
  • Loading branch information
alexpargon authored Feb 7, 2025
2 parents c51ca99 + f77dd1b commit 26474ed
Show file tree
Hide file tree
Showing 12 changed files with 182 additions and 40 deletions.
5 changes: 2 additions & 3 deletions src/api/comms/DeviceTalker.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import log from "electron-log/renderer";
import serial, { isSerialType, DeviceType } from "./serial";
import serial, { DeviceType, isSerialType } from "./serial";
import hid from "./hid";

class DeviceTalker {
Expand All @@ -19,8 +19,7 @@ class DeviceTalker {
log.verbose(`the device is ${device.type} type, and connected as: ${result}`);
return result;
}
const result = hid.connect(device);
return result;
return hid.connect(device);
};
}

Expand Down
4 changes: 2 additions & 2 deletions src/api/comms/serial/SerialAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import log from "electron-log/renderer";
import type { SerialPort as SP } from "serialport";
import type { PortInfo } from "@serialport/bindings-cpp";
import { DygmaDeviceType } from "@Renderer/types/dygmaDefs";
import { DeviceType } from "@Types/devices";
import Hardware from "../../hardware";
import { DeviceType } from "../../../renderer/types/devices";

const { SerialPort } = eval('require("serialport")');
const { DelimiterParser } = eval('require("@serialport/parser-delimiter")');
Expand Down Expand Up @@ -51,7 +51,7 @@ interface SerialProperties {
}

const checkProperties = async (path: string): Promise<SerialProperties> => {
let callbacks: any[] = [];
let callbacks: ((value: string | PromiseLike<string>) => void)[] = [];
let result = "";

function rawCommand(cmd: string, serialPort: SP): Promise<string> {
Expand Down
6 changes: 3 additions & 3 deletions src/api/flash/RaiseTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const RaiseResetKeyboard = async (port: SP, stateUpdate: (state: string,
let bootCount = 6;
while (bootCount > 0) {
stateUpdate("reset", 20 + (10 - bootCount) * 8);
const newPort = await findDevice("bootloader", "Bootloader detected");
const newPort = await findDevice("bootloader");
if (newPort) {
stateUpdate("reset", 100);
result = newPort;
Expand Down Expand Up @@ -101,7 +101,7 @@ export const resetKeyboard = async (currentDevice: Device, stateUpdate: any) =>
try {
let bootCount = 10;
while (bootCount > 0) {
if (await findDevice("bootloader", "Bootloader detected")) {
if (await findDevice("bootloader")) {
stateUpdate("reset", 100);
bootCount = -1;
resolve("Detected Bootloader mode");
Expand Down Expand Up @@ -130,7 +130,7 @@ export const detectKeyboard = async (stateUpdate: any, device: DygmaDeviceType)
try {
let searchFor = 10;
while (searchFor > 0) {
const newPort = await findDevice("serial", "Keyboard detected", device);
const newPort = await findDevice("serial", device);
if (newPort) {
stateUpdate("reset", 100);
searchFor = -1;
Expand Down
65 changes: 34 additions & 31 deletions src/api/flash/findDevice.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,45 @@
import { DygmaDeviceType } from "@Renderer/types/dygmaDefs";
import { DeviceTools } from "@Renderer/DeviceContext";
import log from "electron-log/renderer";
import { DeviceTools } from "@Renderer/DeviceContext";
import { DygmaDeviceType } from "@Renderer/types/dygmaDefs";
import { ExtendedPort } from "../comms/serial/SerialAPI";
import Hardware from "../hardware";

function getDeviceList(deviceType: "serial" | "nonSerial" | "bootloader", desiredDevice?: DygmaDeviceType): DygmaDeviceType[] {
if (deviceType === "serial" && desiredDevice?.info.keyboardType !== undefined) {
return [desiredDevice];
}
return Hardware[deviceType];
}

export const findDevice = async (
deviceType: "serial" | "nonSerial" | "bootloader",
message: string,
desiredDevice?: DygmaDeviceType,
) => {
log.info("Going to list devices");
let devices = Hardware[deviceType] as DygmaDeviceType[];
const bootloader = deviceType === "bootloader";
const list: ExtendedPort[] = (await DeviceTools.enumerateSerial(bootloader)).foundDevices as ExtendedPort[];
if (deviceType === "serial" && desiredDevice?.info.keyboardType !== undefined) devices = [desiredDevice];
log.verbose("List of Devices: ", list);
const detected = list.find(dev => {
log.info("Searching for Device");
let found = false;
devices.forEach(device => {
): Promise<ExtendedPort> => {
log.info(`Going to list devices for type: ${deviceType}`);
const lookupDevices: DygmaDeviceType[] = getDeviceList(deviceType, desiredDevice);

const isBootloader = deviceType === "bootloader";
const hwDevices: ExtendedPort[] = (await DeviceTools.enumerateSerial(isBootloader)).foundDevices;
log.verbose("List of Devices: ", hwDevices);

const matchingDevice: ExtendedPort = hwDevices.find(hwDevice =>
lookupDevices.some(lookupDevice => {
log.info(
`Dev bootloader: ${dev.device.bootloader} & HW: ${bootloader}, Dev KBType: ${device.info.keyboardType} & HW: ${dev.device.info.keyboardType}`,
`Bootloader - Lookup: ${isBootloader} & HW: ${hwDevice.device.bootloader} | KBType - Lookup: ${lookupDevice.info.keyboardType} & HW: ${hwDevice.device.info.keyboardType}`,
);
if (
found !== true && bootloader
? dev.device.bootloader !== undefined &&
dev.device.bootloader === bootloader &&
device.usb.vendorId === dev.device.usb.vendorId &&
device.usb.productId === dev.device.usb.productId
: device.usb.vendorId === dev.device.usb.vendorId &&
device.usb.productId === dev.device.usb.productId &&
device.info.keyboardType === dev.device.info.keyboardType
) {
found = true;

if (lookupDevice.usb.vendorId !== hwDevice.device.usb.vendorId) {
return false;
}
if (lookupDevice.usb.productId !== hwDevice.device.usb.productId) {
return false;
}
if (isBootloader) {
return hwDevice.device.bootloader === true;
}
});
return found;
});
log.info(message, detected);
return detected;
return lookupDevice.info.keyboardType === hwDevice.device.info.keyboardType;
}),
);
log.info(`${deviceType === "serial" ? "keyboard" : deviceType} detected`, matchingDevice);
return matchingDevice;
};
140 changes: 140 additions & 0 deletions src/api/flash/findDevice.unit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import log from "electron-log/renderer";
import { DeviceTools } from "@Renderer/DeviceContext";
import { findDevice } from "./findDevice";
import { DefyWired, DefyWiredBootloader } from "../hardware-dygma-defy-wired";
import { Raise2ANSI } from "../hardware-dygma-raise2-ansi";

const connectedDevices = [
{
manufacturer: "",
serialNumber: "",
pnpId: "",
locationId: "",
vendorId: "35ef",
path: "Defy-Wired",
productId: "0010",
device: { ...DefyWired },
},
{
manufacturer: "",
serialNumber: "",
pnpId: "",
locationId: "",
vendorId: "35ef",
path: "Defy-Wired-Bootloader",
productId: "0011",
device: { ...DefyWiredBootloader },
},
{
manufacturer: "",
serialNumber: "",
pnpId: "",
locationId: "",
vendorId: "35ef",
path: "Dygma-Raise-2-ANSI",
productId: "0021",
device: { ...Raise2ANSI },
},
];

describe("findDevices", () => {
beforeEach(() => {
vi.mock("../../renderer/DeviceContext.tsx", async importOriginal => {
const data = await importOriginal<typeof import("../../renderer/DeviceContext.tsx")>();
const val = {
...data,
};
val.DeviceTools.enumerateSerial = vi.fn();
return val;
});

vi.mock("electron-log/renderer", () => ({
default: {
error: vi.fn(),
warn: vi.fn(),
info: vi.fn(),
verbose: vi.fn(),
debug: vi.fn(),
silly: vi.fn(),
},
}));
});
afterEach(() => {
vi.clearAllMocks();
});

it("should find no device when none connected", async () => {
vi.mocked(DeviceTools).enumerateSerial.mockResolvedValue({ foundDevices: [], validDevices: [] });

expect(await findDevice("serial", undefined)).toBeUndefined();

expect(log.info).toHaveBeenCalledTimes(2);
expect(log.info).toHaveBeenCalledWith("Going to list devices for type: serial");
expect(log.info).toHaveBeenCalledWith("keyboard detected", undefined);

expect(log.verbose).toHaveBeenCalledTimes(1);
expect(log.verbose).toHaveBeenCalledWith("List of Devices: ", []);
});

it("should find a device", async () => {
vi.mocked(DeviceTools).enumerateSerial.mockResolvedValue({
foundDevices: connectedDevices,
validDevices: [],
});

expect(await findDevice("serial", undefined)).toEqual(connectedDevices[0]);

expect(log.info).toHaveBeenCalledTimes(5);
expect(log.info).toHaveBeenCalledWith("Going to list devices for type: serial");
expect(log.info).toHaveBeenCalledWith("Bootloader - Lookup: false & HW: undefined | KBType - Lookup: ISO & HW: wired");
expect(log.info).toHaveBeenCalledWith("Bootloader - Lookup: false & HW: undefined | KBType - Lookup: ANSI & HW: wired");
expect(log.info).toHaveBeenCalledWith("Bootloader - Lookup: false & HW: undefined | KBType - Lookup: wired & HW: wired");
expect(log.info).toHaveBeenCalledWith("keyboard detected", connectedDevices[0]);

expect(log.verbose).toHaveBeenCalledTimes(1);
expect(log.verbose).toHaveBeenCalledWith("List of Devices: ", connectedDevices);
});

it("should find a wireless device", async () => {
vi.mocked(DeviceTools).enumerateSerial.mockResolvedValue({
foundDevices: connectedDevices,
validDevices: [],
});

expect(await findDevice("serial", connectedDevices[2].device)).toEqual(connectedDevices[2]);

expect(log.info).toHaveBeenCalledTimes(5);
expect(log.info).toHaveBeenCalledWith("Going to list devices for type: serial");
expect(log.info).toHaveBeenCalledWith("Bootloader - Lookup: false & HW: undefined | KBType - Lookup: ANSI & HW: wired");
expect(log.info).toHaveBeenCalledWith("Bootloader - Lookup: false & HW: true | KBType - Lookup: ANSI & HW: wired");
expect(log.info).toHaveBeenCalledWith("Bootloader - Lookup: false & HW: false | KBType - Lookup: ANSI & HW: ANSI");
expect(log.info).toHaveBeenCalledWith("keyboard detected", connectedDevices[2]);

expect(log.verbose).toHaveBeenCalledTimes(1);
expect(log.verbose).toHaveBeenCalledWith("List of Devices: ", connectedDevices);
});

it("should finds a bootloader", async () => {
vi.mocked(DeviceTools).enumerateSerial.mockResolvedValue({
foundDevices: connectedDevices,
validDevices: [],
});

expect(await findDevice("bootloader", undefined)).toEqual(connectedDevices[1]);

expect(log.info).toHaveBeenCalledTimes(11);
expect(log.info).toHaveBeenCalledWith("Going to list devices for type: bootloader");
expect(log.info).toHaveBeenCalledWith("Bootloader - Lookup: true & HW: undefined | KBType - Lookup: ANSI & HW: wired");
expect(log.info).toHaveBeenCalledWith("Bootloader - Lookup: true & HW: undefined | KBType - Lookup: ISO & HW: wired");
expect(log.info).toHaveBeenCalledWith("Bootloader - Lookup: true & HW: undefined | KBType - Lookup: wired & HW: wired");
expect(log.info).toHaveBeenCalledWith("Bootloader - Lookup: true & HW: undefined | KBType - Lookup: wireless & HW: wired");
expect(log.info).toHaveBeenCalledWith("Bootloader - Lookup: true & HW: true | KBType - Lookup: ANSI & HW: wired");
expect(log.info).toHaveBeenCalledWith("Bootloader - Lookup: true & HW: true | KBType - Lookup: ISO & HW: wired");
expect(log.info).toHaveBeenCalledWith("Bootloader - Lookup: true & HW: true | KBType - Lookup: wired & HW: wired");
expect(log.info).toHaveBeenCalledWith("bootloader detected", connectedDevices[1]);

expect(log.verbose).toHaveBeenCalledTimes(1);
expect(log.verbose).toHaveBeenCalledWith("List of Devices: ", connectedDevices);
});
});
2 changes: 1 addition & 1 deletion src/renderer/DeviceContext.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable no-await-in-loop */
import React, { useReducer, createContext, useContext, useMemo } from "react";
import log from "electron-log/renderer";
import { VirtualType } from "./types/virtual";
import { VirtualType } from "@Types/virtual";
import serial from "../api/comms/serial";
import Device, { State } from "../api/comms/Device";
import HID from "../api/hid/hid";
Expand Down

0 comments on commit 26474ed

Please sign in to comment.