mirror of
https://github.com/ruvnet/RuView.git
synced 2026-10-18 21:00:22 -05:00
Integrate reviewed source PRs #2201-#2223, #2225-#2231, #2235-#2240, #2242 and #2243 (firmware README hunks remain in #2247). Regenerate one package manifest after integration, validate native Windows test execution, bound MTK listener startup, support official C6 release bundles, and retain stronger release metadata gates.
63 lines
3.3 KiB
JavaScript
63 lines
3.3 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import dgram from 'node:dgram';
|
|
import { spawn } from 'node:child_process';
|
|
import { sparkline } from '../src/cli-ui.js';
|
|
const pause = ms => new Promise(r => setTimeout(r, ms));
|
|
|
|
// Exercise the actual watch command with terminal rendering enabled. Only the
|
|
// stdout terminal capability is supplied; capture and parsing remain real.
|
|
test('CLI watch preserves an absent capture window in a returning node trend', { timeout: 12000 }, async t => {
|
|
const udp = dgram.createSocket('udp4');
|
|
await new Promise(r => udp.bind(0, '127.0.0.1', r));
|
|
const port = udp.address().port;
|
|
await new Promise(r => udp.close(r));
|
|
const sender = dgram.createSocket('udp4');
|
|
t.after(() => sender.close());
|
|
const cli = new URL('../src/cli.js', import.meta.url).href;
|
|
const script = `Object.defineProperty(process.stdout,'isTTY',{value:true}); const {run}=await import(${JSON.stringify(cli)}); console.log('READY'); process.exitCode=await run(['esp32','--watch','--bind','127.0.0.1','--udp-port',${JSON.stringify(String(port))},'--seconds','1','--max-packets','1']);`;
|
|
const child = spawn(process.execPath, ['--input-type=module', '-e', script], { env: { ...process.env, NO_COLOR: '1', FORCE_COLOR: '0' } });
|
|
t.after(async () => {
|
|
if (child.exitCode !== null || child.signalCode !== null) return;
|
|
const closed = new Promise(r => child.once('close', r));
|
|
child.kill('SIGKILL');
|
|
await closed;
|
|
});
|
|
let output = ''; let errors = '';
|
|
child.stdout.on('data', b => { output += b; });
|
|
child.stderr.on('data', b => { errors += b; });
|
|
async function waitFor(predicate) {
|
|
for (let n = 0; n < 500; n++) {
|
|
if (predicate()) return;
|
|
if (child.exitCode !== null) assert.fail(`child exited ${child.exitCode}: ${errors}\n${output}`);
|
|
await pause(10);
|
|
}
|
|
assert.fail(`CLI condition timeout: ${errors}\n${output}`);
|
|
}
|
|
const packet = Buffer.alloc(28);
|
|
packet.writeUInt32LE(0xC5110001, 0); packet[4] = 9; packet[5] = 1; packet.writeUInt16LE(4, 6);
|
|
packet.writeUInt32LE(2437, 8); packet.writeInt8(-52, 16); packet.writeInt8(-95, 17);
|
|
for (let i = 20; i < 28; i += 2) { packet[i] = 3; packet[i + 1] = 4; }
|
|
const windows = () => output.split('RUVIEW / NODE STREAM').length - 1;
|
|
await waitFor(() => output.includes('READY')); await pause(200);
|
|
sender.send(packet, port, '127.0.0.1');
|
|
await waitFor(() => windows() === 1);
|
|
await waitFor(() => windows() === 2); // no packets in the second window
|
|
await pause(50); packet.writeUInt32LE(1, 12); sender.send(packet, port, '127.0.0.1');
|
|
await waitFor(() => windows() === 3);
|
|
const last = output.split('RUVIEW / NODE STREAM').at(-1);
|
|
child.kill('SIGINT');
|
|
const row = last.split('\n').find(l => l.startsWith('esp32'));
|
|
assert.ok(row, last);
|
|
// Packet-limited windows now use their measured elapsed times, so their
|
|
// rates can differ. The missing window must still occupy the middle slot.
|
|
assert.match(row, /[▁▂▃▄▅▆▇█]·[▁▂▃▄▅▆▇█]\s*$/, `one position per capture window: ${row}`);
|
|
});
|
|
|
|
test('sparkline keeps missing positions and finite scale controls', () => {
|
|
assert.equal(sparkline([5, null, 5]), '▄·▄');
|
|
assert.equal(sparkline([null, NaN]), '··');
|
|
assert.equal(sparkline([0, null, 8]), '▁·█');
|
|
assert.equal(sparkline([]), '');
|
|
});
|