import test from 'node:test'; import assert from 'node:assert/strict'; import { sameIdentity, ownedProcesses, rendererMatches, localUrls, moduleMatches, inspectHealth, verifyAttestation, runDev } from './dev.mjs'; const root = 'C:\\Users\\A Name\\YCode'; const p = (pid, parentPid, name, commandLine, created = '2026-10-21T00:00:01.000Z') => ({ pid, parentPid, name, commandLine, created }); const owner = p(10, 1, 'node.exe', `node "${root}\\scripts\\ops\\dev-host.mjs"`); const vite = p(11, 10, 'node.exe', `node "${root}\\node_modules\\electron-vite\\bin\\electron-vite.js" dev`); const main = p(12, 11, 'electron.exe', 'electron.exe .'); const renderer = p(13, 12, 'electron.exe', `electron.exe --type=renderer --app-path="${root}" --other`); const snapshot = () => ({ processes: [owner, vite, main, renderer], windows: [{ pid: 12, title: 'YCode', responding: true }], listeners: [{ pid: 11, port: 5197 }] }); const state = { owner }; const source = 'export function ChatPane() { return "测试" }\n'; const fakeFetch = async url => new Response(url.search === '?raw' ? `export default ${JSON.stringify(source)};\n//# sourceURL=foo` : 'export function ChatPane() {}', { headers: { 'Content-Type': 'text/javascript' } }); test('identity rejects PID reuse, command changes, opaque timestamps', () => { assert.equal(sameIdentity(owner, { ...owner }), true); assert.equal(sameIdentity(owner, { ...owner, created: '2026-10-22T00:00:01.000Z' }), false); assert.equal(sameIdentity(owner, { ...owner, commandLine: 'node other.js' }), false); assert.equal(sameIdentity({ ...owner, created: '' }, { ...owner, created: '' }), false); }); test('ownership excludes unrelated siblings and pre-parent timestamp PID artifacts', () => { const snap = snapshot(); snap.processes.push(p(88, 1, 'node.exe', 'other repo'), p(89, 10, 'node.exe', 'old', '2026-10-20T00:00:00Z'), p(90, 10, 'system', '', '')); assert.deepEqual(ownedProcesses(snap, owner).map(p => p.pid), [10, 11, 12, 13]); assert.deepEqual(ownedProcesses(snap, { ...owner, created: '2025-01-01T00:00:00Z' }), []); }); test('renderer app path is an exact Windows path, not a substring', () => { assert.equal(rendererMatches(renderer.commandLine, root.toUpperCase()), true); assert.equal(rendererMatches(renderer.commandLine.replace('YCode"', 'YCode-other"'), root), false); assert.equal(rendererMatches(`electron.exe --type=renderer --app-path=C:/repo`, 'C:\\repo'), true); assert.equal(rendererMatches(`electron.exe --app-path="${root}"`, root), false); }); test('actual Local URL parses ANSI and variable ports without accepting remote hosts', () => { assert.deepEqual(localUrls('\x1b[32mLocal: http://localhost:5197/\x1b[0m\nLocal: http://localhost:5198/\nLocal: http://evil:5173/'), ['http://localhost:5198/', 'http://localhost:5197/']); }); test('HTTP requires exact source and real transformed JS, not generic 200 HTML', async () => { assert.equal(await moduleMatches('http://localhost:5197/', source, fakeFetch), true); assert.equal(await moduleMatches('http://localhost:5197/', source + '// changed', fakeFetch), false); assert.equal(await moduleMatches('http://localhost:5197/', source, async () => new Response('')), false); assert.equal(await moduleMatches('http://localhost:5197/', source, async url => url.search ? fakeFetch(url) : new Response('')), false); }); test('health requires correct port ownership, target renderer, responsive owned main', async () => { const check = snap => inspectHealth(snap, state, root, source, 'Local: http://localhost:5197/', fakeFetch); assert.equal((await check(snapshot())).healthy, true); assert.equal((await check(snapshot())).ownerAlive, true); for (const change of [s => { s.windows[0].responding = false; }, s => { s.windows[0].pid = 99; }, s => { s.listeners[0].pid = 99; }, s => { s.listeners[0].port = 5173; }, s => { s.processes = s.processes.filter(p => p.pid !== 13); }, s => { s.processes[3] = { ...renderer, commandLine: renderer.commandLine.replace('YCode', 'Other') }; }]) { const snap = snapshot(); snap.windows = snap.windows.map(x => ({ ...x })); snap.listeners = snap.listeners.map(x => ({ ...x })); change(snap); assert.equal((await check(snap)).healthy, false); } }); test('non-Windows native dev is explicitly unsupported, never GUI PASS', { skip: process.platform === 'win32' }, async () => { for (const action of ['dev', 'restart', 'status', 'stop']) { const response = await runDev(action, { repoRoot: '/nonexistent/no-side-effects' }); assert.equal(response.status, 'UNSUPPORTED'); assert.equal(response.code, 'WINDOWS_REQUIRED'); } }); test('renderer attestation requires fresh UUID-bound visible UI and exact process IDs', () => { const now = Date.now(); const tracked = { runId: 'nonce', startedAt: new Date(now - 3000).toISOString() }; const health = { healthy: true, windowPid: 12, rendererPid: 13 }; const proof = { runId: 'nonce', ready: true, checkedAt: now - 500, pid: 12, rendererPid: 13 }; assert.equal(verifyAttestation(proof, tracked, health, root, now), true); for (const change of [{ ready: false }, { runId: 'old-run' }, { pid: 99 }, { rendererPid: 99 }, { checkedAt: now - 6000 }, { checkedAt: now + 5000 }, { checkedAt: NaN }]) { assert.equal(verifyAttestation({ ...proof, ...change }, tracked, health, root, now), false); } assert.equal(verifyAttestation(null, tracked, health, root, now), false); assert.equal(verifyAttestation(proof, tracked, { ...health, healthy: false }, root, now), false); });