fix(#2163): round-2 review fixes — deterministic fail-soft injection tests

- readGitStatus calls execFileSync via the child_process namespace so tests
  can inject spawn failures through the shared module object
- two deterministic tests: ERR_CHILD_PROCESS_STDOUT_MAXBUFFER-shaped and
  ETIMEDOUT-shaped throws both degrade to null (segment absent), proving
  the fail-soft paths the PR previously only asserted

Claude-Session: https://claude.ai/code/session_01Hme55Pvq6BhpgwBcyC5HAg
This commit is contained in:
Cody Anderson
2026-07-11 20:13:10 -06:00
parent 7a6564ed8a
commit 73039d3717
2 changed files with 39 additions and 2 deletions

View File

@@ -1500,6 +1500,41 @@ test('config-set statusline.show_context_tokens yes → rejected', () => {
}
});
// Deterministic IO-failure injection (repo convention, cf. the fs
// monkeypatch in ensure-runtime-build.test.cjs): readGitStatus shares the
// one cached child_process module object, so replacing execFileSync here
// injects the failure without a real hang or oversized repo.
test('maxBuffer overflow degrades to null (segment absent)', () => {
const childProcess = require('node:child_process');
const original = childProcess.execFileSync;
childProcess.execFileSync = () => {
const err = new RangeError('stdout maxBuffer length exceeded');
err.code = 'ERR_CHILD_PROCESS_STDOUT_MAXBUFFER';
throw err;
};
try {
assert.equal(readGitStatus('/tmp'), null);
} finally {
childProcess.execFileSync = original;
}
});
test('spawn timeout degrades to null (segment absent)', () => {
const childProcess = require('node:child_process');
const original = childProcess.execFileSync;
childProcess.execFileSync = () => {
const err = new Error('spawnSync git ETIMEDOUT');
err.code = 'ETIMEDOUT';
err.errno = -110;
throw err;
};
try {
assert.equal(readGitStatus('/tmp'), null);
} finally {
childProcess.execFileSync = original;
}
});
test('fresh repo with an untracked file is counted', () => {
const { dir } = makeGitRepo();
try {