Testing Files Generator
العربية

التوثيق

كل ما تفعله الأداة، مرتبًا على هيئة الأسئلة التي يأتي بها الناس فعلًا. ملف 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 في البيان، مع تسجيل الإتلاف بجانبه. يُرفض أمران قبل كتابة أي شيء، لأن كلًّا منهما كان سيضع على القرص ملفًا يصفه البيان وصفًا خاطئًا:

أما الثالث فلا يمكن معرفته مسبقًا. إذا نُفّذ إتلاف ولم يحرّك أي بايت، يُسقَط ذلك الملف بدل كتابته، ويستمر التشغيل ويذكر أي ملف كان، وينتهي برمز الخروج الجزئي.

خطوة بخطوة، مع اختبار يقرأ البيان: كيف تصنع ملفًا تالفًا للاختبار.

كيف تبدو الوصفة؟

الوصفة ملف 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 الوصفة لتعدّلها من هناك. لكل إعداد مسبق صفحة خاصة تذكر ما يكتشفه عادةً، وما في المجموعة، وكل إعداد يقبله.

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.

هل توجد نافذة سطح مكتب؟

نعم، المحرك نفسه بنافذة فوقه، للاختبار الذي لا يُكتب له سكربت. وهي ليست نسخة مبتورة: يقارن اختبار الواجهتين ميزةً ميزة، وكل ما تستطيع إحداهما فعله دون الأخرى يجب أن يُعلَن ويُبرَّر بدل أن يتباعدا بصمت.

الشاشات هي دفعة واحدة، والإعدادات المسبقة، وعدة دفعات معًا، وحول. تُظهر كلفة التشغيل قبل كتابة أي شيء، وتبلّغ عن التقدم أثناء العمل، ويمكن إلغاؤها في منتصف الطريق دون ترك ملف مكتوب نصفه. لا تفتح ملف وصفة بعد، فالوصفات شأن سطر الأوامر حاليًا، وتبني النافذة دفعاتها في النموذج.