import { describe, it, expect } from 'vitest'; import { createLongevityDb, createIdentityDb, COPERTURA_MINIMA } from '../../src/lib/longevity/db'; describe('schema longevity', () => { it('crea le tabelle previste dalla spec', () => { const db = createLongevityDb(':memory:'); const nomi = (db.prepare(`SELECT name FROM sqlite_master WHERE type='table'`).all() as { name: string }[]) .map((r) => r.name); expect(nomi).toEqual( expect.arrayContaining(['soggetti', 'sessioni', 'misure', 'registro_test', 'pesi', 'profilo_note', 'score']) ); }); it('rifiuta un sesso non previsto', () => { const db = createLongevityDb(':memory:'); expect(() => db.prepare(`INSERT INTO soggetti (client_code, sesso) VALUES ('ISL-0001', 'X')`).run() ).toThrow(); }); it('rifiuta una misura con test_id non nel registro', () => { const db = createLongevityDb(':memory:'); db.prepare(`INSERT INTO soggetti (client_code, sesso) VALUES ('ISL-0001', 'F')`).run(); db.prepare(`INSERT INTO sessioni (client_code, data, tipo) VALUES ('ISL-0001', '2026-08-21', 'checkup')`).run(); expect(() => db.prepare( `INSERT INTO misure (sessione_id, client_code, test_id, valore_num, fonte) VALUES (1, 'ISL-0001', 'test_inventato', 10, 'manuale')` ).run() ).toThrow(); }); it('uno score insufficiente puo non avere valore', () => { const db = createLongevityDb(':memory:'); db.prepare(`INSERT INTO soggetti (client_code, sesso) VALUES ('ISL-0001', 'F')`).run(); db.prepare(`INSERT INTO sessioni (client_code, data, tipo) VALUES ('ISL-0001', '2026-08-21', 'checkup')`).run(); db.prepare( `INSERT INTO score (client_code, sessione_id, tipo, elemento, valore, copertura, stato, model_version) VALUES ('ISL-0001', 1, 'asse', 'Forza & Struttura', NULL, 0.2, 'insufficiente', 'v1.0')` ).run(); const row = db.prepare(`SELECT valore, stato FROM score`).get() as { valore: number | null; stato: string }; expect(row.valore).toBeNull(); expect(row.stato).toBe('insufficiente'); }); it('la tabella rifiuta uno score insufficiente CON un valore scritto', () => { // Il tipo Punteggio protegge il codice, ma l'interfaccia legge dalla tabella, // dove il tipo non c'e' piu': senza questo vincolo si potrebbe scrivere un // numero dichiarato "insufficiente" e chi legge crud dalla tabella lo prenderebbe. const db = createLongevityDb(':memory:'); db.prepare(`INSERT INTO soggetti (client_code, sesso) VALUES ('ISL-0001', 'F')`).run(); db.prepare(`INSERT INTO sessioni (client_code, data, tipo) VALUES ('ISL-0001', '2026-08-21', 'checkup')`).run(); expect(() => db.prepare( `INSERT INTO score (client_code, sessione_id, tipo, elemento, valore, copertura, stato, model_version) VALUES ('ISL-0001', 1, 'asse', 'Forza & Struttura', 42, 0.2, 'insufficiente', 'v1.0')` ).run() ).toThrow(); }); it('la tabella rifiuta uno score ok SENZA valore', () => { const db = createLongevityDb(':memory:'); db.prepare(`INSERT INTO soggetti (client_code, sesso) VALUES ('ISL-0001', 'F')`).run(); db.prepare(`INSERT INTO sessioni (client_code, data, tipo) VALUES ('ISL-0001', '2026-08-21', 'checkup')`).run(); expect(() => db.prepare( `INSERT INTO score (client_code, sessione_id, tipo, elemento, valore, copertura, stato, model_version) VALUES ('ISL-0001', 1, 'asse', 'Forza & Struttura', NULL, 1, 'ok', 'v1.0')` ).run() ).toThrow(); }); it('identity tiene la persona, longevity non la conosce', () => { const id = createIdentityDb(':memory:'); const cols = (id.prepare(`PRAGMA table_info(clienti)`).all() as { name: string }[]).map((c) => c.name); expect(cols).toEqual(expect.arrayContaining(['client_code', 'user_id', 'nome', 'cognome', 'data_nascita'])); const lg = createLongevityDb(':memory:'); const tutte = (lg.prepare(`SELECT name FROM sqlite_master WHERE type='table'`).all() as { name: string }[]) .flatMap((t) => (lg.prepare(`PRAGMA table_info(${t.name})`).all() as { name: string }[]).map((c) => c.name)); expect(tutte).not.toContain('nome'); expect(tutte).not.toContain('cognome'); expect(tutte).not.toContain('data_nascita'); }); it('la soglia di copertura e 0.40', () => { expect(COPERTURA_MINIMA).toBe(0.4); }); });