feat(cybersecurity): auto-commit con 48 cambios

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-04 23:44:39 +02:00
parent efc9911925
commit 729921e16e
48 changed files with 3765 additions and 8 deletions
+114
View File
@@ -0,0 +1,114 @@
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)
}
})
}