62 lines
2.1 KiB
JavaScript
62 lines
2.1 KiB
JavaScript
'use strict';
|
|
// Local verification adapter: capture real child output in files when the
|
|
// environment refuses Node's process pipes. Test assertions stay unchanged.
|
|
const cp = require('node:child_process');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const { PassThrough } = require('node:stream');
|
|
const originalSpawn = cp.spawn;
|
|
const originalSpawnSync = cp.spawnSync;
|
|
let sequence = 0;
|
|
|
|
function captureFiles() {
|
|
const prefix = path.join(__dirname, `child-${process.pid}-${++sequence}`);
|
|
return ['stdout', 'stderr'].map(name => {
|
|
const file = `${prefix}.${name}.log`;
|
|
return { file, fd: fs.openSync(file, 'w'), offset: 0 };
|
|
});
|
|
}
|
|
|
|
cp.spawnSync = function (command, args, options = {}) {
|
|
const captures = captureFiles();
|
|
let result;
|
|
try {
|
|
result = originalSpawnSync(command, args, {
|
|
...options, stdio: ['ignore', ...captures.map(capture => capture.fd)]
|
|
});
|
|
} finally {
|
|
for (const capture of captures) fs.closeSync(capture.fd);
|
|
}
|
|
result.stdout = fs.readFileSync(captures[0].file, options.encoding || null);
|
|
result.stderr = fs.readFileSync(captures[1].file, options.encoding || null);
|
|
result.output = [null, result.stdout, result.stderr];
|
|
return result;
|
|
};
|
|
|
|
cp.spawn = function (command, args, options = {}) {
|
|
const captures = captureFiles();
|
|
const child = originalSpawn(command, args, {
|
|
...options, stdio: ['ignore', ...captures.map(capture => capture.fd)]
|
|
});
|
|
for (const capture of captures) fs.closeSync(capture.fd);
|
|
const streams = captures.map(() => new PassThrough());
|
|
child.stdout = streams[0];
|
|
child.stderr = streams[1];
|
|
function drain() {
|
|
captures.forEach((capture, index) => {
|
|
const bytes = fs.readFileSync(capture.file);
|
|
if (bytes.length > capture.offset) streams[index].write(bytes.subarray(capture.offset));
|
|
capture.offset = bytes.length;
|
|
});
|
|
}
|
|
const interval = setInterval(drain, 10);
|
|
function finish() {
|
|
clearInterval(interval);
|
|
drain();
|
|
streams.forEach(stream => stream.end());
|
|
}
|
|
child.prependOnceListener('exit', finish);
|
|
child.once('error', finish);
|
|
return child;
|
|
};
|