162 lines
4.7 KiB
JavaScript
162 lines
4.7 KiB
JavaScript
import test from 'brittle'
|
|
import { readFile } from 'node:fs/promises'
|
|
import { dirname, join } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
import { attachBareOsTuiSdk } from '../../bare-os-booter/lib/services/bare-os-tui-sdk.js'
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
|
|
async function load() {
|
|
const parts = await Promise.all([
|
|
readFile(join(__dirname, '../lib/irc/irc-parse.js'), 'utf8'),
|
|
readFile(join(__dirname, '../lib/irc/irc-isupport.js'), 'utf8'),
|
|
readFile(join(__dirname, '../lib/irc/irc-sasl.js'), 'utf8'),
|
|
readFile(join(__dirname, '../lib/irc/irc-state.js'), 'utf8'),
|
|
readFile(join(__dirname, '../lib/irc/irc-config.js'), 'utf8'),
|
|
readFile(join(__dirname, '../lib/irc/irc-client.js'), 'utf8'),
|
|
readFile(join(__dirname, '../lib/irc/irc-dial.js'), 'utf8'),
|
|
readFile(join(__dirname, '../lib/irc/irc-commands.js'), 'utf8'),
|
|
readFile(join(__dirname, '../lib/irc/irc-tui.js'), 'utf8')
|
|
])
|
|
const hook = {}
|
|
new Function(
|
|
'exports',
|
|
parts.join('\n') +
|
|
'\nexports.bareIrcCreateClient = bareIrcCreateClient;\nexports.bareIrcCreateTuiApp = bareIrcCreateTuiApp;\n'
|
|
)(hook)
|
|
return hook
|
|
}
|
|
|
|
function makeStream(isTTY) {
|
|
return {
|
|
isTTY: !!isTTY,
|
|
columns: 80,
|
|
rows: 24,
|
|
write() {},
|
|
setRawMode() {},
|
|
resume() {},
|
|
pause() {},
|
|
on() {},
|
|
removeListener() {}
|
|
}
|
|
}
|
|
|
|
function makeCtx() {
|
|
const ctx = {
|
|
env: {},
|
|
console: { error() {}, log() {} },
|
|
replStdin: makeStream(true),
|
|
replStdout: makeStream(true),
|
|
suspendReplForSubprocess() {},
|
|
resumeReplAfterSubprocess() {}
|
|
}
|
|
attachBareOsTuiSdk(ctx)
|
|
return ctx
|
|
}
|
|
|
|
test('irc TUI paints a fixed-height frame', async (t) => {
|
|
const h = await load()
|
|
const ctx = makeCtx()
|
|
const client = h.bareIrcCreateClient({ nick: 'alice', network: 'libera' })
|
|
client.state.connection = 'registered'
|
|
client.state.registered = true
|
|
client.state.nick = 'alice'
|
|
client.handleMessage({
|
|
tags: {},
|
|
source: 'bob!b@h',
|
|
nick: 'bob',
|
|
user: 'b',
|
|
host: 'h',
|
|
command: 'PRIVMSG',
|
|
params: ['#bareos', 'hello from test']
|
|
})
|
|
const chan = Object.values(client.state.buffers).find(
|
|
(b) => b.kind === 'channel'
|
|
)
|
|
t.ok(chan)
|
|
client.state.currentId = chan.id
|
|
const app = h.bareIrcCreateTuiApp(ctx, client)
|
|
app.width = 80
|
|
app.height = 24
|
|
app._sync()
|
|
const view = ctx.tui.style.stripAnsi(app.view())
|
|
t.is(view.split('\n').length, 24)
|
|
t.ok(
|
|
view.includes('libera') ||
|
|
view.includes('#bareos') ||
|
|
view.includes('alice')
|
|
)
|
|
t.ok(view.includes('hello from test'))
|
|
})
|
|
|
|
test('irc TUI keeps nicks in a right-hand column', async (t) => {
|
|
const h = await load()
|
|
const ctx = makeCtx()
|
|
const client = h.bareIrcCreateClient({ nick: 'alice', network: 'libera' })
|
|
client.state.registered = true
|
|
client.handleMessage({
|
|
command: 'JOIN',
|
|
nick: 'alice',
|
|
params: ['#ubuntu']
|
|
})
|
|
client.handleMessage({
|
|
command: '353',
|
|
params: ['alice', '=', '#ubuntu', '@op +voice nickonly']
|
|
})
|
|
client.handleMessage({
|
|
command: 'PRIVMSG',
|
|
nick: 'op',
|
|
source: 'op!a@b',
|
|
params: ['#ubuntu', 'hello room']
|
|
})
|
|
const app = h.bareIrcCreateTuiApp(ctx, client)
|
|
app.width = 120
|
|
app.height = 24
|
|
app.roomsOpen = false
|
|
app._sync()
|
|
const view = ctx.tui.style.stripAnsi(app.view())
|
|
const lines = view.split('\n')
|
|
t.ok(view.includes('hello room'))
|
|
t.ok(view.includes('@op') || view.includes('op'))
|
|
const chatLine = lines.find((l) => l.includes('hello room'))
|
|
t.ok(chatLine)
|
|
const bar = chatLine.lastIndexOf('\u2502')
|
|
t.ok(bar > chatLine.indexOf('hello room'))
|
|
const nickLine = lines.find((l) => l.includes('\u2502') && /@op/.test(l))
|
|
t.ok(nickLine)
|
|
t.ok(nickLine.lastIndexOf('\u2502') < nickLine.indexOf('@op'))
|
|
})
|
|
|
|
test('irc TUI rooms browser lists featured channels', async (t) => {
|
|
const h = await load()
|
|
const ctx = makeCtx()
|
|
const client = h.bareIrcCreateClient({ nick: 'alice' })
|
|
const app = h.bareIrcCreateTuiApp(ctx, client)
|
|
app.width = 80
|
|
app.height = 24
|
|
app._openRooms('')
|
|
app._sync()
|
|
const view = ctx.tui.style.stripAnsi(app.view())
|
|
t.ok(app.roomsOpen)
|
|
t.ok(view.includes('#libera'))
|
|
})
|
|
|
|
test('irc TUI help overlay', async (t) => {
|
|
const h = await load()
|
|
const ctx = makeCtx()
|
|
const client = h.bareIrcCreateClient({ nick: 'alice' })
|
|
const app = h.bareIrcCreateTuiApp(ctx, client)
|
|
app.update(ctx.tui.decode('?')[0])
|
|
t.ok(app.help)
|
|
const ov = app.overlay({ width: 80, height: 24 })
|
|
t.ok(ov && ctx.tui.style.stripAnsi(ov.text).includes('Libera'))
|
|
})
|
|
|
|
test('kernel irc bin includes TEA factory after build', async (t) => {
|
|
const bin = await readFile(join(__dirname, '../../../kernel/bin/irc'), 'utf8')
|
|
t.ok(bin.includes('bareIrcCreateTuiApp'))
|
|
t.ok(bin.includes('ctx.tui.run'))
|
|
t.ok(bin.includes('irc.libera.chat'))
|
|
})
|