import fs from "fs"; import tty from "tty"; import { dlopen } from "bun:ffi"; const suffix = process.platform === "darwin" ? "dylib" : "so.6"; const libc = `libc.${suffix}`; var lazyOpenpty; export function openpty() { if (!lazyOpenpty) { lazyOpenpty = dlopen(libc, { openpty: { args: ["ptr", "ptr", "ptr", "ptr", "ptr"], returns: "int", }, }).symbols.openpty; } const parent_fd = new Int32Array(1).fill(0); const child_fd = new Int32Array(1).fill(0); const name_buf = new Int8Array(1000).fill(0); const term_buf = new Uint8Array(1000).fill(0); const win_buf = new Uint8Array(1000).fill(0); lazyOpenpty(parent_fd, child_fd, name_buf, term_buf, win_buf); return { parent_fd: parent_fd[0], child_fd: child_fd[0], }; } var lazyClose; export function close(fd) { if (!lazyClose) { lazyClose = dlopen(libc, { close: { args: ["int"], returns: "int", }, }).symbols.close; } lazyClose(fd); } describe("TTY", () => { it("ReadStream stdin", () => { const { parent_fd, child_fd } = openpty(); const rs = new tty.ReadStream(parent_fd); const rs1 = tty.ReadStream(child_fd); expect(rs1 instanceof tty.ReadStream).toBe(true); expect(rs instanceof tty.ReadStream).toBe(true); expect(tty.isatty(rs.fd)).toBe(true); expect(tty.isatty(rs1.fd)).toBe(true); expect(rs.isRaw).toBe(false); expect(rs.isTTY).toBe(true); expect(rs.setRawMode).toBeInstanceOf(Function); expect(rs.setRawMode(true)).toBe(rs); expect(rs.isRaw).toBe(true); expect(rs.setRawMode(false)).toBe(rs); expect(rs.isRaw).toBe(false); close(parent_fd); close(child_fd); }); it("WriteStream stdout", () => { const { child_fd, parent_fd } = openpty(); const ws = new tty.WriteStream(child_fd); const ws1 = tty.WriteStream(parent_fd); expect(ws1 instanceof tty.WriteStream).toBe(true); expect(ws instanceof tty.WriteStream).toBe(true); expect(tty.isatty(ws.fd)).toBe(true); expect(ws.isTTY).toBe(true); // pseudo terminal, not the best test because cols and rows can be 0 expect(ws.columns).toBeGreaterThanOrEqual(0); expect(ws.rows).toBeGreaterThanOrEqual(0); expect(ws.getColorDepth()).toBeGreaterThanOrEqual(0); expect(ws.hasColors(2)).toBe(true); close(parent_fd); close(child_fd); }); it("process.stdio tty", () => { // this isnt run in a tty, so stdin will not appear to be a tty expect(process.stdin instanceof fs.ReadStream).toBe(true); expect(process.stdout instanceof tty.WriteStream).toBe(true); expect(process.stderr instanceof tty.WriteStream).toBe(true); expect(process.stdin.isTTY).toBeUndefined(); if (tty.isatty(1)) { expect(process.stdout.isTTY).toBeDefined(); } else { expect(process.stdout.isTTY).toBeUndefined(); } if (tty.isatty(2)) { expect(process.stderr.isTTY).toBeDefined(); } else { expect(process.stderr.isTTY).toBeUndefined(); } }); it("read and write stream prototypes", () => { expect(tty.ReadStream.prototype.setRawMode).toBeInstanceOf(Function); expect(tty.WriteStream.prototype.clearLine).toBeInstanceOf(Function); expect(tty.WriteStream.prototype.clearScreenDown).toBeInstanceOf(Function); expect(tty.WriteStream.prototype.cursorTo).toBeInstanceOf(Function); expect(tty.WriteStream.prototype.getColorDepth).toBeInstanceOf(Function); expect(tty.WriteStream.prototype.getWindowSize).toBeInstanceOf(Function); expect(tty.WriteStream.prototype.hasColors).toBeInstanceOf(Function); expect(tty.WriteStream.prototype.hasColors).toBeInstanceOf(Function); expect(tty.WriteStream.prototype.moveCursor).toBeInstanceOf(Function); }); });