test: tests para deteccion de pasos del pipeline en ProgressReporter
Tests unitarios para formatToolEvent con todos los pipeline hints: create-full.sh, health-check.sh, notify-developer.sh, restart.sh, start.sh, go build, go test, Edit, Read, Glob, Grep, y fallback generico. Incluye tests para el contador de pasos y truncateInput. Actualiza test de integracion existente para el nuevo formato de mensajes (step counter + nombres legibles vs raw tool names). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -69,22 +69,22 @@ func TestIntegration_StreamToProgressReporter(t *testing.T) {
|
|||||||
t.Fatalf("expected 3 edits (tool uses), got %d", len(sender.edits))
|
t.Fatalf("expected 3 edits (tool uses), got %d", len(sender.edits))
|
||||||
}
|
}
|
||||||
|
|
||||||
// First edit: Bash
|
// First edit: Bash with "git status" (generic command, no pipeline hint)
|
||||||
if !strings.Contains(sender.edits[0], "Bash") {
|
if !strings.Contains(sender.edits[0], "Paso 1") {
|
||||||
t.Errorf("edit[0] should mention Bash, got %q", sender.edits[0])
|
t.Errorf("edit[0] should have step 1, got %q", sender.edits[0])
|
||||||
}
|
}
|
||||||
if !strings.Contains(sender.edits[0], "git status") {
|
if !strings.Contains(sender.edits[0], "git status") {
|
||||||
t.Errorf("edit[0] should show input, got %q", sender.edits[0])
|
t.Errorf("edit[0] should show input, got %q", sender.edits[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second edit: Read
|
// Second edit: Read → "Leyendo"
|
||||||
if !strings.Contains(sender.edits[1], "Read") {
|
if !strings.Contains(sender.edits[1], "Leyendo") {
|
||||||
t.Errorf("edit[1] should mention Read, got %q", sender.edits[1])
|
t.Errorf("edit[1] should contain 'Leyendo', got %q", sender.edits[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Third edit: Edit
|
// Third edit: Edit → "Editando"
|
||||||
if !strings.Contains(sender.edits[2], "Edit") {
|
if !strings.Contains(sender.edits[2], "Editando") {
|
||||||
t.Errorf("edit[2] should mention Edit, got %q", sender.edits[2])
|
t.Errorf("edit[2] should contain 'Editando', got %q", sender.edits[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
// All edits should target the same event ID
|
// All edits should target the same event ID
|
||||||
|
|||||||
@@ -67,8 +67,9 @@ func TestProgressReporter_ToolUseEditsMessage(t *testing.T) {
|
|||||||
if len(sender.edits) != 1 {
|
if len(sender.edits) != 1 {
|
||||||
t.Fatalf("expected 1 edit, got %d", len(sender.edits))
|
t.Fatalf("expected 1 edit, got %d", len(sender.edits))
|
||||||
}
|
}
|
||||||
if !strings.Contains(sender.edits[0], "Bash") {
|
// Should contain step number and the command
|
||||||
t.Errorf("edit = %q, should contain tool name", sender.edits[0])
|
if !strings.Contains(sender.edits[0], "Paso 1") {
|
||||||
|
t.Errorf("edit = %q, should contain step number", sender.edits[0])
|
||||||
}
|
}
|
||||||
if !strings.Contains(sender.edits[0], "ls -la") {
|
if !strings.Contains(sender.edits[0], "ls -la") {
|
||||||
t.Errorf("edit = %q, should contain tool input", sender.edits[0])
|
t.Errorf("edit = %q, should contain tool input", sender.edits[0])
|
||||||
@@ -224,3 +225,185 @@ func TestProgressReporter_ToolInputTruncation(t *testing.T) {
|
|||||||
t.Error("truncated input should end with ...")
|
t.Error("truncated input should end with ...")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── formatToolEvent unit tests ──────────────────────────────────────────
|
||||||
|
|
||||||
|
func TestFormatToolEvent_PipelineHints(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
tool string
|
||||||
|
input string
|
||||||
|
wantSub string // substring that must be present
|
||||||
|
wantNot string // substring that must NOT be present (empty = skip)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "create-full.sh detected",
|
||||||
|
tool: "Bash",
|
||||||
|
input: "./dev-scripts/agent/create-full.sh hora-bot \"Hora Bot\"",
|
||||||
|
wantSub: "Creando agente",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "health-check.sh detected",
|
||||||
|
tool: "Bash",
|
||||||
|
input: "./dev-scripts/agent/health-check.sh hora-bot",
|
||||||
|
wantSub: "health check",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "notify-developer.sh detected",
|
||||||
|
tool: "Bash",
|
||||||
|
input: "./dev-scripts/agent/notify-developer.sh hora-bot agent \"Hora Bot\"",
|
||||||
|
wantSub: "bienvenida",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "restart.sh detected",
|
||||||
|
tool: "Bash",
|
||||||
|
input: "./dev-scripts/server/restart.sh",
|
||||||
|
wantSub: "Reiniciando",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "start.sh detected",
|
||||||
|
tool: "Bash",
|
||||||
|
input: "./dev-scripts/server/start.sh",
|
||||||
|
wantSub: "Arrancando",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "go build detected",
|
||||||
|
tool: "Bash",
|
||||||
|
input: "go build -tags goolm ./...",
|
||||||
|
wantSub: "Compilando",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "go test detected",
|
||||||
|
tool: "Bash",
|
||||||
|
input: "go test -tags goolm ./pkg/...",
|
||||||
|
wantSub: "tests",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "generic Bash command",
|
||||||
|
tool: "Bash",
|
||||||
|
input: "cat /etc/hostname",
|
||||||
|
wantSub: "cat /etc/hostname",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Edit tool",
|
||||||
|
tool: "Edit",
|
||||||
|
input: "agents/hora-bot/config.yaml",
|
||||||
|
wantSub: "Editando",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Write tool",
|
||||||
|
tool: "Write",
|
||||||
|
input: "agents/hora-bot/prompts/system.md",
|
||||||
|
wantSub: "Editando",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Read tool",
|
||||||
|
tool: "Read",
|
||||||
|
input: "agents/hora-bot/agent.go",
|
||||||
|
wantSub: "Leyendo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Glob tool",
|
||||||
|
tool: "Glob",
|
||||||
|
input: "agents/*/config.yaml",
|
||||||
|
wantSub: "Buscando",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Grep tool",
|
||||||
|
tool: "Grep",
|
||||||
|
input: "func Rules",
|
||||||
|
wantSub: "Buscando",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unknown tool with input",
|
||||||
|
tool: "CustomTool",
|
||||||
|
input: "some argument",
|
||||||
|
wantSub: "CustomTool",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unknown tool without input",
|
||||||
|
tool: "CustomTool",
|
||||||
|
input: "",
|
||||||
|
wantSub: "CustomTool",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := formatToolEvent(1, tt.tool, tt.input)
|
||||||
|
if !strings.Contains(got, tt.wantSub) {
|
||||||
|
t.Errorf("formatToolEvent(1, %q, %q) = %q, want substring %q",
|
||||||
|
tt.tool, tt.input, got, tt.wantSub)
|
||||||
|
}
|
||||||
|
if tt.wantNot != "" && strings.Contains(got, tt.wantNot) {
|
||||||
|
t.Errorf("formatToolEvent(1, %q, %q) = %q, should NOT contain %q",
|
||||||
|
tt.tool, tt.input, got, tt.wantNot)
|
||||||
|
}
|
||||||
|
// All outputs should have step prefix
|
||||||
|
if !strings.Contains(got, "Paso 1") {
|
||||||
|
t.Errorf("formatToolEvent output %q should contain step number", got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormatToolEvent_StepCounter(t *testing.T) {
|
||||||
|
r1 := formatToolEvent(1, "Bash", "echo hello")
|
||||||
|
r5 := formatToolEvent(5, "Read", "file.go")
|
||||||
|
r12 := formatToolEvent(12, "Edit", "config.yaml")
|
||||||
|
|
||||||
|
if !strings.Contains(r1, "Paso 1") {
|
||||||
|
t.Errorf("step 1: %q", r1)
|
||||||
|
}
|
||||||
|
if !strings.Contains(r5, "Paso 5") {
|
||||||
|
t.Errorf("step 5: %q", r5)
|
||||||
|
}
|
||||||
|
if !strings.Contains(r12, "Paso 12") {
|
||||||
|
t.Errorf("step 12: %q", r12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProgressReporter_StepCounterIncrements(t *testing.T) {
|
||||||
|
sender := &mockProgressSender{}
|
||||||
|
pr := NewProgressReporter(sender, "!room:test", slog.Default())
|
||||||
|
pr.minInterval = 0
|
||||||
|
|
||||||
|
fn := pr.StreamFunc()
|
||||||
|
fn(coretypes.StreamEvent{Kind: coretypes.StreamInit})
|
||||||
|
fn(coretypes.StreamEvent{Kind: coretypes.StreamToolUse, ToolName: "Bash", ToolInput: "echo 1"})
|
||||||
|
fn(coretypes.StreamEvent{Kind: coretypes.StreamToolUse, ToolName: "Read", ToolInput: "file.go"})
|
||||||
|
fn(coretypes.StreamEvent{Kind: coretypes.StreamToolUse, ToolName: "Edit", ToolInput: "file.go"})
|
||||||
|
|
||||||
|
if len(sender.edits) != 3 {
|
||||||
|
t.Fatalf("expected 3 edits, got %d", len(sender.edits))
|
||||||
|
}
|
||||||
|
if !strings.Contains(sender.edits[0], "Paso 1") {
|
||||||
|
t.Errorf("first edit should be Paso 1, got %q", sender.edits[0])
|
||||||
|
}
|
||||||
|
if !strings.Contains(sender.edits[1], "Paso 2") {
|
||||||
|
t.Errorf("second edit should be Paso 2, got %q", sender.edits[1])
|
||||||
|
}
|
||||||
|
if !strings.Contains(sender.edits[2], "Paso 3") {
|
||||||
|
t.Errorf("third edit should be Paso 3, got %q", sender.edits[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTruncateInput(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
input string
|
||||||
|
maxLen int
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"short", 10, "short"},
|
||||||
|
{"exactly10!", 10, "exactly10!"},
|
||||||
|
{"this is longer than ten", 10, "this is..."},
|
||||||
|
{"", 10, ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
got := truncateInput(tt.input, tt.maxLen)
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("truncateInput(%q, %d) = %q, want %q", tt.input, tt.maxLen, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user