test(renderer): 新增 cwd/链接/broadcast 纯函数表驱动测试
CI / typecheck + test + build (windows) (push) Canceled after 0s
CI / typecheck + test + build (windows) (push) Canceled after 0s
渲染层纯逻辑此前零测试覆盖。三个新测试直接 import .ts 源文件(Node 22.18+ 原生类型剥离,不经 esbuild bundle): - terminal-cwd(69 断言):cdArgument 全部 shell 变体与 conemuCwd 载荷 - terminal-links(92 断言):findUrls 真实合同——尾随标点剥离、重叠 收敛、裸 host 补 scheme、36 条不变式 - broadcast-store(39 断言):broadcastFanOut 扇出与 pruneOnTargetLoss (经 unregisterSession 间接覆盖)
This commit is contained in:
1 parent
64982993f3
commit
12ee779040
4 files changed
+555
-1
No files matched your search
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* Working-directory tracking self-test (terminal-cwd.mjs).
|
||||
*
|
||||
* `src/renderer/src/terminal/cwdTracker.ts` is the renderer half of cwd memory:
|
||||
* it turns a submitted command line into a cd argument (or null) and unwraps
|
||||
* ConEmu's OSC 9 payload. Everything platform-specific — path resolution,
|
||||
* existence checks, quote stripping, `cd -` rejection — lives in the main
|
||||
* process (`src/main/cwd.ts`), so the contract pinned here is deliberately
|
||||
* narrow, and the table says which side owns what:
|
||||
*
|
||||
* - the cd family per shell (cd / chdir / sl / Set-Location / pushd /
|
||||
* Push-Location) and the bare `d:` drive switch;
|
||||
* - an EMPTY STRING means "bare cd" (home) and is NOT the same answer as
|
||||
* null ("not a cd line") — the caller only resolves on non-null;
|
||||
* - quotes and trailing arguments are handed to main verbatim: this module is
|
||||
* not a shell parser, so `cd "D:\Program Files"` keeps its quotes and
|
||||
* `cd /tmp && ls` keeps its separator;
|
||||
* - lookalikes (`cdrom`, `cdx`, `sleep 1`, `VAR=x cd y`) never match, since a
|
||||
* false positive would move the remembered directory on an unrelated line.
|
||||
*
|
||||
* Unlike the esbuild-bundled tests, this one imports the .ts module directly:
|
||||
* it has no imports and no runtime-only TS syntax, and Node >= 22.18 strips the
|
||||
* type annotations itself. Run: node tests/terminal-cwd.mjs (must exit 0)
|
||||
*/
|
||||
import { cdArgument, conemuCwd } from '../src/renderer/src/terminal/cwdTracker.ts'
|
||||
|
||||
let failed = 0
|
||||
const ok = (cond, msg) => {
|
||||
console.log(` ${cond ? 'ok' : 'FAIL'}: ${msg}`)
|
||||
if (!cond) failed += 1
|
||||
}
|
||||
|
||||
/** Table-driven: [line, expected] — `null` = "not a cd line", `''` = bare cd. */
|
||||
const table = (label, cases, fn) => {
|
||||
console.log(label)
|
||||
for (const [input, expected] of cases) {
|
||||
const got = fn(input)
|
||||
ok(
|
||||
got === expected,
|
||||
`${JSON.stringify(input)} -> ${JSON.stringify(got)}${got === expected ? '' : ` (want ${JSON.stringify(expected)})`}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
table(
|
||||
'the cd family returns the raw argument (main does the path work)',
|
||||
[
|
||||
['cd /path', '/path'],
|
||||
['cd\t/tmp', '/tmp'],
|
||||
['cd\n/tmp', '/tmp'],
|
||||
['cd ~/x', '~/x'],
|
||||
['cd ../x', '../x'],
|
||||
['cd -', '-'],
|
||||
['cd .', '.'],
|
||||
['cd D:\\projects', 'D:\\projects'],
|
||||
['cd "D:\\Program Files"', '"D:\\Program Files"'],
|
||||
["cd '~/src'", "'~/src'"],
|
||||
['cd ""', '""']
|
||||
],
|
||||
cdArgument
|
||||
)
|
||||
|
||||
table(
|
||||
'every shell spelling is recognised, case-insensitively',
|
||||
[
|
||||
['CD /tmp', '/tmp'],
|
||||
['Cd /tmp', '/tmp'],
|
||||
[' cD /tmp ', '/tmp'],
|
||||
['chdir C:\\x', 'C:\\x'],
|
||||
['CHDIR ..', '..'],
|
||||
['sl .', '.'],
|
||||
['sl', ''],
|
||||
['Set-Location /a', '/a'],
|
||||
['set-location /a', '/a'],
|
||||
['pushd ../b', '../b'],
|
||||
['Push-Location ~/c', '~/c']
|
||||
],
|
||||
cdArgument
|
||||
)
|
||||
|
||||
table(
|
||||
'bare cd is the empty-string sentinel, not null',
|
||||
[
|
||||
['cd', ''],
|
||||
['cd ', ''],
|
||||
[' cd ', ''],
|
||||
['cd\t', '']
|
||||
],
|
||||
cdArgument
|
||||
)
|
||||
|
||||
table(
|
||||
'trailing arguments and separators stay in the argument',
|
||||
[
|
||||
['cd /tmp ', '/tmp'],
|
||||
['cd /a b', '/a b'],
|
||||
['cd /tmp extra', '/tmp extra'],
|
||||
['cd /tmp && ls', '/tmp && ls'],
|
||||
['cd /tmp; ls', '/tmp; ls'],
|
||||
['cd /tmp | more', '/tmp | more']
|
||||
],
|
||||
cdArgument
|
||||
)
|
||||
|
||||
table(
|
||||
'the bare drive switch resolves to the drive root',
|
||||
[
|
||||
['d:', 'D:\\'],
|
||||
['D:', 'D:\\'],
|
||||
[' d: ', 'D:\\'],
|
||||
['a:', 'A:\\'],
|
||||
['z:', 'Z:\\']
|
||||
],
|
||||
cdArgument
|
||||
)
|
||||
|
||||
table(
|
||||
'lines that are not a cd are null (no false positives)',
|
||||
[
|
||||
['', null],
|
||||
[' ', null],
|
||||
['cdx /tmp', null],
|
||||
['cdrom', null],
|
||||
['cdemo /x', null],
|
||||
['slack', null],
|
||||
['sleep 1', null],
|
||||
['VAR=x cd y', null],
|
||||
['sudo cd /x', null],
|
||||
['echo cd /x', null],
|
||||
['ls -la', null],
|
||||
['d:\\', null],
|
||||
['..', null],
|
||||
['~', null]
|
||||
],
|
||||
cdArgument
|
||||
)
|
||||
|
||||
console.log('the empty-string answer is distinct from "not a cd line"')
|
||||
ok(cdArgument('cd') === '', 'a bare cd answers with the empty string')
|
||||
ok(cdArgument('cd') !== null, 'and is not null, so the caller still resolves it')
|
||||
ok(cdArgument('ls') === null, 'a non-cd line answers null')
|
||||
|
||||
table(
|
||||
'ConEmu OSC 9;9 carries a bare path',
|
||||
[
|
||||
['9;/home/a', '/home/a'],
|
||||
['9;C:\\Users\\a', 'C:\\Users\\a'],
|
||||
['9;C:\\Program Files', 'C:\\Program Files'],
|
||||
['9;/a\n', '/a'],
|
||||
['9; /a ', '/a'],
|
||||
['9; ', null],
|
||||
['9;', null],
|
||||
['9', null],
|
||||
['90;x', null],
|
||||
['9;;x', ';x'],
|
||||
['', null],
|
||||
['7;file://host/p', null],
|
||||
['8;/a', null]
|
||||
],
|
||||
conemuCwd
|
||||
)
|
||||
|
||||
console.log('OSC 9 payloads that are not ConEmu cwd reports are rejected')
|
||||
ok(conemuCwd('9;1;2') === '1;2', 'the remainder after the convention marker is the path')
|
||||
ok(conemuCwd('9;file://host/p') === 'file://host/p', 'a file:// body is passed through for main to normalize')
|
||||
|
||||
if (failed > 0) {
|
||||
console.error(`\n[terminal-cwd] ${failed} check(s) FAILED`)
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('\n[terminal-cwd] ALL CHECKS PASSED')
|
||||
Reference in new issue
Block a user