From 3d11a8ffaaa1192266aafb131747d0edd447c394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 24 Sep 2026 20:58:20 +0200 Subject: [PATCH] test(apple,vega): give two runner/Vega probes assertions that can lose MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two tests passed for every possible production bug. Both now fail for a specific one, and both were checked against the mutant they are meant to catch. - `runner-io.test.ts` "a tail whose file disappears stops on its own instead of throwing" discarded every chunk (`onOutput: () => {}`) and asserted nothing, so the sentence the test is named after was never observed. It now collects the chunks and requires the tail to still be silent after the log reappears. Mutating `drain()`'s `catch { stop(); }` to swallow and keep polling — i.e. exactly the give-up-then- resume bug the in-code comment forbids — reddens this test (`1 failed | 7 passed`) while the old body reports `8 passed`. - `inventory.test.ts` "Vega inventory ... accepts only its virtual device" compared discovery output against `parseVegaDeviceList(...)`, a production export, so the parser was its own expected value and both sides moved together. It now spells the device out. Flipping `kind: 'emulator'` to `'physical'` reddens it (`1 failed | 1 passed`) where the oracle reported `2 passed`. That literal is also the first real test of `parseVegaDeviceList`: the oracle call was its only reference outside `inventory.ts`, so `kind`, `booted`, `target`, and the display-name format were pinned nowhere. Dropped from this change after a second read: `runner-sequence.test.ts`'s unasserted `validateRunnerSequenceSteps(...)` accept-paths. A throw fails those tests, and the cap+1 rejection is pinned two tests above the cap case, so the boundary is closed. --- .../src/runner/__tests__/runner-io.test.ts | 8 +++++++- packages/platform-vega/src/inventory.test.ts | 16 ++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/platform-apple/src/runner/__tests__/runner-io.test.ts b/packages/platform-apple/src/runner/__tests__/runner-io.test.ts index 5d5529000a..e5c99e59c8 100644 --- a/packages/platform-apple/src/runner/__tests__/runner-io.test.ts +++ b/packages/platform-apple/src/runner/__tests__/runner-io.test.ts @@ -71,15 +71,21 @@ test('the tail follows a file its writer keeps appending to', async () => { test('a tail whose file disappears stops on its own instead of throwing', async () => { const logPath = logPathIn(); fs.writeFileSync(logPath, ''); - const tail = tailRunnerLogFile({ file: { logPath, startOffset: 0 }, onOutput: () => {} }); + const chunks: string[] = []; + const tail = tailRunnerLogFile({ + file: { logPath, startOffset: 0 }, + onOutput: (chunk) => chunks.push(chunk), + }); fs.rmSync(logPath); await new Promise((resolve) => setTimeout(resolve, 120)); + assert.deepEqual(chunks, []); // Writing a fresh file must not restart a tail that already gave up. fs.writeFileSync(logPath, 'AGENT_DEVICE_RUNNER_LISTENER_READY\n'); await new Promise((resolve) => setTimeout(resolve, 120)); tail.drain(); + assert.deepEqual(chunks, []); }); test('drain reads what the file gained and then stops following it', async () => { diff --git a/packages/platform-vega/src/inventory.test.ts b/packages/platform-vega/src/inventory.test.ts index e5941a3577..db77a1e997 100644 --- a/packages/platform-vega/src/inventory.test.ts +++ b/packages/platform-vega/src/inventory.test.ts @@ -5,7 +5,7 @@ import type { DeviceInventoryHostFor, PlatformRequestScope, } from '@agent-device/contracts/platform-runtime-host'; -import { createVegaInventory, parseVegaDeviceList } from './inventory.ts'; +import { createVegaInventory } from './inventory.ts'; const scope: PlatformRequestScope = { signal: new AbortController().signal, @@ -27,7 +27,19 @@ test('Vega inventory resolves the default CLI lazily and accepts only its virtua const devices = await createVegaInventory(host).discover({}, scope); - assert.deepEqual(devices, parseVegaDeviceList('VirtualDevice : tv\n')); + // Spelled out rather than compared against `parseVegaDeviceList(...)`: using the parser as the + // expected value lets both sides move together, which is exactly how a dropped `physical` row or + // a wrong `kind`/`booted` mapping would stay invisible. + assert.deepEqual(devices, [ + { + platform: 'vega', + id: 'VirtualDevice', + name: 'Vega Virtual Device (VirtualDevice)', + kind: 'emulator', + target: 'tv', + booted: true, + }, + ]); }); test('Vega inventory fails closed when only an unsupported physical target is present', async () => {