العرضar

Errors and testing

Error handling#

فابر تفصل ثلاثة أفكار مترابطة تدمجها لغات كثيرة في شكل واحد:

Constructالمعنى
→ Tقناة عودة النجاح المعتادة
T ∪ نوع_لاشيءغياب في نطاق قيمة النجاح
⇥ Eقناة خروج بديلة قابلة للاسترداد للأخطاء

عودة طبيعية#

دالة porta(عدد x) → عدد {
    إذا x ≺ 0 إذن أعد 0
    أعد x * 2
}

دوال قابلة للفشل#

استخدم ⇥ حين يمكن لدالة أن تخرج عبر قناة خطأ:

دالة divide(عدد a, عدد b) → عدد ⇥ نص {
    إذا b ≡ 0 {
        ارم "division by zero"
    }
    أعد a / b
}

رمي — ارم#

ارم ترسل قيمة على قناة الخطأ:

دالة exigePositivum(عدد value) → فراغ ⇥ نص {
    إذا value ≺ 0 {
        ارم "negative value"
    }
}

استرداد — افعل / التقط#

يسترد المستدعون محليًا بكتلة افعل ومعالج التقط:

دالة divide(عدد a, عدد b) → عدد {
    إذا b ≡ 0 إذن أعد 0
    أعد a / b
}

دالة tutum(عدد a, عدد b) → عدد {
    افعل {
        أعد divide(a, b)
    }
    التقط err {
        نبه err
        أعد 0
    }
}

لا يُعد الاستدعاء المباشر القابل للفشل تعبيرًا عاديًا. ضع استدعاءات الدوال من النمط → T ⇥ E داخل حدود افعل / التقط نشطة.

استرداد تحويل مضمن#

يمكن لـ ⊥ أيضًا تحديد قيمة استرداد مضمنة على تحويلات ↦:

بداية {
    ثابت نص raw ← "42"
    ثابت _ n ← raw ↦ عدد ⊥ 0
}

تأثير قابل للفشل فقط#

للدوال التي تخطئ لكن لا تعيد قيمة نجاح، احذف → T:

دالة exigePositivum(عدد value) → فراغ ⇥ نص {
    إذا value ≺ 0 {
        ارم "negative value"
    }
}

الحالة الراهنة#

→ و أعد و ⇥ و ارم و افعل / التقط هي أسطح نحوية ومدققة حية. خفض Rust و Go لسلوك ⇥ / ارم / التقط الكامل وقت التشغيل لا يزال فجوة خلفية — فهذه تجتاز فحص النمط لكنها لا تصدر بعد شيفرة وقت تشغيل قابلة للفشل إلى كل الأهداف.

Inline testing#

تمتلك Faber إطار عمل اختبارات من الدرجة الأولى مدمجًا في اللغة بثلاث كلمات مفتاحية: مختبر تُعلن عن مجموعة اختبارات، واختبر تُعلن عن حالة اختبار مفردة، وأكد تؤكد صحة شرط. تعيش الاختبارات في نفس الملف مع الشيفرة التي تختبرها، وتُشغَّل عبر faber test، وتدعم نفس خط أنابيب التصريف الخاص بشيفرة الإنتاج — واعية بالإعدادات المحلية، مدققة الأنواع، ومتعددة الأهداف.

الكلمات المفتاحية الثلاث#

الكلمة المفتاحيةالدورالمكافئ التقريبي
مختبرتُعلن عن مجموعة اختبارات مسماةdescribe، #[cfg(test)] mod
اختبرتُعلن عن حالة اختبار مفردةit، #[test]
أكدتؤكد صحة شرط أثناء التنفيذassert!، assert_eq!

مختبر — مجموعة الاختبارات#

تجمّع كتلة مختبر حالات الاختبار المرتبطة ببعضها. يمكن تداخل المجموعات لتنظيم الاختبارات بشكل هرمي:

مختبر "arithmetica" {
    اختبر "unum plus unum" {
        أكد 1 + 1 ≡ 2
    }

    اختبر "multiplicatio" {
        أكد 3 * 4 ≡ 12
    }

    مختبر "implicata" {
        اختبر "comparatio" {
            ثابت _ x ← 10
            أكد x ≥ 10
        }
    }
}

اختبر — حالة الاختبار#

تحتوي كتلة اختبر على منطق الاختبار. يمكنها استخدام أي شيفرة Faber — ارتباطات المتغيرات، استدعاءات الدوال، تدفق التحكم — وتنتهي بتأكيد أكد واحد أو أكثر. يمكن وسم الاختبارات بعلامة وسم اختيارية للتنفيذ الانتقائي:

اختبر "echo formats operands with one space" وسم "coreutils" {
    أكد echo_textus(["hello", "world"]) ≡ "hello world"
}

أكد — التأكيد#

تقيّم أكد تعبيرًا منطقيًا وتُبلغ عن الفشل إذا كان خاطئًا. توفر رسالة نصية اختيارية سياقًا عند الفشل:

بداية {
    ثابت _ x ← 10

    # Simple assertion
    أكد x ≻ 0

    # With custom message
    أكد x ≡ 10 انهر "x decem esse debet"

    # Multiple assertions in sequence
    ثابت _ اسم ← "Marcus"
    أكد اسم ≡ "Marcus"
    أكد اسم ≠ "" انهر "nomen vacuum non sit"
}

سير العمل#

تُشغَّل الاختبارات عبر الأمر faber test:

faber test                        # run all tests in the current package
faber test examples/coreutils/packages/echo  # run tests for a specific package

لأن الاختبارات تعيش جنبًا إلى جنب مع المصدر في نفس ملف .fab، فلا يوجد هيكل مجلدات منفصل للاختبارات، ولا إعلان لوحدة اختبارات، ولا تمييز في سكربت البناء بين بنائي الاختبار والإنتاج. يعرف المصرف أي الكتل هي شيفرة اختبار وأيها شيفرة إنتاج من خلال الكلمات المفتاحية المستخدمة — تُحلَّل مختبر واختبر لكنها تُستبعد من بنائي الإنتاج.

مثال من العالم الحقيقي#

توضح حزمة echo في coreutils إطار عمل الاختبارات عمليًا. تعيش الاختبارات في نفس ملف التنفيذ، وتغطي تحليل الخيارات، توسيع الرموز الخاصة، والحالات الحدية:

مختبر "echo formatting" وسم "coreutils" {
    اختبر "empty operands format as empty text" {
        ثابت قائمة<نص> words ← فارغ
        أكد echo_textus(words) ≡ ""
    }

    اختبر "single operand is unchanged" {
        أكد echo_textus(["hello"]) ≡ "hello"
    }

    اختبر "-E is a leading no-op option" {
        أكد echo_textus(["-E", "hello", "world"]) ≡ "hello world"
    }

    اختبر "-n suppresses the trailing newline flag" {
        أكد echo_novam_lineam(["-n", "hello"]) ≡ خطأ
    }

    اختبر "-e expands the declared escape subset" {
        أكد echo_textus(["-e", "a\\nb"]) ≡ "a\nb"
        أكد echo_textus(["-e", "a\\tb"]) ≡ "a\tb"
    }
}

ملاحظات التصميم#

تميز عدة خيارات تصميمية إطار اختبارات Faber عن النهج التقليدية:

  • لا يوجد ثنائي اختبار منفصل. الاختبارات هي تصريحات في نفس ملف المصدر، وليست هدف تصريف منفصل. يصفي المصرف كتل الاختبار من مخرجات الإنتاج.
  • الوسوم، وليس المجلدات. تُنظم الاختبارات بعلامات وسم بدلًا من هيكل المجلدات. يمكن للاختبار الانتماء إلى عدة محاور تنظيمية دون نقله.
  • خط أنابيب تصريف كامل. الاختبارات مدققة الأنواع، محللة، وواعية بالإعدادات المحلية — نفس علم --reader-locale ينطبق على مخرجات الاختبار.
  • متعدد الأهداف. تشغّل الاختبارات عبر أي خلفية يستهدفها الرزمة — مُنفّذ MIR لـ faber test --interpret، وRust مصرف لـ faber test.
  • مجموعات متداخلة. يمكن تداخل كتل مختبر، معكسةً هيكل الشيفرة التي تختبرها.

المراجع#

  1. examples/corpus/probandum/ — ملفات مختبر النموذجية
  2. examples/corpus/proba/ — ملفات اختبر النموذجية
  3. examples/corpus/adfirma/ — ملفات أكد النموذجية
  4. examples/coreutils/packages/echo/src/main.fab — استخدام واقعي مع الوسوم