test(runtime): enforce ANSI preview-final pre-filter invariant (#27376)

Follow-up to #27344. isTerminalPreviewLineControl now gates on
isTerminalPreviewLineControlFinal, so the normalizeTerminalChunk
pre-filter cannot drop a final the predicate accepts. Add a test over
every CSI final 0x40-0x7e and replace String.prototype.charCodeAt spies
with behavior assertions.
This commit is contained in:
Neil
2026-10-10 21:21:27 -07:00
committed by GitHub
parent f49d0bc764
commit dae2cc9110
2 changed files with 44 additions and 29 deletions
@@ -197,7 +197,7 @@ function trimPendingAnsiControl(value: string): string {
return `${introducer}${value.slice(-suffixBudget)}`
}
/** CSI controls that affect retained preview rows. */
/** CSI finals that affect retained preview rows; the sole gate for isTerminalPreviewLineControl. */
function isTerminalPreviewLineControlFinal(code: number): boolean {
return (
code === 0x4b ||
@@ -214,12 +214,16 @@ function isTerminalPreviewLineControl(parsed: {
params: string
firstParam: number | null
}): boolean {
if (!hasCanonicalNumericCsiParams(parsed.params)) {
// Why: normalizeTerminalChunk pre-filters on this predicate, so any final accepted here must pass it first.
if (
!isTerminalPreviewLineControlFinal(parsed.final.charCodeAt(0)) ||
!hasCanonicalNumericCsiParams(parsed.params)
) {
return false
}
if (parsed.final === 'K') {
const mode = parsed.firstParam ?? 0
return mode === 0 || mode === 1 || mode === 2
}
return isTerminalPreviewLineControlFinal(parsed.final.charCodeAt(0))
return true
}
@@ -1,4 +1,4 @@
import { describe, expect, it, vi } from 'vitest'
import { describe, expect, it } from 'vitest'
import {
containsTerminalVerticalLineControl,
normalizeTerminalChunk
@@ -6,20 +6,42 @@ import {
import { appendNormalizedToTailBuffer } from './terminal-tail-buffer'
describe('terminal vertical-control scanning', () => {
it('scans retained CSI parameters once while normalizing', () => {
it('keeps a line control with long retained CSI parameters', () => {
const input = `\x1b[${'1;'.repeat(2048)}A`
const charCodeAt = vi.spyOn(String.prototype, 'charCodeAt')
let normalized: ReturnType<typeof normalizeTerminalChunk>
let inspections: number
try {
normalized = normalizeTerminalChunk(input)
inspections = charCodeAt.mock.calls.length
} finally {
charCodeAt.mockRestore()
}
expect(normalizeTerminalChunk(input)).toEqual({
text: input,
pendingAnsi: ''
})
})
expect(normalized).toEqual({ text: input, pendingAnsi: '' })
expect(inspections).toBeLessThanOrEqual(input.length + 8)
it('retains exactly the preview line-control CSI finals', () => {
const retained: string[] = []
for (let code = 0x40; code <= 0x7e; code += 1) {
const final = String.fromCharCode(code)
for (const params of ['', '2']) {
const control = `\x1b[${params}${final}`
const { text } = normalizeTerminalChunk(`a${control}b`)
if (text === `a${control}b`) {
retained.push(control)
} else {
expect(text).toBe('ab')
}
}
}
expect(retained).toEqual([
'\x1b[A',
'\x1b[2A',
'\x1b[C',
'\x1b[2C',
'\x1b[D',
'\x1b[2D',
'\x1b[G',
'\x1b[2G',
'\x1b[K',
'\x1b[2K',
'\x1b[`',
'\x1b[2`'
])
})
it('preserves printable spans and carried controls across chunk boundaries', () => {
@@ -35,19 +57,8 @@ describe('terminal vertical-control scanning', () => {
['plain', 'log output '.repeat(8192), false],
['nonvertical CSI', `\x1b[31m${'log output '.repeat(8192)}\x1b[0m`, false],
['vertical CSI', `${'漢字😀 output '.repeat(8192)}\x1b[2A`, true]
] as const)('bounds code-unit inspections on %s output', (_name, input, expected) => {
const charCodeAt = vi.spyOn(String.prototype, 'charCodeAt')
let actual: boolean
let inspections: number
try {
actual = containsTerminalVerticalLineControl(input)
inspections = charCodeAt.mock.calls.length
} finally {
charCodeAt.mockRestore()
}
expect(actual).toBe(expected)
expect(inspections).toBeLessThan(16)
] as const)('detects vertical controls in %s output', (_name, input, expected) => {
expect(containsTerminalVerticalLineControl(input)).toBe(expected)
})
it.each([