التوثيق
كل ما تفعله الأداة، مرتبًا على هيئة الأسئلة التي يأتي بها الناس فعلًا. ملف 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 يصف تشغيلًا كاملًا. أودعها بجانب اختباراتك فتتوقف بيانات الاختبار عن كونها ملفات ثنائية في مستودعك، ويستطيع أي شخص إعادة بنائها، بايتًا ببايت، من ملف بضع مئات من الأحرف.
# 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، وهو معرّف الهدف في الوصفة الذي أنتج الملف، ويحصي
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 يترك بيانًا ولا يترك أبدًا ملفًا مكتوبًا نصفه، لذا يمكن للمهمة التالية أن تنظّف مهمة أُلغيت.
مسارات عمل جاهزة لـ GitHub Actions وGitLab CI: كيف تولّد ملفات الاختبار في خط CI.
هل توجد نافذة سطح مكتب؟
نعم، المحرك نفسه بنافذة فوقه، للاختبار الذي لا يُكتب له سكربت. وهي ليست نسخة مبتورة: يقارن اختبار الواجهتين ميزةً ميزة، وكل ما تستطيع إحداهما فعله دون الأخرى يجب أن يُعلَن ويُبرَّر بدل أن يتباعدا بصمت.
الشاشات هي دفعة واحدة، والإعدادات المسبقة، وعدة دفعات معًا، وحول. تُظهر كلفة التشغيل قبل كتابة أي شيء، وتبلّغ عن التقدم أثناء العمل، ويمكن إلغاؤها في منتصف الطريق دون ترك ملف مكتوب نصفه. لا تفتح ملف وصفة بعد، فالوصفات شأن سطر الأوامر حاليًا، وتبني النافذة دفعاتها في النموذج.