Documentazione
Tutto ciò che fa lo strumento, organizzato come le domande con cui le persone arrivano davvero. Il README nel repository è il riferimento completo e corrisponde sempre alla build che hai scaricato.
Quali comandi esistono?
Ognuno fa una cosa sola:
tfg generate produrre file, da una ricetta o da opzioni
tfg validate controllare una ricetta senza scrivere nulla
tfg verify controllare una directory rispetto a un manifest
tfg cleanup rimuovere i file elencati da un manifest
tfg recipe fmt stampare una ricetta nella sua forma normalizzata
tfg preset costruire un set di file a partire da una domanda di test con nome
tfg formats elencare i formati supportati da questa versione
tfg damage elencare i modi in cui questa versione può rompere un file di proposito
tfg tool piccole utilità per file che hai già
tfg version stampare la versione dello strumento
tfg license stampare la licenza e cosa significa per i file generati
Come genero un singolo file di dimensione esatta?
Indica il formato, la dimensione e la destinazione. Le dimensioni si contano a 1024, quindi
2mb sono 2097152 byte. Funziona anche un semplice numero di byte, quindi
--size 10485761 chiede esattamente quel numero.
tfg generate --format png --size 2mb --out ./out
Le opzioni utili di generate:
| Opzione | Cosa fa |
|---|---|
--format <id> | formato dei file, per esempio txt |
--size <size> | dimensione esatta di ogni file, come 10mb o un semplice numero di byte |
--size-range <a-b> | una dimensione estratta per file da un intervallo, come 1kb-8kb. L'estrazione viene dal seed |
--boundary <size> | tre file attorno a un limite: un byte sotto, il limite, un byte sopra |
--count <n> | quanti file produrre. Predefinito 1 |
--name <template> | modello del nome, per esempio invoice_{index:04}.txt |
--out <dir> | directory in cui scrivere |
--seed <n> | seed dell'esecuzione. Lo stesso seed dà gli stessi byte |
--set <k>=<v> | un'impostazione di formato, ripetibile |
--damage <name> | rompere i file di proposito, ripetibile e applicato in ordine. Esegui tfg damage per l'elenco |
--expected <outcome> | accept, reject, sanitize oppure unspecified |
--dry-run | contare e mostrare, senza scrivere assolutamente nulla |
--json | scrivere il manifest sullo standard output |
Come faccio un file rotto di proposito?
Ogni altro file che questo strumento scrive è corretto per costruzione, il che risponde a due delle
tre domande che pone un validatore di upload. --damage risponde alla terza - il
file si apre, almeno. Il file viene prodotto normalmente e poi rotto, quindi ha ancora la
dimensione che hai chiesto.
tfg generate --format png --size 2mb --damage zero-head --out ./out
tfg generate --format png --size 2mb --damage zero-head:bytes=16 --out ./out
Le impostazioni vanno dopo i due punti. L'opzione si ripete, e l'ordine in cui le scrivi è l'ordine
in cui vengono applicate. tfg damage elenca cosa può fare questa versione e cosa
accetta ciascuno.
In una ricetta la chiave è un elenco, di nomi o di impostazioni:
targets:
- id: broken
format: png
count: 5
size: 2mb
damage:
- zero-head
- type: zero-head
bytes: 16
Un file danneggiato riceve expected: reject nel manifest, con il danno registrato
accanto. Due cose vengono rifiutate prima di scrivere qualsiasi cosa, perché ciascuna metterebbe
su disco un file che il manifest descrive in modo sbagliato:
- un file più piccolo di quanto serve al danno, perché uscirebbe invariato
-
expected: acceptaccanto a un danno, perché nulla potrebbe soddisfarlo. Scrivisanitizese il sistema sotto test deve riparare il file, oppureunspecifiedse è proprio la domanda che stai ponendo
Una terza non si può sapere in anticipo. Se un danno viene eseguito e non sposta alcun byte, quel file viene scartato invece di essere scritto - l'esecuzione prosegue, dice di quale file si trattava e termina con il codice di uscita parziale.
Passo dopo passo, con un test che legge il manifest: come creare un file corrotto per i test.
Che aspetto ha una ricetta?
Una ricetta è un file YAML che descrive un'intera esecuzione. Committala accanto ai tuoi test e le fixture smettono di essere binari nel tuo repository - chiunque può ricostruirle, byte per byte, da un file di poche centinaia di caratteri.
# fixtures.yaml
version: 1
seed: 7741
defaults:
label: true
targets:
- id: invoices
format: pdf
count: 25
size: 300kb
name: invoice_{index:04}.pdf
properties:
pages: 3
page_size: a4
expected: accept
- id: over_the_limit
format: png
count: 2
size: 12mb
expected:
outcome: reject
reason: size_limit
- id: bundle
format: zip
contains:
- format: txt
count: 200
size: 4kb
output:
dir: ./fixtures
manifest: manifest.json
tfg validate fixtures.yaml
tfg generate fixtures.yaml
Ogni target richiede esattamente una di queste chiavi: size, size-range,
boundary o contains. Due è un errore, e anche nessuna. Una ricetta non
valida scrive nessun file e segnala tutti i problemi insieme invece del solo
primo, ognuno con il nome dell'impostazione a cui si riferisce.
Come dichiaro cosa deve fare il mio sistema con un file?
Forma breve quando basta l'esito, forma lunga quando conta il motivo:
expected: accept
expected:
outcome: reject
reason: size_limit
Gli esiti sono accept, reject, sanitize e
unspecified. I motivi sono un elenco chiuso così un report può raggrupparli:
content_malformed, count_limit, dimensions_limit,
duplicate, encoding_invalid, extension_rule,
filename_invalid, filename_too_long, filename_traversal,
malware_signature, mime_mismatch, nesting_depth,
none, size_limit e size_zero.
Un motivo nomina la regola in gioco, non il verdetto. Ecco perché lo stesso motivo
può stare sotto l'uno o l'altro esito - un file un byte sotto un limite è accept, e
la regola in questione resta size_limit.
Cosa c'è nel manifest?
Viene scritto accanto ai file alla fine di ogni esecuzione, compresa un'esecuzione interrotta. Una voce per file:
{
"manifest_version": "1.0",
"tool": { "name": "testing-files-generator", "version": "0.4.0" },
"run": {
"id": "run_b359aa8d94",
"seed": 0,
"command": "tfg generate --format png --size 2mb --out ./out",
"platform": { "os": "windows", "arch": "amd64" },
"complete": true
},
"summary": {
"file_count": 1,
"total_bytes": 2097152,
"by_format": { "png": 1 },
"by_expected": { "unspecified": 1 }
},
"files": [
{
"path": "files_0001.png",
"bytes": 2097152,
"format": "png",
"fidelity": "full",
"determinism": "byte",
"seed": "8dc2d18c",
"hashes": { "sha256": "1a1f7c..." },
"properties": { "width": 640, "height": 480 },
"expected": {
"outcome": "unspecified",
"detail": "No expectation was declared for this file.",
"confidence": "policy_dependent"
}
}
]
}
Un recipe_hash viene aggiunto quando l'esecuzione viene da una ricetta, e
preset con overrides quando viene da un preset, così un manifest si
può sempre ricondurre a ciò che lo ha prodotto.
Ogni voce porta anche target_id, l'id del target della ricetta che ha prodotto il file,
e summary.by_target conta i file a cui è arrivato ciascun target. Una ricetta con
più target si può quindi controllare target per target senza leggere i nomi dei file.
Cos'è un preset?
Un set di file pronto che risponde a una domanda di test comune, così non devi progettare il set tu.
I preset sono ricette ordinarie sotto il cofano, e eject stampa la ricetta così
puoi modificarla da lì. Ogni preset ha una pagina tutta sua con cosa
trova di solito, cosa c'è nel set e ogni impostazione che accetta.
-
Un file valido e piccolo quanto il formato consente passa?
empty-and-minimal -
Il mio sistema salverà, mostrerà e restituirà un nome di file che non si aspettava?
filename-handling -
Un limite di dimensione viene applicato esattamente dove è dichiarato?
size-boundaries -
La mia importazione di tabelle regge a ciò che esportano gli strumenti reali?
tabular-import -
Il mio lettore sa in quale codifica è un file, o tira a indovinare?
text-encoding -
Il mio modulo di upload accetta ciò che deve e respinge il resto?
upload-validation
tfg preset list
tfg preset show size-boundaries
tfg generate --preset size-boundaries --limit 10mb --out ./edges
tfg preset eject size-boundaries > my.yaml
show ti dice quanto costerebbe il set prima di costruirlo, e dice apertamente quando un
numero è un segnaposto nostro anziché un limite tuo.
Cosa significano i codici di uscita?
Ogni conclusione ha il suo codice, l'output leggibile da macchina va sullo standard output, e un'esecuzione fallita non vi stampa nulla. La tabella è un contratto congelato - cambiare il significato di un codice richiede una versione maggiore.
| Codice | Significato |
|---|---|
0 |
Tutto ha funzionato. |
1 |
Un errore imprevisto dentro lo strumento. |
2 |
Comando od opzione errati. |
3 |
La ricetta non è valida. |
4 |
Il formato non può fare ciò che è stato chiesto. |
5 |
Una lettura o una scrittura è fallita. |
6 |
Spazio su disco insufficiente. |
7 |
verify ha trovato una discrepanza. |
8 |
L'esecuzione è terminata ma non tutto è stato prodotto. |
130 |
Interrotto con Ctrl+C. |
143 |
Fermato da un segnale, che è l'aspetto di un timeout della CI. |
- name: build the fixtures
run: tfg generate fixtures.yaml --out ./fixtures
- name: run the tests
run: pytest tests/
- name: nothing moved
run: tfg verify ./fixtures/manifest.json
Un'esecuzione fermata con Ctrl+C lascia comunque un manifest e non lascia mai un file scritto a metà, così un job annullato può ancora essere ripulito dal successivo.
Workflow pronti per GitHub Actions e GitLab CI: come generare file di test in una pipeline CI.
Esiste una finestra desktop?
Sì, lo stesso motore con una finestra sopra, per il test che non è automatizzato. Non è una versione ridotta: un test confronta le due interfacce capacità per capacità, e tutto ciò che può fare solo una delle due va dichiarato e giustificato invece di divergere in silenzio.
Le schermate sono un lotto, i preset, più lotti insieme e Informazioni. Mostra quanto costerebbe un'esecuzione prima di scrivere qualsiasi cosa, riporta l'avanzamento mentre gira e si può annullare a metà senza lasciare un file scritto a metà. Non apre ancora un file di ricetta - per ora le ricette sono una faccenda da riga di comando, e la finestra costruisce i suoi lotti nel modulo.