import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as path from 'path'; import { RustBridge } from '../ts/classes.rustbridge.js'; import type { ICommandDefinition } from '../ts/interfaces/index.js'; const testDir = path.resolve(path.dirname(new URL(import.meta.url).pathname)); const mockBinaryPath = path.join(testDir, 'helpers/mock-rust-binary.mjs'); // Define the command types for our mock binary type TMockCommands = { echo: { params: Record; result: Record }; error: { params: {}; result: never }; emitEvent: { params: { eventName: string; eventData: any }; result: null }; slow: { params: {}; result: { delayed: boolean } }; exit: { params: {}; result: null }; }; tap.test('should spawn and receive ready event', async () => { const bridge = new RustBridge({ binaryName: 'node', binaryPath: 'node', cliArgs: [mockBinaryPath], readyTimeoutMs: 5000, }); const result = await bridge.spawn(); expect(result).toBeTrue(); expect(bridge.running).toBeTrue(); bridge.kill(); expect(bridge.running).toBeFalse(); }); tap.test('should send command and receive response', async () => { const bridge = new RustBridge({ binaryName: 'node', binaryPath: 'node', cliArgs: [mockBinaryPath], readyTimeoutMs: 5000, }); await bridge.spawn(); const result = await bridge.sendCommand('echo', { hello: 'world', num: 42 }); expect(result).toEqual({ hello: 'world', num: 42 }); bridge.kill(); }); tap.test('should handle error responses', async () => { const bridge = new RustBridge({ binaryName: 'node', binaryPath: 'node', cliArgs: [mockBinaryPath], readyTimeoutMs: 5000, }); await bridge.spawn(); let threw = false; try { await bridge.sendCommand('error', {}); } catch (err: any) { threw = true; expect(err.message).toInclude('Test error message'); } expect(threw).toBeTrue(); bridge.kill(); }); tap.test('should receive custom events from the binary', async () => { const bridge = new RustBridge({ binaryName: 'node', binaryPath: 'node', cliArgs: [mockBinaryPath], readyTimeoutMs: 5000, }); await bridge.spawn(); const eventPromise = new Promise((resolve) => { bridge.once('management:testEvent', (data) => { resolve(data); }); }); await bridge.sendCommand('emitEvent', { eventName: 'testEvent', eventData: { key: 'value' }, }); const eventData = await eventPromise; expect(eventData).toEqual({ key: 'value' }); bridge.kill(); }); tap.test('should handle delayed responses', async () => { const bridge = new RustBridge({ binaryName: 'node', binaryPath: 'node', cliArgs: [mockBinaryPath], readyTimeoutMs: 5000, requestTimeoutMs: 5000, }); await bridge.spawn(); const result = await bridge.sendCommand('slow', {}); expect(result).toEqual({ delayed: true }); bridge.kill(); }); tap.test('should handle multiple concurrent commands', async () => { const bridge = new RustBridge({ binaryName: 'node', binaryPath: 'node', cliArgs: [mockBinaryPath], readyTimeoutMs: 5000, }); await bridge.spawn(); const results = await Promise.all([ bridge.sendCommand('echo', { id: 1 }), bridge.sendCommand('echo', { id: 2 }), bridge.sendCommand('echo', { id: 3 }), ]); expect(results[0]).toEqual({ id: 1 }); expect(results[1]).toEqual({ id: 2 }); expect(results[2]).toEqual({ id: 3 }); bridge.kill(); }); tap.test('should throw when sending command while not running', async () => { const bridge = new RustBridge({ binaryName: 'node', binaryPath: 'node', cliArgs: [mockBinaryPath], }); let threw = false; try { await bridge.sendCommand('echo', {}); } catch (err: any) { threw = true; expect(err.message).toInclude('not running'); } expect(threw).toBeTrue(); }); tap.test('should return false when binary not found', async () => { const bridge = new RustBridge({ binaryName: 'nonexistent-binary-xyz', searchSystemPath: false, }); const result = await bridge.spawn(); expect(result).toBeFalse(); expect(bridge.running).toBeFalse(); }); tap.test('should emit exit event when process exits', async () => { const bridge = new RustBridge({ binaryName: 'node', binaryPath: 'node', cliArgs: [mockBinaryPath], readyTimeoutMs: 5000, }); await bridge.spawn(); const exitPromise = new Promise((resolve) => { bridge.once('exit', (code) => { resolve(code); }); }); // Tell mock binary to exit await bridge.sendCommand('exit', {}); const exitCode = await exitPromise; expect(exitCode).toEqual(0); expect(bridge.running).toBeFalse(); }); export default tap.start();