mirror of
https://github.com/stablyai/orca.git
synced 2026-11-13 17:37:40 +00:00
120 lines
3.5 KiB
TypeScript
120 lines
3.5 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { createTerminalDocumentScope } from '../document-scope'
|
|
import * as writeQueue from './write-queue'
|
|
import { terminalDocumentDouble } from '../document-terminal-double.test-support'
|
|
|
|
type QueueSnapshot = { slots: unknown[]; head: number }
|
|
|
|
type WriteQueueRuntime = {
|
|
enqueue: (data: string) => void
|
|
enqueueBoundary: (callback: () => void) => void
|
|
next: () => unknown
|
|
pump: () => void
|
|
reset: () => void
|
|
afterDrained: (callback: () => void) => void
|
|
setGeneration: (generation: number) => void
|
|
snapshot: () => QueueSnapshot
|
|
}
|
|
|
|
type WriteQueueHarness = WriteQueueRuntime & {
|
|
writes: string[]
|
|
pendingWrites: Array<() => void>
|
|
flushWrite: () => void
|
|
queuedCodeUnits: () => number
|
|
}
|
|
|
|
function createWriteQueue(): WriteQueueHarness {
|
|
const writes: string[] = []
|
|
const pendingWrites: Array<() => void> = []
|
|
const scope = createTerminalDocumentScope()
|
|
scope.ready = true
|
|
scope.term = {
|
|
...terminalDocumentDouble().terminal,
|
|
write: (data: string, done?: () => void) => {
|
|
writes.push(data)
|
|
if (done) {
|
|
pendingWrites.push(done)
|
|
}
|
|
}
|
|
}
|
|
const module = writeQueue
|
|
const runtime: WriteQueueRuntime = {
|
|
enqueue: (data) => module.enqueueWrite(scope, data),
|
|
enqueueBoundary: (callback) => module.enqueueWriteBoundary(scope, callback),
|
|
next: () => module.nextQueuedWrite(scope),
|
|
pump: () => module.pumpWrites(scope, scope.terminalGeneration),
|
|
reset: () => module.resetWriteQueue(scope),
|
|
afterDrained: (callback) => module.afterWritesDrained(scope, callback),
|
|
setGeneration: (next) => {
|
|
scope.terminalGeneration = next
|
|
},
|
|
snapshot: () => ({ slots: scope.writeQueue.slice(), head: scope.writeQueueHead })
|
|
}
|
|
return {
|
|
...runtime,
|
|
writes,
|
|
pendingWrites,
|
|
flushWrite: () => {
|
|
const done = pendingWrites.shift()
|
|
expect(done).toBeTypeOf('function')
|
|
done?.()
|
|
},
|
|
queuedCodeUnits: () =>
|
|
runtime
|
|
.snapshot()
|
|
.slots.reduce<number>(
|
|
(total, slot) => total + (typeof slot === 'string' ? slot.length : 0),
|
|
0
|
|
)
|
|
}
|
|
}
|
|
|
|
describe('terminal WebView write queue', () => {
|
|
// Count queue-reachable string units, not heap bytes; xterm may still retain submitted chunks.
|
|
|
|
// Legacy compaction retention grows with backlog because it waits for consumed slots to exceed half the queue.
|
|
|
|
it('runs boundary callbacks between writes', () => {
|
|
const queue = createWriteQueue()
|
|
const order: string[] = []
|
|
queue.enqueue('replay')
|
|
queue.enqueueBoundary(() => order.push('boundary'))
|
|
queue.enqueue('live')
|
|
queue.afterDrained(() => order.push('drained'))
|
|
|
|
queue.pump()
|
|
expect(order).toEqual([])
|
|
queue.flushWrite()
|
|
expect(order).toEqual(['boundary'])
|
|
expect(queue.writes).toEqual(['replay', 'live'])
|
|
queue.flushWrite()
|
|
|
|
expect(order).toEqual(['boundary', 'drained'])
|
|
})
|
|
|
|
it('discards pending writes after a reset mid-flight', () => {
|
|
const queue = createWriteQueue()
|
|
queue.enqueue('first')
|
|
queue.pump()
|
|
queue.enqueue('dropped')
|
|
expect(queue.writes).toEqual(['first'])
|
|
|
|
queue.reset()
|
|
queue.enqueue('after-reset')
|
|
queue.flushWrite()
|
|
|
|
expect(queue.writes).toEqual(['first', 'after-reset'])
|
|
})
|
|
|
|
it('stops the pump for a stale generation', () => {
|
|
const queue = createWriteQueue()
|
|
queue.enqueue('first')
|
|
queue.pump()
|
|
queue.enqueue('second')
|
|
queue.setGeneration(1)
|
|
queue.flushWrite()
|
|
|
|
expect(queue.writes).toEqual(['first'])
|
|
})
|
|
})
|