صفحات التوثيق
الاختبار
يبني sultanc test اختبارات البرنامج ويشغّل كلا منها في عملية مستقلة. الاختبار دالة موسومة بـ@@اختبار
(@@test بالإنجليزية). يبلّغ الأمر عن كل اختبار بأنه نجح أو فشل، ويذكر سبب كل فشل، ثم يختم بملخص وحالة خروج
يمكن للنصوص البرمجية فحصها.
استورد std.debug.assert;
استورد std.error.failure;
عرف ضاعف(س: عدد): عدد { أرجع س * 2; }
@@اختبار
عرف يضاعف(): فراغ {
تأكد(ضاعف(2) == 4);
}
@@اختبار
عرف يضاعف_العشرين(): نتيجة عدد, فشل {
إذا (ضاعف(20) != 40) { أرجع نتيجة.خطأ(فشل_من(«ضاعف(20) ليس 40»)); };
أرجع نتيجة.نجح(0);
}
sultanc test src/main.sn
نجح يضاعف
نجح يضاعف_العشرين
نتيجة الاختبارات: ناجحة. نجح: 2؛ فشل: 0؛ استُبعد: 0
التصريح بالاختبار
@@اختبار و@@test تهجئتان لوسم واحد مدمج من وسوم وقت التعريف، هو نفسه في اللغتين وفي أي ملف. ويوسم دالة
عادية لها جسم:
- لا تأخذ معاملات؛
- ولا تُرجع شيئا (
فراغ/void)، أو تُرجعنتيجة عدد, فشل(result int, Error، ونوع الخطأ هو نوعstd.error.failure)، وهي النتيجة التي يجوز للدالةالرئيسيةإرجاعها. ينجح الاختبار الذي يُرجعنتيجة.نجح(...)أيا كانت القيمة، ويفشل الذي يُرجعنتيجة.خطأ(خ)ويعرض التشغيل نص الخطأ. (لا قيمة تُرجع فينتيجة فراغ, فشل، ولذلك تحمل النتيجة القانونيةعددا.)
يجوز لأي وحدة في الحزمة الجذرية أن تصرح باختبارات: ملف الدخول وملفات حزمته التي يستوردها. أما اختبارات حزم
الاعتماديات (من --package-graph) فلا تُشغَّل، كما يشغّل Cargo اختبارات الحزمة نفسها دون اعتمادياتها؛ وتُشغَّل
اختبارات الاعتمادية حين تكون هي الحزمة الجذرية. يُعثر على
الاختبار بتصريحه بعد تحليل البرنامج وفحصه، لا بالبحث في النص. واسمه هو الاسم كما كُتب: يُسرد الاختبار المصرح
باسم إنجليزي بهذا الاسم، والمصرح باسم عربي باسمه العربي. والدالة ذات الأسماء الأخرى (عرف يجمع مرادف adds)
لها كل منها تهجئةً: يطابق --filter و--test أي تهجئة، وتستعمل التقارير الأولى.
يرفض المترجم الاختبار الذي لا يمكن تشغيله قبل بناء أي شيء، ويبلّغ عن كل اختبار عند اسمه:
| الرمز | المعنى |
|---|---|
SULTANC-TEST-PARAMETERS |
للاختبار معاملات. |
SULTANC-TEST-RESULT-TYPE |
يُرجع الاختبار شيئا غير لا شيء أو نتيجة عدد, فشل. |
SULTANC-TEST-NOT-A-FUNCTION |
يوسم @@اختبار نوعا، أو قيمة وحدة، أو دالة عامة، أو دالة بمعامل وقت_الترجمة، أو دالة خارجية. |
ويشرح sultanc --explain <الرمز> كلا منها.
وتطبّق هذه القواعدَ عمليةُ تحقق واحدة على حقائق الأسماء والأنواع في الواجهة (compiler/test_mode/validation.sn).
يرفض بها sultanc test قبل خفض أي شيء، ويبلّغ تحليل المحرر (طلب أدوات للواجهة، كما يرسله خادم اللغة) عن
التشخيصات نفسها عند اسم الاختبار أثناء كتابته، مع تشخيصاته الأخرى. ولا يبلّغ البناء ولا check عن شيء منها.
البناء العادي
لا أثر للوسم خارج sultanc test. فبناء البرنامج نفسه أو sultanc run يشغّل دالته الرئيسية ولا يشغّل اختبارا
أبدا، ولا تُصدر دالة الاختبار إلا إذا استدعاها البرنامج نفسه. فالبرنامج الذي تجاور اختباراته شيفرته يُبنى كما
كان.
اختبار وtest اسمان للوسم المدمج: لا يُستدعى عبر @@اختبار مزخرف وقت تعريف في البرنامج بأي من الاسمين.
وتعمل مزخرفات وقت التعريف في البرنامج في وضع الاختبار كما تعمل في البناء: تشغّل نقطة الدخول التي يعطيها المترجم
للاختبارات أولا كل تسجيل تشغّله نقطة دخول البناء قبل جسم الرئيسية، بالترتيب نفسه، مترجما ومع --interpret.
فالعداد الذي يزيده مزخرف @@سجل يكون 1 في الاختبار كما في الرئيسية.
تشغيل الاختبارات
يبني sultanc test <ملف> ملفا تنفيذيا واحدا عبر المسار نفسه الذي يمر به أي بناء (الواجهة نفسها وMSIR والمحسّن
والخلفية). ويعطيه المترجم نقطة دخول خاصة به، يولّدها في MSIR من الاختبارات المكتشفة، بدل الرئيسية في البرنامج.
ثم يشغّل الأمر ذلك الملف التنفيذي مرة لكل اختبار، ويمرر رقم الاختبار وسيطا له، فلا يستطيع اختبار ينهار أو يفشل
تأكيده أو يقع في فخ أو يخرج أو يتعطل أن يوقف الاختبارات الأخرى أو يرى حالتها. ويُلتقط الخرج القياسي والخطأ
القياسي لكل اختبار ويُعرضان تحت تقريره إن فشل.
ويذكر الفشل ما أنهى الاختبار:
فشل تأكيد_فاشل: حالة الخروج 1
--> tests/main.sn:19:5
ملاحظة: الاختبار مصرح به في tests/main.sn:18:5
خطأ[SULTANC-RUNTIME-PROGRAM-STOPPED]: توقف البرنامج — فشل تأكيد.
فشل يرجع_خطأ: أرجع خطأ
--> tests/main.sn:28:5
ضاعف(20) هو 40، والمتوقع 41
فشل يقسم_على_صفر: أُنهي بالإشارة 4
--> tests/main.sn:35:5
- أرجع خطأ: أرجع الاختبار
نتيجة.خطأ(خ)، والنص تحته هوخ(صف_فشل). - حالة الخروج N: أنهى الاختبار العملية. ينهيها الانهيار وفشل التأكيد بالحالة 1 ويكتبان السبب (إطار فشل
البرنامج أثناء التشغيل، ورسالة الانهيار) في الخطأ القياسي، فيُعرض تحته. وأي حالة أخرى هي حالة الاختبار نفسه
(
اخرج(7)). - أُنهي بالإشارة N: أوقفت إشارةٌ العملية (فخ أو خطأ وصول).
- تعذر تشغيله: تعذر تشغيل الملف التنفيذي.
سطر --> هو موضع فشل الاختبار حين يذكره: يبلّغ التأكيد الفاشل بموضع نداء تأكد (أدناه)، ويتبعه موضع التصريح
بالاختبار ملاحظةً. وفي غير ذلك (انهيار، أو خطأ مُرجَع، أو حالة خروج، أو إشارة) هو موضع التصريح بالاختبار.
أين فشل التأكيد: @@يتتبع_المستدعي
يطبع تأكد / assert وتأكد_برسالة / assert_with_message (std.debug.assert) موضع النداء الذي فشل تحت إطار
الفشل، --> <ملف>:<سطر>:<عمود>، ويعرضه sultanc test في سطر -->. فهما موسومتان بـ@@يتتبع_المستدعي
(@@track_caller)، مثل #[track_caller] في Rust، ويمكن وسم أي دالة:
استورد std.debug.assert;
استورد std.debug.location;
@@يتتبع_المستدعي
عرف تأكد_موجب(القيمة: عدد, الموقع: موقع_مصدر): فراغ {
تأكد(القيمة > 0);
}
- آخر معاملات الدالة الموسومة
موقع_مصدر(source_location، std.debug.location): مرجع إلى مسار الملف، والسطر والعمود بدءا من 1، وهو قيمة بسيطة. ولا يمرره المستدعون: نوع الدالة في كل استعمال لها بلا ذلك المعامل، ويمرر المترجم موضع كل نداء (وتقرؤهنص_موقع_مصدروملف_موقع_مصدروسطر_موقع_مصدروعمود_موقع_مصدر). - داخل دالة موسومة أخرى يمرر النداء الموقع الذي استقبلته تلك الدالة، فيبلّغ
تأكدفيتأكد_موجبأعلاه بالسطر الذي نادىتأكد_موجب. أما الدالة المساعدة غير الموسومة فيبلّغتأكدفيها بسطره هو. - قيمة الدالة لدالة موسومة (
دع د: دالة(منطقي): فراغ = تأكد;) تمرر موضع تعريف الدالة، كما يفعل غلاف مؤشر الدالة في Rust. - تمرير الموقع بنفسك خطأ (
SULTANC-TRACK-CALLER-EXPLICIT-LOCATION)؛ وكذلك وسم دالة عامة النوع أو خارجية أو لها معاملات وقت ترجمة أو ليس آخر معاملاتهاموقع_مصدر(SULTANC-TRACK-CALLER-SIGNATURE).
والموقع حجة ثابتة عادية (يبنيها خفض MSIR في compiler/msir/lowering/caller_location.sn، ويحذف مرور الأنواع
المعامل من استعمالات الدالة في compiler/frontend/types/semantic_pipeline.sn)، فلا تحتاج الخلفيتان الأصلية وLLVM
ولا المفسران شيئا خاصا بها.
ويعدّ الملخص الاختبارات التي نجحت والتي فشلت والتي استبعدها --filter و--test و--tests-in. وكلماته بلغة --lang مثل كل رسائل
المترجم؛ أما إطارات فشل البرنامج نفسه فتتبع لغة البرنامج كما في أي برنامج.
الخيارات
| الخيار | أثره |
|---|---|
--filter <نص>، --filter=<نص> |
يشغّل الاختبارات التي تحوي إحدى تهجئات اسمها <نص> فقط (بايتات، فأي كتابة). وتُعد الأخرى مستبعدة. |
--test <اسم>، --test=<اسم> |
يتكرر. يشغّل الاختبارات التي تساوي إحدى تهجئات اسمها أحد الأسماء المعطاة بعينها (فلا يشغّل --test=يضاعف الاختبار يضاعف_خطأ). والاسم الذي لا اختبار به في حزمة الجذر هو SULTANC-TEST-NOT-FOUND (الحالة 2). |
--tests-in <ملف>، --tests-in=<ملف> |
يتكرر. يشغّل الاختبارات المصرح بها في الملفات المعطاة فقط. يُنظَّف كل مسار لفظيا كما يسمي المحمّل المصادر، ويُقارن بأسماء مصادر البرنامج، والمسارات النسبية بالنسبة إلى الدليل الحالي. والملف الذي ليس من مصادر البرنامج هو SULTANC-TEST-FILE-NOT-IN-PROGRAM (الحالة 2). والحزمة التي يقع برنامجها (src/main.sn) في جذر مصادر مكتبتها لا تشغّل مع --tests-in=src/main.sn إلا اختبارات البرنامج نفسه، كما يشغّل Cargo اختبارات وحدات المكتبة في هدف المكتبة وحده. |
--list |
يطبع أسماء الاختبارات المختارة، اسما في كل سطر، بترتيب التشغيل، ولا يشغّل شيئا. |
يجتمع --filter و--test و--tests-in بعضها مع بعض ومع قاعدة حزمة الجذر: يُشغَّل الاختبار إذا طابقت كلها. ويحترمها --list. |
|
--interpret |
يشغّل الاختبارات في المفسر بدل بناء ملف تنفيذي: يشغّل sultanc test المترجم من جديد لكل اختبار (--test-index)، فيفسر نقطة الدخول المولدة نفسها. والبرنامج الذي يشغّله المفسر ملفا تنفيذيا (C مستورد، أو مكتبات -l لا يستطيع تحميلها) يُشغَّل ذلك الاختبار فيه أصليا كما يفعل sultanc run. |
--test-index=<n> |
يشغّل الاختبار رقم <n> وحده (ترقيما من 0 بترتيب --list)، في هذه العملية وعلى تياراتها القياسية، ويخرج بحالته. وهو ما تشغّله كل عملية من عمليات --interpret. |
--target و-b و-O0…-O3 |
كما في البناء. ولا ينطبق -b مع --interpret. |
-l و-L و--module-source و--package-graph و--lang و--color و--diagnostic-format |
كما في البناء. ويقرأ --package-graph=- الرسم من الإدخال القياسي (الوحدات والاستيراد)؛ ومع --interpret تُعطى عملية كل اختبار الرسم نفسه. |
ولا ينطبق -o ولا --emit: الملف التنفيذي مؤقت ويُحذف بعد التشغيل.
الأهداف الأخرى
لا يُشغَّل ملف اختبار تنفيذي أبدا على مضيف لا يستطيع تشغيله. فإذا سمّى --target هدفا آخر بُنيت الاختبارات (وفي
ذلك فحص لها وللبرنامج لذلك الهدف) ولم تُشغَّل:
ملاحظة: بُنيت الاختبارات ولم تُشغَّل: لا يشغّل هذا المضيف برامج الهدف aarch64-linux-gnu
ويبقى --list يسردها. والحالة 0 إذا نجح البناء.
حالة الخروج
| الحالة | المعنى |
|---|---|
| 0 | نجحت كل الاختبارات المختارة (أو --list، أو بُنيت لهدف آخر). |
| 1 | فشل اختبار واحد على الأقل. |
| 2 | تعذر بناء الاختبارات: خطأ في البرنامج، أو اختبار غير صالح، أو سطر أوامر غير صالح. |
| 3 | البيئة: مكتبة قياسية أو مكتبة ربط مفقودة، أو هدف لا يصلح، أو ملف تعذرت كتابته. |
| 4 | خطأ داخلي في المترجم. |
ومع --test-index تكون الحالة حالة الاختبار نفسه: 0 نجح، و1 انهيار أو فشل تأكيد، و3 خطأ مُرجع، وأي حالة أخرى
هي حالة خروج الاختبار، و128 + N للإشارة N.
كيف يعمل
- يقرأ الاكتشاف (
compiler/test_mode/discovery.sn) الوسم حيث تقرؤه الواجهة (compiler/frontend/annotations/definition_decorators.snتتعرفه وتزيله قبل مرحلة الأنواع): تُحلَّل من جديد كل وحدة في البرنامج المفحوص تحوي@@بالمحلل نفسه وللهدف نفسه، ويُسجَّل كل تصريح موسوم بـ@@اختبارباسمه ونطاقه. - يطابق الحزام (
compiler/test_mode/harness.sn) كل اختبار مكتشف بدالة MSIR المخفضة من التصريح نفسه، ويتحقق من توقيعه بأنواع MSIR فيstd.testing.harness. ثم يضيف نقطة الدخول: لكل اختبارi،إذا (اختبار_مطلوب_تشغيله(i)) { [ن :=] اختبار_i(); أرجع 0 أو أنه_نتيجة_اختبار(ن) }، ثمأرجع 2. لا يُولَّد نص بلغة السلطان، ولا تُستدعىالرئيسيةفي البرنامج. std.testing.harness(library/std/testing/harness.sn) هو وقت التشغيل: يقرأ رقم الاختبار من أول وسيط للبرنامج (std.process.argument) ويطبع الخطأ المُرجع. ولا ينضم إلى البرنامج إلا في وضع الاختبار.- يشغّل المشغّل (
compiler/driver/process_driver.sn) كل اختبار بـstd.process.commandويلتقط خرجه. وعلى لينكس تبدأ تلك الطبقة العمليات وتنتظرها باستدعاءات نظام خام (بلا مكتبة C)؛ وعلى الأنظمة الأخرى تستعمل واجهة العمليات الخاصة بالنظام، كما تفعل المكتبة القياسية في كل مكان.