Files
AeroFetch/test/lineBuffer.test.ts
T
debont80 814ecac287 feat(audit): Batch 10 — CC conventions (shared line-buffer, cleanError)
The contained consistency consolidations; the sweeping ones are deferred with
their standard documented (they're the audit's own post-1.0 refactors, and
several would be reckless to do unattended).

Landed:
- src/main/lib/lineBuffer.ts (createLineBuffer): one newline line-splitter for
  streamed child-process output, replacing the duplicated buffer loop in
  download.ts and terminal.ts (CC3/CC4/SIMP5). Pure + unit-tested
  (test/lineBuffer.test.ts, 7 cases: partial lines, CRLF, empty lines, flush,
  multi-line chunks). download.ts keeps byte-identical marker parsing and no
  close-flush (yt-dlp template lines are always newline-terminated).
- ytdlp.ts: getYtdlpVersion/updateYtdlp now run stderr through cleanError, the
  same `cleanError(r.stderr) || r.error?.message || ''` idiom already used by
  download/probe/indexer (CC6) — a failed check shows the trailing error line.
- CL6 resolved: the one real redundancy was L15; clearDir/openFile/showInFolder
  are deliberate view-model wrappers (CC13), left as-is.

Deferred with documented standard + rationale (CODE-AUDIT.md): CC1 (breaking
persisted-key rename → migration), CC5+CL4 (security-critical updater
net.request, not live-verifiable here), CC7 (cosmetic arg-order), CC9 (zod dep),
CC10 (electron-store↔jsonStore split is deliberate for DPAPI), CC11 (config.ts
move), CC12 (file-tree reorg), CC13→L93, CC14→L142.

Verified: typecheck (node+web) + 275 tests + eslint + production build green;
touched files prettier-clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 16:48:54 -04:00

64 lines
1.9 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import { createLineBuffer } from '../src/main/lib/lineBuffer'
/** Collect every line a buffer emits, for assertions. */
function collect(): { lines: string[]; buf: ReturnType<typeof createLineBuffer> } {
const lines: string[] = []
const buf = createLineBuffer((l) => lines.push(l))
return { lines, buf }
}
describe('createLineBuffer', () => {
it('emits one line per newline, without the newline', () => {
const { lines, buf } = collect()
buf.push('a\nb\nc\n')
expect(lines).toEqual(['a', 'b', 'c'])
})
it('holds a partial line until its newline arrives across chunks', () => {
const { lines, buf } = collect()
buf.push('hel')
expect(lines).toEqual([])
buf.push('lo\nwor')
expect(lines).toEqual(['hello'])
buf.push('ld\n')
expect(lines).toEqual(['hello', 'world'])
})
it('strips a trailing CR so CRLF streams split cleanly', () => {
const { lines, buf } = collect()
buf.push('one\r\ntwo\r\n')
expect(lines).toEqual(['one', 'two'])
})
it('flush emits a trailing partial line that never saw a newline', () => {
const { lines, buf } = collect()
buf.push('no newline here')
expect(lines).toEqual([])
buf.flush()
expect(lines).toEqual(['no newline here'])
})
it('flush is a no-op when the buffer is empty (e.g. stream ended on a newline)', () => {
const { lines, buf } = collect()
buf.push('done\n')
buf.flush()
buf.flush()
expect(lines).toEqual(['done'])
})
it('preserves empty lines between consecutive newlines', () => {
const { lines, buf } = collect()
buf.push('a\n\nb\n')
expect(lines).toEqual(['a', '', 'b'])
})
it('splits a multi-line chunk that arrives all at once', () => {
const { lines, buf } = collect()
buf.push('1\n2\n3')
expect(lines).toEqual(['1', '2'])
buf.flush()
expect(lines).toEqual(['1', '2', '3'])
})
})