diff --git a/src/framework/Testee.ts b/src/framework/Testee.ts index bb90f07..f3499b6 100644 --- a/src/framework/Testee.ts +++ b/src/framework/Testee.ts @@ -277,6 +277,7 @@ export class Testee { // TODO unified with testbed interface (testee, req, map) => timeout(`sending instruction ${req.type}`, testee.timeout, testee.bed(step.target ?? Target.supervisor)!.sendRequest(map, req)), (testee) => testee.run(`Recover: re-initialize ${testee.testbed?.name}`, testee.connector.timeout, async function () { + await testee.shutdown(); await testee.initialize(description.program, description.args ?? []).catch((o) => { return Promise.reject(o) }); diff --git a/src/messaging/Parsers.ts b/src/messaging/Parsers.ts index 0e14a4f..a416379 100644 --- a/src/messaging/Parsers.ts +++ b/src/messaging/Parsers.ts @@ -29,7 +29,7 @@ export function remoteFunctionResult(result: RemoteFunctionResult): WASM.Value { diff --git a/src/testbeds/Emulator.ts b/src/testbeds/Emulator.ts index ddc5a0d..72068b3 100644 --- a/src/testbeds/Emulator.ts +++ b/src/testbeds/Emulator.ts @@ -20,9 +20,15 @@ export class Emulator extends Platform { this.listen(); } - kill(): Promise { - this.connection.child?.kill(); - return super.kill(); + async kill(): Promise { + const child = this.connection.child; + const closed = child === undefined || child.exitCode !== null || child.signalCode !== null + ? Promise.resolve() + : new Promise((resolve) => child.once('close', resolve)); + + child?.kill(); + await super.kill(); + await closed; } async meta(): Promise { diff --git a/tests/end-to-end/spec.util.ts b/tests/end-to-end/spec.util.ts index e1dc513..e4c70a0 100644 --- a/tests/end-to-end/spec.util.ts +++ b/tests/end-to-end/spec.util.ts @@ -81,7 +81,7 @@ function consume(input: string, cursor: number, regex: RegExp = / /): number { } function shouldParseLine(input: string): boolean { - return input.includes('(assert_return') && !input.replace(/\s+/g, '').startsWith(';;'); + return input.includes('(assert_return') && input.includes('(invoke') && !input.replace(/\s+/g, '').startsWith(';;'); } export function parseAsserts(file: string): string[] { @@ -140,8 +140,8 @@ function parseInteger(hex: string, type: WASM.Integer): WasmInt { const n: number = parseInt(hex); return typeof n !== 'bigint' && isNaN(n) ? WasmInt.nan() : typeof n !== 'bigint' && n === Infinity ? WasmInt.infinity() : WasmInt.finite(BigInt(hex)); } - const mask = BigInt(parseInt('0x80' + '00'.repeat(bytes - 1), 16)); - let integer = BigInt(parseInt(hex, 16)); + const mask = BigInt('0x80' + '00'.repeat(bytes - 1)); + let integer = BigInt(hex); if (integer >= mask) { integer = integer - mask * 2n; } diff --git a/tests/unit/interface.test.ts b/tests/unit/interface.test.ts index b8f052b..458c534 100644 --- a/tests/unit/interface.test.ts +++ b/tests/unit/interface.test.ts @@ -1,5 +1,6 @@ import test from 'ava'; import {Duplex} from 'node:stream'; +import {EventEmitter} from 'node:events'; import {SubProcess} from '../../src/bridge/SubProcess'; import {Message} from '../../src/messaging/Message'; import {SourceMap} from '../../src/sourcemap/SourceMap'; @@ -12,6 +13,7 @@ import { OperationResult } from '../../src/protocol/vendor/debug'; import {WARDuino} from "../../src/debug/WARDuino"; +import {Emulator} from "../../src/testbeds/Emulator"; import {Testee} from "../../src/framework/Testee"; import {EmulatorSpecification} from "../../src/testbeds/TestbedSpecification"; @@ -68,6 +70,23 @@ test('[warduino] start emulator', t => { t.pass(); }); +test('[emulator] shutdown waits for the child process to close', async t => { + const child = Object.assign(new EventEmitter(), { + exitCode: null, + signalCode: null, + kill: () => true + }); + const emulator = new Emulator(new SubProcess(new TestChannel(), child as any)); + let complete = false; + const shutdown = emulator.kill().then(() => { complete = true; }); + + await tick(); + t.false(complete); + child.emit('close', 0, null); + await shutdown; + t.true(complete); +}); + test('[platform] rejects outstanding requests when the connection closes with an error', async t => { const channel = new TestChannel(); const platform = new TestPlatform(channel); diff --git a/tests/unit/parsing.test.ts b/tests/unit/parsing.test.ts index ee3ac55..c14febd 100644 --- a/tests/unit/parsing.test.ts +++ b/tests/unit/parsing.test.ts @@ -55,6 +55,19 @@ test("[protobuf invoke result] : decodes IEEE-754 float bits", t => { t.deepEqual(f64, {type: WASM.Float.f64, value: 2.5}); }); +test("[protobuf invoke result] : selects the first declared result", t => { + const result = remoteFunctionResultParser(RemoteFunctionResult.encode({ + success: true, + results: [ + {i32Bits: 77, index: 0}, + {f64Bits: 0x401c000000000000n, index: 1} + ], + error: Buffer.alloc(0) + }).finish()); + + t.deepEqual(result, {type: WASM.Integer.i32, value: WasmInt.finite(77n)}); +}); + test("[protobuf invoke result] : maps void, malformed, and failed responses", t => { const voidResult = remoteFunctionResultParser(RemoteFunctionResult.encode({success: true, results: [], error: Buffer.alloc(0)}).finish()); t.deepEqual(voidResult, WASM.nothing);