دليل كامل

دليل المستخدم

من ملف التتبع الأول لديك إلى بوابة الامتثال لمعايير السلامة — كل ما يمكن لـ Fucini Coverage Studio فعله، وكيفية تشغيله بالضبط.

تنزيل VSIX

1. مقدمة

يحوّل Fucini Coverage Studio ملفات تتبع التغطية التي ينتجها بناؤك أصلًا إلى تغطية من الدرجة الأولى داخل المحرر — في VS Code وفي Visual Studio. يقرأ خمسة وعشرين تنسيقًا، ويطبّعها في نموذج Fucini قياسي واحد، ويدمج تشغيلات متعددة بشكل حتمي، ويعرضها في المحرر نفسه — الهوامش وCodeLens والتلميح وعرض Covered Files — فلا عارض منفصل تضطر لمغادرة محررك من أجله. يتشارك الإصداران قارئًا واحدًا: التقرير نفسه يعطي الأرقام نفسها، إلى الرقم، في كليهما. كُتب هذا الدليل من منظور VS Code؛ وحيث يختلف Visual Studio، يوضح مربع In Visual Studio كيف.

تم تصميمه مع مراعاة سير عمل السلامة الوظيفية: تغطية MC/DC، وتغطية المناطق ونسخ C++، ودرجة مركّبة مرجّحة حسب السلامة، وحكم COMPLIANT / NON-COMPLIANT قابل للتكوين يتماشى مع فكر IEC 61508 وISO 26262 وDO-178C.

Fucini Coverage Studio in VS Code: a file opened from the Coverage view, uncovered lines and half-taken branches in the editor, the MC/DC hover, the heatmap, the status-bar card and the annotated sourceScreenshot pending — add assets/img/marketplace-demo.gif (see SCREENSHOTS.md).

2. التثبيت والمتطلبات

  • VS Code ≥ 1.88 — أدنى إصدار تدعمه هذه الإضافة — أو Visual Studio 2022 أو 2026، Community أو Professional أو Enterprise (انظر المربع أدناه).
  • ملف تتبع تغطية ينتجه مشروعك أصلًا (انظر §4).

ثبّت من Marketplace، أو من ملف .vsix عبر Extensions → ⋯ → Install from VSIX…. يُفعَّل الامتداد عند بدء التشغيل ويضيف أيقونة Coverage إلى شريط النشاط.

في Visual Studio. يصدر المنتج نفسه كإضافة ثانية، Fucini Coverage Studio لـ Visual Studio، لـ Visual Studio 2022 و2026 — Community وProfessional وEnterprise. لا يستخدم تغطية الكود الخاصة بـ Visual Studio: في Visual Studio 2022 هي ميزة لإصدار Enterprise، لذا على Community وProfessional هذه هي التغطية الوحيدة التي ستعرضها البيئة. ثبّت ملف .vsix بفتحه — يسألك VSIX Installer عن أي Visual Studio — أو عبر Extensions → Manage Extensions؛ تُحمَّل الإضافة عند فتح حل أو مجلد. تحتاج نافذة Coverage إلى Microsoft Edge WebView2 Runtime، الذي يأتي أصلًا مع Windows 11 وVisual Studio 2026؛ أما العلامات في المحرر فتعمل دونه.

3. بداية سريعة

هل تريد رؤية كيفية عمله قبل ربط مشروعك الخاص؟ نزّل مشروع العرض التوضيحي (حوالي 6 كيلوبايت — مشروع C صغير يحتوي على lcov.info جاهز):

  1. فك ضغطه في أي مكان، ثم افتح coverage-studio-demo.code-workspace في VS Code (File → Open Workspace from File…).
  2. ثبّت Fucini Coverage Studio إذا لم تكن قد فعلت ذلك بعد (انظر §2 أعلاه).
  3. يشير ملف .vscode/settings.json الخاص بمساحة العمل بالفعل إلى coverage/lcov.info المرفق، لذا تظهر الأشرطة الجانبية وعرض Covered Files بمجرد تفعيل الامتداد — لا حاجة لخطوة Load Coverage.
  4. هل تريد إعادة إنشاء ملف التتبع بنفسك (مثلاً بمترجم مختلف)؟ شغّل scripts/gen-coverage.sh (أو .ps1 على Windows) — راجع ملف README.md الخاص بمساحة العمل لمعرفة المترجمات المتاحة.

في Visual Studio. افتح حلًا أو مجلدًا (File → Open → Folder، وهكذا يُفتح مشروع CMake) — يُفتح العرض التوضيحي أعلاه كمجلد، ويُقرأ ملف .vscode/settings.json الخاص به هناك أيضًا. يُحمَّل التقرير الموجود في المكان الذي تسمّيه الإعدادات من تلقاء نفسه، ويخبرك جزء Fucini Coverage في نافذة Output بالملفات؛ وإلا فاستخدم Tools → Coverage Studio → Load Coverage File… مرة واحدة — فيُتذكَّر. افتح ملف مصدر واختر Show Coverage in Editor: الأحمر سطر لم يُنفَّذ قط، والكهرماني قرار اتُّخذ في اتجاه واحد فقط، وCtrl+Shift+U, N ينتقل إلى السطر غير المغطى التالي. View → Other Windows → Coverage هي الشجرة التي تعرض أرقام كل ملف ونتيجة واحدة لها جميعًا، ويعرضها شريط الحالة للتشغيل وللملف الذي أنت فيه. Tools → Coverage Studio → Getting Started يفتح هذه الخطوات كصفحة فيها زر لكل خطوة؛ ويُفتح من تلقاء نفسه في المرة الأولى.

  1. أنتج ملف تتبع تغطية باستخدام سير عمل الاختبار المعتاد لديك.
  2. لوحة الأوامر (Ctrl+Shift+P) ← Fucini Coverage: Load Coverage. مع تفعيل watch.enabled (الافتراضي)، يتم تحميل الملف المطابق تلقائيًا.
  3. افتح ملف مصدر مغطى: يعرض شريط الحالة نسبته، ويمتلئ عرض Coverage، ويُظهر التحويم فوق سطر عدد إصاباته، ويظهر التشغيل في لوحة Test Coverage الأصلية. أما الأشرطة على الأسطر غير المغطّاة والخريطة الحرارية لأعداد الإصابات وأعداد ×N المضمّنة فعلى بُعد إعداد واحد (editorGutter.mode، hitCounts.inline).
Covered (green) and uncovered (red) gutters in the editorScreenshot pending — add assets/img/gutters.png (see SCREENSHOTS.md).

4. إنتاج ملفات التتبع

يتم اكتشاف أي مما يلي تلقائيًا عند التحميل:

وصفات كاملة جاهزة للنسخ واللصق لكل مترجم — بما في ذلك Swift وRust وGo وPython و.NET وPHP والمزيد — في صفحة وصفات التغطية: Swift · Clang · GCC · Rust · Go · Python · Java/Kotlin · JS/TS · .NET · PHP · Ruby.

C / C++ — LLVM (llvm-cov)

clang --coverage -fprofile-instr-generate -fcoverage-mapping test.c -o test
LLVM_PROFILE_FILE=test.profraw ./test
llvm-profdata merge -sparse test.profraw -o test.profdata
llvm-cov export ./test -instr-profile=test.profdata --format=json > coverage.json

تُعد صيغة llvm-cov JSON الإدخال الأغنى — فهي تحمل المناطق وMC/DC ونسخ قوالب C++ بالإضافة إلى الأسطر والفروع والدوال.

C / C++ — GCC (gcov ← lcov)

gcc --coverage calc.c calc_test.c -o test && ./test
lcov --capture --directory . --output-file lcov.info
# or gcovr --cobertura coverage.xml
# or skip the conversion entirely: gcovr --json coverage.json

JavaScript / TypeScript — Istanbul / nyc

nyc --reporter=json mocha        # emits coverage/coverage-final.json

Java — JaCoCo

mvn test        # emits target/site/jacoco/jacoco.xml

Ruby — SimpleCov

# .resultset.json (built-in) or coverage.json via the simplecov-json gem

Go

go test ./... -coverprofile=coverage.out    # read directly, no conversion

Python — coverage.py

coverage run --branch -m pytest && coverage json    # emits coverage.json

PHP — PHPUnit (Clover)

XDEBUG_MODE=coverage phpunit --coverage-clover clover.xml

.NET / C# — Coverlet (OpenCover)

dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
التنسيقالملف المعتادمقاييس إضافية
LCOVlcov.infoالأسطر، التفرّعات، الدوال
llvm-cov JSONcoverage.json+ المناطق، MC/DC، إنشاء النسخ
Cobertura XMLcoverage.xmlالأسطر، التفرّعات
JaCoCo XMLjacoco.xmlالأسطر، التفرّعات، الدوال
Istanbul / nyccoverage-final.jsonالعبارات، التفرّعات، الدوال
SimpleCov.resultset.jsonالأسطر
Clover XMLclover.xmlالأسطر، التفرّعات، الدوال
OpenCover XMLcoverage.opencover.xmlالأسطر، التفرّعات، الدوال
coverage.py JSONcoverage.jsonالأسطر، التفرّعات
gcov / gcovr JSONcoverage.jsonالأسطر، التفرّعات، الدوال
Go coverage profilecoverage.outالأسطر
SonarQube genericcoverage.xmlالأسطر، التفرّعات
GNATcoverage XML (Ada)*.xmlالأسطر، التفرّعات، MC/DC
BullseyeCoverage XMLcoverage.xmlالأسطر، الشرط/القرار
Visual Studio*.coveragexmlالأسطر، التفرّعات
Coveralls JSONcoveralls.jsonالأسطر، التفرّعات
Xcode xccov JSONcoverage.jsonالدوال وإجماليات الملف — بلا بيانات لكل سطر
gcov plain text*.gcovالأسطر، التفرّعات، استدعاءات الدوال
VectorCASTcoverage.xmlالأسطر، التفرّعات، أزواج MC/DC، الدوال، استدعاءات الدوال
Testwell CTC++*.txtالأسطر، الشرط/القرار
Lauterbach TRACE32*.xmlالعبارات، القرارات، الشروط، MC/DC، الدوال، الاستدعاءات، الشيفرة الهدف
EMMA XML (Java)coverage.xmlالأسطر
UCIS / Aldec UCDB*.xmlالعبارات، تفرّعات القرار
NCover XMLCoverage.xmlالأسطر، الدوال
dotCover DetailedXMLdotCover.xmlالأسطر، الدوال
PIT (mutation)mutations.xmlدرجة الطفرات — بلا تغطية
Stryker (mutation)mutation-report.jsonدرجة الطفرات — بلا تغطية

مشروع C++ أصلي، مقيس من Visual Studio

في Visual Studio. كانت تغطية Visual Studio نفسه لمشروع C++ مقصورة على Enterprise، وأُوقفت إضافة OpenCppCoverage المجانية التي كانت تسدّ الفجوة. يأخذ Tools → Coverage Studio → Run Native Project with Coverage مشروع بدء التشغيل — ملف .vcxproj — ويسأل MSBuild أين يُبنى وعلى أي مجموعة أدوات، ويقيسه بإحدى طريقتين. على مجموعة أدوات ClangCL، مع وجود llvm-profdata وllvm-cov من LLVM على الجهاز (يجلبهما مكوّن C++ Clang tools for Windows في Visual Studio)، يبني المشروع من جديد في coverage\native\ مع -fprofile-instr-generate -fcoverage-mapping، عبر ملف props يُطلب من MSBuild استيراده أولًا — فلا يتغيّر شيء في المشروع — ويشغّل البرنامج مع ضبط LLVM_PROFILE_FILE، ويدمج الملف التعريفي ويصدّر coverage\native\lcov.info، دقيقًا إلى المنطقة. وعلى أي مجموعة أدوات أخرى، مع تثبيت OpenCppCoverage، يبني المشروع كما هو — فبناء Debug يحوي ملفات PDB — ويشغّله تحت OpenCppCoverage، الذي يكتب coverage\native\opencppcoverage.xml. يذهب كل أمر إلى لوحة Fucini Coverage، ويُحمَّل التقرير ويُتذكَّر كما يُحمَّل تقرير تشغيل اختبارات. والمشروع الذي لا يمكن قياسه يُخبَر لماذا وما الذي ينبغي تثبيته. يلزم MSBuild 17.8 (Visual Studio 2022 17.8) أو أحدث، للسؤال الذي يطرحه.

Visual Studio: Run Native Project with Coverage on a C++ project — the instrumented build, the run, and the gutter filling inScreenshot pending — add assets/img/vs-native-run.gif (see SCREENSHOTS.md).
في Visual Studio: Run Native Project with Coverage على مشروع C++ — البناء، والتشغيل، والمحرر يمتلئ.

5. التحميل والاكتشاف

بشكل افتراضي، يقوم الامتداد بالمسح من جذر مساحة العمل. حدّد ذلك بدقة أكبر باستخدام إعدادين:

{
  "fuciniCoverage.coverageFile.defaultLocation": "${workspaceFolder}/build",
  "fuciniCoverage.coverageFile.paths": [
    "coverage.json",
    "reports/*.info",
    "${env:CI_ARTIFACTS}/lcov.info",
    "https://ci.example.com/artifacts/latest/coverage.xml"
  ]
}
  • كل إدخال في paths نسبي إلى defaultLocation (أو جذر مساحة العمل إذا لم يُحدَّد).
  • يُبحث عن الإدخال الذي يحتوي على * بشكل متكرر؛ يتطابق اسم الملف المجرد فقط مباشرة في المجلد الأساسي.
  • عندما يكون paths فارغًا، يبحث الامتداد عن coverage.json، ثم lcov.info، ويحمّل أيهما يجده أولًا.
  • يستخدم Pick Coverage File الملفات التي تختارها بدل هذه المسارات — كل اختيار يُضاف إلى المجموعة وتُدمج جميعها — حتى تُلغي تحميلها أو تحرّر هذه الإعدادات.
  • المتغيّرات — يوسّع كل إعداد مسار ${workspaceFolder} و${workspaceFolderBasename} و${userHome} و${env:NAME}، ${command:id} و${config:section.key}. والمتغيّر الذي لا يعرفه الامتداد يُترك كما كُتب، فيظهر الخطأ المطبعي في سجل الاكتشاف بوصفه المسار الذي بُحث عنه بدل أن يختفي. يشغّل ${command:id} ذلك الأمر أولًا — في مساحة عمل موثوقة فقط، ولمدة خمس ثوانٍ على الأكثر — لذلك يتبع ${command:cmake.buildDirectory} مجموعة CMake المحددة.
  • مدخلات URL — يُجلب مدخل http(s):// إلى مساحة تخزين الامتداد عند كل تحميل ويُحمَّل من هناك؛ ويذكر عرض Coverage العنوان. كل جلب مشروط (ETag / Last-Modified)، فالملف الذي لم يتغيّر لا ينزّل شيئًا، وحين يفشل الجلب تُحمَّل آخر نسخة منزَّلة بدلًا منه، مع السبب في المخرجات. يضيف remote.headers ترويسات Name: value مع توسيع المتغيّرات، ويعيد remote.refreshMinutes الجلب على مؤقّت، ويسمّي الجزء المُلحق #lcov.info التنسيق حين لا ينتهي العنوان نفسه باسم ملف.
  • أنماط التجاهل — يُسقط fuciniCoverage.ignore ملفات كاملة (مورَّدة أو مولَّدة أو من أطراف ثالثة) من التشغيل أثناء تحميله، فيَعُدّ كل عرض وبوابة وتصدير من دونها؛ وتقول نتيجة التحميل كم ملفًا استُبعد وتسمّيها المخرجات. تُطابَق الأنماط مع المسار النسبي لمساحة العمل ومع المسار المطلق، والنمط الخالي من / يطابق اسم مجلد أو ملف على أي عمق، مثل .gitignore.
  • مساحات العمل متعددة الجذور — يُكتشف كل مجلد بشروطه هو: تُقرأ defaultLocation وpaths وpathRemap وignore وwatch.* وremote.* لكل مجلد على حدة، فيسري ملف .vscode/settings.json الخاص بالمجلد أو مدخله في .code-workspace، ويعني ${workspaceFolder} في المدخل مجلد ذلك المدخل نفسه. وتندمج ملفات التتبع في كل المجلدات في تشغيل واحد، ويجمّع عرض Coverage الملفات حسب المجلد، والمجلد الذي يُضاف إلى مساحة العمل أو يُزال منها يعيد تحميل التغطية من تلقاء نفسه.
  • إعادة التحميل بعد مهمة — يسمّي watch.reloadAfterTasks مهامّ (label من tasks.json، أو source: name كما تعرضها قائمة Run Task) يعيد انتهاؤها تحميل التغطية، سواء كان watch.enabled مفعّلًا أم لا — لعمليات البناء التي لا يستطيع المراقب متابعتها. ويُستطلع أيضًا مدخل paths المطلق خارج مساحة العمل، فالملف الذي يظهر هناك يُحمَّل.
  • تقدّم يمكن إلغاؤه — تحميل عشرة ملفات تتبع أو أكثر، أو 8 ميغابايت أو أكثر منها، يجري تحت إشعار تقدّم بزر Cancel يسمّي الملف الذي يُقرأ والمرحلة؛ أما التحميل الأصغر فلا يفعل سوى تدوير شريط الحالة. والإلغاء يُبقي التشغيل السابق محمَّلًا ويقول ذلك.

منذ 1.2026.6 يمكن أن يحوي المدخل المطلق أيضًا حرف بدل: يحمّل ${workspaceFolder}/build/coverage-merged/*.lcov.info كل ملف من هذا النوع في ذلك المجلد، ويعني ** أي عمق. المجلدات التي تسبق حرف البدل الأول هي حيث يبحث، وهي مراقَبة، فالتقرير الذي تكتبه عملية بناء هناك يُحمَّل من تلقاء نفسه. ويقرأ إصدار Visual Studio مثل هذا المدخل بالطريقة نفسها، ومنذ 1.2026.5 يُبحث عن حرف البدل النسبي على أي عمق هناك أيضًا، كما كان الحال هنا دائمًا.

عند عدم ضبط paths، يُحمَّل أول ما يُعثر عليه تحت المجلد الأساسي من أسماء التقارير المعروفة. أولًا الأسماء الأربعة التي كان يبحث عنها دائمًا — coverage.json وlcov.info وcoverage.out وclover.xml — ثم، منذ 0.2026.83، jacoco.xml وcoverage.xml وcobertura.xml وcoverage.cobertura.xml وcoverage.opencover.xml وcoverage-final.json، ثم الأماكن التي تكتب إليها الإعدادات الافتراضية: coverage/ (nyc وJest وvitest وPHPUnit وSimpleCov) وtarget/site/jacoco/jacoco.xml (Maven) وbuild/reports/jacoco/test/jacocoTestReport.xml (Gradle) وTestResults/*/coverage.cobertura.xml (dotnet test). وهكذا يعرض مشروع Java أو .NET تغطيته عند فتحه أول مرة، كما كان مشروع lcov يفعل دائمًا.

منذ 1.2026.3 يحتاج حل .NET إلى أقل من ذلك: مجلد TestResults/<run>/ لكل مشروع اختبار صار من بين الأماكن المعروفة، لا مجلد مساحة العمل نفسه فحسب، ويُعثر على <user>_<machine>_<date>.cobertura.xml الخاص بجامع Microsoft بجانب coverage.cobertura.xml الخاص بـ Coverlet — فالحل الذي شُغّلت اختباراته في Test Explorer في Visual Studio يعرض تغطيته عند أول فتح، ويُحمَّل كل مجلد تشغيل، ويُبقي الدمج كلمة أحدث تشغيل على كل ملف. كما أن fuciniCoverage.ignore.generated، المفعّل افتراضيًا، يُبقي ملفات المصمّم والملفات المولَّدة — *.Designer.cs و*.g.cs و*.generated.cs و*.razor.g.cs وAssemblyInfo وتوجيهات using العامة وMigrations/ وobj/ — خارج كل مجموع وصفحة وتصدير قبل تطبيق ignore، فلا يكلّف جدولٌ مولَّد لا يختبره أحد الحلَّ بوابته.

في Visual Studio: التغطية بعد كل تشغيل للاختبارات. شغّل اختباراتك كما تفعل دائمًا. يضع Tools → Coverage Studio → Collect Coverage in Test Explorer… ملف .runsettings واحدًا يحوي جامع Cobertura من Microsoft بجانب الحل. يلتقطه Visual Studio عندما يكون Tools → Options → Test → Auto detect runsettings files مفعّلًا؛ وإلا فاختره مرة واحدة تحت Test → Configure Run Settings. ومن ثَمّ يكتب كل تشغيل تقريرًا تحت مشروع الاختبار، وتحمّله مراقبة الحل لحظة ظهوره، مدمجًا مع كل ما تسمّيه الإعدادات — سواء جاء من Test Explorer أو من طرفية أو من نص برمجي. لا شيء يتشعّب في Test Explorer، فيعمل Visual Studio 2026 وMicrosoft.Testing.Platform كما هما. أما Run Tests with Coverage فهو أمر VS Code: يتعرّف على dotnet test وvitest وjest وpytest وgo وcargo وmaven وgradle وphpunit وctest، ويشغّل الاختبارات مع تفعيل التغطية في نافذة Output ويحمّل ما كتبته؛ ومشروع الاختبار الذي يخلو من coverlet.collector يُشغَّل بالجامع الذي تشحنه حزمة SDK للاختبار، ويُبقي testRun.skipWhenTestsFail آخر تغطية سليمة على الشاشة عندما ينتهي التشغيل بالأحمر.

ملف CI ناتج خلف رمز، يُعاد فحصه كل ربع ساعة — يبقى الرمز في البيئة، لا في settings.json أبدًا:

{
  "fuciniCoverage.coverageFile.paths": [
    "https://ci.example.com/api/builds/latest/artifacts/coverage#lcov.info"
  ],
  "fuciniCoverage.remote.headers": ["Authorization: Bearer ${env:CI_TOKEN}"],
  "fuciniCoverage.remote.refreshMinutes": 15
}
A tracefile loaded from a URL: the Coverage view names the address it came fromScreenshot pending — add assets/img/remote-tracefile.png (see SCREENSHOTS.md).

إعادة التحميل صامتة عن قصد — فمربّع حوار بعد كل بناء سؤال له إجابة واحدة. أما ما ليس صامتًا فهو أيقونة Coverage: ما دام العرض ليس أمامك فإنها تحمل عدد ملفات التتبّع التي أُعيدت قراءتها، وتذكر التلميحة أسماءها. افتح العرض فيختفي العدد.

A build rewrites two reports while the Explorer is open: the Coverage icon in the activity bar gains a count, its tooltip names what reloaded, and opening the view clears itScreenshot pending — add assets/img/coverage-badge.gif (see SCREENSHOTS.md).

ملفات لا ينبغي أن تُحتسب أبدًا، مهما قال عنها ملف التتبع:

{
  "fuciniCoverage.ignore": ["vendor/**", "**/*.generated.ts", "build/**"]
}

إعادة تحميل عند انتهاء مهمة الاختبار، لعملية بناء لا يستطيع مراقب الملفات متابعتها — تشغيل يستبدل شجرة مخرجات مربوطة برابط رمزي، أو تقرير على مشاركة شبكية، أو خطوة تغطية تعالج ملفها بعد إنتاجه:

{
  "fuciniCoverage.watch.reloadAfterTasks": ["npm: test", "coverage-report"]
}

6. دمج عمليات التشغيل

يُحمَّل كل إدخال موجود في paths ويُدمج في تشغيل واحد. الدمج حتمي — لا تعتمد النتيجة على ترتيب التحميل — والملف الذي قاسه أكثر من ملف تتبع يأخذ أرقامه من الملف ذي أحدث وقت تعديل على القرص: إعادة تشغيل وحدة بمفردها تستبدل ما قاله عنها تشغيل أوسع وأقدم بدل أن تُضاف إليه. عرض التغطية يُظهر ما فعله ذلك: كل صف ملف يذكر ملف التتبع الذي جاءت منه أرقامه، وتُحاط الشارة بإطار حيث طغت تلك الأرقام على تقرير أقدم، وكل صف ملف تتبع فوق الشجرة يعدّ كم من ملفاته طُغي عليها أو طغت على غيرها، والنقر على صف ملف تتبع يُبرز ملفاته في الشجرة حتى يُنقر عليه مرة أخرى (coverageView.mergedMarks يوقف الإطار والإبراز).

Four reports merged onto one source file: llvm-cov brings lines, functions, regions, branches, MC/DC and instantiations, two TRACE32 exports bring function calls and object code, and a mutation report brings the mutation scoreScreenshot pending — add assets/img/four-reports-one-file.svg (see SCREENSHOTS.md).

يمكن أن يحمل التشغيل المدمج أكثر من المقاييس الكلاسيكية الستة، ويأتي كل مقياس من التقرير الذي يقيسه: استدعاءات الدوال والشيفرة الهدف ودرجة الطفرات إلى جانب الأسطر والدوال والمناطق والتفرّعات وMC/DC وإنشاء النسخ. يعرض عرض Coverage عمودًا لكل مقياس يحمله التشغيل — ولا يعرض أي عمود لمقياس لا يحمله — مرتّبةً حسب وزن كل مقياس في درجتك، الأثقل أولًا، وبأي عرض — وما لا يتّسع له المكان ينزلق جانبًا بدل أن يختفي. اسحبه إلى اللوحة السفلية فيتحوّل إلى جدول. وتتبع بطاقات شريط الحالة وتقرير HTML وعمليات التصدير إلى CSV وMarkdown القاعدة نفسها: ما يحمله التقرير يُعرض، وما لا يحمله يُحذف بدلًا من أن يُطبع صفرًا.

The Coverage view in a real window: eight tracefiles from five languages above a tree with MC/DC, Conditions, Branches, Regions and the weighted score in columns beside every file, and a covered C# file open next to itScreenshot pending — add assets/img/coverage-view-editor.png (see SCREENSHOTS.md).
The Coverage view as a wide panel: C, C++, JavaScript, Python and .NET merged into one tree, with MC/DC, branches, regions, functions, lines, instantiations, mutation score, Max CRAP and the weighted score in columns beside every file, and an em dash where a metric does not applyScreenshot pending — add assets/img/coverage-view-columns.png (see SCREENSHOTS.md).
The Coverage view over a workspace of eleven projects: every tracefile listed, the tree collapsed to one row per project with its percentage and bar, scrolled through, expanded, and a file opened from itScreenshot pending — add assets/img/workspace-overview.gif (see SCREENSHOTS.md).
Visual Studio: the Coverage window over a folder of eleven projects — collapsed to one row per project with its bar, then expanded, then a file opened from itScreenshot pending — add assets/img/vs-workspace-overview.gif (see SCREENSHOTS.md).
في Visual Studio: نافذة Coverage على مجلد من أحد عشر مشروعًا — مطويّة إلى صف واحد لكل مشروع مع شريطه، ثم موسَّعة، ثم ملف فُتح منها.

من أي تقرير يأتي الملف

عندما تقيس عدة تقارير محمَّلة الملفَّ نفسه، يفوز به أحدثها كاملًا — وهذا صحيح حين تحلّ إعادة تشغيل الوحدة نفسها محلّ ما قاله تشغيل أقدم وأوسع. لكنه خطأ حين تقيس التقارير الشفرة نفسها عن قصد: عندها يتنقّل المحرر بينها مع كل بناء، ولا يروي كلٌّ منها إلا جزءًا من القصة. يحدّد coverageFile.sources ما يجب فعله بدلًا من ذلك، لكل ملف. وتستدعيه ثلاث حالات:

  • أحد التقارير هو الأفضل. يحمل coverage.json من llvm-cov بيانات MC/DC، بينما لا يحمل gcov.info من GCC للبناء نفسه إلا الأسطر والفروع: اختر coverage.json، واحتفظ بالآخر للملفات القليلة التي لا يبنيها إلا GCC.
  • عدة مجموعات اختبار لبناء واحد. تكتب اختبارات الوحدات واختبارات التكامل واختبارات العتاد في الحلقة (hardware-in-the-loop) كلٌّ منها تقريرًا؛ وكل تقرير وحده يترك أسطرًا نفّذها الآخرون. الدمج، union: يكون السطر مغطى حيث نفّذه أي تقرير، وتُجمع الأعداد.
  • قاعدة شفرة واحدة، ومترجمان. المصادر نفسها حين يبنيها clang وGCC تسلك مسارات مختلفة عبر الشفرة الخاصة بسلسلة الأدوات — دالة مدمجة (intrinsic) هنا، وبديل محمول هناك — ويقول كل تقرير إن النصف الآخر لم يُنفَّذ قط. الدمج، agree: لا يكون السطر مغطى إلا حيث نفّذه كل تقرير يقيسه، وتُعلَّم الأسطر التي تختلف فيها التقارير باللون الأزرق المخضر. هذا هو السؤال الذي يطرحه فحص المترجمات المتقاطع: ما الذي شغّلته فعلًا كل البناءات التي أشحنها؟

نادرًا ما تكتب القواعد بيدك. انقر بزر الفأرة الأيمن على ملف في عرض Coverage واختر Choose Coverage Source... (أو شغّل Choose Coverage Source for This File... على الملف المفتوح): فيسرد كل تقرير يقيس الملف، ولكلٍّ أسطره وفروعه وMC/DC الخاصة به، ثم Combine them — agree وCombine them — union؛ اختر واحدًا وحدّد هل ينطبق على الملف أو مجلده أو نمط. ويزيل Clear Coverage Source for This File... القاعدة مرة أخرى. في الإعدادات، كل قاعدة هي glob على الملفات، وglob على التقرير (النمط الذي لا يحتوي / يطابق اسم ملف التقرير، و{a,b} يسمّي عدة تقارير)، وللدمج "combine": "agree" أو "union". تحسم الأمر أول قاعدة تطابق ملفاتُها ويقيس تقريرُها الملف؛ والملف الذي لا يقيسه إلا تقرير واحد لا يُنتزع منه أبدًا. تأتي الفروع وMC/DC والمناطق في الملف المدموج من التقرير الأغنى بها. ويحسم coverageFile.mergeStrategy: "order" الملفات التي لا تتناولها أي قاعدة بترتيب coverageFile.paths بدلًا من الأوقات.

{
  "fuciniCoverage.coverageFile.paths": ["clang.json", "gcc/bits.gcov.json.gz"],
  "fuciniCoverage.coverageFile.sources": [
    { "files": "src/**", "report": "{clang.json,bits.gcov.json.gz}", "combine": "agree" }
  ]
}

ما تراه: يسمّي صف الملف في عرض Coverage التقرير الذي تأتي منه أرقامه، أو، عند الدمج، كل التقارير والوضع مع ≠ n للأسطر المختلف عليها. ويعلّم الهامش والمصدر المشروح تلك الأسطر باللون الأزرق المخضر ويذكران أي تقرير نفّذها وكم مرة. وتسمّي بطاقة التمرير في شريط الحالة مصدر الملف المفتوح، وللتشغيل كله، القواعد السارية وكيف حُسمت الملفات الأخرى. وsamples/c-cross-check في العرض التوضيحي هو حالة المترجمين، جاهزة للفتح. ويفعل Visual Studio كل هذا أيضًا: Choose Coverage Source... على صف في عرض Coverage، وChoose وClear Coverage Source for This File... ضمن Tools > Coverage Studio.

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

Choose Coverage Source on bits.c: clang.json with lines, branches and MC/DC, bits.gcov.json.gz with lines and branches, and the two ways to combine them
في VS Code: Choose Coverage Source... على bits.c من عرض Coverage — تقرير clang، أو تقرير GCC، أو كلاهما مدموجين.
Animation in VS Code: bits.c combined by agree with four teal lines, Choose Coverage Source opened from the Coverage view, and the file reloaded combined by union
في VS Code: من agree إلى union بنقرتين — تبقى الأسطر المختلف عليها باللون الأزرق المخضر، وتتغيّر الأرقام.
Animation in Visual Studio: bits.c combined by agree, the Coverage window's row menu, Choose Coverage Source and its two dialogs, and the file reloaded combined by union
في Visual Studio: الأمر نفسه من قائمة الصف في عرض Coverage — التقارير، ثم مدى امتداد القاعدة، ثم الملف وقد أُعيد تحميله.
bits.c with the clang and GCC reports combined by agree: the Coverage view row names both reports with four disputed lines, and the builtin and the portable loop are marked in teal
في VS Code: bits.c، وقد دُمج فيه clang وGCC بطريقة agree — يقول الصف ≠ 4، والأسطر الأربعة التي لم ينفّذها إلا بناء واحد باللون الأزرق المخضر.
bits.c with the clang and GCC reports combined by union: every line covered, the four disputed lines still teal, and the status bar naming the union
الملف نفسه مدموجًا بطريقة union: كل سطر نفّذه أيٌّ من البناءين مغطّى، فيبلغ bits.c نسبة 100% من أسطره — وتبقى الأسطر التي يختلف عليها البناءان باللون الأزرق المخضر.
The Annotated Source of bits.c, combined by agree: the source line under the title names both reports, and each teal row says how often each report ran it
يسمّي Annotated Source الدمج تحت العنوان، ويذكر في كل صف باللون الأزرق المخضر كم مرة نفّذه كل تقرير.
The status bar's hover card for bits.c, ending with the coverage source: both reports, combined by agree, disagreeing on four lines
تذكر بطاقة التمرير الخاصة بالملف في شريط الحالة من أين تأتي أرقامه؛ وتعدّ بطاقة التشغيل الملفات التي حسمتها كل قاعدة.
Visual Studio: Choose Coverage Source on bits.c from the Coverage window's row menu — the clang report, the GCC report and the two ways to combine them; behind it the row's agree badge with four disputed lines and the teal lines in the margin
في Visual Studio: Choose Coverage Source... من صف في عرض Coverage — التقارير نفسها والطريقتان نفسهما لدمجها؛ ويسمّي شريط الحالة طريقة الدمج.

7. إعادة تعيين المسارات

غالبًا ما يسجّل CI مسارات مطلقة لجهاز البناء لا توجد على محطة عملك. أعد كتابتها بقواعد مرتبة:

{
  "fuciniCoverage.pathRemap": [
    { "from": "/builds/ci/project", "to": "${workspaceFolder}" },
    { "from": "\\\\", "to": "/" }
  ]
}

تُطبَّق القواعد بالترتيب؛ وتفوز أول مطابقة لكل بادئة. استخدم هذا لتوحيد اختلافات فواصل Windows/Unix أو لتعيين مسار حاوية إلى نسختك المحلية.

نادرًا ما تضطر إلى كتابة القاعدة بنفسك. أشيع حالات «حُمِّل لكن لا شيء يضيء» هي ملف تتبع تأتي مساراته من حاوية أو من نسخة CI مسحوبة (/build/src/a.c، /home/runner/work/repo/repo/src/a.c، C:\agent\_work\1\s\src\a.c) بينما في مساحة العمل src/a.c. حين يترك التحميل ملفات بلا تطابق، يبحث الامتداد عن أسماء الملفات في مساحة العمل، ويستنتج قاعدة البادئة التي تفسّر أكبر عدد منها، ويسجّلها بوصفها [FUCINI_REMAP_002]، وتعرض نتيجة التحميل Apply Suggested Remap — نقرة واحدة تُلحق القاعدة بـ fuciniCoverage.pathRemap وتعيد التحميل. ويجري Suggest Path Remap Rule التحليل نفسه عند الطلب من لوحة الأوامر. ولا يُكتب شيء من دون النقرة.

يجوز أن يستخدم to المتغيّر ${workspaceRoot}، الذي يمثّل مجلد مساحة العمل الذي يقع فيه ملف التتبع؛ وفي مساحة عمل متعددة الجذور يجرّب ذلك المجلد أولًا، ثم كل مجلد آخر يتبيّن أن الملف موجود فيه. والقواعد نفسها تُقرأ لكل مجلد، فيستطيع كل جذر في مساحة عمل متعددة الجذور أن يحمل قواعده الخاصة.

8. التغطية داخل المحرر

  • الهوامش والمسطرة — يعرض هامش المحرر نفسه افتراضيًا النتائج وحدها: أشرطة MC/DC، ومثلثات «منذ آخر تشغيل»، ونقاط الأسطر المحرَّرة. ويضيف editorGutter.mode أشرطة على غير المغطّى فقط أو خريطة حرارية لأعداد الإصابات (أدناه)؛ أما العرض الملوّن للملف كله فهو Annotated Source.
  • CodeLens للدوال — نسبة التغطية أعلى كل دالة؛ انقر للانتقال إلى أول سطر غير مغطى فيها. بدّل عبر codeLens.enabled.
  • التمرير فوق الفروع وMC/DC — مرّر فوق سطر قرار لمعرفة عدد مرات الأخذ/عدم الأخذ لكل فرع وجدول متجه لكل شرط. فعّل شريط هامش ملوّن عبر mcdcGutter.enabled.
  • تحذيرات الكود الميت — تُميَّز الدوال ذات الأسطر القابلة للقياس والتغطية الصفرية في لوحة Problems (deadCode.enabled).
  • Next / Previous Uncovered — تنقّل بين الثغرات.
  • شريط الحالة — عنصر $(dashboard) NN% على مستوى التشغيل بأكمله وعنصر لكل ملف، كلاهما ملوّن حسب الدرجة المركّبة؛ مرّر الفأرة لعرض جدول مقاييس كامل.
  • شارات المستكشف — شارات تغطية لكل ملف ولكل مجلد، مع تفصيل المقاييس عند التحويم. معطّلة افتراضيًا: فعّلها عبر explorerBadges.enabled.
  • منذ آخر تشغيل — مثلث أحمر على كل سطر نُفِّذ في التشغيل السابق ولم يُنفَّذ في هذا، وأخضر للحالة العكسية، مع مسطرة النظرة العامة وأعداد الإصابات عند التحويم.
  • المخازن المؤقتة المعدَّلة — كل علامة وتلميح وCodeLens يتحرك مع النص أثناء التحرير وينسحب من سطر أُعيدت كتابته، حيث تقول نقطة رمادية السبب.
  • أعداد الإصابات المضمّنة — يكتب hitCounts.inline القيمة ×12 بعد كل سطر تبدأ عنده عبارة، بما في ذلك ×0: الرقم الذي كان دائمًا عند التحويم، من دون تحويم. يبدّله Toggle Inline Hit Counts؛ وتعرضه قائمة شريط الحالة بصيغة إظهار أو إخفاء، أيهما ينطبق.
  • مدخلات Problems لكل سطر — يضع problems.perLine تشخيص Information، مع خط متعرّج في المحرر، على كل كتلة متّصلة من الأسطر التي لم تُنفَّذ قط في مستند مفتوح (الدالة الميتة ذات الأربعين سطرًا مدخل واحد، لا أربعون)، وفي وضع uncoveredAndPartial على كل سطر فيه فرع لم يُسلك قط. وتتبع المدخلات أسطرها أثناء التحرير وتزول عند إغلاق المستند؛ ومدخل الملف الواحد خلف problems.enabled لم يتغيّر.
  • تلوين السطر — يضع lineHighlight لونًا شبه شفاف خلف الأسطر نفسها لما يعلّمه الهامش (uncovered، أو heatmap للأسطر المنفَّذة أيضًا). إعداد مستقل، حتى يبقى الهامش نظيفًا بينما تُلوَّن الفجوات، أو العكس.
  • مسطرة النظرة العامة — يقرّر overviewRuler شأن الشريط في شريط التمرير بمعزل عن الهامش: follow (مع الأعمدة، كما كان)، أو uncovered (دائمًا، فيمكن إيقاف الهامش بينما يظل شريط التمرير يرسم خريطة الفجوات)، أو off.
  • أي ملف تتبّع غطّى سطرًا — عند دمج عدة تقارير، تنتهي تلميحة عدد مرات التنفيذ بعبارة مغطّى بواسطة: وكل تقرير غطّى ذلك السطر، بما في ذلك اسم المجموعة من TN: في lcov؛ والنقر على صف ملف تتبّع في عرض Coverage يضيء الأسطر التي أسهم بها في كل محرّر مفتوح.
Function CodeLens and MC/DC hover tooltipScreenshot pending — add assets/img/codelens-hover.png (see SCREENSHOTS.md).
A function CodeLens on a C# method: 37.14% covered, 13 of 35 lines, branches 10 of 22, complexity 22, CRAP 142.2 — with the uncovered branches of the method marked underneathScreenshot pending — add assets/img/codelens-crap.png (see SCREENSHOTS.md).
Alt+N jumps from one uncovered line to the next, Alt+P goes backScreenshot pending — add assets/img/jump-between-gaps.gif (see SCREENSHOTS.md).
Explorer badges: a coverage percentage on every measured file and folder of all five demo projects, beside a covered C# file with its gutters, hit counts and CodeLensScreenshot pending — add assets/img/explorer-badges.png (see SCREENSHOTS.md).

أوضاع هامش المحرر

يقرّر editorGutter.mode ما يعرضه هامش المحرر نفسه عن التغطية، فوق النتائج التي يعرضها دائمًا. off (الافتراضي) هو تلك وحدها. يضع uncovered شريطًا على كل سطر لم يُنفَّذ قط وشريطًا كهرمانيًا على كل سطر فيه فرع لم يُسلك قط، ولا شيء على الأسطر المغطّاة، فلا يحجب جدار أخضر الأسطر الحمراء الثلاثة. ويضيف coverage شريطًا أخضر على كل سطر مغطّى، فيُقرأ الملف كله بالأحمر والكهرماني والأخضر بألوان سلّم الألوان. ويضيف heatmap بدلًا من ذلك ظلًّا دافئًا على كل سطر نُفِّذ، أشدّ حرارةً كلما كثر تنفيذه — فهو يُظهر عدد مرات تنفيذ السطر، لا ما إذا كان مغطّى، ولذلك يكون الملف ذو نسبة 100% هناك من الأصفر إلى البني، ولا يكون أخضر أبدًا. يختار Choose Editor Gutter Mode... وضعًا من لوحة الأوامر أو قائمة شريط الحالة؛ وينتقل زر الوضع في يمين شريط الحالة، أو Alt+G، إلى الوضع التالي بضغطة واحدة (يُخفي statusBar.showModeToggle الزر). وكلاهما يكتب الإعداد. يفعّل المثال أشرطة غير المغطّى والأعداد المضمّنة معًا:

{
  "fuciniCoverage.editorGutter.mode": "uncovered",
  "fuciniCoverage.hitCounts.inline": true
}
Uncovered mode: a red bar and wash on lines that never ran, amber on a line with a branch arm never taken, and the execution count written after each lineScreenshot pending — add assets/img/gutters.png (see SCREENSHOTS.md).
The coverage mode in VS Code: green bars on lines that ran in full, amber where a branch arm never did, red where nothing ran; the status bar names lcov.info as the report and the mode button reads Coverage
في VS Code: وضع coverage — أخضر حيث نُفِّذ السطر بالكامل، وكهرماني حيث لم يُسلك فرع قط، وأحمر حيث لم يُنفَّذ شيء. يسمّي عنصر شريط الحالة الخاص بالملف التقرير الذي تأتي منه أرقامه؛ ويقول زر الوضع بجانبه Coverage.
Alt+G pressed four times: heatmap, off, uncovered and back to coverage
في VS Code: Alt+G أربع مرات — heatmap، ثم off، ثم uncovered، والعودة إلى coverage.
Visual Studio: Gutter: Coverage on Quote.cs, green, amber and red bars beside the hit counts
في Visual Studio: Gutter: Coverage (Red, Amber, Green) على Quote.cs.

الخريطة الحرارية نسبية إلى الملف. تقارن درجة لون السطر عدّادَه بأسخن سطر في الملف نفسه، على مقياس لوغاريتمي وفي خمس درجات — وبذلك يظهر كلٌّ من جسم حلقة نُفِّذ ألف مرة ودالة نُفِّذت مرتين، بدلًا من أن يطغى أحدهما على الآخر، ويبدو الملف الذي نُفِّذ فيه كل شيء مرة واحدة بالضبط دافئًا بانتظام لا باهتًا بانتظام. في السمة الداكنة يمتد التدرّج من الزيتوني الخافت إلى البرتقالي الزاهي، وفي السمة الفاتحة من الأصفر الباهت إلى البني: وفي الحالتين يعني اللون الأكثر عددًا أكبر من مرات التنفيذ، ويبقى الأحمر مخصّصًا للأسطر التي لم تُنفَّذ قط. يضع lineHighlight: "heatmap" الدرجات اللونية نفسها خلف الشيفرة كخلفية ملوّنة، ويكتب hitCounts.inline العدد الدقيق بعد السطر.

{
  "fuciniCoverage.editorGutter.mode": "heatmap",
  "fuciniCoverage.lineHighlight": "heatmap",
  "fuciniCoverage.hitCounts.inline": true
}
The heatmap on a dark theme: functions that ran once in dim olive, the decision that ran five times in vivid orange, lines that never ran in redScreenshot pending — add assets/img/heatmap-dark.png (see SCREENSHOTS.md).
The same file on a light theme: pale yellow for lines that ran once, brown for the hottestScreenshot pending — add assets/img/heatmap-light.png (see SCREENSHOTS.md).
Switching from uncovered mode to the heatmap, on a dark and then on a light themeScreenshot pending — add assets/img/heatmap.gif (see SCREENSHOTS.md).

الألوان لك. يلوّن colorScale.lowColor وmidColor وhighColor الأحمر والكهرماني والأخضر في الهامش وفي الألوان خلف الأسطر وفي كل نسبة مئوية؛ ويحمل heatmap.colors وheatmap.colorsDark درجات الخريطة الحرارية الخمس للسمة الفاتحة والداكنة، من السطر الأقل تنفيذًا إلى الأكثر تنفيذًا. تُظهر صفحة الإعدادات النتيجة قبل حفظ أي شيء: تحت Colour scale تبقى معاينة ظاهرة بينما تمرّ الصفوف — التدرّج بنقطتي ارتكازه، وبعض النسب المئوية بألوانها، ومحرر فاتح صغير ومحرر داكن صغير ملوَّنان بوضع coverage وبالخريطة الحرارية — وتُعاد رسمها كلما اختير لون.

{
  "fuciniCoverage.heatmap.colors": ["#e3f2fd", "#90caf9", "#42a5f5", "#1e88e5", "#0d47a1"]
}
The settings page in VS Code: two colours typed in, the pinned colour preview repainting each time
في VS Code: لونان يُكتبان في صفحة الإعدادات — وتُعاد رسم المعاينة في كل مرة.
Visual Studio: the same settings page and the same colour preview
في Visual Studio: الصفحة نفسها، والمعاينة نفسها.

الجزء الذي لم يُنفَّذ قط من السطر

السطر إما مغطّى وإما غير مغطّى، لكن الحقيقة كثيرًا ما تكون بين الاثنين: return x > hi ? hi : x; نُفِّذ، أما فرعه hi فلم يُنفَّذ قط. عند تفعيل lineHighlight، يُلوَّن في المحرّر الجزء الذي لم يُنفَّذ قط من سطر منفَّذ، وذلك لكل تنسيق يحمل نطاقات الأعمدة (llvm-cov وIstanbul وGo وdotnet-coverage) — وهي النطاقات نفسها التي يعلّمها المصدر المُعلَّق. ولا يكون ذلك إلا في الأسطر التي نُفِّذت: فالسطر الذي لم يُنفَّذ قط معلَّم بكامله أصلًا. ويُحتسب قالب C++ منفَّذًا حيثما نفّذته أي عملية استنساخ (instantiation)؛ أما ما فعلته كل عملية استنساخ على حدة فهو ما يبلّغ عنه مقياس الاستنساخ.

An executed line whose opening brace is tinted: the if ran, the block it opens never didScreenshot pending — add assets/img/partial-line.png (see SCREENSHOTS.md).

أي الاختبارات نفّذت هذا السطر

بعض التقارير لا تذكر أن السطر نُفِّذ فحسب، بل تذكر أيضًا أي الاختبارات نفّذته: coverage.py المكتوب باستخدام coverage json --show-contexts مع dynamic_context = test_function في .coveragerc، وOpenCover المجموع باستخدام -coverbytest، وملف تتبع lcov مكتوب بقسم لكل اختبار (TN:)، تُجمع أقسامه في سجل واحد فيه اختبارات لكل سطر. مرّر المؤشر فوق بداية السطر، حيث يظهر عدد مرات التنفيذ، فتظهر أسماء الاختبارات — مختصرةً إلى الصنف والتابع، الخمسة الأولى بأسمائها والبقية كعدد؛ ويقول CodeLens الخاص بالدالة كم اختبارًا نفّذها. يسرد Show Tests That Ran This Line — من Command Palette، أو قائمة سياق المحرر، أو في Visual Studio من Tools → Coverage Studio أو Ctrl+Shift+U, T — تلك الاختبارات، الأكثر تنفيذًا أولًا، ويفتح ما تختاره حيث كُتب في مساحة العمل. لا يستطيع تشغيل dotnet test أن يقول أي اختبار نفّذ ماذا؛ اضبط testRun.perTest فيسرد Run Tests with Coverage أصناف الاختبار ويشغّلها واحدًا تلو الآخر، كل تقرير موسومًا بصنفه، فيستطيع التلميح وCodeLens والأمر الإجابة لـ .NET أيضًا. وتُحفظ هذه المعلومات لكل ملف، ولذلك تبقى بعد الدمج مع تقرير لا يعرف شيئًا عن الاختبارات.

{
  "fuciniCoverage.testRun.perTest": true
}
# .coveragerc
[run]
dynamic_context = test_function

coverage run -m pytest && coverage json --show-contexts
Hovering the start of two lines of a Python file: each names the tests that ran it; an uncovered line names noneScreenshot pending — add assets/img/tests-per-line.gif (see SCREENSHOTS.md).
Show Tests That Ran This Line: the caret on a line, the list of tests that ran it busiest first, and the picked test opened where it is writtenScreenshot pending — add assets/img/tests-for-line.gif (see SCREENSHOTS.md).
Show Tests That Ran This Line: القائمة، الأكثر تنفيذًا أولًا، والاختبار مفتوحًا حيث كُتب.
Visual Studio: the caret on line 62 of Quote.cs, Show Tests That Ran This Line, the dialog listing Tests.QuoteTests, and Go to Test opening QuoteTests.cs
في Visual Studio: Show Tests That Ran This Line على السطر 62 من Quote.cs — الاختبار الذي نفّذه، وGo to Test يفتحه.

النجاح أو الفشل على العلامات

السطر المغطّى يبدو واحدًا سواء نجح اختباره أم لم ينجح. حيث يقول التقرير أي الاختبارات نفّذت سطرًا ويقول ملف نتائج المشغّل كيف انتهت، يحصل السطر الذي نفّذه اختبار فاشل على شريط أحمر عند بدايته وعلى شريط في مسطرة النظرة العامة؛ ويسمّي تلميحُ السطر الاختباراتِ الفاشلة، ويكتب Show Tests That Ran This Line كلمة فشل بجانب كل منها. فحين يكون اختبارٌ أحمر، الموضع الذي يُنظر فيه هو الشيفرة التي مرّ بها. تُقرأ النتائج عند كل تحميل من مجلد كل تقرير — أي ملف .trx، والأسماء التي تستعملها أدوات كتابة JUnit (TEST-*.xml وjunit*.xml وtest-results*.xml) — ومن testResults.paths، مساراتٍ أو أنماط glob نسبيةً إلى المجلد. يطلب Run Tests with Coverage من dotnet test ملف test-results.trx بجانب التقرير، فمع تفعيل testRun.perTest لا يلزم إعداد أي شيء. ويوقف testResults.enabled هذه القراءة.

{
  "fuciniCoverage.testResults.paths": ["build/test-results/**/*.xml", "reports/junit.xml"]
  }
A failing test: a red bar on the lines it ran, the hover naming it under Failing tests that ran this line, and Show Tests That Ran This Line writing failed beside itScreenshot pending — add assets/img/pass-fail.gif (see SCREENSHOTS.md).
Visual Studio: a failing test — the red bar on the lines it ran, the hover naming it, and Show Tests That Ran This Line writing failed beside itScreenshot pending — add assets/img/vs-pass-fail.gif (see SCREENSHOTS.md).
في Visual Studio: اختبار أحمر — الشريط الأحمر على الأسطر التي نفّذها، والتلميح الذي يسمّيه، وShow Tests That Ran This Line يكتب failed بجانبه.

الاختبارات التي يمسّها تغيير

التشغيل الكامل يجيب ببطء عمّا يجيب عنه Run Tests Affected by My Changes… في الحال: من بين كل الاختبارات، أيّها مرّ بالشيفرة التي عدّلتُها للتو؟ يُسأل git عن فرق شجرة العمل مقابل testImpact.baseRef — وهو HEAD افتراضيًا، أي ما لم يُودَع بعد؛ أو origin/main لكل ما يغيّره الفرع — وتُسرد الاختبارات التي نفّذت سطرًا متغيّرًا، والاختبار الذي نفّذ أكبر قدر من التغيير أولًا. اختيار اختبار يفتحه. وحيث جاءت التقارير من تشغيل لكل اختبار على حدة (testRun.perTest)، يشغّل المدخل الأول تلك الاختبارات وحدها، كل صنف في تقرير خاص به، فيبقى تقرير كل صنف آخر قائمًا وتبقى الإجماليات إجماليات مجموعة الاختبارات كلها. والاختبار الذي لم ينفّذ إلا أسطرًا تحت إدراج أو حذف يُسرد أيضًا: فلولا ذلك لسمّى تقريره الأسطر الخطأ.

An uncommitted edit, Run Tests Affected by My Changes…, the list with the test that ran most of the change first, and the run of only those testsScreenshot pending — add assets/img/test-impact.gif (see SCREENSHOTS.md).
Visual Studio: an edit, Run Tests Affected by My Changes…, the list with the test that ran most of the change first, and the run of only thoseScreenshot pending — add assets/img/vs-test-impact.gif (see SCREENSHOTS.md).
في Visual Studio: تعديل، ثم Run Tests Affected by My Changes…، والقائمة وفي أولها الاختبار الذي نفّذ معظم التغيير، ثم تشغيل تلك الاختبارات وحدها.

أقل عدد من الاختبارات يظل ينفّذ كل سطر

يجيب Show Minimal Test Set… عن سؤالين من الأسطر نفسها المسجَّلة لكل اختبار: أيّ اختبارات قليلة تظل تنفّذ كل سطر تنفّذه مجموعة الاختبارات — للتشغيل السريع قبل الإيداع — وأيّ الاختبارات لا تنفّذ أي سطر لا ينفّذه اختبار آخر أصلًا. تأتي الاختبارات المختارة أولًا، كلٌّ منها مع الأسطر التي يضيفها والأسطر التي لا ينفّذها سواه؛ ثم البقية، كلٌّ منها معلَّم بأنه لا يضيف شيئًا. الاختيار هو الاختيار الجشع — الاختبار الذي ينفّذ أكثر الأسطر، ثم الذي يضيف أكثرها إليه — فهو قريب من أصغر مجموعة وهو نفسه في كل مرة. الزائد بحسب الأسطر ليس زائدًا بحسب ما يتحقق منه الاختبار: فالاختبار الذي لا يضيف أي سطر قد يكون مع ذلك الوحيد الذي يتحقق من قيمة على تلك الأسطر. القائمة تقول أين يُنظر حين تُقلَّص مجموعة اختبارات، ولا تقول أبدًا ما الذي يُحذف.

Show Minimal Test Set…: the chosen tests first, then the tests that add nothingScreenshot pending — add assets/img/minimal-test-set.png (see SCREENSHOTS.md).
Visual Studio: Show Minimal Test Set… — the chosen tests, then the tests that add nothingScreenshot pending — add assets/img/vs-minimal-test-set.png (see SCREENSHOTS.md).
في Visual Studio: Show Minimal Test Set… — الاختبارات المختارة، ثم الاختبارات التي لا تضيف شيئًا.

تشغيل هذا الاختبار، مع التغطية

ضع المؤشر في اختبار وشغّل Run This Test with Coverage — من Command Palette، أو قائمة سياق المحرر، أو في Visual Studio من Tools → Coverage Studio أو Ctrl+Shift+U, R — فيُشغَّل ذلك الاختبار وحده مع تفعيل التغطية: تابع الاختبار الذي فيه المؤشر، أو صنف الاختبار أو كتلة describe عندما يكون بين التوابع، أو الملف عندما يكون فوق كل الأصناف. ما تحت المؤشر يُقرأ من النص، فيعمل مع C# وVB وF# ([Fact] و[Test] و[TestMethod] وأمثالها)، وJavaScript وTypeScript (it وtest وdescribe)، وPython (def test_…) أيًّا كانت خدمة اللغة المثبّتة. تُضيَّق وصفة المجلد إليه — dotnet test --filter "FullyQualifiedName~…"، أو jest أو vitest <file> -t "…"، أو معرّف عقدة pytest — ويُحمَّل ما كتبته كأي تشغيل؛ والمشغّل الذي لا يمكن تضييقه يقول ذلك ويشغّلها Run Tests with Coverage كلها.

Run This Test with Coverage: the caret in a Fact, the one dotnet test --filter run in the terminal, the gutter of the class under test filling inScreenshot pending — add assets/img/run-this-test.gif (see SCREENSHOTS.md).
Run This Test with Coverage: اختبار واحد، تشغيل واحد، والصنف قيد الاختبار مضاء.
Visual Studio: the caret in the Fact AGoldCustomerGetsTenPercent, Run This Test with Coverage, the run appearing in the Tracefiles list and the lenses saying run by 1 test(s)
في Visual Studio: Run This Test with Coverage داخل [Fact] — التشغيل في قائمة Tracefiles، والأسطر فوق الدوال تقول إن اختبارًا واحدًا نفّذ الشيفرة.

Go وRust. في ملف Go تُشغَّل الدالة func TestXxx التي عندها المؤشر (أو Fuzz… أو Example…) وحدها، في حزمتها وباسمها بالضبط — go test ./pkg/calc -run "^TestTotal$" — وخارج أي اختبار تُشغَّل حزمة الملف. وفي ملف Rust تُشغَّل الدالة الموسومة بـ #[test] بمسارها في الـ crate مع --exact؛ وحين يكون المؤشر في mod وليس في أي اختبار، تُشغَّل اختبارات تلك الوحدة؛ واختبار التكامل تحت tests/ يُشغَّل في ملفه الثنائي الخاص (--test api). ولا يُسلَّم المشغّل إلا ملفات لغته: ملف TypeScript في مجلد Go يحصل على جملة، لا على تشغيلٍ للاشيء.

التغطية بعد كل حفظ

مع تفعيل testRun.onSave، يشغّل حفظُ ملف مصدر الاختباراتِ التي تغطّيه، مع التغطية، بعد لحظة من الحفظ، ويتبعه الهامش. لحلّ .NET يُعثر على مشروع الملف المحفوظ عبر رسم .csproj البياني ولا تُشغَّل إلا مشاريع الاختبار التي تشير إليه — مباشرة أو عبر مشاريع أخرى — بأمر dotnet test <project> واحد لكل منها؛ وأي مشغّل آخر يشغّل وصفته كاملة؛ والملف الذي لا يملكه مشروع ولا يقيسه تقرير لا يشغّل شيئًا. عدة عمليات حفظ متتالية تشغيلٌ واحد، والتشغيل الجاري لا يُقاطَع. والباقي كما يفعله Run Tests with Coverage: الطرفية، ولوحة Output، والتقرير محمَّلًا. معطّل افتراضيًا — فهو عادة تُختار، لا إعداد افتراضي يُكتشف.

{
  "fuciniCoverage.testRun.onSave": true
}
Coverage after every save: an edit to a C# file, Ctrl+S, the covering test project runs by itself, and the gutter changesScreenshot pending — add assets/img/coverage-on-save.gif (see SCREENSHOTS.md).
التغطية بعد كل حفظ: عدّل واحفظ، ويتبعك الهامش بعد لحظة.
Visual Studio: with testRun.onSave on, a comment line added to Quote.cs and saved, the tests running by themselves and the lens above Price changing
في Visual Studio: testRun.onSave مفعّل — حُفظ Quote.cs، فتعمل الاختبارات من تلقاء نفسها ويتغيّر السطر فوق الدالة.

التطبيق نفسه، مع التغطية

تشغيل الاختبارات يقول ما تبلغه الاختبارات. وما يبلغه إنسان — وهو يتنقّل بالنقر بين الشاشات قبل إصدار، أو يعيد خطوات عميل — تغطيةٌ أيضًا، وRun App with Coverage… يجمعها. تطبيق .NET الخاص بالمجلد — Exe أو WinExe أو مشروع ويب أو مشروع worker، وليس مشروع اختبار أبدًا؛ ويُختار واحد حيث يوجد أكثر من تطبيق — يُبدأ تحت dotnet-coverage من Microsoft في نافذة console خاصة به، حتى يمكن الكتابة في تطبيق console، ويعمل إلى أن تغلقه. وما مررتَ به يُحمَّل بعدها كأي تشغيل، وفي جلسة تغطية يُضاف إلى ما نفّذته الاختبارات. وكيفما انتهى التطبيق، لا يُحسب ذلك على التشغيل. يلزم تثبيت الأداة مرة واحدة: dotnet tool install --global dotnet-coverage.

Run App with Coverage…: the console app started under dotnet-coverage, a few inputs, closed, and its coverage loadedScreenshot pending — add assets/img/run-app.gif (see SCREENSHOTS.md).
Visual Studio: Run App with Coverage… — the console app, a few inputs, closed, and its coverage loadedScreenshot pending — add assets/img/vs-run-app.gif (see SCREENSHOTS.md).
في Visual Studio: Run App with Coverage… — تطبيق وحدة التحكم، وبضعة مدخلات، وإغلاقه، وتغطيته محمّلة.

الطفرات وأماكن وجودها

أداة الطفرات — PIT للغة Java، وStryker للغات JavaScript وC# وScala، وMull للغتي C وC++ — تغيّر شيفرتك بطرق صغيرة وتشغّل الاختبارات على كل تغيير. والتغيير الذي لا يلاحظه أي اختبار هو طفرة ناجية: نُفِّذت الشيفرة، ولم يتحقق شيء مما فعلته. تبيّن درجة الطفرات عدد ما أُمسك به منها؛ ومنذ 0.2026.83 يبيّن المحرّر أين توجد البقية. فالسطر الذي فيه طفرة ناجية تتبعه ملاحظة (⚑ 2 mutants survived)، ويوضع خط تحت النص المتغيّر حيثما يذكر التقرير أي نص كان ذلك (كما يفعل Stryker وMull)، ويظهر شريط في مسطرة النظرة العامة، ويعرض التمرير فوق السطر ما الذي تغيّر، وكم اختبارًا نفّذه، وبالنسبة إلى الطفرات التي أُمسك بها، أي اختبار أمسك بها.

A surviving mutant in the editor: the note after the line, the underlined text, and the hover naming the change — ConditionalBoundary: value <= loScreenshot pending — add assets/img/mutant-hover.png (see SCREENSHOTS.md).

ناجية تعني أن الاختبارات نفّذت الشيفرة المتغيّرة ونجحت كلها. وغير مُختبَرة (وهي no coverage في التقرير) تعني أنه لا يوجد اختبار ينفّذ تلك الشيفرة أصلًا، فلم يكن ممكنًا أن يلاحظ شيء. أما الطفرات التي أُمسك بها فتُعدّ عند التمرير ولا تُعلَّم أبدًا، والطفرات التي لم تكن يومًا اختبارًا منصفًا — كالتي لا تُترجَم (لا تجتاز التصريف) — تبقى خارج الدرجة. وفي المصدر المُعلَّق صفّ تحت كل سطر من هذه الأسطر وزر Next Mutant (U)، وفي تقارير HTML قسم Surviving Mutants يرتبط بالسطر. لا يلزم تفعيل أي شيء، والمشروع الذي ليس له تقرير طفرات لا يرى شيئًا من ذلك.

Surviving mutants marked in the editor, the hover naming the change, and the annotated source jumping from one to the next with UScreenshot pending — add assets/img/mutants.gif (see SCREENSHOTS.md).

هل كان اختبارٌ سيلاحظ؟ تشغيل طفرات عند المؤشر

تشغيل الطفرات لمشروع كامل يستغرق ساعة؛ ولدالة واحدة يستغرق دقيقة. Run Mutation Tests Here يشغّل تلك الدقيقة: الدالة التي فيها المؤشر — أو الأسطر المحدَّدة، أو الملف — هي ما يُطلب من مشغّل الطفرات الخاص بالمجلد أن يُجري عليه الطفرات، ويُحمَّل تقريره بجانب التغطية المعروضة على الشاشة، حيث تُعلَّم الطفرات الناجية. لـ C# المشغّل هو Stryker.NET (dotnet tool install --global dotnet-stryker)، ويُعطى مدى المحارف ومشروع الاختبار الذي يصل إلى مشروع الملف؛ ولـ JavaScript وTypeScript هو StrykerJS، ويُعطى الأسطر؛ ولـ Java هو PIT مع Maven، ويُعطى الصنف. وكيفما انتهى المشغّل، لا يُحسب ذلك على التشغيل: الدرجة التي دون عتبته رمز خروج، وتبقى مع ذلك تقريرًا. والمشغّل الذي لم يكتب شيئًا يُذكر ذلك عنه، مع ما يلزم تثبيته له.

Run Mutation Tests Here on one function: Stryker.NET runs that minute, and the surviving mutants are marked in the editorScreenshot pending — add assets/img/mutation-here.gif (see SCREENSHOTS.md).
Visual Studio: Run Mutation Tests Here on one function, and the surviving mutants markedScreenshot pending — add assets/img/vs-mutation-here.gif (see SCREENSHOTS.md).
في Visual Studio: Run Mutation Tests Here على دالة واحدة، والطفرات الناجية معلَّمة.

عرض Test Coverage الخاص بـ VS Code نفسه

مع تفعيل testCoverage.publish (الافتراضي)، يذهب كل تشغيل محمَّل أيضًا إلى عرض Test Coverage الأصلي في المحرر — لوحة التغطية في Test Explorer، والنسب المئوية لكل ملف التي يضعها في Explorer، ومفتاح Show Inline Coverage الخاص بالمحرر نفسه — بوصفه أسطرًا وفروع قرارات ودوالّ، مع تحميل التفاصيل عند الطلب، أيًّا كان ملف التتبع الذي جاءت منه ومن دون أي محوّل اختبارات. ينشر Show in Test Coverage View التشغيل النشط ويفتح اللوحة أيًّا كان الإعداد؛ وتعرضه قائمة شريط الحالة خلف quickActions.showTestCoverage. وعند التعطيل لا يظهر مدخل Fucini Coverage في Test Explorer إطلاقًا. عندما يسمّي ملف التتبع اختباراته (أقسام TN: في lcov)، يظهر كل اختبار تحت Fucini Coverage في Test Explorer، ويمكن للعرض تصفية تغطية الملف حسب الاختبار.

VS Code's own Test Coverage view filled from the loaded reports, one bar each for statements, branches and functionsScreenshot pending — add assets/img/test-coverage-view.png (see SCREENSHOTS.md).

الأسطر غير المغطّاة في لوحة Problems

معطّل افتراضيًا لأنه صاخب بطبيعته، ولا يعمل إلا على المستندات المفتوحة — فلا يستطيع تشغيل من ألفي ملف أن يُغرق اللوحة. مستقل عن problems.enabled، الذي يقتصر على مدخل واحد لكل ملف:

{
  "fuciniCoverage.problems.perLine": "uncoveredAndPartial"
}
The Problems panel: one entry per file below the statement threshold, and a possible-dead-code entry for every function that never ranScreenshot pending — add assets/img/problems-panel.png (see SCREENSHOTS.md).

9. تغطية الفروقات

اقصر الزخارف على الأسطر التي تغيرت مقارنة بمرجع أساسي في git — مثالي لمراجعة ما غطاه طلب السحب (PR) بالضبط وما لم يغطّه:

{
  "fuciniCoverage.gitDiff.enabled": true,
  "fuciniCoverage.gitDiff.baseRef": "origin/main"
}
Diff coverage: only the five lines changed against the base ref are marked and judged — 5 of 5 lines, 7 of 8 branchesScreenshot pending — add assets/img/diff-coverage.png (see SCREENSHOTS.md).

في Visual Studio. الإعدادان نفسهما، يُقرآن من الملفات نفسها: تشغّل الإضافة git diff <baseRef> بنفسها لكل ملف في التشغيل وتقلّص التشغيل إلى الأسطر التي غيّرها فرعك — في الهامش وفي نافذة Coverage وفي البوابات. وعندما لا يجيب git بشيء، يقول جزء Output بما أجاب.

بوابة على الشيفرة الجديدة

threshold.newCode بوابة قائمة بذاتها، إلى جانب البوابات على التشغيل كله: من بين الأسطر المتغيّرة مقابل gitDiff.baseRef التي يمكن قياسها، أدنى نسبة مئوية يجب أن تكون قد نُفِّذت. فالمشروع الذي يقف عند 62% إجمالًا يستطيع مع ذلك أن يطلب أن يكون ما يُكتب اليوم مختبَرًا. تُحسب هذه البوابة عند كل تحميل على التشغيل كله، الذي يبقى على الشاشة — أما gitDiff.enabled فشيء آخر: الأسطر المتغيّرة بدلًا من التشغيل. ويعلن Check Coverage Thresholds ومدخلات الامتثال في Problems إخفاقها بجملة خاصة بها: New code 72.00% < 80% (18 of 25 line(s) changed against origin/main ran). والتغيير الذي ليس فيه سطر يمكن قياسه — تعليقات، ملف README — لا يُفشل شيئًا.

{
  "fuciniCoverage.threshold.newCode": 80,
  "fuciniCoverage.gitDiff.baseRef": "origin/main"
  }
Check Coverage Thresholds failing New code 72.00% < 80% beside a run that passes its own gatesScreenshot pending — add assets/img/new-code-gate.png (see SCREENSHOTS.md).
Visual Studio: Check Coverage Thresholds failing the new-code gate in the Error List, beside a run that passes its own gatesScreenshot pending — add assets/img/vs-new-code-gate.png (see SCREENSHOTS.md).
في Visual Studio: Check Coverage Thresholds يفشل في بوابة الشيفرة الجديدة، بجانب تشغيل يجتاز بواباته.

الشيفرة الجديدة حسب الوسم، وحسب المؤلف، وحسب التاريخ

الشيفرة الجديدة هي افتراضيًا الأسطر التي تغيّرها شجرة العمل مقابل gitDiff.baseRef — فرع، أو إيداع، أو وسم: "v1.4.0" هو كل ما جاء منذ ذلك الإصدار. وإعدادان يسألان عمّا لا يستطيع مرجعٌ أن يسأل عنه. يأخذ gitDiff.author جزءًا من اسم مؤلف، فتكون الشيفرة الجديدة عندئذ الأسطر التي ينسبها git إلى ذلك المؤلف؛ ويأخذ gitDiff.since يومًا، فتكون الأسطر التي كان آخر تغيير لها في ذلك اليوم أو بعده، أيًّا كان الفرع الذي جاءت عبره؛ والاثنان معًا: أسطر ذلك المؤلف منذ ذلك اليوم. تُقرأ هذه الأسطر من git blame، ملفًا ملفًا — وهو ما سيشعر به تشغيل كبير عند كل تحميل — وتحلّ محل الفرق في تغطية الفروقات وفي البوابة المذكورة أعلاه. والسطر الذي لم يُودَع بعد يُحتسب في الحالتين.

{
  "fuciniCoverage.gitDiff.author": "Ada",
  "fuciniCoverage.gitDiff.since": "2026-09-01"
  }
The same gate scoped by author and date: new code by Ada since 2026-09-01Screenshot pending — add assets/img/new-code-author.png (see SCREENSHOTS.md).

التغييرات غير المباشرة: ما تغيّر وإن لم يمسّه أحد

الفرق يقول أي الأسطر تغيّرت؛ وتشغيلان يقولان أي الأسطر لم تعد تُنفَّذ أو بدأت تُنفَّذ. والأسطر التي تستحق نظرة هي التي يختلف فيها الاثنان: شيفرة لم يعدّلها أحد ولم تعد تُنفَّذ، لأن اختبارًا حُذف، أو لأن فرعًا يسبقها صار يعود مبكرًا، أو لأن تجهيزة اختبار (fixture) تغيّرت. مراجعة الفرق لا تستطيع أن ترى هذه الأسطر — فهي خارجه بالتعريف. يسردها Show Indirect Coverage Changes… لكل ملف، الملف الأكثر خسارةً أولًا، ويفتح الملف الذي تختاره عند أول سطر من هذا النوع فيه. يُقارَن التشغيل بخط أساس CI حيث يسمّي baseline.report واحدًا — وهو ما يُحكم به على طلب السحب — وبالتشغيل الذي قبله في غير ذلك؛ وتُترك خارجًا الأسطر التي تغيّرها شجرة العمل مقابل gitDiff.baseRef، وكل ما يقع تحت موضع يزيح فيه ذلك التغيير أسطر الملف.

Show Indirect Coverage Changes…: a file that lost lines nobody edited, after a test was removed between two runsScreenshot pending — add assets/img/indirect-changes.png (see SCREENSHOTS.md).
Visual Studio: Show Indirect Coverage Changes… — a file that lost lines nobody editedScreenshot pending — add assets/img/vs-indirect-changes.png (see SCREENSHOTS.md).
في Visual Studio: Show Indirect Coverage Changes… — ملف فقد أسطرًا لم يعدّلها أحد، بعد إزالة اختبار بين تشغيلين.

10. الدرجة المركّبة

بدلًا من الإبلاغ عن ستة أرقام، يدمجها الامتداد في متوسط توافقي مرجّح (WHM) واحد. بالنسبة للمقاييس ذات النسب المئوية pᵢ والأوزان wᵢ:

WHM = ( Σ wᵢ ) / ( Σ wᵢ / pᵢ )

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

المقياسالوزنالمبرّر
MC/DC4IEC 61508 SIL 3–4 / ISO 26262 ASIL C–D / DO-178C DAL A–B.
التفرّعات2IEC 61508 SIL 2+ / ISO 26262 ASIL B+.
الشروط3بين التفرّعات وMC/DC (DO-178C وISO 26262).
المناطق1.5المسارات داخل العبارة (مثل التقييم القصير الجزئي).
الأسطر1IEC 61508 SIL 1+ / ISO 26262 ASIL A+.
الدوال1فحص الكود الميت.
إنشاء النسخ0.5تغطية قوالب C++‎؛ أضيق نطاق.
استدعاءات الدوال1مواضع الاستدعاء التي نُفِّذت (gcov، VectorCAST، Testwell CTC++، TRACE32).
الشيفرة الهدف0معطَّل ما لم تمنحه وزنًا: فهو يتضمّن تغطية العبارات.
درجة الطفرات0معطَّل ما لم تمنحه وزنًا: فهو ليس تغطية.

اضبط أي وزن على 0 لإسقاط ذلك المقياس من الدرجة. المقاييس غير الموجودة في البيانات (مثل MC/DC في تشغيل lcov عادي) تُحذف ببساطة.

وزن الشيفرة الهدف ودرجة الطفرات هو 0 إلى أن تقرّر خلاف ذلك (whmWeights.objectCode، whmWeights.mutation). تتضمّن تغطية الشيفرة الهدف تغطية العبارات، ولذلك فإن منح الاثنتين وزنًا يعني احتساب الدليل نفسه مرتين؛ أما درجة الطفرات فليست تغطية على الإطلاق — إذ يمكن لمجموعة اختبارات أن تنفّذ كل سطر دون أن تكتشف شيئًا. ومع ذلك يبقى لكلٍّ منهما عموده الخاص وعتبته الخاصة.

The default weights of the composite score: MC/DC 4, branches 2, regions 1.5, lines, functions and function calls 1, instantiations 0.5; object code and mutation score 0 until given a weightScreenshot pending — add assets/img/score-weights.svg (see SCREENSHOTS.md).

تغطية الشروط

a && b قرار واحد — تفرّعان — وشرطان بأربع نتائج. وقد تسلك مجموعة الاختبارات كلا التفرّعين دون أن ترى b خاطئًا قط: فتكون تغطية التفرّعات كاملة وتغطية الشروط ثلاثًا من أربع. يقع هذا المستوى بين تغطية التفرّعات وMC/DC في DO-178C وISO 26262، ومنذ 0.2026.83 صار مقياسًا قائمًا بذاته بدلًا من دمجه في التفرّعات: صفّ في بطاقات شريط الحالة، وعمود في عرض Coverage وفي التقارير وعمليات التصدير، ووزن قدره 3 في الدرجة (whmWeights.conditions)، وبوابة (threshold.conditions؛ بلا بوابة في ملف التعريف standard، و100 في safety).

One decision, a && b, and the same two tests: branches 2 of 2, conditions 3 of 4 because b is never seen false, MC/DC 1 of 2 because b is never shown to matterScreenshot pending — add assets/img/branch-condition-mcdc.svg (see SCREENSHOTS.md).

تُقرأ من مجسّات condition في BullseyeCoverage، ومن تصدير cond في TRACE32، ومن GCC 14 المبني باستخدام -fcondition-coverage. والتقرير الذي لا يميّز الشروط من القرارات ليس له صفّ ولا عمود ولا وزن من هذا النوع. إذا كنت تستخدم Bullseye أو TRACE32: كانت الشروط تُحتسب سابقًا كتفرّعات، ولذلك تتغيّر نسبة التفرّعات لديك مع هذا الإصدار، وتتغيّر مع الوزن الجديد درجتك المركّبة؛ اضبط whmWeights.conditions على 0 للحصول على الدرجة كما كانت.

GCC 14، سطرًا سطرًا. يجعل -fcondition-coverage أداة gcov تقول أي نتيجة لأي شرط مفقودة — الشرط 1 لم يكن صحيحًا قط، الشرط 0 لم يكن صحيحًا ولا خاطئًا قط — ويُعلَّم كل شرط على سطره ويُسمّى في التلميح، من JSON الخاص بـ gcov ومن قائمته النصية (condition outcomes covered 3/6). والمقياس حيث توجد المقاييس الأخرى: threshold.conditions بوابته، ويُترك بلا حكم حيث لا يحمل التشغيل رقمًا كهذا، ولـ Copy Coverage Summary عمود Conditions، ويقبل badge.metric القيمة conditions، ويقبل مربع البحث conditions < 80. ورقم الفروع لدالة يترك نتائج شروطها خارجًا، كما يفعل رقم الملف ورقم التشغيل.

GCC 14 condition coverage: the mark on the line and the hover naming the outcome never seenScreenshot pending — add assets/img/gcc-conditions.png (see SCREENSHOTS.md).

التعقيد وCRAP

تحمل بعض التقارير التعقيد الدوري (cyclomatic complexity) لكل دالة: OpenCover (وهو ما يكتبه Coverlet) وJaCoCo وClover وCobertura. وحيثما توفّر ذلك، تحسب الإضافة درجة CRAP — Change Risk Anti-Patterns — للدالة، انطلاقًا من ذلك التعقيد ومن التغطية التي قاستها بنفسها:

CRAP = complexity² × (1 − coverage)³ + complexity

الدالة البسيطة المختبَرة بالكامل تحصل على درجة تساوي تعقيدها لا أكثر؛ أما الدالة المعقّدة التي تكاد لا تُختبر فتبلغ درجتها المئات. في عيّنة C# من المشروع التجريبي، يبلغ تعقيد Price() 22 مع تغطية نحو 37% من أسطرها، فتكون النتيجة 142.2، بينما يبلغ تعقيد Shipping() 12 وهي مغطّاة بالكامل، فتكون النتيجة 12. الحدّ المتعارف عليه هو 30: تُدرَج الدالة التي تبلغه أو تتجاوزه ضمن Riskiest Methods في تقرير HTML، بدءًا بالأسوأ.

CRAP against line coverage for two methods: Price() with complexity 22 sits at 142.2 and needs about 75% coverage to get under 30; Shipping() with complexity 12 is fully covered and scores 12Screenshot pending — add assets/img/crap-curve.svg (see SCREENSHOTS.md).

يظهر التعقيد والدرجة في CodeLens الخاص بالدالة وبجوار الدالة في الشيفرة المصدرية المشروحة. Max CRAP هي أعلى درجة بين دوال الملف — أي الأسوأ لا المتوسط — وهي عمود في عرض Coverage وفي تقرير HTML وفي عمليات التصدير إلى CSV وMarkdown. وهي معلومة فحسب: ليست لها عتبة ولا وزن في الدرجة المركّبة. أما التقارير التي لا تحمل التعقيد (lcov وgcov وIstanbul وcoverage.py) فلا CRAP لها، ولا عمود فارغ كذلك.

منذ 0.2026.83 صار ذلك متاحًا للغتي C وC++ أيضًا. لا يبلّغ llvm-cov عن التعقيد، ولذلك يُحسب من بيانات التفرّعات التي يحملها التقرير أصلًا: الشروط المكتوبة في ملف الدالة نفسه، زائد واحد — وهو تعريف McCabe، وهو ما تحسبه الأدوات العاملة على مستوى المصدر في .NET وJava. أما الشروط الناتجة عن ماكرو من ملف آخر — وكل assert مثال على ذلك — فلا تُحتسب.

The Riskiest Methods section of the HTML report: Price() with complexity 22, 37.14% of its lines covered, CRAP 142.2Screenshot pending — add assets/img/riskiest-methods.png (see SCREENSHOTS.md).

Risk hotspots، وأي الملفات تُعرض

تحت شجرة عرض Coverage، تسرد Risk hotspots الدوال التي يلتقي فيها الكود المعقّد بتغطية قليلة، الأسوأ أولًا، ويفتح كل منها ملفه عند الدالة. تتأهل الدالة بدرجة CRAP — hotspots.crapThreshold، وهي 30 افتراضيًا، الرقم الذي اقترحه واضعو هذا المقياس — أو بالتعقيد الدوري وحده، hotspots.complexityThreshold، وهو معطَّل افتراضيًا؛ ولا يحوي أيًّا منها إلا التقارير التي تحمل التعقيد (OpenCover، وCobertura من Coverlet، وJaCoCo، وllvm-cov). ترى Community العدد والدرجة الأسوأ؛ أما القائمة المرتّبة فهي في Pro. وبجانب الفرز، تقول قائمة منسدلة ثانية أي الملفات تعرضها الشجرة — الكل، أو الملفات ذات الثغرات، أو الملفات غير المختبَرة، أو الملفات التي تغيّرت منذ آخر تشغيل؛ وتتبع المجلدات ملفاتها وتحتفظ بأرقامها. وكلاهما موجود في Visual Studio أيضًا، في نافذة Coverage.

Visual Studio: the Coverage window with the filter beside the sort and the risk hotspots under the treeScreenshot pending — add assets/img/vs-hotspots.png (see SCREENSHOTS.md).
في Visual Studio: نافذة Coverage، مع عامل التصفية بجانب الفرز وقسم Risk hotspots أسفل الشجرة.

مساحات الأسماء والأصناف والتوابع

لتقرير .NET يسمّي أصنافه — Cobertura وملف coverage.cobertura.xml من Coverlet، وOpenCover — ترسم قائمة منسدلة ثالثة، Folders / Namespaces، التشغيلَ نفسه مساحاتِ أسماء وأصنافًا وتوابع: رقم مساحة الأسماء هو مجموع أصنافها، ورقم الصنف مجموع توابعه، تمامًا كما أن رقم المجلد مجموع ملفاته، بالفرز نفسه والمرشّح نفسه. يفتح صفُّ التابع الملفَ عند التابع؛ والصنف المعلَن خارج أي مساحة أسماء يقع تحت (no namespace). يُكتب الاختيار في coverageView.perspective؛ والتشغيل الذي لا يحمل أسماء أصناف لا قائمة منسدلة له ويعرض مجلداته. وفي Visual Studio لنافذة Coverage القائمة المنسدلة نفسها.

The Coverage view drawn as namespaces, classes and methods, the dropdown on Namespaces, a method row about to open its fileScreenshot pending — add assets/img/namespace-perspective.png (see SCREENSHOTS.md).
التشغيل نفسه بحسب مساحة الأسماء والصنف والتابع.
Visual Studio: the Coverage window with the dropdown on Namespaces, the Pricing namespace open on Customer and its methods
في Visual Studio: نافذة Coverage حسب مساحة الأسماء والصنف والدالة.

تحت الأزرار والقوائم المنسدلة، مربع بحث. الكلمة تُبقي الصفوف التي يحمل اسمها أو مسارها إياها — وكل كلمة مكتوبة يجب أن توجد؛ والمقارنة تُبقي الصفوف التي يجتازها رقمها — < 80% على الدرجة، وlines >= 90، وbranches = 0، وfunctions != 100، وmcdc < 50 — وinvoice < 80 يطلب الاثنين معًا. تُبحث صفوف التوابع في منظور مساحات الأسماء وبؤر الخطر مع الملفات، فتوجد الدالة حيث يضعها التشغيل. تُرشَّح الشجرة أثناء الكتابة، في الصفحة، دون إعادة رسم؛ والمجلد الذي يحوي تطابقًا يُفتح له ويُغلق ثانية عندما يفرغ المربع؛ وEsc يمسحه. المربع نفسه، والقواعد نفسها، في Visual Studio.

Typing lines < 80 into the Coverage view's search box: the tree keeps only the files under eighty percent, folders opening to show themScreenshot pending — add assets/img/tree-search.gif (see SCREENSHOTS.md).
البحث في الشجرة: اسم، ثم lines < 80.

الشجرة تتبع المحرّر

الملف الذي تنظر إليه يُميَّز في عرض Coverage، وتُفتح المجلدات التي فوقه ويُمرَّر صفّه إلى حيث يُرى — لم يعد لازمًا البحث في الشجرة عن الملف المفتوح أصلًا. وفي غير ذلك تحتفظ الشجرة بموضع تمريرها، ولا يُعاد رسم شيء. والإعداد coverageView.followActiveEditor، وهو مفعَّل افتراضيًا، يتيح إيقاف ذلك لمن يفضّل أن تبقى الشجرة حيث وضعها.

Switching editor tabs: the Coverage view's highlighted row follows, the folders above it openedScreenshot pending — add assets/img/follow-editor.gif (see SCREENSHOTS.md).
Visual Studio: switching documents, and the Coverage window's highlighted row followingScreenshot pending — add assets/img/vs-follow-editor.gif (see SCREENSHOTS.md).
في Visual Studio: التبديل بين المستندات، والصف المميَّز في نافذة Coverage يتبعه.

11. بوابة الامتثال

يتحدد حكم COMPLIANT / NON-COMPLIANT (الذي يظهر في عرض المصدر المُعلَّق وتقرير HTML وكلا تلميحي شريط الحالة) بعتبات لكل مقياس ووضع معيّن:

The status-bar hover card: NON-COMPLIANT, 3 of 5 gates below threshold — functions and regions pass, lines and branches miss narrowly (amber), MC/DC misses outright (red)Screenshot pending — add assets/img/statusbar.png (see SCREENSHOTS.md).
الوضعCOMPLIANT عندما…
strict (default)كل مقياس يخضع لعتبة خاصة يبلغ عتبته — دون مساومات.
whmالدرجة المركّبة المرجّحة الواحدة تبلغ threshold.weighted.
bothيتحقّق كل من الفحص المرجّح والفحص الصارم لكل مقياس.
eitherيتحقّق الفحص المرجّح أو الفحص الصارم لكل مقياس (الأكثر تساهلًا).

العتبة 0 تعطّل تلك البوابة، والمقياس الذي لا يحمله التقرير لا يُقيَّم أبدًا. أما ما تعنيه العتبة التي لم تضبطها فيحدّده ملف التعريف الموضّح أدناه. شغّل Fucini Coverage: Check Coverage Thresholds للتقييم عند الطلب.

في Visual Studio. يحكم Tools → Coverage Studio → Check Coverage Thresholds على التشغيل بمفاتيح threshold.* نفسها ويقول ذلك في شريط الحالة وجزء Output؛ ومع compliance.diagnostics أو problems.enabled أو problems.perLine أو deadCode.enabled تستقر النتائج في Error List بجانب نتائج المترجم نفسه — إدخال واحد لكل ملف دون البوابة، وواحد لكل نطاق غير مغطى، وواحد لكل دالة لم تُشغَّل قط — ويفتح كل منها ملفه عند السطر.

Visual Studio: Check Coverage Thresholds, with the findings in the Error List beside the compiler's ownScreenshot pending — add assets/img/vs-error-list.png (see SCREENSHOTS.md).
في Visual Studio: Check Coverage Thresholds، مع النتائج في Error List.

ملفات تعريف العتبات

يحدّد threshold.profile ما تعنيه العتبة التي لم تضبطها. standard، وهو الإعداد الافتراضي منذ 0.2026.82، هو ما يمكن أن يُطالَب به مشروع عادي لا صلة له بالسلامة. أما safety فيعني أن كل بوابة عند 100 — وهو ما تتطلّبه حالة السلامة (safety case)، وهو بالضبط ما كان يُشحن حتى 0.2026.81.

المقياسstandardsafety
الأسطر80100
الدوال80100
المناطق75100
التفرّعات70100
الدرجة المركّبة75100
MC/DC، إنشاء النسخ، استدعاءات الدوال، الشيفرة الهدفبلا بوابة100
الشروطبلا بوابة100
درجة الطفراتبلا بوابةبلا بوابة

العتبة التي ضبطتها بنفسك تتقدّم على أيٍّ من الملفّين. يضع المثال بوابة التفرّعات عند 90 وكل ما عداها عند 100؛ ولإلزام بعض المقاييس فقط بـ 100، ابقَ على standard واضبط تلك المقاييس بنفسك. وثمّة تحفّظ واحد ينتج عن طريقة عمل الإعدادات: القيمة المساوية للقيمة الافتراضية المشحونة لا يمكن تمييزها عن غياب القيمة أصلًا، ولذلك فإن العتبة المكتوبة في ظل safety بقيمتها القياسية تمامًا — مثل 80 للأسطر — تظل تُحتسب 100.

{
  "fuciniCoverage.threshold.profile": "safety",
  "fuciniCoverage.threshold.branch": 90
}
The settings panel: the threshold profile above the grid of thresholds, showing the standard figuresScreenshot pending — add assets/img/threshold-profile.png (see SCREENSHOTS.md).
Switching the threshold profile to safety in the settings panel: the live preview asks for 100% everywhere; back on standard it asks for 80, 70, 80 and 75 and marks the rest as not gatedScreenshot pending — add assets/img/threshold-profiles.gif (see SCREENSHOTS.md).

إذا كنت تعتمد على القيم الافتراضية القديمة، فسيجري تقييمك بتساهل أكبر بعد التحديث إلى 0.2026.82 إلى أن تختار safety. ويُبلَّغ التثبيت الذي سبق تشغيله بذلك مرة واحدة، مع زر Keep 100% (safety) الذي يكتب ملف التعريف في إعدادات المستخدم لديك؛ وفي المشاريع المشتركة ضعه في إعدادات مساحة العمل أيضًا، حتى يُقيَّم الجميع بالمعيار نفسه. يعرض Configure Coverage Compliance & Thresholds... ملف التعريف فوق شبكة العتبات، وتقيّم معاينته المباشرة وفق البوابات السارية فعليًا. وفي كل بطاقة وتقرير، يعرض المقياس الذي عُطِّلت بوابته قيمته مع شرطة محايدة بدلًا من علامة صح أو علامة خطأ.

The status-bar card under the standard profile: two of four gates below threshold, and a neutral mark on the metrics that are not gatedScreenshot pending — add assets/img/statusbar-metrics.png (see SCREENSHOTS.md).

11a. تغطية الشيفرة الهدف

كل مقياس آخر هنا يُقاس من الشيفرة المصدرية: تقوم أداة بتجهيز شيفرتك، ثم يُشغَّل البناء المجهَّز، وتخبر العدادات أي العبارات أو التفرّعات أو الشروط جرى تنفيذها. أما تغطية الشيفرة الهدف فتقيس شيئًا آخر — كم من الملف الثنائي المبني نُفِّذ فعليًا، محسوبًا ببايتات التعليمات، عبر مراقبة تدفّق التعليمات بدلًا من تجهيز المصدر. وهذا مهم لأن المترجم يُصدر شيفرة لا يقابلها أي سطر في مصدرك: فحوص حدود المصفوفات، وجداول القفز الخاصة بـ switch، وإفراغ المسجّلات، وفحوص المكدس، واستدعاءات روتينات المساعدة في زمن التشغيل للقسمة أو الفاصلة العائمة على أنوية تفتقر إلى التعليمة. وهي أيضًا المقياس الوحيد هنا الذي يجيب عن سؤال هل يغطي هذا لغة التجميع؟ — فشيفرة التجميع المكتوبة يدويًا لا تُجهَّز أبدًا، والأداة القائمة على المصدر لا تصل إليها. وتنص DO-178C صراحةً على السبب: في المستوى A، حين يولّد مترجم أو رابط شيفرةً لا يمكن تتبّعها مباشرة إلى عبارات المصدر، يطلب الهدف 6.4.4.2b تحققًا إضافيًا من تلك الشيفرة المولّدة تحديدًا.

إنها تشمل تغطية العبارات — فكل تعليمة نُفِّذت جاءت من عبارة ما، ومن ثم فإن تغطية شيفرة هدف بنسبة 100% تعني تغطية عبارات بنسبة 100%. والعكس غير صحيح، وهذا التفاوت هو كل المغزى من قياسها. ويترتب على ذلك أمران. ليس لها أي وزن في الدرجة المركّبة، لأن حساب متوسط مقياسين لنفس عمليات التنفيذ يَعُدّ الدليل نفسه مرتين؛ بل تُضبط بدلًا من ذلك عبر fuciniCoverage.threshold.objectCode — متطلَّب لا وزن، وهكذا يطلبها المعيار. والفجوة هي المُخرَج: تشغيلٌ بتغطية أسطر 100% وتغطية شيفرة هدف أقل من 100% يكون قد حدّد بدقة الشيفرة التي ولّدها المترجم ولا يقابلها شيء في مصدرك، ولذلك تقول بطاقة الامتثال 312 بايت لم تُنفَّذ قط، مع تغطية أسطر 100% بدل دفنها تحت «94%». والعكس — أن يُبلَّغ عن تنفيذ الملف الثنائي بأكمله بينما لم يُنفَّذ مصدره — تناقضٌ لا درجةٌ منخفضة: يكون في الغالب ملف تتبّع قديمًا في أحد طرفَي الدمج، أو أسماء وحدات لم تطابق مسارات الملفات قط. ويُبلَّغ عن ذلك كنتيجة تدقيق.

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

  1. بناء مجهَّز يعمل على الهدف. تقبل مترجمات GCC المتقاطعة الخيارين -fprofile-arcs -ftest-coverage، فالتجهيز الذي يعمل على محطة العمل يعمل على الهدف أيضًا — غير أن النظام العاري لا يملك نظام ملفات يكتب فيه عدادات .gcda، وكثيرًا ما لا يملك exit() يكتبها عنده. والعدادات موجودة في الذاكرة على أي حال، فالحل هو تفريغ تلك الذاكرة وإعادة بناء الملفات خارج الهدف؛ ومشروع embedded-gcov من NASA JPL (رخصة Apache-2.0) يفعل ذلك تمامًا، بلا نظام ملفات ولا نظام تشغيل ولا مكتبة C قياسية. وهذا يمنحك تغطية العبارات والتفرّعات والدوال لبناءٍ أنتجه مترجمك المتقاطع، لمجموعة تعليماتك، على عتادك — لا تغطية شيفرة هدف، كما أن الملف الثنائي المقاس مجهَّز، أي أكبر وأبطأ مما تشحنه. حمّل النتيجة بصيغة LCOV أو gcovr JSON أو gcov JSON، أو — على سلسلة أدوات أقدم من GCC 9 — بصيغة قائمة .gcov النصية.
  2. محاكي مجموعة التعليمات. شغّل الملف الثنائي الهدف الحقيقي داخل محاكٍ واستنتج التغطية من العناوين التي نُفِّذت: بلا عتاد ولا تجهيز ولا مجس، ولأنه يرصد التعليمات فبإمكانه إنتاج تغطية شيفرة هدف حقيقية. والحدّ هنا هو الأمانة في المحاكاة: المحاكي يمثّل النواة تمثيلًا جيدًا والمحيطيات تمثيلًا أضعف، فتعامل مع نتائج النظام ككل بحذر ما لم يكن يحاكي شريحتك عن كثب.
  3. التتبّع داخل الشريحة مع مُنقِّح. هذا هو المسار بدرجة الاعتماد، والوحيد غير التدخّلي حقًا: تُبلِّغ وحدة التتبّع في النواة تدفّقَ التعليمات إلى مُنقِّح يحوّله إلى تغطية. لا شيء يُجهَّز، وحجم الشيفرة لا يتغيّر، والتوقيت لا يتأثر — وهذا بالضبط ما يجعل النتيجة دليلًا على الملف الثنائي الذي تشحنه فعلًا. تحقّق من الشريحة قبل رصد ميزانية لذلك: في عائلات كثيرة من المتحكّمات الدقيقة لا يتوفر التتبّع الكامل إلا في نسخة محاكاة أو تطوير ذات ذاكرة تتبّع كبيرة ومنفذ تتبّع عالي السرعة، بينما تعرض القطع الإنتاجية وحدة تتبّع مختزلة، وحلّ المورّد البديل لها تتبّعٌ برمجي يجهّز الشيفرة ويستهلك وقت المعالج — فيلغي الخاصية نفسها التي اختير المسار من أجلها.

تقيس مشاريع مضمّنة كثيرة التغطية بترجمة الشيفرة المصدرية نفسها لجهاز التطوير وتشغيل اختبارات الوحدة هناك. الأمر سريع، ولا يحتاج عتادًا، وهو الخيار الافتراضي الصحيح لمعظم الفرق — لكن يستحق الأمر أن نكون واضحين بشأن ما يصفه ذلك الدليل فعلًا: مترجم مختلف، ومُحسِّن مختلف، ومجموعة تعليمات مختلفة، وملف ثنائي مختلف عن ذلك الذي يُشحن. بالنسبة لمعظم البرمجيات، هذه مقايضة مقبولة ومفهومة جيدًا. أما بالنسبة للأعمال التي تُقيَّم وفق IEC 61508 أو ISO 26262 أو DO-178C، فهذا هو الاعتراض المعتاد «المضيف مقابل الهدف»، والمسارات أعلاه هي الردود المعتادة عليه — الأول يُغلقه لتغطية المصدر، والثالث للشيفرة الهدف.

اليوم، التصدير الذي تُقرأ منه الشيفرة الهدف هو تصدير Lauterbach TRACE32 عبر COVerage.EXPORT.ListModule بـ metric="object"؛ حمّله كما تحمّل أي ملف تتبّع آخر. يُحتسب هذا المقياس ويُضبط فقط في ظل ترخيص مدفوع وأثناء فترة التقييم. لا يحتسبه تثبيت Community — لكنه يُبلَّغ عندما يحمل ملف تتبّع هذه البيانات، لأن حكم امتثال يُسقط بصمت أقوى دليل في الملف سيكون أسوأ من حكم يذكر ما أسقطه.

12. استبعاد الأسطر غير البرمجية

مع تفعيل excludeComments (الافتراضي)، تُستبعد العبارات التي تقع بالكامل على أسطر تحتوي فقط على تعليقات أو أسطر فارغة من الإجماليات — كما يعالج هذا أيضًا خللًا معروفًا في llvm-cov/gcov حيث ينتهي عدد إصابة عشوائي على تعليق. تُحترَم أيضًا العلامات القياسية:

x = risky();          // LCOV_EXCL_LINE
// LCOV_EXCL_START
debug_only_block();
// LCOV_EXCL_STOP

لا تُعدّ موجّهات المعالج المسبق شفرةً أيضًا، في C وC++ وObjective-C وCUDA وC#: السطر الذي يبدأ بـ# — #define و#include و#if — والأسطر التي تمدّه إليها شرطة مائلة عكسية في آخره. ينسب gcov كل استخدام لماكرو إلى السطر الذي عُرِّف فيه، ولذلك كان ملف الترويسة الذي سطره الوحيد المبلَّغ عنه هو #define CHANNEL_COUNT (33U) يُقرأ مغطّى بنسبة 100% لأن حلقة في ملف .c نُفِّذت حتى بلغته، وكان الملف الذي لم يستخدم أحدٌ ثابته يُقرأ 0%. مثل هذه الترويسة لم يعد فيها ما يُقاس، ولا تُدرج.

اضبط excluded.includeInTotals على true لعدّ الأسطر المستبعدة رغم ذلك.

استبعاد ملف أو مجلد، من الشجرة

انقر بزر الفأرة الأيمن على ملف أو مجلد في عرض Coverage واختر Exclude from Coverage — وهو أيضًا ضمن إجراءات المسار في الصف — أو شغّل Exclude This File from Coverage على الملف المفتوح: يذهب مسار الملف النسبي إلى مساحة العمل، أو /** الخاص بالمجلد، إلى fuciniCoverage.ignore في إعدادات المجلد، مرة واحدة، وتُخرجه إعادة التحميل من كل مجموع وكل صفحة؛ والنمط هناك ليُزال متى شئت. وفي Visual Studio لقائمة الصف وTools → Coverage Studio الأمران نفسهما، يكتبان الإعداد نفسه في الملف نفسه.

Right-click a folder row in the Coverage view, Exclude from Coverage, and the tree redraws without it while the pattern appears in settings.jsonScreenshot pending — add assets/img/exclude-from-tree.gif (see SCREENSHOTS.md).
Exclude from Coverage على مجلد: الشجرة من دونه، والنمط في الإعدادات.
Visual Studio: Exclude This File from Coverage on fees.ts, the tree without fees.ts, then .vscode/settings.json with the pattern src/fees.ts under fuciniCoverage.ignore
في Visual Studio: Exclude This File from Coverage على fees.ts — الشجرة من دونه، والنمط في .vscode/settings.json.

السمات ومساحات الأسماء، لـ .NET

إعدادان يقرآن من المصدر ما لا يستطيع التقرير قوله. ignore.attributes — ExcludeFromCodeCoverage افتراضيًا — يستبعد الصنف أو التابع أو الخاصية الواقعة تحت سمة يسمّيها، كما يفعل LCOV_EXCL_START/STOP، أيًّا كانت الأداة التي كتبت التقرير: يحترم Coverlet السمة، ولا يحترمها OpenCover وdotCover وlcov المحوَّل، والآن تتفق جميعها. الأسماء مع اللاحقة Attribute أو دونها، مع مساحة أسماء أو دونها؛ أضف GeneratedCode أو Obsolete أو سماتك الخاصة. وignore.namespaces يترك خارجًا كل ملف يطابق إعلانُ مساحة الأسماء فيه بادئةً، و* حرف البدل — Acme.Generated وAcme.*.Migrations و*Tests — وتسمّي لوحة Output الملفات التي أخذها. يُقرأ الاثنان في التمريرة نفسها التي تقرأ علامات التعليقات، في كلا الإصدارين.

{
  "fuciniCoverage.ignore.attributes": ["ExcludeFromCodeCoverage", "GeneratedCode"],
  "fuciniCoverage.ignore.namespaces": ["Acme.Generated", "*.Migrations"]
}

الاستبعاد من المحرر

حدّد الأسطر وخذ Exclude Selection from Coverage من المصباح، أو قائمة سياق المحرر، أو Command Palette — وفي Visual Studio من المصباح (Ctrl+.)، أو قائمة النقر الأيمن في نافذة الشيفرة، أو Tools → Coverage Studio، أو Ctrl+Shift+U, X — فيُكتب الاستبعاد حيث توجد الشيفرة: [ExcludeFromCodeCoverage] فوق صنف أو تابع أو خاصية في C# أو VB أو F#، باسمه المختصر إذا كان الملف يستورد System.Diagnostics.CodeAnalysis أصلًا، وباسمه الكامل إذا لم يكن، حتى لا يلزم إضافة أي using؛ وLCOV_EXCL_LINE في نهاية سطر واحد من الشيفرة؛ وLCOV_EXCL_START وLCOV_EXCL_STOP حول عدة أسطر، بمقدار إزاحة السطر الأول — بعلامة التعليق الخاصة باللغة، // أو # أو ' أو -- أو ;. خطوة تراجع واحدة. ويعرضه المصباح أيضًا على سطر تسِمه مدخلات Problems بأنه غير مغطى. أما السطر الموسوم أصلًا، أو العضو الذي يحمل السمة أصلًا، فيُترك كما هو.

A selection in a C# method, the light bulb, Exclude from coverage, and the LCOV_EXCL_START and STOP lines appearing around itScreenshot pending — add assets/img/exclude-selection.gif (see SCREENSHOTS.md).
Exclude Selection from Coverage: العلامات مكتوبة حول التحديد، بعلامة التعليق الخاصة بالملف.
Visual Studio: four lines of an else-if branch in Quote.cs selected, Exclude Selection from Coverage writing LCOV_EXCL_START and LCOV_EXCL_STOP around them, then ExcludeFromCodeCoverage above a method
في Visual Studio: Exclude Selection from Coverage — علامات LCOV_EXCL حول فرع، ثم [ExcludeFromCodeCoverage] فوق دالة.

الفروع وحدها، وعلامات gcovr

else دفاعية، أو default: لا تبلغها أي قيمة، أو الذراع التي يضيفها المصرّف من أجل استثناء: السطر يُنفَّذ وينبغي أن يُحتسب، وفرعه وحده هو الذي لا يمكن سلوكه. تُخرج LCOV_EXCL_BR_LINE وLCOV_EXCL_BR_START … LCOV_EXCL_BR_STOP الفروع التي على أسطرها من العدّ وتُبقي الأسطر فيه. وتُخرج LCOV_EXCL_EXCEPTION_BR_LINE ومنطقتها أقل من ذلك — الأذرع التي يبلغها استثناء فقط، حيث يقول التقرير أيّها هي، كما يفعل JSON الخاص بـ gcov. وتُقرأ كل علامة تحت بادئات gcovr أيضًا: GCOVR_EXCL_LINE وGCOVR_EXCL_START وGCOVR_EXCL_BR_LINE وGCOV_EXCL_STOP والبقية تعني ما تعنيه علامات LCOV_EXCL_، فالمصدر المكتوب لـ gcovr يُقرأ هنا بالطريقة نفسها أيًّا كانت الأداة التي أنتجت التقرير. ما لا يُقرأ: GCOVR_EXCL_FUNCTION — فلا شيء على ذلك السطر يقول أين تنتهي الدالة.

if (handle == NULL) return E_FAIL;   // LCOV_EXCL_BR_LINE: the allocator never fails on target
  // LCOV_EXCL_BR_START generated state table
  switch (state) { /* … */ }
  // LCOV_EXCL_BR_STOP
LCOV_EXCL_BR_LINE on a line: the line still counted, its branch gone from the countScreenshot pending — add assets/img/branch-markers.png (see SCREENSHOTS.md).

ذكر السبب: استبعادات مبرَّرة

إخراج شيفرة من العدّ ادّعاء — «هذا لا يمكن اختباره»، «هذه أداة مساعدة للمطوّر» — وبموجب DO-178C أو ISO 26262 أو IEC 61508 يجب أن يُدوَّن الادّعاء الذي يغيّر الرقم الذي تستند إليه شهادة، وأن يكون قابلًا للمراجعة. لذلك يمكن للاستبعاد أن يذكر السبب، في الموضع الذي كُتب فيه: النص الذي يلي LCOV_EXCL_LINE أو LCOV_EXCL_START، أو Justification الخاصة بـ [ExcludeFromCodeCoverage].

abort();                 // LCOV_EXCL_LINE: defensive, unreachable by construction
  // LCOV_EXCL_START debug dump, never built for the target

  [ExcludeFromCodeCoverage(Justification = "a developer aid")]
  public static void DebugDump(decimal amount) { /* … */ }

تُقرأ الأسباب عند كل تحميل وتعدّها لوحة Output. يكتب Export Coverage Report… القائمة — الاستبعادات ومبرّراتها، بصيغة Markdown أو CSV: الملف، والأسطر، وطريقة كتابة الاستبعاد، والمبرّر أو none given (لم يُذكر). والملف الذي لم يبقَ فيه ما يُقاس يبقى في تلك القائمة. ومع تفعيل exclusions.requireReason، يُعدّ الاستبعاد الذي لا يذكر سببًا ملاحظةً تُسجَّل عليه: تحذير في Problems عند سطره، وإخفاق في Check Coverage Thresholds. وعندها يسأل Exclude Selection from Coverage عن السبب أولًا ويكتبه مع العلامة أو بوصفه Justification السمة؛ وإذا أُغلق السؤال أو تُرك فارغًا، لا يُستبعد شيء.

An exclusion without a reason flagged as a warning at its line, and the exported list with none givenScreenshot pending — add assets/img/justified-exclusions.png (see SCREENSHOTS.md).
Visual Studio: an exclusion without a reason as a warning at its line, and the exported list with none givenScreenshot pending — add assets/img/vs-justified-exclusions.png (see SCREENSHOTS.md).
في Visual Studio: استبعاد بلا سبب يظهر تحذيرًا عند سطره، والقائمة المصدَّرة وفيها none given.

12a. هل ما تزال هذه التغطية تصف هذا الملف؟

التغطية المقروءة من ملف تتبع تصف الشيفرة كما كانت حين جرت الاختبارات، ومعظم الصيغ لا تقول أي نسخة كانت. لذلك يكون كل ملف في لوحة التغطية في واحدة من ثلاث حالات:

  • ✓ تم التحقق — يسجّل ملف التتبع ما كان في كل سطر جرى قياسه، وهو ما يزال مطابقًا للملف.
  • بلا علامة — لم يُدحض. لا شيء يناقض التغطية ولا شيء يؤكدها. وهذه هي الحالة المعتادة.
  • ⚠ مدحوض — الملف نفسه يدحض تغطيته. يُعتَّم الصف وتوضّح التلميحة ما وُجد.

لا تستطيع نيل علامة الصح إلا صيغتان، لأن اثنتين فقط تسجّلان شيئًا عن الشيفرة التي قاستها: lcov المكتوب بخيار --checksum (معطّل افتراضيًا في geninfo، والغرض الموثّق منه هو تحديدًا منع دمج تغطية نسختين من ملف) وGNATcoverage XML الذي يضمّن نص كل سطر جرى قياسه. ويستحق تفعيل خيار lcov العناء.

لا يحتاج التحذير إلى أيٍّ منهما ويعمل مع كل التنسيقات: تغطية مسجّلة بعد نهاية الملف، أو دالة مسمّاة لم تعد حيث يضعها التقرير، أو أسطر منفَّذة فارغة في الملف. الطوابع الزمنية لا تكفي وحدها أبدًا — git checkout يغيّرها كلها دون تغيير بايت واحد — لذا فإن طابعًا زمنيًا متغيّرًا هو على الأكثر سبب لإعادة النظر. يعمل الفحص عند تحميل التغطية ومجددًا كلما حُفظ ملف أو تغيّر على القرص، فتتبع العلامة الملف: تعديل يناقض التشغيل يضعها، وسحب يعيد النسخة المقيسة يزيلها. يذكر التلميح بدقة ما أثبت ذلك. اضبط staleWarning.enabled على false لإيقاف كل ذلك.

12b. غير مقيس مقابل غير مغطّى

الملف الذي لا يذكره التشغيل قط غير مقيس: لم يحمّله أي اختبار، فلم تكتب أي أداة سطرًا عنه. وهذا يختلف عن غير مغطّى — أي مقيس بصفر إصابة — ولم يحتسب الامتداد يومًا ملفًا غائبًا 0%. ما لم يكن يفعله، حتى 0.2026.69، هو إظهار الغائبين أصلًا: فالوحدة التي لا اختبارات لها البتّة لم تكن تظهر في الشجرة ولا في الإجماليات ولا في فحص العتبات، وكان القارئ يرى «92%» لمشروع نصف ملفاته لم يُختبر قط.

الآن، مع تشغيل محمَّل، يقول عنصر شريط الحالة الخاص بالملف غير مقيس لملف مصدر من نوع التشغيل نفسه لا يحويه التشغيل — و«من نوع التشغيل» تعني أن له أحد امتدادات الملفات التي قاسها التشغيل، فترويسات مشروع C ومصادره مرشّحة أما سكربتات Python فيه فلا. وكل ما وراء ذلك اختياري عبر fuciniCoverage.unmeasured.mode:

  • off (الافتراضي) — لا يتغيّر شيء آخر.
  • list — يحصل عرض Coverage على مجموعة Unmeasured في الأسفل تسمّي كل ملف كهذا، وكل صف يفتحه؛ وتعدّها نتيجة التحميل؛ وتعلّمها الشارات بـ ? في Explorer؛ ويستطيع fuciniCoverage.threshold.unmeasuredFiles إفشال Check Coverage Thresholds حين يتجاوز عددها رقمًا تحدّده. ولا تتحرّك أي نسبة مئوية.
  • count — كل ما يفعله list، ويُحتسب كل ملف غير مقيس أيضًا على التشغيل ملفًا غير مغطّى بعدد أسطر شيفرته، فيعرض شريط الحالة والعتبات والشارات والسجل وكل تصدير وعرض Test Coverage الرقم الأدنى. ويُرسم الملف بوصفه غير مقيس أينما ظهر، وتقول أشرطة هامشه «غير مقيس» لا «لم يُنفَّذ قط»، ويتركه فحص عدم التطابق وشأنه — فلا قياس لمحتوياته كي تناقضه.
{
  "fuciniCoverage.unmeasured.mode": "list",
  "fuciniCoverage.threshold.unmeasuredFiles": 0
}

ملفات الترويسات هي الإيجابية الكاذبة المعروفة في C: فهي من عائلة امتدادات التشغيل ولن يسمّي أي ملف تتبع واحدًا منها أبدًا، لأنها وحدها لا تُترجم إلى شيء. ولذلك يستبعد fuciniCoverage.unmeasured.exclude افتراضيًا **/*.h و**/*.hpp و**/*.hh و**/*.inl و**/*.d.ts، بصيغة glob نفسها التي في fuciniCoverage.ignore؛ أضف منفذ منصّة لا يُبنى هنا، أو بدائل مولَّدة، فتخرج من القائمة ومن العدّ ومن حالة شريط الحالة. والملف الذي يسمّيه ignore لا يُسمّى غير مقيس أيضًا — فاستبعاده كان هو المقصود. ويكون threshold.unmeasuredFiles افتراضيًا -1، أي بلا فحص؛ و0 يُخفق ما إن يوجد أي ملف من نوع التشغيل لم يحمّله اختبار قط، ولا يسري إلا حين يكون unmeasured.mode هو list أو count.

13. تقارير HTML

  • Generate Full HTML Report — تقرير متعدد الصفحات يُنشأ ذاتيًا لكل دليل. يذهب الإخراج إلى htmlReport.outputDir، أو إلى مساحة التخزين العامة للامتداد إذا لم تُحدَّد.
  • Open Annotated Source — عرض مُعلَّق لملف واحد. وجّه externalHtmlReport.dir إلى دليل llvm-cov show --format=html مبني مسبقًا لاستخدام تلك الصفحات بدلًا من العارض المدمج.
  • Export Fucini JSON — النموذج المُطبّع الكامل لأدواتك الخاصة.
  • Export Coverage Report... — التشغيل بصيغة CSV (لكل ملف أو لكل دالة)، أو ملخّص Markdown، أو ملف تتبع LCOV، أو Cobertura XML، أو SARIF، أو شارة SVG مستقلة لملف README. يمكن الوصول إليه أيضًا من الزر المجاور لـGenerate Full HTML Report في عرض Covered Files. كل شيء عدا ملفات CSV فاقد للبيانات — إذ لا موضع لـMC/DC ولا للمناطق ولا للتنفيذات في LCOV أو Cobertura أو SARIF — لذا يبقى Fucini JSON وملفا CSV هما التنسيقين الحاملين لكل مقياس.
  • Copy Uncovered Lines — ملخص Markdown لكل ثغرة، جاهز للصق في طلب سحب.

في Visual Studio. مجموعة Reports في Tools → Coverage Studio: يفتح Show Annotated Source المستند النشط صفحةً في منطقة المستندات — كل سطر بلونه، والنتائج بجانبه — تتمرّر مع المحرر في الاتجاهين؛ ويكتب Open HTML Report التقرير ذا الصفحة الواحدة إلى htmlReport.outputDir (أو %LOCALAPPDATA%\Fucini\CoverageStudio\html-report) ويفتح المتصفح؛ ويكتب Generate Full HTML Report هناك الفهرس لكل مجلد والصفحة لكل ملف؛ ويعرض Export Coverage Report… التنسيقات الثمانية نفسها ويسأل أين يُحفظ؛ ويكتب Generate Coverage Badge الشارة حيث يقول badge.outputPath، وبعد كل تحميل مع badge.autoUpdate. تحتاج الصفحة المشروحة إلى WebView2 كما تحتاجه نافذة Coverage؛ أما التقارير على القرص فلا.

Visual Studio: Show Annotated Source — the file as a page in the document well, beside the editorScreenshot pending — add assets/img/vs-annotated-source.png (see SCREENSHOTS.md).
في Visual Studio: Show Annotated Source — الملف كصفحة في منطقة المستندات، بجانب المحرر.
Multi-page HTML report directory indexScreenshot pending — add assets/img/report.png (see SCREENSHOTS.md).
The report, Directory Coverage Summary: one row per folder, a column for every metric the run carriesScreenshot pending — add assets/img/report-directory-summary.png (see SCREENSHOTS.md).
The report, File Coverage Summary: one row per file, with Max CRAP where the report carries complexityScreenshot pending — add assets/img/report-file-summary.png (see SCREENSHOTS.md).
The report, Coverage Gaps: every function with uncovered branches or MC/DC conditions, named as writtenScreenshot pending — add assets/img/report-coverage-gaps.png (see SCREENSHOTS.md).
The report, MC/DC Expression Detail: conditions covered per decisionScreenshot pending — add assets/img/report-mcdc-detail.png (see SCREENSHOTS.md).
Export Coverage Report: CSV per file or per function, a Markdown summary, LCOV, Cobertura XML, SARIF, or an SVG badgeScreenshot pending — add assets/img/export-picker.png (see SCREENSHOTS.md).
The report’s annotated page for src/calc.c: per-line hit counts, a fully covered function, an uncovered else branch, a 1/2 partial branch, an MC/DC expansion and a never-called functionScreenshot pending — add assets/img/annotated-source.png (see SCREENSHOTS.md).

المصدر المشروح مقابل المصدر العادي

Open Annotated Source يستبدل التبويب النشط بعرض ويب ملوّن للتغطية لذلك الملف، في نفس العمود؛ ويقوم Open Annotated Source to the Side بنفس الشيء لكن في عرض مقسّم، بحيث يظهر المصدر والعرض المشروح جنبًا إلى جنب. للتبديل ذهابًا وإيابًا في المكان نفسه بدلاً من ذلك — وهو مفيد على الشاشات الصغيرة حيث يجعل التقسيم كل لوحة ضيقة جدًا — استخدم Toggle Annotated Source: فهو يبدّل التبويب النشط بين الاثنين، ويتذكر أيّهما تشاهده حاليًا. من داخل العرض المشروح نفسه، ينقلك Show Source مباشرة إلى المحرر العادي لذلك الملف.

يعتمد نوع HTML الذي تراه فعليًا على externalHtmlReport.dir: عندما يكون معينًا وتوجد بالفعل صفحة تطابق الملف النشط هناك (يرتب llvm-cov الصفحات لكل ملف بصيغة <اسم-repo>/<المسار-النسبي>.html، لذا لا يحتاج مجلد اسم repo الخاص بالتقرير إلى الإعداد أبدًا)، تُعرض تلك الصفحة التي أنشأتها سلسلة الأدوات بدلاً من العارض المدمج — تتم إعادة كتابة روابطها/ورقة الأنماط المحلية لتعمل داخل عرض الويب، وتحتوي على تفاصيل لا يعيد العرض المدمج إنتاجها (عروض توسيع MC/DC، وتمييز المناطق، وملخصات الدلائل). لا توجد صفحة مطابقة لذلك الملف، أو تُرك الإعداد فارغًا؟ عندها يُستخدم العارض المدمج بدلاً من ذلك. لا يقوم الامتداد إلا بقراءة هذا الدليل — ولا يكتب فيه أبدًا.

شارة تغطية لملف README

يكتب Generate Coverage Badge شارة SVG على طراز shields للتشغيل النشط في مساحة العمل — badge.outputPath، افتراضيًا coverage-badge.svg، نسبةً إلى مجلد مساحة العمل أو مطلقًا، بالمتغيّرات نفسها التي في كل إعداد مسار آخر — ويعرض فتحها. وهي ملف عادي في مستودعك، فيضمّنها README من دون أي خدمة خلفها ولا رحلة ذهاب وإياب إلى shields.io، وتعمل أيضًا في مستودع معزول عن الشبكة:

![coverage](coverage-badge.svg)

coverage: 83%

يختار badge.metric ما تعرضه الشارة: lines (بتسمية coverage)، أو branches، أو mcdc، أو weighted، وهي الدرجة المركّبة نفسها التي يعرضها شريط الحالة، بتسمية score. والتشغيل الذي لا بيانات فيه للمقياس المختار يحصل على n/a رمادية بدل 0% حمراء. ويتبع اللون مستويات colorScale.* الخاصة بك: lowColor دون lowThreshold، وmidColor حتى highThreshold، وhighColor من هناك فصاعدًا. ومع تفعيل badge.autoUpdate تُعاد كتابة الشارة بعد كل تحميل ناجح، بصمت، وتسجّل قناة الإخراج كل كتابة بوصفها [FUCINI_BADGE] — معطّل افتراضيًا لأنه يكتب في مساحة العمل عند كل تحميل. أودِع ملف SVG مع الشيفرة فتتبع الصورة على صفحة المستودع الرقم الذي في المحرر.

{
  "fuciniCoverage.badge.outputPath": "docs/coverage-badge.svg",
  "fuciniCoverage.badge.metric": "weighted",
  "fuciniCoverage.badge.autoUpdate": true
}

14. السجل والاتجاهات

فعّل history.enabled لحفظ عمليات التشغيل محليًا (مع الاحتفاظ بعدد history.retention منها). ستحصل بعدها على سهم اتجاه (▲/▼) في شريط الحالة، ومخطط الاتجاه في عرض Coverage، وأمرَي مقارنة: Compare with Last Run وCompare Two History Runs، وكل منهما ينتج فرق تراجع/تحسّن لكل ملف.

في Visual Studio. يُقارن كل تحميل بالذي قبله: مثلث في الهامش على كل سطر بدأ يعمل أو توقّف عن العمل (sinceLastRun.enabled)، والاتجاه بجانب النتيجة في شريط الحالة، وCompare with Last Run للملفات التي تحرّكت أرقامها. ومع history.enabled تُحفظ التشغيلات تحت %LOCALAPPDATA%\Fucini\CoverageStudio\history، بعدد history.retention منها، فتبقى المقارنة بعد إعادة التشغيل، ويجد مخطط الاتجاه ما يرسمه، ويختار Compare Two History Runs… أي اثنين منها.

Compare with Last Run: the run moved from 83.89% to 83.05%, calc.c lost 4.54 points, and the status bar carries the trendScreenshot pending — add assets/img/history-compare.png (see SCREENSHOTS.md).
Since last run: a red mark on the lines that ran in the previous run and not in this one, a green one on the lines that are newly coveredScreenshot pending — add assets/img/since-last-run.png (see SCREENSHOTS.md).

مخطط الاتجاه

تحت شريط أدوات عرض Coverage، مع تشغيلين محفوظين أو أكثر، تغطية الأسطر في السجل خطًا، من الأقدم إلى الأحدث، أحدث ثلاثين: نقطة لكل تشغيل تقول تاريخه ورقمه عند تمرير المؤشر، وآخر رقم بجانبها مع سهم لاتجاه التغيّر منذ الأول. المقياس الرأسي هو مدى التشغيلات نفسها، فيرى فريق عند 92–94% الحركة بدل خط مسطّح تحت 100. يرسمه الإصداران من السجل نفسه.

The trend chart under the Coverage view's toolbar: a line over a dozen runs, a dot per run, the last figure and an arrow upScreenshot pending — add assets/img/trend-chart.png (see SCREENSHOTS.md).
الاتجاه: نقطة لكل تشغيل محفوظ، وآخر رقم بجانبها.
Visual Studio: the trend line under the Coverage window toolbar, the last figure 68.25%
في Visual Studio: الاتجاه تحت شريط أدوات نافذة Coverage، وآخر رقم 68.25%.

جلسات التغطية

نادرًا ما يغطي تشغيل اختبارات واحد كل ما مسّه تغيير: اختبارات الوحدة تعمل هنا، ومجموعة التكامل هناك، وجولة في واجهة المستخدم مع تفعيل التغطية في مكان آخر. يحوّل Start Coverage Session التحميلات التالية إلى مجموع واحد — يُضاف كل تشغيل إلى ما قبله سطرًا سطرًا اتحادًا، فالسطر الذي نفّذه أي منها مغطى والعدّادات تُجمع — فيعرض الهامش والشجرة والدرجة ما بلغته كلها معًا. والتشغيل المعروض، إن وُجد، هو أول الجلسة. شريط فوق الشجرة يقول كم تشغيلًا ومنذ متى وينهي الجلسة؛ ويفعل End Coverage Session الشيء نفسه، ويقف التحميل التالي وحده من جديد. وفي Visual Studio مدخل واحد تحت Tools → Coverage Studio يبدأ الجلسة، وعندما يكون معلَّمًا، ينهيها.

A coverage session: the unit test run loads, the session starts, the integration run loads on top, and the bar says two runs while the tree's numbers riseScreenshot pending — add assets/img/coverage-session.gif (see SCREENSHOTS.md).
جلسة من تشغيلين: الثاني مضافًا إلى الأول، والشريط فوق الشجرة يعدّهما.
Visual Studio: the unit run loaded, Start Coverage Session, the integration run added, the bar saying 2 runs and lines at 68.25%, then the session ended
في Visual Studio: Start Coverage Session، وتشغيل ثانٍ أُضيف إلى الأول — الشريط يعدّ تشغيلين، والأسطر ترتفع من 50.79% إلى 68.25%.

خط أساس CI: أين أقف من main؟

يجيب Compare with Last Run عمّا فعله تغييرك الأخير؛ أما قبل طلب السحب فالسؤال هو أين تقف من main، والجواب على خادم البناء. يسمّي baseline.report التقرير الذي ينشره بناء الفرع الرئيسي، ويُقارن به كل تحميل: تحمل بطاقة شريط الحالة الفرق في سطر واحد — vs CI baseline: 84.20% → 85.10% (+0.90%), 3 file(s) moved — ويسرد Compare with CI Baseline الملفات التي تحرّكت، ملفًا ملفًا، بالكلمات نفسها التي يستعملها Compare with Last Run. وفي Visual Studio الأمر تحت Tools → Coverage Studio ويجلب التقرير أو يقرأه عندما تطلب. ثلاث طرق لتسميته، في .vscode/settings.json:

  1. عنوان URL يقدّمه CI. يحتفظ GitLab بمُخرَجات آخر مهمة لفرع ما على عنوان ثابت؛ ويبقى الرمز خارج ملف الإعدادات عبر ${env:…} في remote.headers. Jenkins: https://jenkins.example.com/job/app/job/main/lastSuccessfulBuild/artifact/coverage/lcov.info. TeamCity: https://tc.example.com/repository/download/App_Main/.lastSuccessful/coverage/lcov.info مع Authorization: Bearer ${env:TC_TOKEN}. يُجلب عنوان URL ويُخزَّن مؤقتًا تمامًا كما يُخزَّن عنوان URL في coverageFile.paths (ETag، وremote.refreshMinutes).
  2. ملف نسخه خط الأنابيب إلى مشاركة شبكية — مسار مطلق مثل \\build\drops\app\main\coverage.cobertura.xml.
  3. مُخرَج منزَّل محفوظ تحت المجلد، وليكن ci/main.lcov.info (ضع المجلد في .gitignore) — مسار نسبي إلى المجلد.
{
  "fuciniCoverage.baseline.report": "https://gitlab.example.com/api/v4/projects/42/jobs/artifacts/main/raw/coverage/lcov.info?job=test",
  "fuciniCoverage.remote.headers": ["PRIVATE-TOKEN: ${env:GITLAB_TOKEN}"]
}

أي تنسيق يعرفه القارئ يفي بالغرض. والمسار الذي كتبه CI نسبيًا إلى نسخته — src/Billing/Invoice.cs، كما يكتبه Coverlet على المشغّل — يوضع تحت هذا المجلد قبل المقارنة، فيلتقي بالملف الذي حلّه التشغيل المحلي؛ أما المسار المطلق من جهاز آخر فلا يطابق شيئًا، فاجعل خط الأنابيب يكتب مسارات نسبية. وخط الأساس الذي لا يمكن جلبه أو قراءته سطرٌ في لوحة Output، لا تحميل فاشل أبدًا.

Compare with CI Baseline: the status bar's card with the vs CI baseline line, then the command listing the files that moved against main, regressions firstScreenshot pending — add assets/img/ci-baseline.gif (see SCREENSHOTS.md).
خط أساس CI: الفرق على البطاقة، والملفات التي تحرّكت مقابل main.
Visual Studio: baseline.report set to the unit suite report, then Compare with CI Baseline showing statements 50.79% to 68.25% and branches 30.43% to 50.00%, one file changed
في Visual Studio: Compare with CI Baseline — العبارات والفروع مقابل تقرير اختبارات الوحدة، والملف الذي تغيّر.

المُخرَج (artifact) ملف zip، وهذا يُقرأ أيضًا. يسلّم GitHub وGitLab المُخرَج أرشيفًا، أيًّا كان ما وُضع فيه. سمِّ التقرير الذي فيه بعد #: يُعثر على العضو بمساره أو بنهاية مساره؛ ومن دون # يكون هو الملف الوحيد في الأرشيف، أو الملف الوحيد فيه الذي يبدو تقريرًا، وحيث يوجد أكثر من واحد تسمّيها لوحة Output. ويصحّ الأمر نفسه على ملف zip نزّلته (ci/artifact.zip#lcov.info)، وفي VS Code على عنوان URL في coverageFile.paths. يذهب الرمز المميز إلى الخادم الذي ضُبط له ولا يتجاوزه: إعادة التوجيه إلى التخزين الذي يحوي الأرشيف تُتبَع من دونه.

{
  "fuciniCoverage.baseline.report": "https://api.github.com/repos/acme/app/actions/artifacts/1234567/zip#coverage/lcov.info",
  "fuciniCoverage.remote.headers": ["Authorization: Bearer ${env:GITHUB_TOKEN}"]
  }

14a. لوكلاء الذكاء الاصطناعي: التغطية المعروضة على الشاشة

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

الأداةعمّ تجيب
coverage_summaryإجماليات التشغيل لكل مقياس، والملفات الأبعد عن أن تكون مغطّاة. أول ما يُسأل عنه.
coverage_gapsما لم يُنفَّذ قط في ملف أو دالة أو نطاق من الأسطر: الأسطر غير المغطّاة، وأذرع الفروع التي لم تُسلك، وشروط MC/DC التي ليس لها زوجها، والطفرات الناجية.
tests_for_lineأي الاختبارات نفّذت سطرًا، حيث يقول التقرير ذلك — تشغيل لكل اختبار على حدة.
patch_coverageتغطية فرق (diff) — شجرة العمل مقابل مرجع، أو رقعة (patch) مسلَّمة — وأسطر الفرق التي لم تُنفَّذ قط.
coverage_deltaما تغيّر منذ التشغيل السابق: الإجماليات، والملفات التي كسبت أو خسرت.
test_run_commandالأمر الذي يشغّل اختبارات مساحة العمل هذه مع التغطية. يشغّله الوكيل؛ ويعيد المحرّر تحميل التقرير من تلقاء نفسه.

وكيل VS Code نفسه يملكها أدواتٍ دون أي إعداد. وكل الوكلاء الباقين — أي عميل يتحدث MCP، وهو Model Context Protocol — يصلون إليها عبر خادم يشغّله المحرّر عند تفعيل mcp.enabled، في VS Code وفي Visual Studio على السواء. يضع Copy MCP Server Configuration مدخل العميل في الحافظة، كما يقرؤه VS Code وVisual Studio في ملف mcp.json؛ والعميل الذي يسمّي المفتاح الخارجي mcpServers يأخذ المدخل نفسه تحت ذلك الاسم.

Copy MCP Server Configuration and its message, the token painted overScreenshot pending — add assets/img/mcp-config.png (see SCREENSHOTS.md).
Visual Studio: Copy MCP Server Configuration and its message; the token painted overScreenshot pending — add assets/img/vs-mcp-config.png (see SCREENSHOTS.md).
في Visual Studio: Copy MCP Server Configuration ورسالته؛ الرمز المميز مطموس.
{
  "servers": {
    "fucini-coverage": {
      "type": "http",
      "url": "http://127.0.0.1:39217/mcp",
      "headers": { "Authorization": "Bearer …" }
    }
  }
  }
  • الخادم متوقف ما لم تشغّله، ويستمع على 127.0.0.1 فقط: لا شيء من خارج هذا الجهاز يصل إليه.
  • يجب أن يحمل الاستدعاء رمزك المميز، الذي يُنشأ مرة واحدة ويُحتفظ به لك؛ ومن دونه يكون الجواب 401. والإعدادات المنسوخة تحمل الرمز المميز: أبقِها خارج المستودع.
  • الاستدعاء الذي أرسلته صفحة ويب — وهو يقول ذلك في ترويسة Origin — يُرفض، أيًّا كان ما يحمله.
  • يقرأ الخادم التشغيل المحمَّل ولا يكتب شيئًا. تشغيل الاختبارات يُسمّى ولا يُبدأ: الوكيل يشغّل الأمر في طرفيته هو.

المنفذ هو mcp.port، وهو 39217 ما لم يُضبط. وحيث يكون هذا المنفذ مشغولًا — نافذة ثانية، أو الإصدار الآخر بجانب هذا — يُستخدم المنفذ الحر التالي، وتسمّي الإعدادات المنسوخة المنفذ الذي يعمل. تقول لوحة Output أين يستمع الخادم ([FUCINI_MCP]) ولماذا لم يستطع ([FUCINI_MCP_001]). وما لا تتضمنه خطة — أسماء الاختبارات، تفاصيل MC/DC — تعدّه الأدوات دون أن تفصّله، كما يفعل التلميح.

15. مرجع الأوامر

في Visual Studio. كل الأوامر تحت Tools → Coverage Studio، بأسمائها في الجدول دون البادئة Fucini Coverage:؛ ويحوي شريط أدوات نافذة Coverage وقائمة النقر الأيمن على صف ما يخصهما، وتحوي قائمة النقر الأيمن في نافذة الشيفرة الأوامر الثلاثة التي تعمل على المحرر: Run This Test with Coverage وShow Tests That Ran This Line وExclude Selection from Coverage. الأوامر ذات المفاتيح هي أوتار بضغطتين بعد Ctrl+Shift+U: R يعيد التحميل، وN وP ينتقلان إلى السطر غير المغطى التالي والسابق، وB إلى القرار التالي المختبَر جزئيًا، وT يسرد الاختبارات التي نفّذت السطر، وX يستبعد التحديد — وليس Alt+N الخاص بـ VS Code، لأن Alt مع حرف يفتح قائمة في Visual Studio. غيّرها تحت Tools → Options → Keyboard، حيث تُدرج باسم Coverage Studio: …. غير موجود في هذا الإصدار: لوحة Test Coverage واجهة VS Code — والتشغيل في نافذة Coverage بدلًا منها — ولا يستطيع Solution Explorer عرض الشارات. وفي هذا الإصدار وحده: Run Native Project with Coverage، لمشروع بدء تشغيل C++.

في Visual Studio: أين يوجد كل شيء. نافذة Coverage موجودة تحت View → Other Windows → Coverage، وفي المقام الأول تحت Tools → Coverage Studio، حيث يوجد كل أمر في هذا الإصدار، في مجموعات: التحميل وإعادة التحميل، ومراقبة الملف، وأمرا النسخ، والبطاقات؛ وRun Tests with Coverage وRun Native Project with Coverage وCollect Coverage in Test Explorer…؛ وNext وPrevious Uncovered والقرارات المختبرة جزئيًا؛ والتلوين وعدّادات التنفيذ وأوضاع الهامش؛ ومصدر تغطية الملف، والاختبارات التي نفّذت سطرًا، واختبار واحد مع التغطية، وطريقتا الاستبعاد؛ وCompare with Last Run وCompare Two History Runs… وCompare with CI Baseline وجلسة التغطية وCheck Coverage Thresholds؛ ومجموعة Reports — Show Annotated Source وOpen HTML Report وGenerate Full HTML Report وExport Coverage Report… وGenerate Coverage Badge؛ ثم Getting Started وحدود الامتثال وLicence…. يحتوي شريط أدوات النافذة نفسها على الخمسة الأكثر استخدامًا: Load Coverage وReload وToggle Coverage Painting وCopy Coverage Summary وحدود الامتثال؛ وتحتها المنظور والمرشّح والفرز، ومربع البحث؛ وتحت تلك الاتجاه. ضع المؤشر على صف في الشجرة واضغط على ⋯ الخاص به لفتح قائمة الصف — فتح الملف، وفتح مجلده، ونسخ مساره، مطلقًا أو نسبيًا، بأي من نوعي الشرطة المائلة، واستبعاده من التغطية. في الطرف الأيمن من شريط الحالة توجد نتيجة التشغيل ونتيجة الملف المفتوح، مع الاتجاه منذ آخر تشغيل؛ ويفتح Show Coverage Card وShow Coverage Card for This File البطاقتين اللتين تفصّلانهما، وهما البطاقتان نفسهما اللتان يعرضهما VS Code عندما يستقر المؤشر على عنصر شريط الحالة الخاص به.

Visual Studio: Tools → Coverage Studio, open, with every command of the edition
في Visual Studio: Tools → Coverage Studio، مع كل أوامر هذه الإصدارة.
Visual Studio: View → Other Windows, where the Coverage window is
في Visual Studio: View → Other Windows، حيث توجد نافذة Coverage.
Visual Studio: the Coverage window's toolbar — Load Coverage, Reload, Toggle Coverage Painting, Copy Coverage Summary, compliance thresholds
في Visual Studio: شريط أدوات نافذة Coverage — Load Coverage وReload وToggle Coverage Painting وCopy Coverage Summary وعتبات الامتثال.
Visual Studio: a row's menu in the Coverage window — Open, Open Containing Folder, and the four Copy Path entries
في Visual Studio: قائمة ⋯ لصفّ — فتح الملف، فتح مجلده، نسخ مساره بأربعة أشكال.
Visual Studio: the status bar's two items, the run's score and the open file's
في Visual Studio: عنصرا شريط الحالة، درجة التشغيل ودرجة الملف المفتوح.
Visual Studio: the run's coverage card, opened by Show Coverage Card
في Visual Studio: بطاقة تغطية التشغيل، من Show Coverage Card.
Visual Studio: the open file's coverage card, opened by Show Coverage Card for This File
في Visual Studio: بطاقة الملف المفتوح، من Show Coverage Card for This File.
The status-bar hover cards for the run and the file, then the Coverage view toolbar: Pick Coverage File, Load Coverage, Export Coverage Report and Generate Full HTML Report, ending on the generated reportScreenshot pending — add assets/img/statusbar-and-toolbar.gif (see SCREENSHOTS.md).
في VS Code: بطاقات التحويم في شريط الحالة للتشغيل والملف، ثم شريط أدوات عرض Coverage، وانتهاءً بالتقرير المولَّد.
The status-bar menu: select a coverage file, run tests with coverage, reload, open the HTML report, choose the gutter modeScreenshot pending — add assets/img/statusbar-menu.png (see SCREENSHOTS.md).
في VS Code: قائمة شريط الحالة — اختيار ملف تغطية، تشغيل الاختبارات مع التغطية، إعادة التحميل، فتح التقرير، اختيار وضع الهامش.
Show Worst-Covered Functions: every function of the run, lowest coverage first, with its CRAP score where the report carries complexityScreenshot pending — add assets/img/worst-functions.png (see SCREENSHOTS.md).
في VS Code: Show Worst-Covered Functions، الأقل تغطية أولًا، مع درجة CRAP حيث يحمل التقرير التعقيد.
الأمرما الذي يفعله
Load Coverageاكتشاف التغطية لمساحة العمل وتحميلها. افتراضيًا Alt+Shift+R (وCtrl+Alt+R على macOS).
Pick Coverage Fileاختيار ملفات التتبّع — واحدًا أو عدة ملفات أو ملفًا إضافيًا في كل مرة؛ تتراكم الاختيارات وتُدمج وتُكتب في coverageFile.paths فتُحمَّل تلقائيًا من ذلك الحين.
Show Loaded Coverage Filesسرد ملفات التتبّع في التشغيل النشط. يسردها عرض التغطية أيضًا، ولكل منها زر إلغاء تحميل وزر اختيار بجانبها.
Toggle Tracefile Watchمراقبة ملفات التتبّع بحثًا عن تغييرات وإعادة التحميل تلقائيًا.
Run Tests with Coverageالتعرّف على مشغّل الاختبارات، وتشغيله مع التغطية في مهمة طرفية، وتحميل ما يكتبه، وعرض إضافة المسار إلى الإعدادات.
Run This Test with Coverageالاختبار الواقع تحت المؤشر — التابع أو الصنف أو كتلة describe أو الملف — يُشغَّل بالوصفة مضيَّقةً إليه، ثم يُحمَّل كأي تشغيل. وفي قائمة سياق المحرر أيضًا.
Show Tests That Ran This Lineحيث يذكر التقرير أي الاختبارات نفّذت ماذا، اسرد الاختبارات التي نفّذت السطر الواقع تحت المؤشر، الأكثر تنفيذًا أولًا، وافتح ما تختاره حيث كُتب.
Run Tests Affected by My Changes…سرد الاختبارات التي نفّذت سطرًا تغيّره شجرة العمل مقابل testImpact.baseRef، وفتح الاختبار الذي تختاره، أو تشغيل تلك الاختبارات وحدها حيث جاءت التقارير من تشغيل لكل اختبار على حدة.
Show Minimal Test Set…أقل عدد من الاختبارات يظل ينفّذ كل سطر تنفّذه مجموعة الاختبارات، ثم الاختبارات التي لا تضيف أي سطر من عندها.
Run App with Coverage…بدء تطبيق .NET الخاص بالمجلد تحت dotnet-coverage، وتحميل ما مررتَ به عند إغلاق التطبيق.
Run Mutation Tests Hereإجراء الطفرات على الدالة التي فيها المؤشر — أو على التحديد، أو على الملف — بواسطة Stryker.NET أو StrykerJS أو PIT، وتحميل التقرير بجانب التغطية المعروضة على الشاشة.
Exclude This File from Coverage / Exclude from Coverageضع الملف المفتوح — أو، على صف في عرض Coverage، الملف أو /** الخاص بالمجلد — في fuciniCoverage.ignore في إعدادات المجلد، مرة واحدة.
Exclude Selection from Coverageاكتب الاستبعاد حيث توجد الشيفرة: [ExcludeFromCodeCoverage] فوق عضو .NET، وLCOV_EXCL_LINE على سطر واحد، وLCOV_EXCL_START/STOP حول عدة أسطر، بعلامة التعليق الخاصة بالملف. وأيضًا من المصباح وقائمة سياق المحرر.
Start Coverage Session / End Coverage Sessionما دامت الجلسة مفعّلة، يُضاف كل تحميل إلى ما قبله اتحادًا؛ وشريط فوق الشجرة يعدّ التشغيلات وينهيها.
Next / Previous Uncoveredالتنقّل بين المناطق غير المغطّاة. افتراضيًا Alt+N / Alt+P (وCtrl+Alt+N / Ctrl+Alt+P على macOS).
Choose Editor Gutter Mode...إيقاف، أو أشرطة على غير المغطّى فقط، أو أشرطة حمراء وكهرمانية وخضراء، أو خريطة حرارية لأعداد الإصابات في هامش المحرر.
Cycle Editor Gutter Modeخطوة واحدة إلى الأمام عبر off وuncovered وcoverage وheatmap — بـAlt+G، أو بزر الوضع في شريط الحالة.
Choose Coverage Source for This File...عندما يقيس أكثر من تقرير محمَّل الملفَّ المفتوح، اختر من أيّها تأتي أرقامه، للملف أو لمجلده أو لنمط — يكتب قاعدة في coverageFile.sources.
Clear Coverage Source for This File...إزالة قواعد coverageFile.sources التي تنطبق على الملف المفتوح.
Toggle Inline Hit Countsإظهار أعداد التنفيذ ×N بعد كل سطر أو إخفاؤها — يبدّل hitCounts.inline.
Show in Test Coverage Viewنشر التشغيل النشط إلى لوحة Test Coverage الخاصة بـ VS Code نفسه (حتى مع تعطيل testCoverage.publish) وفتحها.
Suggest Path Remap Ruleاستنتاج قاعدة pathRemap التي تطابق الملفات غير المتطابقة في التشغيل النشط مع مساحة العمل، وعرض إضافتها.
What Community Includesكل حد وكل ميزة محجوبة في المستوى المجاني في قائمة واحدة، مع ما استُهلك من كل حد.
Open HTML Reportفتح التقرير الثابت المُولَّد.
Generate Full HTML Reportإنشاء التقرير متعدّد الصفحات.
Open Annotated Source / …to the Sideعرض التغطية المشروح لملف.
Toggle Annotated Sourceالتبديل بين المصدر والعرض المشروح. افتراضيًا Alt+A (وCtrl+Alt+A على macOS).
Show Worst-Covered Files / Folders / Functionsقائمة Quick Pick مرتّبة من الأدنى.
Copy Uncovered Linesملخّص Markdown لكل نطاق غير مغطّى.
Compare Two History Runs / with Last Runفرق انحدار لكل ملف — تشغيلان احتفظ بهما السجل، أو التشغيل المعروض مقابل الذي حلّ محله.
Compare with CI Baselineالتشغيل المحمَّل مقابل التقرير الذي يسمّيه baseline.report — تقرير الفرع الرئيسي من CI، عنوان URL أو مُخرَج منزَّل — ملفًا ملفًا.
Show Indirect Coverage Changes…الأسطر التي تغيّرت تغطيتها وإن لم يعدّلها أحد، مقابل خط أساس CI أو التشغيل السابق، لكل ملف.
Check Coverage Thresholdsتقييم فحوص الامتثال.
Export Fucini JSONتصدير التشغيل الحالي بصيغة Fucini JSON.
Export Coverage Report...اختر تنسيقًا — CSV أو Markdown أو LCOV أو Cobertura XML أو SARIF أو شارة SVG — ووجهةً للحفظ.
Generate Coverage Badgeكتابة شارة SVG للتشغيل النشط في badge.outputPath، تعرض badge.metric، وعرض فتحها.
Copy MCP Server Configurationوضع ما يحتاج إليه عميل MCP ليسأل عن التغطية المعروضة على الشاشة — عنوان الخادم ورمزك المميز — في الحافظة؛ وإذا كان الخادم متوقفًا، عرض تشغيله.
Show Status Bar Menuفتح قائمة الإجراءات السريعة.
Browse for External HTML Report / Full Report Output Dir…تعيين مجلدات التقارير عبر أداة اختيار.

16. مرجع الإعدادات

يوجد جدول الإعدادات الكامل والمصنّف — كل خيار بقيمته الافتراضية — في صفحة الميزات والإعدادات. تحمل جميع المفاتيح بادئة fuciniCoverage..

يجدر الذكر: يقوم fuciniCoverage.language بتثبيت واجهة وقت التشغيل الخاصة بهذا الامتداد (شريط الحالة، الإشعارات، التلميحات، طرق عرض الويب) على لغة معينة، بشكل مستقل عن لغة عرض VS Code — القيمة الافتراضية هي auto ويأتي مزودًا بحزم لجميع اللغات الـ18 المدعومة. وهو لا يغيّر عناصر لوحة الأوامر أو تسميات واجهة الإعدادات، التي يواصل VS Code تحديدها من لغة العرض الخاصة به.

في Visual Studio. مفاتيح fuciniCoverage.* نفسها، تُقرأ من أربعة ملفات على الأكثر، والأخير يغلب: إعدادات المستخدم الخاصة بـ VS Code إن كان VS Code على الجهاز — تُقرأ ولا تُكتب أبدًا، فتأتي ألوانك وعتباتك معك؛ و%APPDATA%\Fucini\CoverageStudio\settings.json، إعدادات المستخدم لهذا الإصدار؛ و.vscode\settings.json في المجلد أو بجانب الحل، فالمستودع المهيأ لـ VS Code مهيأ لـ Visual Studio؛ وfucini-coverage.json في جذر الحل، للفريق الذي يفضّل ألا يحتفظ بمجلد .vscode في مستودع .NET — ويقرؤه إصدار VS Code أيضًا. يفتح الترس في شريط أدوات نافذة Coverage نافذة إعدادات تكتب ملف المستخدم أو ملف المجلد الموجود، كما يقول محدِّد Write changes to فيها، وتحافظ على تعليقات الملف الذي تحرره. يعمل fuciniCoverage.language هناك بالطريقة نفسها؛ والقوائم تتبع لغة Visual Studio نفسه.

17. رموز الأخطاء

تُرسَل التشخيصات إلى قناة إخراج Fucini Coverage (View → Output → Fucini Coverage)، ولكل منها رمز FUCINI_* ثابت.

في Visual Studio. تذهب الرموز نفسها إلى جزء Fucini Coverage في نافذة Output (View → Output) وتُحفظ في %LOCALAPPDATA%\Fucini\CoverageStudio\coverage-studio.log، للسؤال الذي يأتي بعد إغلاق البيئة. ثلاثة تتكرر: لا شيء معلَّم مع أن الجزء يقول إن الملفات حُمِّلت — وضع الهامش off، اختر Show Coverage in Editor؛ FUCINI_REMAP_001 وشريط معلومات — يسمّي التقرير مسارات غير موجودة هنا، ويقترح الجزء قاعدة pathRemap؛ تقول نافذة Coverage إنها تحتاج WebView2 — ثبّت Microsoft Edge WebView2 Runtime، فالعلامات في المحرر لا تحتاجه.

الرمزالمعنى
FUCINI_PARSE_001تنسيق تغطية غير مدعوم/غير معروف — لم يطابق الملفَّ أي محلّل.
FUCINI_PARSE_010لم يحتوِ ملف lcov على سجلات SF.
FUCINI_PARSE_020ملف llvm-cov بصيغة JSON غير صالح، أو ينقصه data[]، أو لا يحتوي على ملفات.
FUCINI_PARSE_030جذر Cobertura <coverage> مفقود أو XML غير صالح.
FUCINI_PARSE_040جذر JaCoCo <report> مفقود أو لا توجد ملفات مصدرية.
FUCINI_PARSE_050ملف Istanbul/SimpleCov بصيغة JSON غير صالح أو لا يحتوي على ملفات.
FUCINI_PARSE_060ملف SimpleCov بصيغة JSON غير صالح أو ينقصه مصفوفة files على المستوى الأعلى.
FUCINI_PARSE_070ملف تعريف Go بلا ترويسة mode:، أو لا يحتوي كتل تغطية.
FUCINI_PARSE_080جذر Clover <coverage> أو <project> مفقود، أو لا ملفات بداخله.
FUCINI_PARSE_090جذر OpenCover <CoverageSession> مفقود، أو لا ملفات بداخله.
FUCINI_PARSE_100‏JSON الخاص بـ coverage.py غير صالح أو يفتقد كائن files في المستوى الأعلى.
FUCINI_PARSE_110‏JSON الخاص بـ gcov/gcovr غير صالح أو يفتقد مصفوفة files في المستوى الأعلى.
FUCINI_PARSE_120ملف GNATcoverage XML بلا عنصر <source>، أو ملف index.xml لم تُحلّ عناصر xi:include فيه — حمّل بدلًا منه ملفات *.xml الخاصة بكل ملف مصدر.
FUCINI_PARSE_130العنصر الجذر <BullseyeCoverage> مفقود، أو لا يحتوي على عناصر <src>.
FUCINI_PARSE_140العنصر الجذر <CoverageDSPriv> مفقود، أو لا يوجد جدول <SourceFileNames> لحلّ صفوف الأسطر، أو لا توجد بيانات أسطر.
FUCINI_PARSE_150JSON تغطية Xcode غير صالح، أو يفتقد مصفوفة targets في المستوى الأعلى.
FUCINI_PARSE_160العنصر الجذر <coverage> الخاص بـ SonarQube مفقود، أو لا يحتوي على عناصر <file>.
FUCINI_PARSE_170JSON الخاص بـ Coveralls غير صالح، أو يفتقد مصفوفة source_files في المستوى الأعلى.
FUCINI_LOADأُلغي تحميل من إشعار تقدّمه؛ ويبقى التشغيل السابق، إن وُجد، محمَّلًا.
FUCINI_REMOTE_001تعذّر جلب عنوان URL في coverageFile.paths، مع السبب؛ وتُحمَّل آخر نسخة منزَّلة بدلًا منه. وتسجّل أسطر [FUCINI_REMOTE] العادية كل تنزيل وكل فحص لم يتغيّر فيه شيء (304).
FUCINI_REMOTE_002لم يعطِ عنوان URL في coverageFile.paths جوابًا كاملًا خلال 30 ثانية — غالبًا وكيل أو VPN يقبل الاتصال ثم يصمت؛ وتُحمَّل آخر نسخة منزَّلة بدلًا منه.
FUCINI_REMOTE_003أجاب عنوان URL في coverageFile.paths بصفحة HTML بدلًا من ملف تتبّع — صفحة تسجيل دخول على الأرجح. لا تُخزَّن الصفحة مؤقتًا وتُحمَّل آخر نسخة منزَّلة بدلًا منها؛ تحقّق من الرمز المميز في remote.headers.
FUCINI_REMAP_002اقتُرحت قاعدة pathRemap للمسارات التي تركها التحميل بلا تطابق، مع عدد ما تفسّره منها — أو تعذّر استنتاج أي قاعدة، أو أن القاعدة المستنتجة موجودة أصلًا في الإعداد ولم تحلّها.
FUCINI_REMAP_003أُلحقت القاعدة المقترحة بـ fuciniCoverage.pathRemap عبر Apply Suggested Remap وتجري إعادة تحميل التغطية.
FUCINI_GITDIFF_001امتداد Git غير متاح؛ يُتخطّى غطاء الفرق (diff) ويُعرض التشغيل كاملًا.
FUCINI_GITDIFF_002يبدأ gitDiff.baseRef بـ -، وهو ما لا يمكن لأي مرجع git أن يبدأ به (سيقرؤه git كخيار)؛ يُتخطّى غطاء الفرق (diff) ويُعرض التشغيل كاملًا.
FUCINI_IGNOREعدد الملفات التي استبعدها fuciniCoverage.ignore من التشغيل، وأيّها.
FUCINI_UNMEASURED_001الملفات من نوع التشغيل التي لم يحمّلها أي اختبار، واحد في كل سطر.
FUCINI_UNMEASURED_002أكثر من 5,000 ملف في مساحة العمل طابق أحد امتدادات التشغيل؛ ولم يُنظر إلا في أول 5,000 منها لقائمة Unmeasured.
FUCINI_UNMEASURED_003في وضع count، بعض الملفات غير المقيسة مُدرجة لكنها غير محتسبة: بلغ التحميل سقف القراءة (2,000 ملف أو 50 ميغابايت لكل تحميل).
FUCINI_UNMEASURED_004تعذّرت قراءة ملف غير مقيس؛ فهو مُدرج لكنه غير محتسب.
FUCINI_TESTCOVERAGEعدد الملفات التي نُشرت إلى عرض Test Coverage الخاص بـ VS Code.
FUCINI_BADGEكُتبت الشارة، مع مسارها وتسميتها وقيمتها.
FUCINI_BADGE_001تعذّرت كتابة الشارة، مع السبب.
FUCINI_WORKSPACEأُضيف مجلد إلى مساحة العمل أو أُزيل منها؛ ويُعاد اكتشاف التغطية.
FUCINI_VARIABLESما الذي أعاده كل ${command:…} في إعدادات المسارات، أو لماذا تُرك كما كُتب: فشل الأمر، أو لم يُعِد شيئًا صالحًا، أو أن مساحة العمل غير موثوقة.
FUCINI_WATCHما يفعله المراقب: المسارات المراقَبة، أو ملف مُعدّ ظهر، أو مهمة مسمّاة في watch.reloadAfterTasks انتهت (مع رمز خروجها) وأطلقت إعادة تحميل، أو مسار تحت files.watcherExclude يُستطلع بدلًا من مراقبته.

18. الخصوصية

تُتحكَّم بيانات الاستخدام عبر الإعداد telemetry.enabled ذي النطاق window. وهي مُعطَّلة افتراضيًا. ويتطلّب الملخّص اليومي وإشعار الإزالة أيضًا أن يسمح الإعداد العام telemetry.telemetryLevel في VS Code بالقياس؛ أمّا إشعار التثبيت وبعض الأحداث الصغيرة فتُرسَل في كل الأحوال، وكذلك مُدخَل سجلّ الاستخدام الخاص بتثبيت في الفترة التجريبية أو في مستوى Community المجاني. في Community، يبادل Unlock Full Features بيانات الاستخدام هذه بكل ميزات Pro، بما فيها MC/DC، لمدة 30 يومًا، مرة واحدة لكل جهاز — عطّلها من جديد وتُطبَّق مجموعة Community القياسية؛ والترخيص المدفوع لا يتأثر في الحالتين. لمعرفة ما يُرسَل، راجع سياسة الخصوصية.

هناك أمران يستحقّان المعرفة لأن بإمكانك التصرّف بناءً عليهما. الأول هو معرّف سجلّ الاستخدام الخاص بك: في الفترة التجريبية وفي Community يعرضه الامتداد تحت Show License / Activation وفي أسفل What Community Includes، حيث يؤدي اختيار ذلك الصفّ إلى نسخه وفتح السياسة. لا يعرف السجلّ جهازك إلا بتجزئة ولا يعرفه بأي شيء آخر، ولذلك فهذا المعرّف هو السبيل الوحيد لتسأل عمّا يحتفظ به السجلّ عنك، أو تطلب حذفه، أو تعترض عليه — اذكره لنا نجد صفّك؛ ومن دونه لا نستطيع. والثاني هو سجلّ التثبيت: صفّ واحد يُكتب في أول مرة يُبلغ فيها تثبيتٌ ما، ويُحتفظ به بدلًا من حذفه بعد 90 يومًا، ويتضمّن معرّف التثبيت، واليوم، والمكان الذي حُدِّد من عنوانه، والإصدارات، ونظام التشغيل — لا العنوان نفسه، ولا أي شيء عن شفرتك. وبه نستطيع أن نقول كم بلغ عدد التثبيتات على مدى السنين. وكلاهما موصوف بالتفصيل في سياسة الخصوصية، وكلاهما يُحذف إذا طلبت ذلك.

The bottom of What Community Includes: the ways to lift the caps, and How these are counted — the row that copies your usage ledger ID and opens the privacy policy
نهاية What Community Includes: كيف تُحتسب الحدود، والصفّ الذي يمنحك معرّف سجلّ الاستخدام.

19. التقييم والتفعيل

يُوزَّع Fucini Coverage Studio بصفته نسخة تجريبية مسبقة للتقييم. عند أول تشغيل يُطلب منك الموافقة على تقييمه، فتبدأ الفترة التجريبية — وكل الميزات متاحة خلال فترة تجريبية مدتها 14 يومًا، تُحتسب من أول استخدام على ذلك التثبيت. ولا يوجد تاريخ ثابت يتوقف بعده أي شيء.

ابتداءً من الإصدار 2.2026.2 تبدأ الفترة التجريبية لتثبيت جديد حالما يصل الامتداد إلى خادم التراخيص مرة واحدة؛ وحتى ذلك الحين يعمل على مستوى Community ويُعلِم بذلك. في حاوية تطوير أو Codespace لا تبدأ أي فترة تجريبية — رمز اشتراك أو مفتاح أو تصريح الأيام السبعة يفتح المجموعة الكاملة هناك.

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

Show License / Activation: the trial state, and the buttons to enter a subscription code, see the plans or request a licenceScreenshot pending — add assets/img/licence-dialog.png (see SCREENSHOTS.md).
  1. شغّل Fucini Coverage: Show License / Activation (ويمكن الوصول إليه أيضًا من شريط الحالة بعد انتهاء الفترة التجريبية أو المفتاح) ثم انقر Request License… (أو Request Renewed Key… إن سبق أن فعّلت).
  2. أكّد الطلب. يُصدر المفتاح تلقائيًا، وتُعاد الاستفادة من بيانات التواصل الخاصة بك من أي طلب سابق بدلًا من سؤالك عنها مجددًا.
  3. هذا كل شيء. يُولَّد مفتاح التفعيل ويُكتب تلقائيًا في fuciniCoverage.license.key. وينتقل شريط الحالة خلال لحظات من الفترة التجريبية إلى ترخيص مُفعَّل.

الطريق اليدوي في صورة واحدة: افتح لوحة الترخيص، واختر Enter Key، والصق المفتاح الوارد في بريدك، فيتحوّل الشريط إلى «Activated».

Activating by hand: the licence panel, the activation dialog, Enter Key, the pasted key, and the banner turning to ActivatedScreenshot pending — add assets/img/activate-key.gif (see SCREENSHOTS.md).

إذا فشل الطلب الآلي في أي وقت (لا يوجد اتصال، أو مشكلة في الخادم): شغّل Fucini Coverage: Copy Activation Request Code، وأرسله عبر صفحة الاتصال أو info@fucini.consulting، ثم الصق مفتاح FCK1.… الذي تستلمه ردًا باستخدام Fucini Coverage: Enter Activation Key (أو مباشرة في settings.json):

{ "fuciniCoverage.license.key": "FCK1.…الصق المفتاح بالكامل هنا…" }

اسم الإعداد هو fuciniCoverage.license.key (نطاق المستخدم/العام). المفتاح مرتبط بجهازك ومستخدم نظام التشغيل، وقد يحمل تاريخ انتهاء صلاحية، ويمكنه تفعيل أو تقييد ميزات فردية والحد من عمليات تحميل التغطية يوميًا. إذا ظهرت رسالة "invalid for this machine"، فاطلب مفتاحًا جديدًا من هذا التثبيت — فالمفتاح الصادر لجهاز آخر لن يُقبل هنا أبدًا.

في Visual Studio. لا يوجد مستوى مجاني في ذلك الإصدار: من دون اشتراك لا يُقرأ شيء. ومع اشتراك، تقرّر الخطة هناك ما تقرّره في VS Code — الميزة التي لا تتضمنها الخطة تُحجب، ويقول أمرها ذلك بدل أن يُنفَّذ. والحدّ الأدنى للإصدار الذي ما زال خادم التراخيص يدعمه يسري هناك أيضًا: البناء الأقدم منه يُبلَّغ بذلك مرة في اليوم، مع التاريخ الذي يتوقف فيه، ويواصل العمل حتى ذلك التاريخ. وانعدام الاتصال لا يوقف أي بناء أبدًا.

فئة Community المجانية: حصة أسبوعية

لا يتوقف Community أبدًا عن عرض التغطية. فالهامش، ومسطرة النظرة العامة، وتلميحات التمرير، وCodeLens، وعرض Coverage، ووضع المراقبة، وتغطية الفروقات، والسجل لا تُحتسب إطلاقًا، وتحميل ملف تتبع عبر أمر محدود فقط بـ 25 مرة في اليوم. ما يُقاس هو المخرجات: خمس مرات في الأسبوع لكل من فتح تقرير HTML، والتصدير، ومقارنة تشغيلين، وفحص العتبات، وعرض المصدر المشروح في مكانه.

الأسبوع أسبوعك أنت، لا أسبوع التقويم: يبدأ مع أول استخدام وينتهي بعد سبعة أيام. عند استنفاد إحدى الحصص تذكر الرسالة الإجراء واليوم الذي تعود فيه الحصة، وبعد تلك الرسالة الواحدة لا يشير إلى الأمر سوى شريط الحالة. يسرد الأمر Fucini Coverage: What Community Includes كل حصة مع مقدار ما استُخدم منها وموعد إعادة تعيينها، قبل أن تصل إلى أي منها.

The weekly allowance: five uses of Open HTML Report across three days, a sixth refused with the day the count resets, and the week ending seven days after the first use; gutters, hovers, CodeLens and the Coverage view are never countedScreenshot pending — add assets/img/weekly-allowance.png (see SCREENSHOTS.md).
The message at a Community limit: Checking coverage thresholds, all 5 used, the day it resets, and the buttons Subscribe, 7-Day Pass and What Community IncludesScreenshot pending — add assets/img/community-limit-prompt.png (see SCREENSHOTS.md).
What Community Includes: each allowance with how much is used and the day it resets, then the features that are not includedScreenshot pending — add assets/img/community-includes-weekly.png (see SCREENSHOTS.md).

ثلاثة تفاصيل تخص الخطط المدفوعة بينما تبقى نتائجها مجانية: يضع Community علامة على كل سطر فيه طفرات ناجية ويذكر عددها، لكنه لا يذكر ما غيّرته كل طفرة؛ ويذكر عدد الاختبارات التي نفّذت السطر، لكن دون أسمائها؛ ويعرض Max CRAP للتشغيل، لكن دون قائمة Riskiest Methods المرتبة.

A mutant hover in Community: 2 mutants survived and 2 more detected on the line; what each mutant changed is part of the paid plansScreenshot pending — add assets/img/mutant-hover-community.png (see SCREENSHOTS.md).

إذا كنت تستخدم Community بالفعل عند وصول الحصة الأسبوعية (0.2026.83)، فستبقى حدودك السابقة سارية لمدة 30 يومًا؛ وسيتم إعلامك بذلك مرة واحدة مع التاريخ. تُحفظ العدادات على جهازك — في وحدة تخزين VS Code نفسها وفي ~/.fucini-coverage/، بحيث يواصل أي ملف تعريف جديد في VS Code الأسبوع نفسه — ولا تُرسل إلى أي مكان أبدًا.

تصريح 7 أيام

لست مستعدًا للاشتراك بعد؟ تصريح 7 أيام هو كل ما في Pro لمدة أسبوع واحد، يُدفع مرة واحدة: لا شيء يتجدد ولا شيء يحتاج إلى إلغاء. اشترِه من صفحة الأسعار (تتضمن الرسالة التي تظهر عند بلوغ أحد حدود Community زرًا لذلك)، ويصلك رمز التفعيل عبر البريد الإلكتروني.

The 7-day pass on the pricing page: everything in Pro for one week, paid once, with the Get a 7-day pass buttonScreenshot pending — add assets/img/pricing-week-pass.png (see SCREENSHOTS.md).
  1. شغّل Fucini Coverage: Enter Subscription Code — الأمر موجود في إصدار Community وفي Pro على حد سواء.
  2. اختر Pro والصق رمز FCB1-… الوارد في البريد الإلكتروني.
  3. هذا كل شيء. يُصدر المفتاح ويُطبَّق نيابة عنك، ويعمل دون اتصال بالإنترنت. يبدأ الأسبوع من وقت الدفع، لذا فعّله عند الشراء. وعند انتهائه تعود الإضافة إلى Community من تلقاء نفسها وتواصل عرض التغطية.
Enter Subscription Code, step 1: choose Pro from the list of plansScreenshot pending — add assets/img/pass-step-plan.png (see SCREENSHOTS.md).
Enter Subscription Code, step 2: paste the FCB1 code from the purchase email and press EnterScreenshot pending — add assets/img/pass-step-code.png (see SCREENSHOTS.md).

في Visual Studio. الرمز نفسه يفعّل Fucini Coverage Studio لـ Visual Studio، 2022 و2026: افتح Tools → Coverage Studio → Licence…، والصق الرمز، واختر الخطة التي يخصّها، واضغط Activate. تعرض نافذة Coverage بعدها Activated فوق الشجرة؛ وعند فتح الصف بسهمه يظهر التاريخ الذي يبقى المفتاح صالحًا حتى حلوله وزرّ إلى حسابك. الجهاز الواحد مقعد واحد: فعّل VS Code أو Visual Studio، فيتبعه المحرّر الآخر على الجهاز نفسه من تلقاء نفسه — يقرأ Visual Studio مفتاح VS Code ويقرأ VS Code مفتاح Visual Studio — فلا يُدخل شيء مرتين ولا يُشغل مقعد ثانٍ. وكلاهما يبقي المفتاح حيًّا بالطريقة نفسها: يسجّل Pro Plus وBusiness وEnterprise حضورهم مرتين يوميًا، ويُجدَّد مفتاح Pro في الأسبوع الذي يسبق انتهاءه.

Visual Studio: the Coverage window says no subscription covers this machine, and the Licence dialog takes the subscription code
Visual Studio: the Coverage window after an activation — Activated, valid until a date, and a button to the account

الانتقال إلى حاسوب جديد وإدارة المقاعد

يرتبط المفتاح بجهاز واحد، لذا يحتاج الحاسوب الجديد إلى مفتاح جديد — والاشتراك لا يغطي أكثر من عدد الأجهزة المذكور فيه. حرِّر القديم بنفسك: سجّل الدخول إلى إدارة اشتراكك، وابحث عن المقعد الذي لم تعد تستخدمه، واختر Free up، ثم فعّل الجهاز الجديد بالرمز نفسه. شراء Pro لا يرسل إليك كلمة مرور — حسابك موجود، لكنه بلا كلمة مرور بعد، لذا استخدم في المرة الأولى تعيين كلمة المرور أو إعادة تعيينها بالعنوان الذي اشتركت به.

في خطتَي Business وEnterprise تدعو كل زميل بالبريد الإلكتروني من الصفحة نفسها. يحصل كلٌّ على رمز تفعيل خاص به وحده، وما إن يستخدمه حتى يظهر عنوانه إلى جانب مقعده — وعندما يغادر أحدهم ترى أي مقعد كان له فتحرّره لمن يليه. تحجز الدعوة مقعدًا منذ لحظة إرسالها وتنتهي صلاحيتها بعد 14 يومًا إن لم تُستخدم؛ اسحبها لتستعيد المقعد فورًا.

اختبار إصدارات ما قبل الإطلاق

يصل العمل الجديد إلى fucini.software قبل وصوله إلى Marketplace، ويمكنك أن تطلب تقديمه إليك. افتح عرض Coverage، ووسّع لوحة الترخيص، ثم اضغط اختبار إصدارات ما قبل الإطلاق… — أو فعّل fuciniCoverage.update.preRelease. ومن حينها يفحص الامتداد هنا موجزًا منفصلًا لإصدارات ما قبل الإطلاق إلى جانب الموجز المعتاد، ويقدّم الأحدث من الاثنين.

The licence panel in the Coverage view, expanded: a Pro licence valid until 2027-03-19, and the button labelled Test pre-release buildsScreenshot pending — add assets/img/licence-prerelease.png (see SCREENSHOTS.md).

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

The same panel once the install has joined: an update bar offering 0.2026.84 while 0.2026.83 is running, the button now reading Leave the pre-release channel, and a line saying the install is on the channelScreenshot pending — add assets/img/licence-prerelease-joined.png (see SCREENSHOTS.md).

20. الاتصال والترخيص

للأسئلة أو الإبلاغ عن الأخطاء أو شروط الترخيص البديلة — راجع صفحة الاتصال أو راسلنا عبر البريد الإلكتروني على info@fucini.consulting. مرخّص بموجب MIT مع شرط الإسناد في ملاحظات الإصدار؛ راجع أيضًا Notice.

21. على سطر الأوامر

يعمل القارئ بلا محرر أيضًا: npm install -g fucini-coverage، مجانًا، على Windows وLinux وWSL وmacOS. fucini-coverage check coverage/lcov.info --lines 80 هو البوابة التي يفشل عندها خط الأنابيب؛ وsummary وexport وreport وbadge وcompare تفعل ما تفعله أوامر المحررين التي تحمل هذه الأسماء، وmcp يقدّم الأدوات الست الواردة في القسم أعلاه لوكيل على خادم. وهو يقرأ fucini-coverage.json، ملف الإعدادات الذي يقرؤه إصدار Visual Studio، فتُضبط العتبات مرة واحدة. fucini-coverage help <command> يشرح كل أمر؛ والصفحة الكاملة هي fucini-coverage على npm.

The command line on the demo: --help, summary, check with two gates passing, export as Markdown, compare against a baseline, badge, report and the MCP server's helpScreenshot pending — add assets/img/cli-demo.gif (see SCREENSHOTS.md).