Документація
Усе, що робить інструмент, розкладено за питаннями, з якими люди справді приходять. README у репозиторії - повний довідник, і він завжди відповідає завантаженій вами збірці.
Які є команди?
Кожна робить одну справу:
tfg generate створити файли за рецептом або за прапорцями
tfg validate перевірити рецепт, нічого не записуючи
tfg verify звірити каталог із маніфестом
tfg cleanup видалити файли, перелічені в маніфесті
tfg recipe fmt вивести рецепт у усталеному вигляді
tfg preset зібрати набір файлів за іменованим тестовим питанням
tfg formats перелічити формати цієї збірки
tfg damage перелічити способи, якими ця збірка може навмисно зіпсувати файл
tfg tool невеликі інструменти для вже наявних файлів
tfg version вивести версію інструмента
tfg license вивести ліцензію та що вона означає для створених файлів
Як створити один файл точного розміру?
Укажіть формат, розмір і місце призначення. Розміри рахуються по 1024, тому 2mb - це
2097152 байти. Підійде й просте число байтів, тож --size 10485761 запитує рівно
стільки.
tfg generate --format png --size 2mb --out ./out
Корисні прапорці команди generate:
| Прапорець | Що робить |
|---|---|
--format <id> | формат файлів, наприклад txt |
--size <size> | точний розмір кожного файлу, наприклад 10mb або просте число байтів |
--size-range <a-b> | розмір, що вибирається для кожного файлу з діапазону, наприклад 1kb-8kb. Вибір іде від seed |
--boundary <size> | три файли навколо ліміту: на байт менше, сам ліміт, на байт більше |
--count <n> | скільки файлів створити. За замовчуванням 1 |
--name <template> | шаблон імені, наприклад invoice_{index:04}.txt |
--out <dir> | каталог, у який записувати |
--seed <n> | seed запуску. Той самий seed дає ті самі байти |
--set <k>=<v> | налаштування формату, можна повторювати |
--damage <name> | навмисно зіпсувати файли, можна повторювати, застосовується по порядку. Список виводить tfg damage |
--expected <outcome> | accept, reject, sanitize або unspecified |
--dry-run | порахувати й показати, нічого не записуючи |
--json | записати маніфест у стандартний вивід |
Як зробити навмисно зламаний файл?
Будь-який інший файл, що його записує цей інструмент, коректний за побудовою, і це відповідає на два
з трьох питань, які ставить перевірка завантаження. --damage відповідає на третє -
чи відкривається файл узагалі. Файл створюється як зазвичай, а потім псується, тому в нього
лишається запитаний розмір.
tfg generate --format png --size 2mb --damage zero-head --out ./out
tfg generate --format png --size 2mb --damage zero-head:bytes=16 --out ./out
Налаштування вказуються після двокрапки. Прапорець можна повторювати, і порядок запису - це порядок
застосування. tfg damage перелічує, що вміє ця збірка та що приймає кожен вид
пошкодження.
У рецепті ключ - це список імен або налаштувань:
targets:
- id: broken
format: png
count: 5
size: 2mb
damage:
- zero-head
- type: zero-head
bytes: 16
Пошкоджений файл отримує в маніфесті expected: reject із записаним поруч пошкодженням.
Дві речі відхиляються до запису чого-небудь, бо кожна залишила б на диску файл, неправильно
описаний маніфестом:
- файл менший, ніж потрібно пошкодженню, бо він вийшов би без змін
-
expected: acceptпоруч із пошкодженням, бо цьому не міг би відповідати жоден файл. Пишітьsanitize, якщо тестована система має полагодити файл, абоunspecified, якщо саме це питання ви й ставите
Третє наперед дізнатися не можна. Якщо пошкодження виконується й не змінює жодного байта, такий файл відкидається, а не записується - запуск триває, повідомляє, що це був за файл, і завершується кодом часткового завершення.
Крок за кроком, з тестом, який читає маніфест: як зробити пошкоджений файл для тестів.
Як виглядає рецепт?
Рецепт - це файл YAML, що описує цілий запуск. Закомітьте його поряд із тестами, і фікстури перестануть бути бінарними файлами у вашому репозиторії - будь-хто зможе відтворити їх байт у байт із файлу в кілька сотень символів.
# 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
Кожній цілі потрібен рівно один із ключів size, size-range,
boundary або contains. Два - це помилка, і жодного - теж. Недійсний
рецепт записує жодного файлу і повідомляє про всі проблеми одразу, а не лише
про першу, щоразу називаючи налаштування, якого вона стосується.
Як оголосити, що моя система має робити з файлом?
Коротка форма, коли досить результату, і довга, коли важлива причина:
expected: accept
expected:
outcome: reject
reason: size_limit
Результати - accept, reject, sanitize і
unspecified. Причини утворюють закритий список, щоб звіт міг за ними групувати:
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 і size_zero.
Причина називає чинне правило, а не вердикт. Тому та сама причина може стояти під
будь-яким результатом - файл на байт менший за ліміт отримує accept, а правило, про
яке йдеться, усе одно size_limit.
Що в маніфесті?
Він записується поряд із файлами наприкінці кожного запуску, зокрема й перерваного. Один запис на файл:
{
"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"
}
}
]
}
recipe_hash додається, якщо запуск був за рецептом, а preset з
overrides - якщо за пресетом, тож маніфест завжди можна простежити до того, що його
створило.
Кожен запис також містить target_id - id цілі рецепта, що створила файл, а
summary.by_target рахує файли кожної цілі. Рецепт із кількома цілями можна тому
перевірити ціль за ціллю, не читаючи імена файлів.
Що таке пресет?
Готовий набір файлів, що відповідає на поширене тестове питання, щоб вам не доводилося проєктувати
набір самостійно. Пресети - звичайні рецепти всередині, а eject виводить рецепт,
щоб ви могли його відредагувати. Кожен пресет має окрему сторінку про
те, що він зазвичай знаходить, що входить у набір і які налаштування приймає.
-
Чи пройде коректний файл, настільки малий, наскільки дозволяє формат?
empty-and-minimal -
Чи збереже, покаже та поверне моя система ім'я файлу, якого не очікувала?
filename-handling -
Чи застосовується ліміт розміру саме там, де його оголошено?
size-boundaries -
Чи переживе мій імпорт таблиць те, що експортують справжні інструменти?
tabular-import -
Чи знає мій читач, у якому кодуванні файл, чи вгадує?
text-encoding -
Чи приймає моя форма завантаження те, що має, і відхиляє решту?
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 повідомляє, скільки коштував би набір, перш ніж ви його зберете, і прямо каже,
коли число - наша тимчасова підстановка, а не ваш ліміт.
Що означають коди завершення?
Кожен кінець має власний код, машиночитний вивід іде в стандартний вивід, а невдалий запуск нічого туди не друкує. Таблиця - заморожений контракт: зміна значення коду вимагає підвищення мажорної версії.
| Код | Значення |
|---|---|
0 |
Усе спрацювало. |
1 |
Непередбачена помилка всередині інструмента. |
2 |
Неправильна команда або прапорець. |
3 |
Рецепт недійсний. |
4 |
Формат не може зробити те, що просили. |
5 |
Не вдалося прочитати або записати. |
6 |
Недостатньо місця на диску. |
7 |
verify виявив розбіжність. |
8 |
Запуск завершено, але створено не все. |
130 |
Перервано за допомогою Ctrl+C. |
143 |
Зупинено сигналом, так виглядає тайм-аут у 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
Запуск, зупинений за допомогою Ctrl+C, усе одно залишає маніфест і ніколи не залишає наполовину записаного файлу, тож скасоване завдання може бути прибране наступним.
Готові workflow для GitHub Actions і GitLab CI: як генерувати тестові файли в конвеєрі CI.
Чи є десктопне вікно?
Так, той самий рушій із вікном згори, для тестування, яке не автоматизується. Це не урізана версія: тест порівнює два інтерфейси можливість за можливістю, і все, що вміє лише один із них, має бути оголошене й обґрунтоване, а не тихо розходитися.
Екрани: одна партія, пресети, кілька партій одночасно та про програму. Вікно показує, скільки коштував би запуск, перш ніж щось записати, відображає перебіг роботи й може бути скасоване на півдорозі без наполовину записаного файлу. Файл рецепта воно поки не відкриває - рецепти поки справа командного рядка, а вікно збирає свої партії у формі.