Wire-compatible with C mosh. AES-128-OCB3, SSP transport, fragmentation, protobuf state sync, latch extension fields. Includes ServeRW bridge mode for embedding.
156 lines
3.6 KiB
Go
156 lines
3.6 KiB
Go
package mosh
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestFramebufferDiffIdentical(t *testing.T) {
|
|
fb := NewFramebuffer(80, 24)
|
|
old := NewFramebuffer(80, 24)
|
|
diff := fb.Diff(old)
|
|
// Should just be cursor positioning + show cursor, no cell updates.
|
|
if strings.Contains(string(diff), "\033[2J") {
|
|
t.Fatal("identical framebuffers should not trigger full clear")
|
|
}
|
|
}
|
|
|
|
func TestFramebufferDiffSingleCell(t *testing.T) {
|
|
old := NewFramebuffer(80, 24)
|
|
fb := NewFramebuffer(80, 24)
|
|
fb.CellAt(5, 3).Rune = 'A'
|
|
fb.CellAt(5, 3).Width = 1
|
|
|
|
diff := fb.Diff(old)
|
|
s := string(diff)
|
|
// Should contain CUP to row 4, col 6 (1-indexed).
|
|
if !strings.Contains(s, "\033[4;6H") {
|
|
t.Fatalf("expected CUP \\033[4;6H, got %q", s)
|
|
}
|
|
if !strings.Contains(s, "A") {
|
|
t.Fatal("diff should contain 'A'")
|
|
}
|
|
}
|
|
|
|
func TestFramebufferFullRedraw(t *testing.T) {
|
|
fb := NewFramebuffer(80, 24)
|
|
fb.CellAt(0, 0).Rune = 'X'
|
|
fb.CellAt(0, 0).Width = 1
|
|
|
|
diff := fb.Diff(nil)
|
|
s := string(diff)
|
|
if !strings.Contains(s, "\033[2J") {
|
|
t.Fatal("nil old should trigger full redraw with clear")
|
|
}
|
|
if !strings.Contains(s, "X") {
|
|
t.Fatal("full redraw should contain 'X'")
|
|
}
|
|
}
|
|
|
|
func TestFramebufferDiffSizeChange(t *testing.T) {
|
|
old := NewFramebuffer(80, 24)
|
|
fb := NewFramebuffer(132, 43)
|
|
diff := fb.Diff(old)
|
|
s := string(diff)
|
|
if !strings.Contains(s, "\033[2J") {
|
|
t.Fatal("size change should trigger full redraw")
|
|
}
|
|
}
|
|
|
|
func TestFramebufferDiffWithAttrs(t *testing.T) {
|
|
old := NewFramebuffer(80, 24)
|
|
fb := NewFramebuffer(80, 24)
|
|
|
|
c := fb.CellAt(0, 0)
|
|
c.Rune = 'B'
|
|
c.Width = 1
|
|
c.Attr = Attr{Bold: true, FG: Color{Type: ColorIndex, Value: 1}}
|
|
|
|
diff := fb.Diff(old)
|
|
s := string(diff)
|
|
// Should contain bold (1) and red fg (31).
|
|
if !strings.Contains(s, "1") {
|
|
t.Fatal("diff should contain bold SGR")
|
|
}
|
|
if !strings.Contains(s, "31") {
|
|
t.Fatal("diff should contain red FG SGR")
|
|
}
|
|
if !strings.Contains(s, "B") {
|
|
t.Fatal("diff should contain 'B'")
|
|
}
|
|
// Should reset at end.
|
|
if !strings.Contains(s, "\033[m") {
|
|
t.Fatal("diff should reset attributes at end")
|
|
}
|
|
}
|
|
|
|
func TestFramebufferDiffRGBColor(t *testing.T) {
|
|
old := NewFramebuffer(80, 24)
|
|
fb := NewFramebuffer(80, 24)
|
|
|
|
c := fb.CellAt(0, 0)
|
|
c.Rune = 'R'
|
|
c.Width = 1
|
|
c.Attr.FG = Color{Type: ColorRGB, Value: 0xFF8000} // orange
|
|
|
|
diff := fb.Diff(old)
|
|
s := string(diff)
|
|
if !strings.Contains(s, "38;2;255;128;0") {
|
|
t.Fatalf("expected RGB SGR, got %q", s)
|
|
}
|
|
}
|
|
|
|
func TestFramebufferDiffWideChar(t *testing.T) {
|
|
old := NewFramebuffer(80, 24)
|
|
fb := NewFramebuffer(80, 24)
|
|
|
|
// Wide character at (0,0) with continuation at (1,0).
|
|
fb.CellAt(0, 0).Rune = '中'
|
|
fb.CellAt(0, 0).Width = 2
|
|
fb.CellAt(1, 0).Rune = 0
|
|
fb.CellAt(1, 0).Width = 0
|
|
|
|
diff := fb.Diff(old)
|
|
s := string(diff)
|
|
if !strings.Contains(s, "中") {
|
|
t.Fatal("diff should contain wide character")
|
|
}
|
|
}
|
|
|
|
func TestFramebufferDiffCursorPosition(t *testing.T) {
|
|
old := NewFramebuffer(80, 24)
|
|
fb := NewFramebuffer(80, 24)
|
|
fb.CurX = 10
|
|
fb.CurY = 5
|
|
|
|
diff := fb.Diff(old)
|
|
s := string(diff)
|
|
// Final cursor position should be at row 6, col 11 (1-indexed).
|
|
if !strings.Contains(s, "\033[6;11H") {
|
|
t.Fatalf("expected cursor at [6;11H, got %q", s)
|
|
}
|
|
}
|
|
|
|
func TestFramebufferDiffCursorHidden(t *testing.T) {
|
|
old := NewFramebuffer(80, 24)
|
|
fb := NewFramebuffer(80, 24)
|
|
fb.CurVis = false
|
|
|
|
diff := fb.Diff(old)
|
|
s := string(diff)
|
|
if strings.Contains(s, "\033[?25h") {
|
|
t.Fatal("cursor should not be shown when CurVis=false")
|
|
}
|
|
}
|
|
|
|
func TestAppendCUP(t *testing.T) {
|
|
buf := appendCUP(nil, 0, 0)
|
|
if string(buf) != "\033[1;1H" {
|
|
t.Fatalf("got %q", string(buf))
|
|
}
|
|
buf = appendCUP(nil, 23, 79)
|
|
if string(buf) != "\033[24;80H" {
|
|
t.Fatalf("got %q", string(buf))
|
|
}
|
|
}
|