Skip to content

Commit

Permalink
Finished out driver, protocol, and core tests
Browse files Browse the repository at this point in the history
  • Loading branch information
6XGate committed Nov 11, 2024
1 parent 5bae111 commit 9d0101a
Show file tree
Hide file tree
Showing 26 changed files with 303 additions and 170 deletions.
9 changes: 9 additions & 0 deletions src/core/error-handling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ export function toError(cause: unknown) {
return new Error(getMessage(cause))
}

export function isNodeError(value: unknown): value is NodeJS.ErrnoException
export function isNodeError<E extends new (...args: any[]) => Error>(
value: unknown,
type: E
): value is InstanceType<E> & NodeJS.ErrnoException
export function isNodeError(value: unknown, type: new (...args: any[]) => Error = Error) {
return value instanceof type && (value as NodeJS.ErrnoException).code != null
}

export function raiseError(factory: () => Error): never {
throw factory()
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/rpc/transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default function useSuperJson() {
{
isApplicable: (v): v is () => undefined => typeof v === 'function',
serialize: (_: () => undefined) => raiseError(() => new TypeError('Functions may not be serialized')),
deserialize: (_: never) => () => undefined
deserialize: (_: never) => raiseError(() => new TypeError('Functions may not be serialized'))
},
'Function'
)
Expand Down
1 change: 1 addition & 0 deletions src/main/services/protocols/protocols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const useProtocol = memo(function useProtocol(name: string, options: Prot
Logger.debug(`${name}; returned ${String(data)}`)
})
connection.on('error', (error) => {
/* v8 ignore next 1 */ // TODO: Will attempt to mock later.
Logger.error(`${name}; ${error.message}`)
})

Expand Down
12 changes: 0 additions & 12 deletions src/main/services/protocols/sonyRs485.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,6 @@ export class PacketError extends SonyDriverError {
}
}

export class ChecksumError extends PacketError {
constructor(message?: string) {
super(message ?? 'Unknown checksum error')
}
}

export class CommandBlockError extends SonyDriverError {
constructor(message?: string) {
super(message ?? 'Unknown command block error')
}
}

/** Calculates the checksum for a packet. */
export function calculateChecksum(data: Buffer) {
let x = 0n
Expand Down
3 changes: 2 additions & 1 deletion src/main/services/updater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import autoBind from 'auto-bind'
import { app } from 'electron'
import { autoUpdater } from 'electron-updater'
import { memo } from 'radash'
import { isNodeError, logError } from '../utilities'
import { logError } from '../utilities'
import type { UpdateCheckResult, ProgressInfo, CancellationToken, UpdateInfo } from 'electron-updater'
import { isNodeError } from '@/error-handling'

export type { UpdateInfo, ProgressInfo } from 'electron-updater'

Expand Down
9 changes: 0 additions & 9 deletions src/main/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,3 @@ export function logError<E extends Error>(e: E) {
Logger.error(e)
return e
}

export function isNodeError(value: unknown): value is NodeJS.ErrnoException
export function isNodeError<E extends new (...args: any[]) => Error>(
value: unknown,
type: E
): value is InstanceType<E> & NodeJS.ErrnoException
export function isNodeError(value: unknown, type: new (...args: any[]) => Error = Error) {
return value instanceof type && (value as NodeJS.ErrnoException).code != null
}
5 changes: 5 additions & 0 deletions src/tests/core/error-handling.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as mock from '../support/mock'
import {
getMessage,
getZodMessage,
isNodeError,
logPromiseFailures,
raiseError,
toError,
Expand Down Expand Up @@ -70,6 +71,10 @@ test('toError', () => {
expect(toError(typeError)).toBe(typeError)
})

test('isNodeError', () => {
expect(isNodeError(new Error('test'))).toBe(false)
})

test('raiseError', () => {
expect(() => raiseError(() => new ReferenceError('test'))).toThrowError(new ReferenceError('test'))
expect(() => raiseError(() => new TypeError('test'))).toThrowError(new TypeError('test'))
Expand Down
70 changes: 35 additions & 35 deletions src/tests/core/location.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,53 +25,53 @@ afterAll(() => {

describe('isIpOrValidPort', () => {
test('port', () => {
expect(isIpOrValidPort('port:/dev/ttyS0', ports)).toBeTruthy()
expect(isIpOrValidPort('port:/dev/ttyS5', ports)).toBeFalsy()
expect(isIpOrValidPort('port:', ports)).toBeFalsy()
expect(isIpOrValidPort('port', ports)).toBeFalsy()
expect(isIpOrValidPort('port:/dev/ttyS0', ports)).toBe(true)
expect(isIpOrValidPort('port:/dev/ttyS5', ports)).toBe(false)
expect(isIpOrValidPort('port:', ports)).toBe(false)
expect(isIpOrValidPort('port', ports)).toBe(false)
})
test('ip', () => {
expect(isIpOrValidPort('ip:example.com', ports)).toBeTruthy()
expect(isIpOrValidPort('ip:example', ports)).toBeTruthy()
expect(isIpOrValidPort('ip:127.5.0.111', ports)).toBeTruthy()
expect(isIpOrValidPort('ip:', ports)).toBeFalsy()
expect(isIpOrValidPort('ip', ports)).toBeFalsy()
expect(isIpOrValidPort('ip:example.com', ports)).toBe(true)
expect(isIpOrValidPort('ip:example', ports)).toBe(true)
expect(isIpOrValidPort('ip:127.5.0.111', ports)).toBe(true)
expect(isIpOrValidPort('ip:', ports)).toBe(false)
expect(isIpOrValidPort('ip', ports)).toBe(false)
})
test('random', () => {
expect(isIpOrValidPort('file:', ports)).toBeFalsy()
expect(isIpOrValidPort('', ports)).toBeFalsy()
expect(isIpOrValidPort('file:', ports)).toBe(false)
expect(isIpOrValidPort('', ports)).toBe(false)
})
})

describe('isValidLocation', () => {
test('port', () => {
expect(isValidLocation('port:/dev/ttyS0', ports)).toBeTruthy()
expect(isValidLocation('port:/dev/ttyS5', ports)).toBeFalsy()
expect(isValidLocation('port:', ports)).toBeFalsy()
expect(isValidLocation('port', ports)).toBeFalsy()
expect(isValidLocation('port:/dev/ttyS0', ports)).toBe(true)
expect(isValidLocation('port:/dev/ttyS5', ports)).toBe(false)
expect(isValidLocation('port:', ports)).toBe(false)
expect(isValidLocation('port', ports)).toBe(false)
})
test('ip', () => {
expect(isValidLocation('ip:example.com', ports)).toBeTruthy()
expect(isValidLocation('ip:example', ports)).toBeTruthy()
expect(isValidLocation('ip:127.5.0.111', ports)).toBeTruthy()
expect(isValidLocation('ip:127.5.0.4111', ports)).toBeTruthy() // Host not IP.
expect(isValidLocation('ip:[2561:1900:4545:0003:0200:F8FF:FE21:67CF]', ports)).toBeTruthy()
expect(isValidLocation('ip:[2260:F3A4:32CB:715D:5D11:D837:FC76:12FC]', ports)).toBeTruthy()
expect(isValidLocation('ip:[FE80::2045:FAEB:33AF:8374]', ports)).toBeTruthy()
expect(isValidLocation('ip:[::2045:FAEB:33AF:8374]', ports)).toBeTruthy()
expect(isValidLocation('ip:[FE80:2045:FAEB:33AF::]', ports)).toBeTruthy()
expect(isValidLocation('ip:[::11.22.33.44]', ports)).toBeTruthy()
expect(isValidLocation('ip:[F:F:F:F:F:F:192.168.0.1]', ports)).toBeTruthy()
expect(isValidLocation('ip:[2001:db8::123.123.123.123]', ports)).toBeTruthy()
expect(isValidLocation('ip:[2001:db8::123.123.123.123]:55', ports)).toBeTruthy()
expect(isValidLocation('ip:[2001:db8::123.123.123.123]:ab', ports)).toBeFalsy()
expect(isValidLocation('ip:[::]:59', ports)).toBeTruthy()
expect(isValidLocation('ip:[]:59', ports)).toBeFalsy()
expect(isValidLocation('ip://', ports)).toBeFalsy()
expect(isValidLocation('ip:', ports)).toBeFalsy()
expect(isValidLocation('ip:example.com', ports)).toBe(true)
expect(isValidLocation('ip:example', ports)).toBe(true)
expect(isValidLocation('ip:127.5.0.111', ports)).toBe(true)
expect(isValidLocation('ip:127.5.0.4111', ports)).toBe(true) // Host not IP.
expect(isValidLocation('ip:[2561:1900:4545:0003:0200:F8FF:FE21:67CF]', ports)).toBe(true)
expect(isValidLocation('ip:[2260:F3A4:32CB:715D:5D11:D837:FC76:12FC]', ports)).toBe(true)
expect(isValidLocation('ip:[FE80::2045:FAEB:33AF:8374]', ports)).toBe(true)
expect(isValidLocation('ip:[::2045:FAEB:33AF:8374]', ports)).toBe(true)
expect(isValidLocation('ip:[FE80:2045:FAEB:33AF::]', ports)).toBe(true)
expect(isValidLocation('ip:[::11.22.33.44]', ports)).toBe(true)
expect(isValidLocation('ip:[F:F:F:F:F:F:192.168.0.1]', ports)).toBe(true)
expect(isValidLocation('ip:[2001:db8::123.123.123.123]', ports)).toBe(true)
expect(isValidLocation('ip:[2001:db8::123.123.123.123]:55', ports)).toBe(true)
expect(isValidLocation('ip:[2001:db8::123.123.123.123]:ab', ports)).toBe(false)
expect(isValidLocation('ip:[::]:59', ports)).toBe(true)
expect(isValidLocation('ip:[]:59', ports)).toBe(false)
expect(isValidLocation('ip://', ports)).toBe(false)
expect(isValidLocation('ip:', ports)).toBe(false)
})
test('random', () => {
expect(isValidLocation('file:', ports)).toBeFalsy()
expect(isValidLocation('', ports)).toBeFalsy()
expect(isValidLocation('file:', ports)).toBe(false)
expect(isValidLocation('', ports)).toBe(false)
})
})
46 changes: 46 additions & 0 deletions src/tests/core/superjson.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { beforeAll, describe, expect, test } from 'vitest'
import type { SuperJSONResult } from 'superjson'
import { Attachment } from '@/attachments'
import useSuperJson from '@/rpc/transformer'

describe('superjson', () => {
let superjson: ReturnType<typeof useSuperJson>
beforeAll(() => {
superjson = useSuperJson()
})

describe('attachments', () => {
test('serialize', () => {
const payload = { file: new Attachment('test.txt', 'text/plain', Buffer.from('Hello World')) }
expect(superjson.serialize(payload)).toStrictEqual({
json: { file: { name: 'test.txt', type: 'text/plain', data: 'SGVsbG8gV29ybGQ=' } },
meta: { values: { file: [['custom', 'Attachment']] } }
})
})

test('deserialize', () => {
const payload = {
json: { file: { name: 'test.txt', type: 'text/plain', data: 'SGVsbG8gV29ybGQ=' } },
meta: { values: { file: [['custom', 'Attachment']] } }
} satisfies SuperJSONResult
expect(superjson.deserialize(payload)).toStrictEqual({
file: new Attachment('test.txt', 'text/plain', Buffer.from('Hello World'))
})
})
})

describe('functions', () => {
test('serialize', () => {
const payload = { hello: () => undefined }
expect(() => superjson.serialize(payload)).toThrow(new TypeError('Functions may not be serialized'))
})

test('deserialize', () => {
const payload = {
json: { file: null },
meta: { values: { file: [['custom', 'Function']] } }
} satisfies SuperJSONResult
expect(() => superjson.deserialize(payload)).toThrow(new TypeError('Functions may not be serialized'))
})
})
})
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { afterEach, beforeEach, expect, test, vi } from 'vitest'
import type { MockStreamContext } from '../../support/stream'
import type { MockStreamContext } from '../../../support/stream'

const mock = await vi.hoisted(async () => await import('../../support/mock'))
const port = await vi.hoisted(async () => await import('../../support/serial'))
const stream = await vi.hoisted(async () => await import('../../support/stream'))
const mock = await vi.hoisted(async () => await import('../../../support/mock'))
const port = await vi.hoisted(async () => await import('../../../support/serial'))
const stream = await vi.hoisted(async () => await import('../../../support/stream'))

beforeEach<MockStreamContext>(async (context) => {
vi.mock('electron-log')
vi.mock('serialport', port.serialPortModule)
vi.doMock('../../../main/services/stream', stream.commandStreamModule(context))
vi.doMock('../../../../main/services/stream', stream.commandStreamModule(context))
await port.createMockPorts()
})

Expand All @@ -21,8 +21,8 @@ afterEach(async () => {
const kDriverGuid = '4C8F2838-C91D-431E-84DD-3666D14A6E2C'

test('available', async () => {
const { default: driver } = await import('../../../main/drivers/extron/sis')
const { default: useDrivers } = await import('../../../main/services/drivers')
const { default: driver } = await import('../../../../main/drivers/extron/sis')
const { default: useDrivers } = await import('../../../../main/services/drivers')

const drivers = useDrivers()

Expand All @@ -45,7 +45,7 @@ test<MockStreamContext>('power on', async (context) => {

context.stream = new stream.MockCommandStream()

const { default: useDrivers } = await import('../../../main/services/drivers')
const { default: useDrivers } = await import('../../../../main/services/drivers')
const drivers = useDrivers()

// Power on is a no-op
Expand All @@ -61,7 +61,7 @@ test<MockStreamContext>('power off', async (context) => {

context.stream = new stream.MockCommandStream()

const { default: useDrivers } = await import('../../../main/services/drivers')
const { default: useDrivers } = await import('../../../../main/services/drivers')
const drivers = useDrivers()

// Power off is a no-op
Expand All @@ -77,7 +77,7 @@ test<MockStreamContext>('activate tie', async (context) => {

context.stream = new stream.MockCommandStream()

const { default: useDrivers } = await import('../../../main/services/drivers')
const { default: useDrivers } = await import('../../../../main/services/drivers')
const drivers = useDrivers()

const input = 1
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { afterEach, beforeEach, expect, test, vi } from 'vitest'
import type { MockStreamContext } from '../../support/stream'
import type { MockStreamContext } from '../../../support/stream'

const mock = await vi.hoisted(async () => await import('../../support/mock'))
const port = await vi.hoisted(async () => await import('../../support/serial'))
const stream = await vi.hoisted(async () => await import('../../support/stream'))
const mock = await vi.hoisted(async () => await import('../../../support/mock'))
const port = await vi.hoisted(async () => await import('../../../support/serial'))
const stream = await vi.hoisted(async () => await import('../../../support/stream'))

beforeEach<MockStreamContext>(async (context) => {
vi.mock('electron-log')
vi.mock('serialport', port.serialPortModule)
vi.doMock('../../../main/services/stream', stream.commandStreamModule(context))
vi.doMock('../../../../main/services/stream', stream.commandStreamModule(context))
await port.createMockPorts()
})

Expand All @@ -21,8 +21,8 @@ afterEach(async () => {
const kDriverGuid = '75FB7ED2-EE3A-46D5-B11F-7D8C3C208E7C'

test('available', async () => {
const { default: driver } = await import('../../../main/drivers/shinybow/v2')
const { default: useDrivers } = await import('../../../main/services/drivers')
const { default: driver } = await import('../../../../main/drivers/shinybow/v2')
const { default: useDrivers } = await import('../../../../main/services/drivers')

const drivers = useDrivers()

Expand All @@ -45,7 +45,7 @@ test<MockStreamContext>('power on', async (context) => {

context.stream = new stream.MockCommandStream()

const { default: useDrivers } = await import('../../../main/services/drivers')
const { default: useDrivers } = await import('../../../../main/services/drivers')
const drivers = useDrivers()

const command = `POWER 01;\r\n`
Expand All @@ -61,7 +61,7 @@ test<MockStreamContext>('power off', async (context) => {

context.stream = new stream.MockCommandStream()

const { default: useDrivers } = await import('../../../main/services/drivers')
const { default: useDrivers } = await import('../../../../main/services/drivers')
const drivers = useDrivers()

const command = `POWER 00;\r\n`
Expand All @@ -77,7 +77,7 @@ test<MockStreamContext>('activate tie', async (context) => {

context.stream = new stream.MockCommandStream()

const { default: useDrivers } = await import('../../../main/services/drivers')
const { default: useDrivers } = await import('../../../../main/services/drivers')
const drivers = useDrivers()

const input = 1
Expand Down
Loading

0 comments on commit 9d0101a

Please sign in to comment.