
# الاختبار

يُتحقق من Greph عبر ثلاث طبقات من الاختبارات:

1. **اختبارات الوحدة** للمكونات المنفردة (المحللات، والمتجوّلات، وبرامج الترميز، والخيارات).
2. **مجموعة اختبارات التراجع المرجعية** التي تقارن مخرجات Greph مع ملفات `grep` و`ripgrep` و`ast-grep` التنفيذية المعتمدة، ضمن مجموعة ثابتة من السيناريوهات.
3. **مصفوفة ميزات قائمة على الاختبارات المسبقة** تتحقق من النطاق المؤكد لأغلفتي `rg` و`sg`.

تشغّل CI عند كل دفع إلى `main` وعند كل طلب دمج (`.github/workflows/ci.yml`). وتشغّل معايير كتابة الشيفرة (`composer cs`) والتحليل الساكن (`composer analyse`) ومجموعتي اختبارات الوحدة والتكامل في PHPUnit (`composer test`) و`composer audit` على PHP 8.4. مجموعة الاختبارات المرجعية (`composer test:oracle`) غير مشمولة في CI، وتُعاد كتابة مصفوفة الميزات يدويًا باستخدام `php bin/feature-matrix`. تتضمن مجموعة PHPUnit اختبارًا ينشئ المصفوفة مع اعتبار `rg` و`sg` من أدوات المنبع غير متاحتين، ويتحقق من بنية التقرير، لذا لا يفشل عند تراجع اختبار مسبق واحد.

## العمل من نسخة مستنسخة

تتطلب كل المعلومات في هذه الصفحة استنساخ المستودع. منذ الإصدار 0.2.3، لا تتضمن حزمة Composer سوى `src/` والبرامج التنفيذية الأربعة؛ أما `tests/` و`scenarios/` و`benchmarks/` وسكربتات التطوير في `bin/` فمستثناة منها.

```bash
git clone https://github.com/inline0/greph
cd greph
composer install
```

## تشغيل الاختبارات

```bash
# PHPUnit unit and integration suites
composer test

# Oracle regression corpus
composer test:oracle

# Static analysis
composer analyse

# Coding standards
composer cs
composer cs:fix

# Full release-grade verification (analyse + cs + test + test:oracle)
composer verify
```

يمثل `composer verify` الحد الأدنى المطلوب لأي إصدار. إذا لم يجتز الاختبار، فالتغيير غير مكتمل.

## نموذج المرجع

يتبع Greph نموذج تحقق قائمًا على المرجع. تُشغّل ثلاثة أوامر لكل سيناريو:

1. **المرجع**: `grep` أو `ripgrep` أو `ast-grep`، مع التقاط المخرجات استنادًا إلى مجموعة السيناريوهات.
2. **الناتج الفعلي**: Greph، مع التقاط المخرجات استنادًا إلى المجموعة نفسها.
3. **أداة المقارنة**: مقارنة منظّمة تتحقق من التطابق سطرًا بسطر أو من التكافؤ الدلالي.

إذا لم يتفق Greph مع المرجع، فهذا يعني أن Greph غير صحيح. وإذا اختلف `grep` و`rg`، يسجّل السيناريو هذا الخلاف ضمن `oracle_disagreement`، ويحدد الأداة التي يتبعها Greph في `greph_follows`، ويضبط المقارنة مع الأداة الأخرى على `skip`. وكلا الاتجاهين وارد في المجموعة.

تُقارن سيناريوهات النص مع `grep` و`rg`، بينما تُقارن سيناريوهات AST وإعادة الكتابة مع `sg`. تُلتقط مخرجات المرجع مرة واحدة وتُحفظ ضمن مجلد `oracle/` الخاص بكل سيناريو، لذا لا يحتاج التشغيل المعتاد إلا إلى PHP؛ ولا تُحتاج الأدوات الخارجية إلا لالتقاط مخرجات المرجع أو تحديثها.

يوجد التنفيذ في `tests/Oracle/`، والسيناريوهات في `scenarios/text/` و`scenarios/ast/` و`scenarios/rewrite/` و`scenarios/edge/`.

## بنية السيناريو

كل سيناريو مجلد مستقل ومتكامل:

```
scenarios/text/literal-simple/
├── scenario.json     # name, category, pattern, flags, path
├── setup/            # corpus to search through
├── oracle/           # captured oracle output (grep.txt, rg.txt, rg.json, ...)
├── actual/           # captured greph output (generated, git-ignored)
└── reports/          # comparison results (generated, git-ignored)
```

يحدد `scenario.json` النمط والرايات ومسار البحث. ويضبط كائن `expectations` اختياري وضع المقارنة لكل مرجع (`exact` أو `semantic` أو `skip`)؛ وفي غيابه، تُقارن سيناريوهات النص كلًا من `grep` و`rg` بدقة، ويُقارن `rg` JSON دلاليًا، بينما تُقارن سيناريوهات AST وإعادة الكتابة مع `sg`.

## تشغيل سيناريو واحد

يحتوي المستودع على مجموعة صغيرة من أدوات CLI للعمل على سيناريوهات منفردة. وهي أدوات تطوير وليست نقاط دخول وقت التشغيل: توجد إلى جانب الملفات التنفيذية وقت التشغيل في `bin/`، لكنها غير مشمولة في حزمة Composer. تتلقى كل أداة اسم السيناريو نسبةً إلى `scenarios/`.

```bash
# Capture oracle output for a scenario (needs grep and rg, or sg)
./bin/oracle text/literal-simple

# Run greph against a scenario, capture its output
./bin/actual text/literal-simple

# Diff oracle vs actual
./bin/compare text/literal-simple

# Full pipeline: oracle (only if missing) -> actual -> compare
./bin/test-scenario text/literal-simple

# Recapture the oracle output first
./bin/test-scenario text/literal-simple --refresh
```

## تشغيل مجموعة اختبارات التراجع كاملة

```bash
# All scenarios (the same as composer test:oracle)
./bin/test-regression

# Filter by category
./bin/test-regression --category text
./bin/test-regression --category ast
./bin/test-regression --category rewrite
./bin/test-regression --category edge

# Print only failures and the summary
./bin/test-regression --fast

# Recapture every oracle before comparing
./bin/test-regression --refresh
```

تُشغّل السيناريوهات دائمًا واحدًا تلو الآخر. يُقبل `--jobs N` ويُطبع في سطر الملخص، لكنه لا يشغّل أي شيء بالتوازي ([#7](https://github.com/inline0/greph/issues/7)). وفي النسخة المستنسخة حديثًا، يفشل `text/no-ignore` و`text/explicit-file-input` لأن ملفات التجهيزات في `setup/vendor/` غير محفوظة في المستودع ([#6](https://github.com/inline0/greph/issues/6)).

مجموعة اختبارات التراجع هي معيار قبول السلوك الجديد. يتطلب أي راية جديدة أو حالة طرفية جديدة أو إصلاح لخلل جديد سيناريو يحدد السلوك المتوقع بالاستناد إلى مرجع.

## إعداد تقارير الامتثال

```bash
./bin/verify-compliance
```

لا يشغّل `verify-compliance` أي شيء بنفسه. بل يقرأ ملفات المرجع والنتائج الفعلية والتقارير التي خلّفها آخر تشغيل للسيناريو، ثم يطبع السيناريوهات الناجحة والفاشلة وتلك التي لا يتوفر لها تقرير بعد. شغّل `./bin/test-regression` أولًا. يكتب `--output report.json` التقرير أيضًا في JSON. هذا هو الأمر المناسب لمعرفة ما إذا كان الفرع الحالي جاهزًا للإصدار.

## سير عمل التطوير القائم على الاختبارات

عند إضافة ميزة:

1. اكتب مجلد سيناريو يتضمن مجموعة الاختبارات والرايات التي تختبر السلوك الجديد.
2. شغّل `./bin/oracle <scenario>` لالتقاط مخرجات الأداة المعتمدة.
3. نفّذ الميزة في `src/`.
4. شغّل `./bin/test-scenario <scenario>` للتحقق من تطابق Greph مع المرجع.
5. شغّل `./bin/test-regression --fast` للتأكد من عدم تراجع أي شيء آخر.
6. شغّل `composer verify` قبل الإيداع.

عند إصلاح خلل:

1. التقط المدخل الذي يسبب الفشل كسيناريو.
2. تحقق من أن المرجع ينتج المخرجات المتوقعة.
3. تحقق من أن Greph لا ينتجها.
4. أصلح الخلل.
5. تحقق من أن Greph يطابق المرجع الآن.
6. شغّل `composer verify`.

يبقى السيناريو في مجموعة الاختبارات دائمًا، لذا لا يمكن أن يعود الخلل دون أن يفشل `composer test:oracle` (و`composer verify`).
