package services import ( "strings" "testing" ) // Registrar una factura dictando los datos no era posible: la única // herramienta de venta era adjuntar_factura, que exige un archivo pendiente. // Sin una alternativa, el modelo no tenía con qué guardar y el usuario recibía // un "guardado exitosamente" sobre algo que nunca se creó. func TestExisteHerramientaParaFacturaSinAdjunto(t *testing.T) { tools := agentTools() nombres := map[string]agentTool{} for _, tl := range tools { nombres[tl.Function.Name] = tl } crear, ok := nombres["crear_factura"] if !ok { t.Fatal("falta crear_factura: no habría forma de registrar una factura de venta sin archivo adjunto") } if _, ok := nombres["adjuntar_factura"]; !ok { t.Error("adjuntar_factura debe seguir existiendo para el caso con documento") } // La descripción tiene que distinguirlas, o el modelo elige la equivocada // y falla por falta de adjunto — que es justo el problema original. d := strings.ToLower(crear.Function.Description) if !strings.Contains(d, "sin archivo adjunto") { t.Error("la descripción debe dejar claro que no necesita adjunto") } if !strings.Contains(d, "adjuntar_factura") { t.Error("la descripción debe remitir a adjuntar_factura cuando sí hay documento") } // cliente_id y monto son obligatorios: sin ellos la factura no sirve. req := strings.Join(crear.Function.Parameters.Required, ",") for _, campo := range []string{"cliente_id", "monto"} { if !strings.Contains(req, campo) { t.Errorf("%q debería ser obligatorio en crear_factura", campo) } } } // El modelo puede informar éxito aunque la herramienta haya fallado — pasó con // una factura que nunca se creó. El aviso lo escribe el código a partir del // resultado real, así que no depende de que el modelo se porte bien. func TestErrorDeTool(t *testing.T) { casos := []struct { nombre string resultado string esperado string }{ {"error de la herramienta", `{"error": "cliente_id requerido"}`, "cliente_id requerido"}, {"resultado exitoso", `{"ok": true, "factura_id": 12}`, ""}, {"lista de datos", `{"items": [], "total": 0}`, ""}, {"resultado no JSON", `algo suelto`, ""}, {"error vacío no cuenta", `{"error": ""}`, ""}, } for _, cas := range casos { if got := errorDeTool(cas.resultado); got != cas.esperado { t.Errorf("%s: errorDeTool(%s) = %q, esperaba %q", cas.nombre, cas.resultado, got, cas.esperado) } } }