import { readFile } from 'node:fs/promises' import path from 'node:path' import { fileURLToPath } from 'node:url' import test from 'brittle' const __dirname = path.dirname(fileURLToPath(import.meta.url)) async function loadTelnetFns() { const body = await readFile(path.join(__dirname, '../src/telnet.js'), 'utf8') const fn = new Function( `${body} return { TELNET_IAC, TELNET_DO, TELNET_DONT, TELNET_WILL, TELNET_WONT, TELNET_SB, TELNET_SE, TELNET_OPT_ECHO, TELNET_OPT_NAWS, TELNET_OPT_TTYPE, bareTelnetNewParseState, bareTelnetParseChunk, bareTelnetMakeNego, bareTelnetHandleNeg, bareTelnetHandleSB, bareTelnetEncodeNAWS, bareTelnetEncodeTTYPEIs }` ) return fn() } test('telnet parser separates data and negotiation records', async (t) => { const tel = await loadTelnetFns() const st = tel.bareTelnetNewParseState() const data = new Uint8Array([65, tel.TELNET_IAC, tel.TELNET_WILL, tel.TELNET_OPT_ECHO, 66]) const out = tel.bareTelnetParseChunk(st, data) t.is(new TextDecoder().decode(out.data), 'AB') t.is(out.commands.length, 1) t.is(out.commands[0].kind, 'neg') t.is(out.commands[0].cmd, tel.TELNET_WILL) t.is(out.commands[0].opt, tel.TELNET_OPT_ECHO) }) test('telnet negotiation responds to DO NAWS with WILL + SB NAWS', async (t) => { const tel = await loadTelnetFns() const nego = tel.bareTelnetMakeNego({ nawsCols: 120, nawsRows: 40, ttype: 'xterm' }) const r = tel.bareTelnetHandleNeg(nego, tel.TELNET_DO, tel.TELNET_OPT_NAWS) t.ok(r.responses.length >= 2) t.is(r.responses[0][0], tel.TELNET_IAC) t.is(r.responses[0][1], tel.TELNET_WILL) t.is(r.responses[0][2], tel.TELNET_OPT_NAWS) }) test('telnet subnegotiation SEND TTYPE returns IS TTYPE', async (t) => { const tel = await loadTelnetFns() const nego = tel.bareTelnetMakeNego({ ttype: 'xterm-256color' }) const r = tel.bareTelnetHandleSB(nego, tel.TELNET_OPT_TTYPE, new Uint8Array([1])) t.ok(r.responses.length >= 1) const sb = r.responses[0] t.is(sb[0], tel.TELNET_IAC) t.is(sb[1], tel.TELNET_SB) t.is(sb[2], tel.TELNET_OPT_TTYPE) })