ПОВНИЙ ПОСІБНИК

Посібник користувача

Від першого файлу трасування до відповідності стандартам безпеки — усе, що вміє 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 це єдине покриття, яке IDE покаже. Встановіть .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

JSON від llvm-cov — найбагатше джерело даних: окрім рядків, гілок і функцій він містить регіони, 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. Власне покриття проєкту C++ у Visual Studio було лише в Enterprise, а безкоштовний плагін OpenCppCoverage, що закривав цю прогалину, знято з підтримки. Tools → Coverage Studio → Run Native Project with Coverage бере стартовий проєкт — .vcxproj — питає в MSBuild, куди він збирається і на якому наборі інструментів, і вимірює його одним із двох способів. На наборі інструментів ClangCL, з llvm-profdata і llvm-cov із LLVM на машині (їх приносить компонент Visual Studio C++ Clang tools for Windows), він збирає проєкт заново в 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 називає URL-адресу. Кожне отримання умовне (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: рядок покритий лише там, де його виконав кожен звіт, що його вимірює, а рядки, щодо яких звіти розходяться, позначено бірюзовим. Саме це питання ставить перевірка між компіляторами: що насправді випробувала кожна збірка, яку я постачаю?

Правила рідко доводиться писати вручну. Клацніть правою кнопкою файл у поданні Покриття і виберіть 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" }
  ]
}

Що ви бачите: рядок файлу в поданні Покриття називає звіт, з якого взято його числа, або, якщо звіти поєднано, кожен звіт і режим із ≠ n для спірних рядків. Поле редактора та Annotated Source позначають ці рядки бірюзовим і кажуть, який звіт скільки разів їх виконав. Спливаюча підказка рядка стану називає джерело відкритого файлу, а для всього прогону — чинні правила і те, як вирішено решту файлів. samples/c-cross-check із демо — це випадок двох компіляторів, готовий до відкриття. Visual Studio робить усе це теж: Choose Coverage Source... на рядку подання Покриття, а також 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 з подання Покриття — звіт 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: те саме з меню рядка подання Покриття — звіти, потім докуди сягає правило, потім знову завантажений файл.
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... з рядка подання Покриття — ті самі звіти й ті самі два способи їх поєднати; рядок стану називає поєднання.

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++ вважається виконаним там, де його виконало будь-яке інстанціювання; що зробило кожне окреме інстанціювання, показує метрика інстанціювань.

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 перелічить тестові класи й запустить їх по одному, позначаючи кожен звіт його класом, щоб підказка, лінза й команда могли відповісти й для .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 пише failed біля кожного. Коли тест червоний, дивитися треба в код, який він виконував. Результати читаються під час кожного завантаження з теки кожного звіту — будь-який .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 запитується diff робочого дерева відносно 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] запускається за своїм шляхом у крейті з --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 у власній консолі, щоб у консольний застосунок можна було вводити, і працює, доки ви його не закриєте. Те, що ви пройшли, потім завантажується як будь-який запуск, а в сеансі покриття додається до того, що виконали тести. Те, як застосунок завершився, на запуск не впливає. Інструмент потрібно один раз установити: 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, пофайлові відсотки, які воно ставить у Провіднику, і власний перемикач редактора 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. Покриття diff

Обмежте оформлення лише рядками, що змінилися відносно базового посилання 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 і в порогах. Панель Output каже, що відповів git, коли він не відповідає нічого.

Поріг для нового коду

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, файл за файлом, — що великий запуск відчує під час кожного завантаження, — і заступають diff для покриття diff і для порога вище. Ще не закомічений рядок рахується в будь-якому разі.

{
  "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).

Непрямі зміни: що змінилося, хоча ніхто цього не чіпав

Diff каже, які рядки змінилися; два запуски кажуть, які рядки перестали або почали виконуватися. Варті уваги ті рядки, де ці двоє розходяться: код, якого ніхто не редагував і який більше не виконується, бо видалено тест, гілка раніше за ходом виконання тепер повертається достроково, змінилася фікстура. Рецензія diff їх побачити не може — вони поза ним за означенням. Show Indirect Coverage Changes… перелічує їх за файлами, першим той, що втратив найбільше, і відкриває вибраний на першому такому рядку. Запуск звіряється з базовою лінією CI, якщо baseline.report її називає, — саме за нею оцінюють pull request, — а інакше з попереднім запуском; рядки, які робоче дерево змінює відносно 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 хибним: покриття гілок повне, а покриття умов — три з чотирьох. Цей рівень у DO-178C та ISO 26262 розташований між покриттям гілок і MC/DC, і починаючи з 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

Деякі звіти містять цикломатичну складність кожної функції: 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: те, чого вимагає обґрунтування безпеки, і саме те, що постачалося до 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, це стандартне заперечення «хост проти цілі», і наведені вище шляхи є стандартними відповідями на нього — перший закриває питання для покриття вихідного коду, третій — для об'єктного коду.

Наразі експорт, який читається для об'єктного коду, — це COVerage.EXPORT.ListModule Lauterbach TRACE32 з 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) { /* … */ }

Причини читаються під час кожного завантаження, і журнал їх рахує. Export Coverage Report… записує список — exclusions and their justifications, у 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 змінює кожну, не змінюючи жодного байта — тож змінена позначка часу є щонайбільше приводом поглянути ще раз. Перевірка виконується при завантаженні покриття і знову щоразу, коли файл зберігається або змінюється на диску, тож позначка йде за файлом: правка, що суперечить прогону, її ставить, checkout, що повертає виміряну версію, її знімає. Підказка каже точно, що це довело. Установіть staleWarning.enabled у false, щоб вимкнути все це.

12b. Невиміряне проти непокритого

Файл, якого прогін ніколи не згадує, — невиміряний: його не завантажив жоден тест, тож жоден інструмент не записав для нього ані рядка. Це не те саме, що непокритий — виміряний, з нулем влучань, — і розширення ніколи не оцінювало відсутній файл як 0%. Чого воно не робило до 0.2026.69 — так це взагалі не показувало відсутні: модуль без жодних тестів ніколи не з'являвся ні в дереві, ні в підсумках, ні в перевірці порогів, і читач бачив «92%» для проєкту, половину файлів якого ніколи не було виконано.

Тепер, із завантаженим прогоном, пофайловий елемент рядка стану каже не виміряно для вихідного файлу того ж виду, що й прогін, якого в прогоні немає — «того ж виду, що й прогін» означає, що він має одне з розширень файлів, які прогін вимірював, тож заголовки й джерела проєкту на C є кандидатами, а його скрипти на Python — ні. Усе понад це вмикається за бажанням через fuciniCoverage.unmeasured.mode:

  • off (типово) — більше нічого не змінюється.
  • list — подання Coverage отримує внизу групу Невиміряні, яка називає кожен такий файл, і кожен рядок відкриває його; результат завантаження рахує їх; значки позначають їх ? у Провіднику; а 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, у тому самому глоб-синтаксисі, що й 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, XML Cobertura, SARIF або автономний значок SVG для вашого README. Доступно також із кнопки поруч із Generate Full HTML Report у поданні Covered Files. Усе, крім CSV, втрачає дані — MC/DC, регіонам та інстанціюванням немає місця в LCOV, Cobertura чи SARIF — тож Fucini JSON і CSV лишаються форматами, що несуть кожну метрику.
  • Copy Uncovered Lines — зведення прогалин у форматі Markdown, готове для вставки в PR.

У 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-name>/<relative-path>.html, тож папку з назвою репозиторію налаштовувати не потрібно), показується саме ця згенерована набором інструментів сторінка замість вбудованого рендерера — її локальні посилання/стилі переписуються для роботи всередині вебпанелі, і вона містить деталі, яких вбудований перегляд не відтворює (розгортання 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, кожна з яких формує diff регресій/покращень для кожного файлу.

У 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 відповідає, що зробила ваша остання зміна; перед pull request питання в тому, де ви відносно main, і відповідь — на сервері збірки. baseline.report називає звіт, який публікує збірка гілки main, і кожне завантаження звіряється з ним: картка в рядку стану несе однорядкову дельту — 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 відносно свого checkout — 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 — інструкції та гілки порівняно зі звітом модульних тестів, і файл, що змінився.

Артефакт — це 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. Для агентів ШІ: покриття на екрані

Агент, який пише тести, може запустити їх і прочитати відсоток. Чого він сам не може — це запитати про те, що знає редактор: які рядки цієї функції жодного разу не виконалися, який бік якої гілки, які тести виконують рядок, чи покрито diff, який він щойно написав. Шість інструментів відповідають саме на це, словами, за якими агент може діяти, із завантаженого запуску — ті самі виключення, те саме переспрямування шляхів, ті самі числа, що й на екрані. Тож агент, якому сказано покрити прогалини функції, і рецензент, який дивиться на поле редактора, говорять про ті самі рядки.

ІнструментНа що відповідає
coverage_summaryПідсумки запуску за кожною метрикою і файли, найдальші від повного покриття. Перше, про що варто запитати.
coverage_gapsЩо жодного разу не виконалося у файлі, функції чи діапазоні рядків: непокриті рядки, не взяті вітки гілок, умови MC/DC без своєї пари, мутанти, що вижили.
tests_for_lineЯкі тести виконали рядок, якщо звіт це каже — потестовий запуск.
patch_coverageПокриття diff — робочого дерева відносно посилання або переданого патча — і його рядки, які жодного разу не виконалися.
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, бо у Visual Studio Alt з літерою відкриває меню. Змініть їх у Tools → Options → Keyboard, де вони перелічені як Coverage Studio: …. Немає в цій редакції: панель Test Coverage — це API 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 / FunctionsQuick Pick із сортуванням від найгіршого.
Copy Uncovered LinesПідсумок у Markdown для кожного непокритого діапазону.
Compare Two History Runs / with Last RunПофайлова різниця регресії — два запуски, збережені історією, або запуск на екрані відносно того, який він замінив.
Compare with CI BaselineЗавантажений запуск відносно звіту, названого в baseline.report — звіту гілки main із CI, URL чи завантаженого артефакту — файл за файлом.
Show Indirect Coverage Changes…Рядки, покриття яких змінилося, хоча ніхто їх не редагував, відносно базової лінії CI або попереднього запуску, за файлами.
Check Coverage ThresholdsОцінити перевірки відповідності.
Export Fucini JSONЕкспортувати поточний запуск як Fucini JSON.
Export Coverage Report...Виберіть формат — CSV, Markdown, LCOV, XML Cobertura, 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. Довідник налаштувань

Повна, категоризована таблиця налаштувань — кожен параметр із типовим значенням — розміщена на сторінці Features & Settings. Усі ключі мають префікс 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 — для запитання, що надходить після закриття IDE. Три, що трапляються: нічого не позначено, хоча панель каже, що файли завантажено — режим поля 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_020JSON llvm-cov недійсний, без data[] або не містив файлів.
FUCINI_PARSE_030Кореневий елемент Cobertura <coverage> відсутній або XML недійсний.
FUCINI_PARSE_040Кореневий елемент JaCoCo <report> відсутній або немає вихідних файлів.
FUCINI_PARSE_050JSON Istanbul/SimpleCov недійсний або не містив файлів.
FUCINI_PARSE_060JSON SimpleCov недійсний або без масиву files верхнього рівня.
FUCINI_PARSE_070Профіль Go без заголовка mode: або без блоків покриття.
FUCINI_PARSE_080У Clover відсутній кореневий <coverage> чи <project>, або немає файлів.
FUCINI_PARSE_090У OpenCover відсутній кореневий <CoverageSession> або немає файлів.
FUCINI_PARSE_100JSON coverage.py недійсний або без об'єкта files верхнього рівня.
FUCINI_PARSE_110JSON gcov/gcovr недійсний або без масиву files верхнього рівня.
FUCINI_PARSE_120GNATcoverage XML без елемента <source> або index.xml, чиї xi:include так і не було розгорнуто — завантажте натомість файли *.xml для кожного джерела.
FUCINI_PARSE_130Відсутній кореневий елемент <BullseyeCoverage> або в ньому немає елементів <src>.
FUCINI_PARSE_140Відсутній кореневий елемент <CoverageDSPriv>, немає таблиці <SourceFileNames> для зіставлення рядків або немає даних про рядки.
FUCINI_PARSE_150Некоректний JSON покриття Xcode або відсутній масив targets верхнього рівня.
FUCINI_PARSE_160Відсутній кореневий елемент <coverage> SonarQube або в ньому немає елементів <file>.
FUCINI_PARSE_170Некоректний JSON Coveralls або відсутній масив source_files верхнього рівня.
FUCINI_LOADЗавантаження скасовано з його сповіщення про поступ; попередній прогін, якщо він був, лишається завантаженим.
FUCINI_REMOTE_001URL-адресу coverageFile.paths не вдалося отримати, з причиною; натомість завантажується остання завантажена копія. Звичайні рядки [FUCINI_REMOTE] записують кожне завантаження та кожну перевірку без змін (304).
FUCINI_REMOTE_002URL-адреса з coverageFile.paths не дала повної відповіді за 30 секунд — найчастіше це проксі або VPN, що приймає з’єднання й далі мовчить; натомість завантажується остання завантажена копія.
FUCINI_REMOTE_003URL-адреса з coverageFile.paths відповіла HTML-сторінкою замість файлу трасування — найімовірніше, сторінкою входу. Сторінка не кешується, натомість завантажується остання завантажена копія; перевірте токен у remote.headers.
FUCINI_REMAP_002Для шляхів, які завантаження лишило незіставленими, запропоновано правило pathRemap, зі скількома з них воно пояснює — або жодного не вдалося вивести, або виведене правило вже є в налаштуванні й їх не розв'язало.
FUCINI_REMAP_003Запропоноване правило дописано до fuciniCoverage.pathRemap командою Apply Suggested Remap, і покриття перезавантажується.
FUCINI_GITDIFF_001Розширення Git недоступне; покриття diff пропускається й показується весь прогін.
FUCINI_GITDIFF_002gitDiff.baseRef починається з -, з чого жодне посилання git починатися не може (git прочитав би його як опцію); покриття diff пропускається й показується весь прогін.
FUCINI_IGNOREСкільки файлів fuciniCoverage.ignore вилучив із прогону, і які саме.
FUCINI_UNMEASURED_001Файли того ж виду, що й прогін, яких не завантажив жоден тест, по одному на рядок.
FUCINI_UNMEASURED_002Понад 5 000 файлів робочої області збіглися з одним із розширень прогону; для списку невиміряних розглянуто лише перші 5 000.
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; на платну ліцензію це не впливає в жодному разі. Що саме надсилається, див. у політиці конфіденційності.

Дві речі варто знати, бо з ними ви можете щось зробити. Перша — ваш ID журналу використання: на пробному періоді та на Community розширення показує його в Show License / Activation і внизу розділу What Community Includes, де вибір цього рядка копіює ID і відкриває політику. Журнал знає вашу машину за гешем і більше ні за чим, тож цей ID — єдиний спосіб запитати, що журнал зберігає про вас, вимагати видалення чи заперечити проти нього: наведіть його — і ми знайдемо ваш рядок; без нього не знайдемо. Друга — запис про встановлення: один рядок, який створюється, коли встановлення звітує вперше, і зберігається, а не видаляється через 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: як рахуються ліміти і рядок, що видає вам ID журналу використання.

19. Оцінка та активація

Fucini Coverage Studio розповсюджується як оцінювальна передрелізна версія. Під час першого запуску вас просять погодитися її оцінювати, і починається пробний період — усі можливості доступні протягом 14-денного пробного періоду, який відлічується від першого використання на цій інсталяції. Немає фіксованої дати, після якої щось припиняє працювати.

Починаючи з версії 2.2026.2 пробний період нової інсталяції починається, щойно розширення один раз зв’яжеться із сервером ліцензій; до того часу воно працює на рівні Community і повідомляє про це. У контейнері розробки або Codespace пробний період не починається — повний набір там відкриває код підписки, ключ або 7-денна перепустка.

Коли пробний період завершується, нічого не блокується: розширення переходить на безкоштовний рівень 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 (область user/global). Ключ прив'язаний до вашої машини та користувача ОС, може мати термін дії і може вмикати чи обмежувати окремі функції та обмежувати кількість завантажень покриття на день. Якщо з'являється повідомлення «invalid for this machine», запросіть новий ключ із цього встановлення — ключ, виданий для іншої машини, тут ніколи не пройде перевірку.

У Visual Studio. У цій редакції немає безкоштовного рівня: без підписки нічого не читається. З підпискою план вирішує там те саме, що й у VS Code, — функція, якої план не включає, недоступна, і її команда каже про це замість того, щоб виконатися. Найстаріша версія, яку ще підтримує сервер ліцензій, діє й там: старіша збірка повідомляє про це раз на день, із датою, коли вона перестане працювати, і працює до того часу. Робота без мережі ніколи не зупиняє збірку.

Безкоштовний рівень Community: тижнева квота

Community ніколи не перестає показувати покриття. Позначки на полях, оглядова лінійка, підказки при наведенні, CodeLens, подання Coverage, режим спостереження, покриття diff та історія не рахуються взагалі, а завантаження tracefile командою обмежене лише 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).