/** Check dei profili giocatore: `bun test/unit/profili-core.test.ts`. */ import assert from "node:assert/strict"; import { aRigaProfilo, completamento, csvTesseramento, daRigaProfilo, sezioniComplete, statoScadenza, type Profilo, } from "@/lib/profili-core"; import { dividiNome, rosaFallback, slotDi, slotLiberi, type GiocatoreSquadra, } from "@/lib/giocatori-squadra"; const vuoto: Profilo = { giocatoreId: "g1", dataNascita: null, luogoNascita: null, indirizzo: null, telefono: null, email: null, documentoTipo: null, documentoNumero: null, documentoRilasciatoDa: null, documentoEmissione: null, documentoScadenza: null, documentoFrontePath: null, documentoRetroPath: null, certificatoScadenza: null, certificatoPath: null, fotoPath: null, }; const completo: Profilo = { ...vuoto, dataNascita: "1995-05-01", luogoNascita: "Bologna", indirizzo: "Via Roma 1", telefono: "3331234567", email: "ivan@example.com", documentoTipo: "Carta d'identità", documentoNumero: "CA12345", documentoRilasciatoDa: "Comune di Bologna", documentoEmissione: "2020-01-01", documentoScadenza: "2030-01-01", documentoFrontePath: "g1/documento-fronte.jpg", documentoRetroPath: "g1/documento-retro.jpg", certificatoScadenza: "2027-06-30", certificatoPath: "g1/certificato.pdf", fotoPath: "g1/foto.jpg", }; // --- completamento ----------------------------------------------------------- assert.equal(completamento(null), 0, "profilo inesistente = 0%"); assert.equal(completamento(vuoto), 0); assert.equal(completamento(completo), 100, "tutte le sezioni piene = 100%"); assert.equal(completamento({ ...completo, fotoPath: null }), 90, "la foto pesa 10"); assert.equal(completamento({ ...completo, certificatoPath: null }), 70, "il certificato pesa 30"); assert.equal( completamento({ ...completo, email: null }), 70, "i dati personali sono completi solo tutti insieme", ); // I metadati senza file (o viceversa) non contano come sezione completa. assert.equal(sezioniComplete({ ...completo, certificatoScadenza: null }).certificato, false); assert.equal( sezioniComplete({ ...completo, documentoRetroPath: null }).documento, false, "il documento vale solo con fronte e retro", ); assert.equal(sezioniComplete({ ...completo, documentoFrontePath: null }).documento, false); // --- aRigaProfilo ------------------------------------------------------------ const riga = aRigaProfilo({ ...completo, luogoNascita: " ", telefono: " 333 " }); assert.equal(riga.luogo_nascita, null, "i campi solo-spazi tornano NULL, non stringa vuota"); assert.equal(riga.telefono, "333", "il resto viene ripulito ai bordi"); assert.equal(riga.documento_fronte_path, "g1/documento-fronte.jpg"); assert.deepEqual( daRigaProfilo(aRigaProfilo(completo)), completo, "modello -> riga -> modello non perde niente", ); // --- statoScadenza ----------------------------------------------------------- const oggi = "2026-08-30"; assert.equal(statoScadenza(null, null, oggi), "mancante"); assert.equal(statoScadenza("2027-01-01", null, oggi), "mancante", "senza file non vale"); assert.equal(statoScadenza(null, "g1/cert.pdf", oggi), "mancante", "senza data non vale"); assert.equal(statoScadenza("2026-08-29", "g1/cert.pdf", oggi), "scaduto"); assert.equal( statoScadenza("2026-08-30", "g1/cert.pdf", oggi), "valido", "scade oggi = ancora valido", ); assert.equal(statoScadenza("2026-12-31", "g1/cert.pdf", oggi), "valido"); // --- csvTesseramento --------------------------------------------------------- const squadra: GiocatoreSquadra[] = [ { id: "g1", nome: "Ivan", cognome: "Cacciari", numero: 23, ruolo: "Banda", authUserId: null, attivo: true, }, { id: "g2", nome: "Anna", cognome: 'De "Rossi"', numero: 7, ruolo: "Libero", authUserId: "u2", attivo: true, }, ]; const csv = csvTesseramento(squadra, { g1: completo }); const righe = csv.split("\n"); assert.equal(righe.length, 3, "intestazione + un giocatore per riga"); assert.equal(righe[0]?.split(";").length, 12, "i 12 campi richiesti dal CSI"); assert.match(righe[1] ?? "", /^Ivan;Cacciari;1995-05-01;Bologna/); assert.match( righe[2] ?? "", /^Anna;"De ""Rossi""";;;/, "chi non ha profilo esce con i campi vuoti", ); // --- anagrafica squadra ------------------------------------------------------ assert.deepEqual(dividiNome("Ivan Cacciari"), { nome: "Ivan", cognome: "Cacciari" }); assert.deepEqual( dividiNome("Carlo Di Castelnuovo"), { nome: "Carlo", cognome: "Di Castelnuovo" }, "il cognome composto resta intero", ); assert.deepEqual(dividiNome("Ivan"), { nome: "Ivan", cognome: "" }); assert.equal(slotDi(squadra, null), null, "senza sessione nessuno slot"); assert.equal(slotDi(squadra, "u2")?.id, "g2"); assert.equal(slotDi(squadra, "sconosciuto"), null); assert.deepEqual( slotLiberi(squadra).map((g) => g.id), ["g1"], "uno slot già collegato non è più libero", ); assert.deepEqual( slotLiberi([...squadra, { ...squadra[0]!, id: "g3", attivo: false }]).map((g) => g.id), ["g1"], "i giocatori non attivi restano fuori", ); const fallback = rosaFallback(); assert.ok(fallback.length > 0, "il fallback da crapp-data non è mai vuoto"); assert.ok( fallback.every((g) => g.authUserId === null && g.attivo), "il fallback non può collegare account", ); console.log("profili-core: ok");