- M0: libghostty SSH 终端(渲染/输入/连接)+ 白屏修复(OutputGate) + 会话状态机/自动重连 - M1: tsnet 用户态组网 + SSH-over-tsnet(fd 桥),shell 级真机验证;R5(Go+gvisor+C+++Swift 同进程) retire - M1.5: tmux -CC 原生 tab(MVP) - 结构: packages/(TXCore·TXTransport), apps/TerminalX, vendor/(libghostty-spm/libssh2/mbedtls/tsnet-bridge), artifacts/ - 文档: CLAUDE.md + docs/HANDOFF.md(新会话入口) - 环境: 认证代理→依赖 vendor 本地化;Go 在 ~/.local/go;仅模拟器/未签名 - 待续: M2 mosh, tmux 多 pane, M4 安全(host key/SE) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
60 lines
2.5 KiB
Swift
60 lines
2.5 KiB
Swift
import Testing
|
|
@testable import TXCore
|
|
|
|
@Suite("tmux layout 字符串解析")
|
|
struct TmuxLayoutTests {
|
|
|
|
@Test("单 pane")
|
|
func single() throws {
|
|
let l = try TmuxLayout.parse("bc62,80x24,0,0,0")
|
|
#expect(l.root == .leaf(pane: TmuxPaneID(0),
|
|
rect: .init(width: 80, height: 24, x: 0, y: 0)))
|
|
#expect(l.paneIDs == [TmuxPaneID(0)])
|
|
}
|
|
|
|
@Test("左右分屏 {} → horizontal")
|
|
func horizontalSplit() throws {
|
|
let l = try TmuxLayout.parse("a1b2,80x24,0,0{40x24,0,0,1,39x24,41,0,2}")
|
|
guard case .horizontal(let children, let rect) = l.root else {
|
|
Issue.record("期望 horizontal"); return
|
|
}
|
|
#expect(rect == .init(width: 80, height: 24, x: 0, y: 0))
|
|
#expect(children.count == 2)
|
|
#expect(children[0] == .leaf(pane: TmuxPaneID(1), rect: .init(width: 40, height: 24, x: 0, y: 0)))
|
|
#expect(children[1] == .leaf(pane: TmuxPaneID(2), rect: .init(width: 39, height: 24, x: 41, y: 0)))
|
|
#expect(l.paneIDs == [TmuxPaneID(1), TmuxPaneID(2)])
|
|
}
|
|
|
|
@Test("上下分屏 [] → vertical")
|
|
func verticalSplit() throws {
|
|
let l = try TmuxLayout.parse("ffff,80x24,0,0[80x12,0,0,1,80x11,0,13,2]")
|
|
guard case .vertical(let children, _) = l.root else {
|
|
Issue.record("期望 vertical"); return
|
|
}
|
|
#expect(children.count == 2)
|
|
#expect(l.paneIDs == [TmuxPaneID(1), TmuxPaneID(2)])
|
|
}
|
|
|
|
@Test("嵌套:左右分屏,右侧再上下分屏")
|
|
func nested() throws {
|
|
let l = try TmuxLayout.parse("0000,100x40,0,0{50x40,0,0,1,49x40,51,0[49x20,51,0,2,49x19,51,21,3]}")
|
|
guard case .horizontal(let top, _) = l.root else {
|
|
Issue.record("期望 horizontal"); return
|
|
}
|
|
#expect(top.count == 2)
|
|
#expect(top[0] == .leaf(pane: TmuxPaneID(1), rect: .init(width: 50, height: 40, x: 0, y: 0)))
|
|
guard case .vertical(let inner, _) = top[1] else {
|
|
Issue.record("期望嵌套 vertical"); return
|
|
}
|
|
#expect(inner.count == 2)
|
|
#expect(l.paneIDs == [TmuxPaneID(1), TmuxPaneID(2), TmuxPaneID(3)])
|
|
}
|
|
|
|
@Test("畸形字符串抛错而非崩溃")
|
|
func malformed() {
|
|
#expect(throws: TmuxLayout.ParseError.self) { try TmuxLayout.parse("garbage") }
|
|
#expect(throws: TmuxLayout.ParseError.self) { try TmuxLayout.parse("abcd,80x24,0,0{") }
|
|
#expect(throws: TmuxLayout.ParseError.self) { try TmuxLayout.parse("abcd,80x,0,0,0") }
|
|
}
|
|
}
|