110 lines
3.0 KiB
TypeScript
110 lines
3.0 KiB
TypeScript
import { expect, test } from "bun:test";
|
|||
|
|
import { openSync } from "fs";
|
||
|
|
import { bunEnv, bunExe, normalizeBunSnapshot } from "harness";
|
||
|
|
import tty from "tty";
|
||
|
|
|
||
|
|
test("tty.ReadStream should have ref/unref methods when opened on /dev/tty", () => {
|
||
|
|
// Skip this test if /dev/tty is not available (e.g., in CI without TTY)
|
||
|
|
let ttyFd: number;
|
||
|
|
try {
|
||
|
|
ttyFd = openSync("/dev/tty", "r");
|
||
|
|
} catch (err: any) {
|
||
|
|
if (err.code === "ENXIO" || err.code === "ENOENT") {
|
||
|
|
// No TTY available, skip the test
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
throw err;
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
// Create a tty.ReadStream with the /dev/tty file descriptor
|
||
|
|
const stream = new tty.ReadStream(ttyFd);
|
||
|
|
|
||
|
|
// Verify the stream is recognized as a TTY
|
||
|
|
expect(stream.isTTY).toBe(true);
|
||
|
|
|
||
|
|
// Verify ref/unref methods exist
|
||
|
|
expect(typeof stream.ref).toBe("function");
|
||
|
|
expect(typeof stream.unref).toBe("function");
|
||
|
|
|
||
|
|
// Verify ref/unref return the stream for chaining
|
||
|
|
expect(stream.ref()).toBe(stream);
|
||
|
|
expect(stream.unref()).toBe(stream);
|
||
|
|
|
||
|
|
// Clean up - destroy will close the fd
|
||
|
|
stream.destroy();
|
||
|
|
} finally {
|
||
|
|
// Don't double-close the fd - stream.destroy() already closed it
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
test("tty.ReadStream ref/unref should behave like Node.js", async () => {
|
||
|
|
// Skip on Windows - no /dev/tty
|
||
|
|
if (process.platform === "win32") {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Create a test script that uses tty.ReadStream with ref/unref
|
||
|
|
const script = `
|
||
|
|
const fs = require('fs');
|
||
|
|
const tty = require('tty');
|
||
|
|
|
||
|
|
let ttyFd;
|
||
|
|
try {
|
||
|
|
ttyFd = fs.openSync('/dev/tty', 'r');
|
||
|
|
} catch (err) {
|
||
|
|
// No TTY available
|
||
|
|
console.log('NO_TTY');
|
||
|
|
process.exit(0);
|
||
|
|
}
|
||
|
|
|
||
|
|
const stream = new tty.ReadStream(ttyFd);
|
||
|
|
|
||
|
|
// Test that ref/unref methods exist and work
|
||
|
|
if (typeof stream.ref !== 'function' || typeof stream.unref !== 'function') {
|
||
|
|
console.error('ref/unref methods missing');
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Unref should allow process to exit
|
||
|
|
stream.unref();
|
||
|
|
|
||
|
|
// Set a timer that would keep process alive if ref() was called
|
||
|
|
const timer = setTimeout(() => {
|
||
|
|
console.log('TIMEOUT');
|
||
|
|
}, 100);
|
||
|
|
timer.unref();
|
||
|
|
|
||
|
|
// Process should exit immediately since both stream and timer are unref'd
|
||
|
|
console.log('SUCCESS');
|
||
|
|
|
||
|
|
// Clean up properly
|
||
|
|
stream.destroy();
|
||
|
|
`;
|
||
|
|
|
||
|
|
// Write the test script to a temporary file
|
||
|
|
const path = require("path");
|
||
|
|
const os = require("os");
|
||
|
|
const tempFile = path.join(os.tmpdir(), "test-tty-ref-unref-" + Date.now() + ".js");
|
||
|
|
await Bun.write(tempFile, script);
|
||
|
|
|
||
|
|
// Run the script with bun
|
||
|
|
const proc = Bun.spawn({
|
||
|
|
cmd: [bunExe(), tempFile],
|
||
|
|
env: bunEnv,
|
||
|
|
stdout: "pipe",
|
||
|
|
stderr: "pipe",
|
||
|
|
});
|
||
|
|
|
||
|
|
const [exitCode, stdout, stderr] = await Promise.all([proc.exited, proc.stdout.text(), proc.stderr.text()]);
|
||
|
|
|
||
|
|
if (stdout.includes("NO_TTY")) {
|
||
|
|
// No TTY available in test environment, skip
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
expect(stderr).toBe("");
|
||
|
|
expect(exitCode).toBe(0);
|
||
|
|
expect(normalizeBunSnapshot(stdout)).toMatchInlineSnapshot(`"SUCCESS"`);
|
||
|
|
});
|