729921e16e
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
115 lines
3.6 KiB
Go
115 lines
3.6 KiB
Go
package tui
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestVTRender(t *testing.T) {
|
|
t.Run("layout absoluto basico A y B separados por movimiento de cursor", func(t *testing.T) {
|
|
// ESC[1;5H mueve el cursor a fila 1 columna 5 (1-indexed).
|
|
// Resultado esperado: 'A' en col 1, espacios, 'B' en col 5.
|
|
out := VTRender("A\x1b[1;5HB", 2, 10)
|
|
lines := strings.Split(out, "\n")
|
|
if len(lines) == 0 {
|
|
t.Fatalf("resultado vacio")
|
|
}
|
|
first := lines[0]
|
|
if len(first) < 5 {
|
|
t.Fatalf("linea demasiado corta: %q", first)
|
|
}
|
|
if first[0] != 'A' {
|
|
t.Errorf("esperaba 'A' en columna 0, got %q en linea %q", string(first[0]), first)
|
|
}
|
|
if first[4] != 'B' {
|
|
t.Errorf("esperaba 'B' en columna 4 (0-indexed), got %q en linea %q", string(first[4]), first)
|
|
}
|
|
// Verificar que hay espacios entre A y B (no están pegadas).
|
|
if strings.Contains(first, "AB") {
|
|
t.Errorf("A y B estan pegadas en %q, deberían estar separadas", first)
|
|
}
|
|
})
|
|
|
|
t.Run("dos palabras separadas por movimiento de columna no aparecen pegadas", func(t *testing.T) {
|
|
// ESC[10G mueve el cursor a la columna 10 (1-indexed) de la línea actual.
|
|
out := VTRender("foo\x1b[10Gbar", 2, 20)
|
|
lines := strings.Split(out, "\n")
|
|
if len(lines) == 0 {
|
|
t.Fatalf("resultado vacio")
|
|
}
|
|
first := lines[0]
|
|
if strings.Contains(first, "foobar") {
|
|
t.Errorf("foo y bar estan pegadas: %q — esperaba espacios entre ellas", first)
|
|
}
|
|
if !strings.Contains(first, "foo") {
|
|
t.Errorf("no encontre 'foo' en %q", first)
|
|
}
|
|
if !strings.Contains(first, "bar") {
|
|
t.Errorf("no encontre 'bar' en %q", first)
|
|
}
|
|
// foo en col 0-2, bar en col 9-11 (columna 10 es 0-indexed 9).
|
|
if len(first) < 12 {
|
|
t.Fatalf("linea demasiado corta para verificar: %q", first)
|
|
}
|
|
// Debe haber al menos un espacio entre foo y bar.
|
|
fooEnd := strings.Index(first, "foo") + 3
|
|
barStart := strings.Index(first, "bar")
|
|
if barStart <= fooEnd {
|
|
t.Errorf("bar empieza en %d pero foo termina en %d — sin separacion en %q", barStart, fooEnd, first)
|
|
}
|
|
})
|
|
|
|
t.Run("texto multilinea simple con CRLF", func(t *testing.T) {
|
|
out := VTRender("linea1\r\nlinea2", 5, 40)
|
|
if !strings.Contains(out, "linea1") {
|
|
t.Errorf("no encontre 'linea1' en %q", out)
|
|
}
|
|
if !strings.Contains(out, "linea2") {
|
|
t.Errorf("no encontre 'linea2' en %q", out)
|
|
}
|
|
lines := strings.Split(out, "\n")
|
|
// linea1 y linea2 deben estar en líneas distintas.
|
|
found1, found2 := -1, -1
|
|
for i, l := range lines {
|
|
if strings.Contains(l, "linea1") {
|
|
found1 = i
|
|
}
|
|
if strings.Contains(l, "linea2") {
|
|
found2 = i
|
|
}
|
|
}
|
|
if found1 == found2 {
|
|
t.Errorf("linea1 y linea2 estan en la misma linea (%d) de la salida: %q", found1, out)
|
|
}
|
|
})
|
|
|
|
t.Run("trim de filas vacias al final de grid grande", func(t *testing.T) {
|
|
// Input corto en un grid de 40 filas — no debe producir 40 lineas.
|
|
out := VTRender("hola", 40, 120)
|
|
count := strings.Count(out, "\n")
|
|
if count >= 3 {
|
|
t.Errorf("demasiadas lineas (%d) para 'hola' en grid de 40 filas: %q", count, out)
|
|
}
|
|
if !strings.Contains(out, "hola") {
|
|
t.Errorf("no encontre 'hola' en %q", out)
|
|
}
|
|
})
|
|
|
|
t.Run("determinismo misma entrada misma salida", func(t *testing.T) {
|
|
input := "foo\x1b[10Gbar\r\n\x1b[2;1Hbaz"
|
|
out1 := VTRender(input, 10, 40)
|
|
out2 := VTRender(input, 10, 40)
|
|
if out1 != out2 {
|
|
t.Errorf("resultados distintos:\nout1=%q\nout2=%q", out1, out2)
|
|
}
|
|
})
|
|
|
|
t.Run("defaults rows y cols al pasar cero", func(t *testing.T) {
|
|
// Verificar que no entra en pánico con valores <= 0.
|
|
out := VTRender("test", 0, 0)
|
|
if !strings.Contains(out, "test") {
|
|
t.Errorf("no encontre 'test' con defaults (rows=0,cols=0): %q", out)
|
|
}
|
|
})
|
|
}
|