Testing Files Generator
Français

Comment fabriquer un fichier corrompu pour les tests

Un validateur à qui l'on n'a jamais montré que des fichiers sains n'a pas vraiment été testé. Voici comment obtenir un fichier cassé volontairement, qui sort à exactement la taille demandée et qui porte un manifeste disant ce que votre système doit en faire.

La réponse courte

tfg generate --format png --size 2mb --damage zero-head --out ./out écrit un PNG d'exactement 2097152 octets dont les premiers octets sont des zéros, et le manifeste à côté note que votre système doit le rejeter.

La méthode habituelle

Pourquoi un fichier corrompu à la main fait un mauvais test

Les moyens habituels sont un éditeur hexadécimal, un script qui inverse quelques octets au hasard, ou un fichier raccourci avec head ou truncate. Ça marche une fois, puis ça coûte :

Ce que vous obtenez

Un fichier abîmé garde la taille demandée

Le fichier est généré normalement puis cassé, en route vers le disque. Il garde la taille demandée, et la même commande écrit de nouveau les mêmes octets.

tfg generate --format png --size 2mb --damage zero-head --out ./out
tfg generate --format pdf --size 1mb --count 5 --damage zero-head:bytes=16 --out ./broken

Les réglages se placent après deux-points. L'option peut être répétée, et les dommages s'appliquent dans l'ordre où vous les écrivez. Ça marche avec chacun des 26 formats.

Ce qu'il sait faire

Quels dommages existe-t-il ?

Voici la liste que le programme affiche, lue dans le programme au moment de construire cette page. tfg damage affiche la même, et tfg damage <id> dit ce que prend l'un d'eux.

Dommage Ce qu'il fait aux octets Plus petit fichier Réglages
zero-head Écrase les premiers octets du fichier avec des zéros, sans toucher à sa longueur. La plupart des lecteurs regardent d'abord là, donc presque tout remarque ce dommage. 8 bytes

zero-head écrit des zéros sur le début du fichier. La plupart des lecteurs regardent d'abord là, la signature et l'en-tête qui disent ce qu'est le fichier, donc presque tout lecteur le remarque. Le texte brut et les journaux n'ont pas de signature et sont refusés eux aussi, car une suite d'octets nuls n'est pas du texte. En dessous de quatre octets, certains formats sortent avec un dommage dont aucun lecteur ne se plaint, c'est pourquoi le réglage commence à quatre.

Ce que dit le manifeste

Un manifeste qui dit ce qui doit se passer

Chaque fichier abîmé reçoit une entrée disant que votre système doit le rejeter, avec le dommage noté à côté :

"expected": {
  "outcome": "reject",
  "reason": "content_malformed",
  "confidence": "certain"
},
"damage": [
  {
    "type": "zero-head",
    "settings": {
      "bytes": "8"
    }
  }
]

Deux demandes sont refusées avant que rien ne soit écrit, car chacune laisserait sur le disque un fichier que le manifeste décrit mal :

Dans une recette

Fichiers sains et cassés dans une même exécution

Mettez les deux dans une seule recette, et le manifeste porte l'attente de chaque fichier, de sorte que le test n'a pas besoin d'une liste disant lequel est lequel :

version: 1
targets:
  - id: healthy
    format: pdf
    size: 1mb
    expected: accept
  - id: broken
    format: pdf
    size: 1mb
    damage:
      - zero-head

Dans un test

En faire un test

Le test lit le manifeste et vérifie que ce qui s'est passé est ce qui a été déclaré. Il n'a pas besoin d'une liste de noms de fichiers :

import json, os

directory = "healthy-and-broken"
manifest = json.load(open(os.path.join(directory, "manifest.json")))

for entry in manifest["files"]:
    response = upload(os.path.join(directory, entry["path"]))
    if entry["expected"]["outcome"] == "reject":
        assert not response.ok
    else:
        assert response.ok

Un bon refus est un refus net. Un message qui dit ce qui n'allait pas est la réponse voulue. Une erreur serveur, un blocage ou un fichier à moitié enregistré est le défaut que ce test existe pour trouver.

Suite

Où aller ensuite