
# اختبار المرجع

يخضع كل قرار تنفيذي في Phasis لسؤال واحد: **هل ينتج V8 المخرجات نفسها؟**

لدى JavaScript دلالات دقيقة — `NaN !== NaN`، `-0 === 0`، `[1] + 1 === "11"`، والترتيب الدقيق لتعداد الخصائص، وتوقيت المهام الدقيقة في `Promise`. وإعادة اشتقاقها بقراءة المواصفات بطيئة ومعرّضة للأخطاء. يتجاوز Phasis ذلك بالتعامل مع Node.js (V8) بوصفه مرجعًا: اكتب سيناريو JS، وشغّله عبر V8، وسجّل المخرجات كحقيقة مرجعية؛ ثم شغّله عبر Phasis، وسجّل المخرجات مجددًا؛ وقارن بينهما.

```
1. SETUP    → a JavaScript source file or snippet
2. ORACLE   → Node.js executes it, output captured as truth
3. ACTUAL   → Phasis executes it, output captured
4. COMPARE  → oracle vs actual, diff measures the gap
```

## مستويان للاختبار

### المستوى 1 — سيناريوهات مخصصة

كل سيناريو في `scenarios/` هو برنامج JS صغير ذو مخرجات معروفة. شغّل سيناريو واحدًا:

```bash
./bin/test-scenario operators/arithmetic
```

شغّلها كلها، أو فئة واحدة فقط، أو بالتوازي:

```bash
./bin/test-regression
./bin/test-regression --jobs 4
./bin/test-regression --category expressions
```

حدّث المرجع (e.g، بعد تحديث إصدار Node.js):

```bash
./bin/oracle --refresh operators/arithmetic
```

نُظّمت السيناريوهات بحسب فصول ECMAScript: الثوابت، والمعاملات، والمتغيرات، وتدفق التحكم، والدوال، والكائنات، والمصفوفات، والأصناف، والمكوّنات المضمّنة، والأخطاء، والتشغيل البيني، والحالات الطرفية.

### المستوى 2 — test262

تُسحب مجموعة المطابقة الرسمية لـ TC39 كوحدة فرعية في git ضمن `test262/`. كل اختبار يتحقق من نفسه: ينجح إذا لم يُطلق استثناءً، ويفشل إذا أطلقه (أو العكس في اختبارات `negative`). يحمّل مشغّل الاختبارات `assert.js` و`sta.js` قبل كل اختبار.

```bash
./bin/test262                                    # full suite
./bin/test262 --category built-ins/Array         # subset
./bin/test262 --jobs 4                           # parallel
./bin/test262 --failures                         # one line per failing test
./bin/compat-report                              # full COMPAT.md + compat.json
```

توجد لقطة المجموعة الكاملة في [`COMPAT.md`](https://github.com/inline0/phasis/blob/main/COMPAT.md)، ويُعاد إنشاؤها بواسطة `bin/compat-report`. وفي CI، يشغّل سير عمل `compat-matrix.yml` الاختبارات على دفعات ويحفظ النتيجة؛ ويُشغّل هذا السير يدويًا، لا مع كل دفعة تغييرات.

## فحص محلي قبل الدفع

يشغّل `./bin/verify-all` بوابة الجودة التي يفرضها CI:

```
=== PHPStan ===                  level 6, zero errors
=== Code Standards ===           PHPCS, zero warnings
=== PHPUnit ===                  unit suite passes
=== Oracle Regression ===        scenarios under `scenarios/` pass
```

لا يكفي هذا **بمفرده** — يجب أيضًا إجراء اختبارات عيّنية من test262 لأي تغيير يمس المحلّل أو المفسّر أو المكوّنات المضمّنة. وفي كل طلب سحب، يشغّل CI ‏PHPStan وPHPCS ومجموعة اختبارات الوحدة واختبار تراجع المرجع؛ كما يشغّل مجموعتي WPT والحزم الشائعة عندما يغيّر طلب السحب `src/` أو نماذجهما. مصفوفة test262 الكاملة ليست ضمن CI لطلبات السحب، لذا اختبر محليًا الفئات المتأثرة.

## لماذا ينجح هذا

إن اعتماد V8 مصدرًا للحقيقة المرجعية يزيل تقريبًا كل الحاجة إلى قراءة المواصفات خلال دورة التطوير. وأي اختلاف عن V8 يشير دائمًا إلى وجود خطأ في Phasis — وليس إلى غموض في المواصفات يمكن الجدال بشأنه. وبعد إدخال الإصلاح، تصبح اختبارات test262 المقابلة اختبارات تراجع دائمة.

معدل النجاح البالغ 100 % نتيجة لهذا الانضباط: يُقيّم كل طلب سحب بمقارنته مع V8، ويرفض CI التراجعات في مجموعات اختبارات المرجع وWPT والحزم الشائعة، وتؤكد مصفوفة test262 نتيجة المجموعة الكاملة عند تشغيلها.
