Piano dei test
Decisioni (strumenti, livelli, struttura): ADR-0003. Qui: regola, flusso, soglie e matrice requisito → test, sorgente di verità per la copertura. Le spunte [ ] passano a [x] quando il test esiste e passa.
Regola
Nuova funzione, correzione o cambio di comportamento ⇒ test nello stesso commit. Niente test, funzione non finita.
- Una nuova funzione aggiunge righe alla matrice qui sotto (con ID) prima di scrivere il codice.
- Una correzione di bug parte da un test che fallisce e lo lascia come regressione.
- Una modifica che cambia un requisito aggiorna prima il doc, poi la riga della matrice, poi i test, poi il codice.
- Una riga senza test non è copertura: va lasciata
[ ] e conta come debito visibile.
Flusso (estende il doc-first di README.md)
ADR (se serve) → MVP.md (requisito e criterio) → riga in questa matrice → test che falliscono → codice → test verdi → ROADMAP/README/CLAUDE.md.
Livelli
| Livello |
Cosa prova |
Come |
| U — unitario |
Core/ e MainViewModel |
xUnit, finto runner, cartella dati temporanea |
| R — renderer |
MarkdownView |
xUnit + Headless, asserzioni sull'albero visuale |
| G — GUI headless |
MainWindow, template, tastiera, finestre di dialogo |
xUnit + Headless, senza schermo |
| P — processo |
avvio reale di un processo (Claude) |
FakeClaude nel PATH |
| E — end-to-end |
l'eseguibile pubblicato (CLI, 127, exit code) |
publish + processo figlio + FakeClaude |
Struttura prevista
Predisposizioni di testabilità (prerequisito dei test)
Soglie di copertura (la build fallisce sotto soglia)
| Area |
Righe |
Rami |
Core/ |
≥ 95% |
≥ 90% |
Gui/MainViewModel |
≥ 95% |
≥ 90% |
Gui/MarkdownView |
≥ 90% |
≥ 85% |
Gui/MainWindow*, ConfirmDialog (code-behind) |
≥ 85% |
— |
| Totale |
≥ 90% |
— |
Esclusi dal calcolo: XAML generato, Program.cs (tre righe, coperte da E2E), App.axaml.cs. La soglia non sostituisce la matrice: copertura di righe alta con requisiti scoperti non basta.
Matrice requisito → test
Fonte dei requisiti: MVP.md e gli ADR. Livello: vedi sopra. Il nome del test è indicativo.
Avvio di claude — Core/Claude.cs
| ID |
Requisito |
Liv. |
Test |
|
| CL-01 |
Il prompt è un solo argomento, anche con virgolette e spazi (criterio MVP 4) |
U/P |
Prompt_con_virgolette_arriva_intatto |
[ ] |
| CL-02 |
Primo messaggio: --session-id <guid>; successivi: --resume <guid> |
U |
Sessione_prima_e_ripresa |
[ ] |
| CL-03 |
--model/--effort omessi se vuoti, presenti se valorizzati |
U |
Flag_opzionali |
[ ] |
| CL-04 |
Cartella di lavoro = cartella dell'exe, non la cwd del chiamante (criterio MVP 1) |
U/P |
Cartella_di_lavoro_e_quella_dell_exe |
[ ] |
| CL-05 |
Stdin chiuso subito: nessuna attesa di 3 s |
P |
Stdin_chiuso_non_blocca |
[ ] |
| CL-06 |
CLI: l'exit code di claude è propagato (criterio MVP 3) |
P/E |
ExitCode_propagato |
[ ] |
| CL-07 |
CLI: claude assente ⇒ messaggio chiaro ed exit code 127 |
P/E |
Claude_assente_127 |
[ ] |
| CL-08 |
CLI: stdout/stderr ereditati e ritrasmessi (criterio MVP 2: streaming) |
E |
Output_ereditato_in_tempo_reale |
[ ] |
| CL-09 |
GUI: output catturato e ripulito agli estremi; stderr separato |
P |
Output_catturato |
[ ] |
| CL-10 |
GUI: claude assente ⇒ eccezione riconoscibile, non crash |
P |
Claude_assente_in_GUI |
[ ] |
| CL-11 |
Il catalogo modelli contiene gli ID attesi e gli effort previsti |
U |
Catalogo_modelli_ed_effort |
[ ] |
| CL-12 |
Senza argomenti non parte la CLI; con argomenti sì (tutti uniti in un prompt) |
E |
Argomenti_uniti_in_un_prompt |
[ ] |
Cronologia — Core/ChatStore.cs, Core/AppInfo.cs
| ID |
Requisito |
Liv. |
Test |
|
| ST-01 |
Salvataggio e rilettura: id, titolo, data, started, messaggi con ruolo e testo |
U |
Salva_e_rileggi |
[ ] |
| ST-02 |
Una chat senza messaggi non viene salvata |
U |
Chat_vuota_non_salvata |
[ ] |
| ST-03 |
Titolo = inizio del primo messaggio utente: 50 caratteri + "…", a capo sostituiti da spazi |
U |
Titolo_troncato |
[ ] |
| ST-04 |
L'id deve essere un Guid: un id con .. o separatori non tocca il disco fuori dalla cartella |
U |
Id_non_guid_rifiutato |
[ ] |
| ST-05 |
L'elenco è ordinato dalla più recente |
U |
Elenco_ordinato |
[ ] |
| ST-06 |
File JSON corrotto ignorato senza eccezioni |
U |
File_corrotto_ignorato |
[ ] |
| ST-07 |
Eliminazione: rimuove solo il file di quella chat; id inesistente senza errori |
U |
Elimina_chat |
[ ] |
| ST-08 |
Compatibilità del formato: un JSON scritto dalla versione WinForms si legge |
U |
Formato_storico_compatibile |
[ ] |
| ST-09 |
Migrazione: la cartella di un nome precedente (LlmRun) si sposta nella nuova al primo avvio; se la nuova esiste non si tocca nulla |
U |
Migrazione_da_nome_precedente |
[ ] |
| ST-10 |
AppInfo.Name = AssemblyName del csproj |
U |
Nome_da_assembly |
[ ] |
| ST-11 |
Errore di I/O nel salvataggio non perde la chat a schermo |
U |
vedi VM-12 |
[ ] |
Logica della chat — Gui/MainViewModel.cs
| ID |
Requisito |
Liv. |
Test |
|
| VM-01 |
Senza chat salvate: schermata iniziale (ShowEmpty), elenco vuoto |
U |
Avvio_senza_chat |
[ ] |
| VM-02 |
All'avvio si riapre la chat più recente |
U |
Avvio_riapre_ultima |
[ ] |
| VM-03 |
CanSend falso se il testo è vuoto o solo spazi, o se occupato |
U |
CanSend |
[ ] |
| VM-04 |
Invio: il messaggio utente compare e viene salvato prima della risposta |
U |
Messaggio_salvato_prima_della_risposta |
[ ] |
| VM-05 |
Risposta riuscita: aggiunta come "ai", started diventa vero, il secondo invio usa --resume |
U |
Risposta_e_ripresa |
[ ] |
| VM-06 |
Risposta fallita (exit ≠ 0): messaggio "err" con codice e stderr; started resta falso e il tentativo successivo usa ancora --session-id |
U |
Errore_non_avvia_la_sessione |
[ ] |
| VM-07 |
claude assente: messaggio "'claude' non trovato nel PATH." |
U |
Claude_assente_messaggio |
[ ] |
| VM-08 |
Durante l'attesa: Invia e Nuova chat disabilitati; aprire/eliminare è ignorato |
U |
Occupato_blocca_azioni |
[ ] |
| VM-09 |
Modello: "Predefinito" ⇒ nessun flag; modello scelto ⇒ ID; "Altro ID…" ⇒ testo libero ripulito |
U |
Scelta_modello |
[ ] |
| VM-10 |
Effort: "Predefinito" ⇒ nessun flag; altrimenti il valore |
U |
Scelta_effort |
[ ] |
| VM-11 |
Nuova chat: svuota la vista, nuovo guid, started falso, elenco aggiornato |
U |
Nuova_chat |
[ ] |
| VM-12 |
Errore di I/O nel salvataggio non interrompe l'invio né cancella i messaggi |
U |
Salvataggio_fallito_non_perde_chat |
[ ] |
| VM-13 |
Apertura chat: carica messaggi, started e id; chat inesistente ⇒ elenco ricaricato |
U |
Apri_chat |
[ ] |
| VM-14 |
Eliminazione: con conferma rimuove; senza conferma non fa nulla; se è la chat aperta parte una nuova |
U |
Elimina_con_e_senza_conferma |
[ ] |
| VM-15 |
Suggerimento: precompila il campo e chiede il focus |
U |
Suggerimento_precompila |
[ ] |
| VM-16 |
Barra laterale: il comando commuta SidebarOpen |
U |
Barra_laterale |
[ ] |
| VM-17 |
Copia: il comando passa il testo alla funzione degli appunti |
U |
Copia_negli_appunti |
[ ] |
| VM-18 |
Notifiche di proprietà: HasMessages, ShowEmpty, CanSend, IsCustomModel cambiano quando devono |
U |
Notifiche_proprieta |
[ ] |
| VM-19 |
Il titolo e la data dell'elenco riflettono l'ultimo scambio; la chat aperta è marcata attiva |
U |
Elenco_chat_attiva |
[ ] |
Renderer markdown — Gui/MarkdownView.cs
| ID |
Requisito |
Liv. |
Test |
|
| MD-01 |
Sorgente vuota o nulla ⇒ nessun contenuto, senza errori |
R |
Sorgente_vuota |
[ ] |
| MD-02 |
Titoli h1–h6 con dimensioni decrescenti e peso semi-grassetto |
R |
Titoli |
[ ] |
| MD-03 |
Paragrafi; a capo morbido = spazio, a capo forzato = riga nuova |
R |
A_capo |
[ ] |
| MD-04 |
Grassetto, corsivo, barrato, anche annidati |
R |
Enfasi |
[ ] |
| MD-05 |
Codice inline in carattere monospazio con sfondo |
R |
Codice_inline |
[ ] |
| MD-06 |
Blocco di codice: monospazio, scorrimento orizzontale, pulsante Copia che copia solo il codice |
R/G |
Blocco_codice_e_copia |
[ ] |
| MD-07 |
Liste puntate e numerate (rispetta il numero iniziale), annidate |
R |
Liste |
[ ] |
| MD-08 |
Citazioni con barra laterale, anche annidate |
R |
Citazioni |
[ ] |
| MD-09 |
Tabelle: intestazione in evidenza, allineamenti sinistra/centro/destra, righe irregolari |
R |
Tabelle |
[ ] |
| MD-10 |
Linea orizzontale |
R |
Linea_orizzontale |
[ ] |
| MD-11 |
Link: colore d'accento e sottolineatura; il clic apre solo http(s) |
R |
Link_http_https |
[ ] |
| MD-12 |
Link: nessuna apertura se c'è una selezione in corso; cursore a mano sopra il link |
R |
Link_con_selezione |
[ ] |
| MD-13 |
Posizioni dei link corrette con enfasi, codice inline e a capo prima del link |
R |
Intervalli_link |
[ ] |
| MD-14 |
Immagini: si mostra il testo alternativo, non si scarica nulla |
R |
Immagini_come_testo |
[ ] |
| MD-15 |
HTML grezzo disabilitato: i tag compaiono come testo, non come elementi |
R |
Html_disabilitato |
[ ] |
| MD-16 |
Cambio di tema (chiaro/scuro): i colori si aggiornano ricostruendo la vista |
R |
Cambio_tema |
[ ] |
| MD-17 |
Markdown malformato o blocchi sconosciuti non fanno crashare |
R |
Markdown_malformato |
[ ] |
| MD-18 |
Testo selezionabile |
R |
Testo_selezionabile |
[ ] |
Finestra e interazione — Gui/MainWindow*, Gui/App.axaml, Gui/ConfirmDialog.cs
| ID |
Requisito |
Liv. |
Test |
|
| UI-01 |
La finestra si apre e mostra la schermata iniziale con quattro suggerimenti |
G |
Apertura_schermata_iniziale |
[ ] |
| UI-02 |
Proporzioni 16:10, 75% dell'area utile (max 1440), minimo 900x600; senza schermo primario 1280x800 |
G |
Dimensioni_finestra |
[ ] |
| UI-03 |
Invio invia, Maiusc+Invio va a capo, nessun invio a campo vuoto |
G |
Tasti_invio |
[ ] |
| UI-04 |
Il pulsante Invia è disabilitato con campo vuoto o in attesa |
G |
Pulsante_invia |
[ ] |
| UI-05 |
I messaggi hanno aspetto per ruolo: utente, Claude (con Copia), errore |
G |
Template_per_ruolo |
[ ] |
| UI-06 |
La conversazione scorre in fondo a ogni nuovo messaggio |
G |
Scorrimento_in_fondo |
[ ] |
| UI-07 |
Indicatore di attesa visibile solo durante l'elaborazione |
G |
Indicatore_attesa |
[ ] |
| UI-08 |
Elenco chat: voce attiva evidenziata, clic apre, ✕ elimina; "Nessuna chat salvata" se vuoto |
G |
Elenco_chat |
[ ] |
| UI-09 |
Il campo "Altro ID…" compare solo con quella voce del modello |
G |
Campo_modello_personalizzato |
[ ] |
| UI-10 |
Il pulsante a tre linee mostra/nasconde la barra laterale |
G |
Mostra_nascondi_barra |
[ ] |
| UI-11 |
Dialogo di conferma: restituisce vero con Elimina, falso con Annulla o chiusura |
G |
Dialogo_conferma |
[ ] |
| UI-12 |
Accessibilità: ogni pulsante a sola icona e il campo messaggio hanno AutomationProperties.Name |
G |
Nomi_accessibili |
[ ] |
| UI-13 |
Tema: sia il chiaro sia lo scuro risolvono tutti i token usati (nessuna risorsa mancante) |
G |
Token_tema_completi |
[ ] |
| UI-14 |
Focus sul campo messaggio all'apertura, dopo la risposta e dopo "Nuova chat" |
G |
Focus_campo |
[ ] |
| UI-15 |
Il nome dell'app compare nel titolo della finestra e nella barra laterale |
G |
Nome_app_visibile |
[ ] |
Eseguibile pubblicato
| ID |
Requisito |
Liv. |
Test |
|
| PUB-01 |
Il publish single-file linux-x64 si compila e la CLI risponde con FakeClaude |
E |
Publish_linux_smoke |
[ ] |
| PUB-02 |
Il publish single-file win-x64 si compila e la CLI risponde con FakeClaude |
E |
Publish_windows_smoke |
[ ] |
| PUB-03 |
Le librerie native (Skia/HarfBuzz) vengono estratte e la GUI si avvia (provata con timeout) |
E |
Gui_si_avvia |
[ ] |
Più motori (ADR-0002) — da compilare quando si implementa la Fase 4
Per ogni motore, la stessa batteria di contratto:
| ID |
Requisito |
Liv. |
|
| EN-01 |
Argomenti del primo messaggio e della ripresa |
U |
[ ] |
| EN-02 |
Rilevamento nel PATH; assente ⇒ disabilitato e messaggio chiaro |
U/P |
[ ] |
| EN-03 |
Lettura dell'id di sessione dall'output (Codex) |
U |
[ ] |
| EN-04 |
Parser dell'output → markdown, con output di esempio reali salvati nei test |
U |
[ ] |
| EN-05 |
Modelli ed effort mostrati secondo il motore |
U/G |
[ ] |
| EN-06 |
Il JSON della chat memorizza il motore; cambiare motore apre una nuova chat |
U |
[ ] |
| EN-07 |
Politica dei permessi: nessun flag che salta i controlli senza scelta esplicita |
U |
[ ] |
| EN-08 |
Impostazioni persistite e rilette |
U |
[ ] |
| EN-09 |
Gestione del blocco di agy -p con output rediretto (timeout, errore chiaro) |
P |
[ ] |
Come si eseguono (a implementazione avvenuta)
Comandi previsti, da confermare con ADR-0003 → "Da verificare":
- Tutti i test:
dotnet test
- Con copertura e soglie:
dotnet test --collect:"XPlat Code Coverage" e controllo delle soglie della tabella sopra
- Solo una categoria:
dotnet test --filter "Category=Unit" (o Gui, Process, E2E)
Su Linux i test GUI girano senza display (Headless).
Definition of Done di una modifica