package services
import (
"os"
"strings"
"testing"
)
func TestParsearItems(t *testing.T) {
items, total := parsearItems(`[{"descripcion":"Licencia","cantidad":3,"precio":200000}]`)
if len(items) != 1 || total != 600000 {
t.Fatalf("items=%d total=%v, esperaba 1 ítem y 600000", len(items), total)
}
// Sin cantidad se asume 1: el modelo la omite seguido y un total en cero
// en una cotización es peor que uno aproximado.
items, total = parsearItems(`[{"descripcion":"Servicio","precio":50000}]`)
if len(items) != 1 || items[0].Cantidad != 1 || total != 50000 {
t.Errorf("cantidad omitida: items=%+v total=%v", items, total)
}
// JSON roto no puede tumbar la generación entera.
if items, total := parsearItems(`{no es json`); items != nil || total != 0 {
t.Errorf("JSON inválido debería dar vacío, dio %+v / %v", items, total)
}
if items, _ := parsearItems(""); items != nil {
t.Error("sin ítems debería dar vacío")
}
}
func TestValidarPlantillaHTML(t *testing.T) {
if err := ValidarPlantillaHTML(`
{{.Cliente}}
{{range .Items}}{{.Descripcion}}
{{end}}`); err != nil {
t.Errorf("una plantilla válida fue rechazada: %v", err)
}
if err := ValidarPlantillaHTML(`{{.Cliente}
`); err == nil {
t.Error("una plantilla rota tiene que rechazarse antes de guardarse")
}
}
// Cada PDF levanta un Chrome entero. Sin semáforo, cien clientes generando a
// la vez son cien navegadores y el servidor se cae antes que por la IA.
func TestGeneracionDePDFTieneSemaforo(t *testing.T) {
b, err := os.ReadFile("umind_documento_tools.go")
if err != nil {
t.Fatal(err)
}
s := string(b)
if cap(pdfEnCurso) == 0 || cap(pdfEnCurso) > 5 {
t.Errorf("el semáforo de PDF tiene capacidad %d: debería ser chica y mayor que cero", cap(pdfEnCurso))
}
i := strings.Index(s, "func renderPDFDesdePlantilla")
cuerpo := s[i:]
cuerpo = cuerpo[:strings.Index(cuerpo, "\n// guardarPDF")]
if !strings.Contains(cuerpo, "pdfEnCurso <- struct{}{}") || !strings.Contains(cuerpo, "<-pdfEnCurso") {
t.Error("RenderHTMLToPDF tiene que llamarse con el semáforo tomado y liberarlo después")
}
}
// Las plantillas globales del staff no pueden salir en un documento de un
// cliente, ni al revés. Es el mismo patrón que ya se corrigió en AiConfig.
func TestPlantillaGlobalFiltraPorTenantNulo(t *testing.T) {
b, err := os.ReadFile("../models/plantilla_documento.go")
if err != nil {
t.Fatal(err)
}
s := string(b)
i := strings.Index(s, "func GetPlantillaDocumentoActiva")
cuerpo := s[i:]
cuerpo = cuerpo[:strings.Index(cuerpo, "\n// GetPlantillaDocumentoDeTenant")]
if !strings.Contains(cuerpo, "tenant_id IS NULL") {
t.Error("la plantilla global tiene que filtrar tenant_id IS NULL, si no puede devolver la de un cliente")
}
}