// Negative + positive coverage for the two highest-stakes dry-run detectors (5d112cb). // // 99-dryrun.sh force-fresh re-extracts all 11 targets every run (10-extract.sh wipes $dest first), so a // "plant a dropped file in $WORK/" negative test against the full dry-run would be silently undone by // the re-extract. So the two load-bearing detectors are extracted into standalone, side-effect-free scripts // — sc6-check.sh (the SC6 DROP detector, the guard against the llm-security 87-file-drop class) and // sc2-regression.sh (the SC2 regression-FAIL detector) — which 99-dryrun.sh now calls. This suite drives // those exact scripts directly, proving each detector FIRES (DROP / regression → label + non-zero exit) and // does NOT false-positive (retained content / subset failures → exit 0). When the dry-run calls them and // they exit non-zero, it sets ok=0 → exit 1, so the dry-run's "report DROP/regression + exit non-zero" // behaviour follows by construction from this coverage. import test from 'node:test'; import assert from 'node:assert/strict'; import { spawnSync } from 'node:child_process'; import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; const here = path.dirname(fileURLToPath(import.meta.url)); const SC6 = path.join(here, 'sc6-check.sh'); const SC2 = path.join(here, 'sc2-regression.sh'); function run(script, args) { return spawnSync('bash', [script, ...args], { encoding: 'utf8' }); } // --- sc6-check.sh — the SC6 DROP detector --------------------------------------------------------------- test('SC6 DROP fires: a real shortfall (llm-security 87-file class) → DROP label + non-zero exit', () => { const r = run(SC6, ['334', '421', 'false']); // the actual dual-rename defect: 334 of 421 files retained assert.notEqual(r.status, 0, 'a non-blob-strip shortfall must exit non-zero (the dry-run sets ok=0)'); assert.match(r.stdout, /334\/421 DROP/, `DROP label expected: ${r.stdout}`); }); test('SC6 blob-strip shortfall is allowed: intentional >1MB strip → (blob-strip) label + exit 0', () => { const r = run(SC6, ['100', '200', 'True']); // ms-ai-architect screenshot blob-bomb: legitimate shortfall assert.equal(r.status, 0, `blob-strip shortfall must exit 0: ${r.stderr}`); assert.match(r.stdout, /100\/200 \(blob-strip\)/, `blob-strip label expected: ${r.stdout}`); assert.ok(!/DROP/.test(r.stdout), 'a blob-strip shortfall must NOT be labelled DROP'); }); test('SC6 retained content: ext == live → no DROP, exit 0', () => { const r = run(SC6, ['421', '421', 'false']); assert.equal(r.status, 0, `full retention must exit 0: ${r.stderr}`); assert.equal(r.stdout.trim(), '421/421'); }); test('SC6 more files than live (e.g. path-rename overlap) → no DROP, exit 0', () => { const r = run(SC6, ['500', '421', 'false']); assert.equal(r.status, 0); assert.ok(!/DROP/.test(r.stdout), `${r.stdout}`); }); // --- sc2-regression.sh — the SC2 regression-FAIL detector ----------------------------------------------- function fixtureFiles(standalone, baseline) { const dir = mkdtempSync(path.join(os.tmpdir(), 'sc2-')); const sf = path.join(dir, 'sf'); const bf = path.join(dir, 'bf'); writeFileSync(sf, standalone.length ? standalone.join('\n') + '\n' : ''); writeFileSync(bf, baseline.length ? baseline.join('\n') + '\n' : ''); return { dir, sf, bf }; } test('SC2 regression fires: a standalone-only failure (not in baseline) → printed + non-zero exit', () => { // The extraction introduced a NEW failure absent from the in-repo baseline — a real regression. const { dir, sf, bf } = fixtureFiles(['extract regressed test', 'shared pre-existing fail'], ['shared pre-existing fail']); try { const r = run(SC2, [sf, bf]); assert.equal(r.status, 1, `a regression must exit 1 (the dry-run sets ok=0): ${r.stdout}${r.stderr}`); assert.match(r.stdout, /extract regressed test/, `the regressing test name must be reported: ${r.stdout}`); } finally { rmSync(dir, { recursive: true, force: true }); } }); test('SC2 subset PASS: standalone failures ⊆ baseline (pre-existing red) → exit 0, nothing printed', () => { const { dir, sf, bf } = fixtureFiles(['shared pre-existing fail'], ['shared pre-existing fail', 'other baseline-only fail']); try { const r = run(SC2, [sf, bf]); assert.equal(r.status, 0, `a subset must exit 0 (no migration regression): ${r.stdout}${r.stderr}`); assert.equal(r.stdout.trim(), '', 'no regression should be printed for a subset'); } finally { rmSync(dir, { recursive: true, force: true }); } }); test('SC2 missing capture file is an ERROR (exit 2), never a silent zero-regression PASS (4044c49)', () => { const r = run(SC2, ['/nonexistent/sf', '/nonexistent/bf']); assert.equal(r.status, 2, `a missing capture file must be a hard error, not a false PASS: ${r.stdout}`); });