Testing Files Generator
Română

Documentație

Tot ce face instrumentul, aranjat ca întrebările cu care vin oamenii de fapt. README-ul din repository este referința completă și se potrivește mereu cu versiunea pe care ai descărcat-o.

Ce comenzi există?

Fiecare face un singur lucru:

tfg generate    produce fișiere, dintr-o rețetă sau din opțiuni
tfg validate    verifică o rețetă fără a scrie nimic
tfg verify      verifică un director față de un manifest
tfg cleanup     șterge fișierele pe care le listează un manifest
tfg recipe fmt  afișează o rețetă în forma ei normalizată
tfg preset      construiește un set de fișiere dintr-o întrebare de test cu nume
tfg formats     listează formatele acceptate de această versiune
tfg damage      listează modurile în care această versiune poate strica un fișier intenționat
tfg tool        mici unelte pentru fișiere pe care le ai deja
tfg version     afișează versiunea instrumentului
tfg license     afișează licența și ce înseamnă ea pentru fișierele generate

Cum generez un singur fișier de dimensiune exactă?

Spune formatul, dimensiunea și unde merge. Dimensiunile se numără din 1024 în 1024, deci 2mb sunt 2097152 octeți. Merge și un simplu număr de octeți, deci --size 10485761 cere exact atât.

tfg generate --format png --size 2mb --out ./out

Opțiunile utile ale comenzii generate:

OpțiuneCe face
--format <id>formatul fișierelor, de exemplu txt
--size <size>dimensiunea exactă a fiecărui fișier, precum 10mb sau un simplu număr de octeți
--size-range <a-b>o dimensiune extrasă pentru fiecare fișier dintr-un interval, precum 1kb-8kb. Extragerea vine din seed
--boundary <size>trei fișiere în jurul unei limite: un octet sub, limita, un octet peste
--count <n>câte fișiere să producă. Implicit 1
--name <template>șablon de nume, de exemplu invoice_{index:04}.txt
--out <dir>directorul în care se scrie
--seed <n>seed-ul rulării. Același seed dă aceiași octeți
--set <k>=<v>o setare de format, repetabilă
--damage <name>strică fișierele intenționat, repetabil și aplicat în ordine. Rulează tfg damage pentru listă
--expected <outcome>accept, reject, sanitize sau unspecified
--dry-runnumără și arată, nu scrie absolut nimic
--jsonscrie manifestul la ieșirea standard

Cum fac un fișier stricat intenționat?

Orice alt fișier scris de acest instrument este corect prin construcție, ceea ce răspunde la două din cele trei întrebări pe care le pune un validator de încărcare. --damage răspunde la a treia - se deschide oare fișierul. Fișierul este produs normal și apoi stricat, deci are în continuare dimensiunea cerută.

tfg generate --format png --size 2mb --damage zero-head --out ./out
tfg generate --format png --size 2mb --damage zero-head:bytes=16 --out ./out

Setările se pun după două puncte. Opțiunea se repetă, iar ordinea în care le scrii este ordinea în care se aplică. tfg damage listează ce poate face această versiune și ce acceptă fiecare.

Într-o rețetă cheia este o listă, de nume sau de setări:

targets:
  - id: broken
    format: png
    count: 5
    size: 2mb
    damage:
      - zero-head
      - type: zero-head
        bytes: 16

Un fișier deteriorat primește expected: reject în manifest, cu deteriorarea consemnată alături. Două lucruri sunt refuzate înainte de a se scrie ceva, pentru că fiecare ar pune pe disc un fișier pe care manifestul îl descrie greșit:

O a treia nu se poate ști dinainte. Dacă o deteriorare rulează și nu mută niciun octet, fișierul respectiv este abandonat în loc să fie scris - rularea continuă, spune care a fost fișierul și se termină cu codul de ieșire parțial.

Pas cu pas, cu un test care citește manifestul: cum faci un fișier corupt pentru teste.

Cum arată o rețetă?

O rețetă este un fișier YAML care descrie o rulare întreagă. Comite-o lângă testele tale și fixture-urile nu mai sunt binare în repository - oricine le poate reconstrui, octet cu octet, dintr-un fișier de câteva sute de caractere.

# 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

Fiecare target are nevoie de exact una dintre cheile size, size-range, boundary sau contains. Două este o eroare și la fel niciuna. O rețetă invalidă nu scrie niciun fișier și raportează toate problemele deodată, nu doar prima, fiecare numind setarea la care se referă.

Cum declar ce trebuie să facă sistemul meu cu un fișier?

Formă scurtă când rezultatul e de ajuns, formă lungă când contează motivul:

expected: accept
expected:
  outcome: reject
  reason: size_limit

Rezultatele sunt accept, reject, sanitize și unspecified. Motivele sunt o listă închisă ca un raport să poată grupa după ele: 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 și size_zero.

Un motiv numește regula în joc, nu verdictul. De aceea același motiv poate sta sub oricare dintre rezultate - un fișier cu un octet sub o limită este accept, iar regula la care se referă rămâne size_limit.

Ce conține manifestul?

Se scrie lângă fișiere la sfârșitul fiecărei rulări, inclusiv a uneia întrerupte. O intrare pentru fiecare fișier:

{
  "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"
      }
    }
  ]
}

Se adaugă un recipe_hash când rularea a venit dintr-o rețetă și preset cu overrides când a venit dintr-o presetare, astfel încât un manifest poate fi mereu urmărit până la ce l-a produs.

Fiecare intrare poartă și target_id, id-ul targetului din rețeta care a produs fișierul, iar summary.by_target numără fișierele la care a ajuns fiecare target. O rețetă cu mai multe targeturi poate fi verificată astfel target cu target, fără a citi nume de fișiere.

Ce este o presetare?

Un set de fișiere gata făcut care răspunde unei întrebări de test obișnuite, ca să nu trebuiască să proiectezi tu setul. Presetările sunt rețete obișnuite pe dedesubt, iar eject afișează rețeta ca s-o poți edita de acolo. Fiecare presetare are o pagină proprie cu ce găsește de obicei, ce este în set și fiecare setare pe care o acceptă.

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 îți spune cât ar costa setul înainte să-l construiești și spune pe față când un număr este o valoare provizorie de-a noastră, nu o limită de-a ta.

Ce înseamnă codurile de ieșire?

Fiecare final are propriul cod, ieșirea citibilă de mașină merge la ieșirea standard, iar o rulare eșuată nu tipărește nimic acolo. Tabelul este un contract înghețat - schimbarea sensului unui cod cere o versiune majoră.

Cod Semnificație
0 Totul a mers.
1 O eroare neașteptată în interiorul instrumentului.
2 Comandă sau opțiune greșită.
3 Rețeta nu este validă.
4 Formatul nu poate face ce s-a cerut.
5 O citire sau o scriere a eșuat.
6 Nu este destul spațiu pe disc.
7 verify a găsit o nepotrivire.
8 Rularea s-a terminat, dar nu s-a produs totul.
130 Întreruptă cu Ctrl+C.
143 Oprită de un semnal, așa arată o depășire de timp în 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

O rulare oprită cu Ctrl+C lasă totuși un manifest și nu lasă niciodată un fișier scris pe jumătate, așa că un job anulat poate fi curățat de următorul.

Workflow-uri gata făcute pentru GitHub Actions și GitLab CI: cum generezi fișiere de test într-un pipeline CI.

Există o fereastră desktop?

Da, același motor cu o fereastră deasupra, pentru testarea care nu e automatizată. Nu e o versiune redusă: un test compară cele două interfețe capacitate cu capacitate, iar tot ce poate face doar una dintre ele trebuie declarat și justificat, nu lăsat să divergă pe tăcute.

Ecranele sunt un lot, presetări, mai multe loturi deodată și Despre. Arată cât ar costa o rulare înainte să scrie ceva, raportează progresul cât rulează și poate fi anulată pe la jumătate fără să lase un fișier scris pe jumătate. Nu deschide încă un fișier de rețetă - rețetele sunt deocamdată treaba liniei de comandă, iar fereastra își construiește loturile în formular.