文件
工具的全部功能,依人們實際會問的問題來組織。儲存庫中的 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。抽取結果來自種子 |
--boundary <size> | 圍繞一個限制的三個檔案:小一位元組、恰好等於限制、大一位元組 |
--count <n> | 產生多少個檔案。預設 1 |
--name <template> | 檔名範本,例如 invoice_{index:04}.txt |
--out <dir> | 寫入的目錄 |
--seed <n> | 本次執行的種子。相同的種子得到相同的位元組 |
--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 檔案。把它與測試放在一起提交,fixture 就不再是儲存庫裡的二進位檔,任何人都可以用一個只有幾百個字元的檔案逐位元組重建它們。
# 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
每個 target 必須恰好有 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,也就是配方中產生該檔案的 target 的 id,summary.by_target 則統計每個 target
產生的檔案數。因此有多個 target 的配方可以逐個 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 停止的執行仍會留下清單,也絕不會留下寫了一半的檔案,所以被取消的工作仍可由下一次執行清理。
適用於 GitHub Actions 和 GitLab CI 的現成工作流程:如何在 CI 流程中產生測試檔案。
有桌面視窗嗎?
有,它就是在同一個引擎上加了一個視窗,用於不走腳本的測試。它不是縮水版:有測試逐項比對這兩種介面,只有其中一方能做的事必須被宣告並說明理由,而不是悄悄地漸行漸遠。
畫面有單批產生、預設集、同時多批與關於。它會在寫入任何內容之前顯示一次執行的開銷,執行時回報進度,並且可以在中途取消而不會留下寫了一半的檔案。它目前還不能開啟配方檔,配方暫時只屬於命令列,視窗透過表單來建立批次。