命令行上的 Coverage Studio 2.2026.4 —— 两个引擎测量的文件只计一次,无论你从哪里启动命令
2026-10-04
修复
- 你启动命令所在的目录不决定一份报告的含义。 2.2026.3 把报告中的相对路径以该报告写入的目录为根——但只对在别处启动的命令生效。从被测量的树的根目录运行时,也就是覆盖率命令通常运行的地方,相对路径仍由那个目录来回答,于是 llvm-cov 已用完整路径指明的文件被第二次计入:一棵 5,258 行的树读成了 5,836 行。现在只有
--cwd 和报告自身的位置能决定。同样的修复也在两个编辑器版本里,那里的目录是 VS Code 或 Visual Studio 被启动的目录。 export --format json 把运行结果覆盖到了你的设置上。 它的文件名是 fucini-coverage.json——正是读取设置的那个名字——所以在按常规配置的目录里,这次导出毁掉了它刚刚据以判断的阈值。运行结果现在写入 coverage-run.json,并且 export 和 badge 会拒绝指向设置文件的 --out。 --cwd 无论怎么写都当作目录。 相对写法——--cwd .、--cwd ../tree——会被原样保留,并按错误的路径规则解读:在 Windows 上它会回答一个半 POSIX 半 Windows 的设置文件无法读取,而且一份报告也找不到。结尾的分隔符也不再属于目录的一部分。 - 没有人声明过的选项不是报告。
summary -o out.json 把 -o 当成报告,并说没有这个文件。只有 -h 和 -v 是短选项;-- 仍然可以传入名字以连字符开头的文件,而写在命令之前的选项会在错误信息中被指名,而不是以整篇帮助作答。 check --json 与它自己的退出码一致。 在没有设置任何阈值时,它在退出码 0 旁边写下 "passed": false,于是读取 JSON 而不是退出码的流水线,会让一次命令判为通过的运行失败。passed 是退出码的一词化表达;说明根本没有门禁的是 configured。空的 --lines "" 会被拒绝,而不是悄悄关闭那道门禁。 - 比较把基线放到它放置本次运行的同一位置。
pathRemap 和报告声明的根只应用于本次运行,没有应用于基线,因此在构建服务器上写出的基线与任何文件都配不上对,比较便在总数明明已经变化的情况下报告“没有任何变化”。
命令行上的 Coverage Studio 2.2026.3 —— 两个引擎测量的文件重新成为一个文件
2026-10-04
修复
- 报告中的相对路径以该报告写入的位置为根。 llvm-cov 写出文件的完整路径;gcovr 写出的是相对于其报告所在构建目录的路径。同时给出一棵树的两份报告时,
summary 会把两者共有的每个文件列出两次——各带一个引擎的数字——并把两者都计入总数,因为相对路径没有可供解析的根,只能相对于 shell 当时所在的目录来解析。一棵 5,258 行的树被报告为 5,836 行,多出的部分属于某个并不包含任何这些文件的路径下的文件。现在每份报告都以自己的目录及其上级目录为根,一直到命令运行的目录,这正是两个编辑器版本早已采用的做法——于是两者作为同一组文件相遇,无需为每个构建目录写一条 pathRemap 规则。 - 以字节顺序标记开头的设置文件此前也会被拒绝。 Windows 上的编辑器可能会把它写在文本前面;它不再被当作 JSON 的一部分。
- 输出管道给提前停止读取的一方时会安静结束。 把
summary 管道给 head,或给 PowerShell 的 Select-Object -First,会以未处理的 EPIPE 和堆栈跟踪告终。读取方关闭管道是它自己的选择,而不是命令的失败:命令现在以它已经达到的退出码结束。
命令行上的 Coverage Studio 2.2026.1 —— 含有模式的设置文件可以读取了
2026-10-04
修复
- 含有模式的设置文件曾被拒绝。当
fuciniCoverage.coverageFile.paths 的一个路径中有 **/*.lcov.info,而下一个路径中有 **/coverage.json 时,每条命令都以 is not JSON 结束:两者之间的内容被当成了注释。现在文件的读取方式与编辑器一致,包括值后面的注释和右括号前的逗号。
命令行上的 Coverage Studio 2.2026.0 —— fucini-coverage,首个发布
2026-10-04
新增
- 命令行上的读取器,免费。
npm install -g fucini-coverage —— 与两个版本相同的读取器,用于没有编辑器的地方。一个包,一种行为,在 Windows、Linux、WSL 和 macOS 上,Node 20 或更新版本。
check,门禁。行、分支、函数、MC/DC、条件、区域、变异或加权评分低于阈值时退出码为 1,阈值来自设置或命令行;--new-code 80 --base-ref origin/main 评判一个分支改动的行,依据由工具自己运行的 git diff;--require-reasons 让没有理由的排除标记失败。
summary、export、report、badge、compare。总计和每个文件;把运行写成按文件或按函数的 CSV、Markdown、LCOV、Cobertura、SARIF、排除项列表、徽章或 Fucini 的 JSON;多页的 HTML 报告;按设置中的色阶着色的徽章;本次运行与基线的对比,回归在前,并有用于拉取请求检查的 --fail-on-regression。
mcp,供 AI 智能体使用。两个版本的六个工具,基于本次运行在 127.0.0.1 上提供,由令牌保护,并打印出客户端 mcp.json 所需的条目。
- Visual Studio 版的设置文件。代码旁边的
fucini-coverage.json,使用 VS Code 设置的 fuciniCoverage.* 键;其次是 .vscode/settings.json。报告可按文件、文件夹或模式指定,.gz 会被解包,每个命令都自带说明:fucini-coverage help <command>。
Coverage Studio for VS Code 2.2026.2 —— 试用自许可证服务器应答时开始
2026-10-04
变更
- 新安装的试用自许可证服务器的首次应答开始。 在扩展成功连接 fucini.software 一次之前,它以 Community 层级运行并说明原因。已在试用期内或已有许可证的安装不会察觉任何变化。
- 开发容器或 Codespace 中没有试用。 扩展在那里以 Community 层级启动;订阅代码、密钥或 7 天通行证可解锁全部功能。
- 用量台账通过第二个哈希识别机器,即操作系统自身标识符的哈希。发送的只有哈希;参见隐私政策。
Coverage Studio for Visual Studio 2.2026.1 —— 小修复
2026-10-04
修复
- 小修复。 这是一个维护版本:内部的一些小修正,不改变您看到的内容,也不改变使用方式。
Coverage Studio for VS Code 2.2026.1 —— 小修复
2026-10-04
修复
- 小修复。 这是一个维护版本:内部的一些小修正,不改变您看到的内容,也不改变使用方式。
Coverage Studio for Visual Studio 2.2026.0 —— 屏幕上的覆盖率,供 AI 智能体使用
2026-10-04
新增
- 屏幕上的覆盖率,供 AI 智能体使用。编写测试的智能体可以运行测试并读到一个百分比;却无法询问 Visual Studio 所知道的内容。六个工具用智能体可以据以行动的语言来回答:
coverage_summary、coverage_gaps、tests_for_line、patch_coverage、coverage_delta 和 test_run_command。支持 MCP 的智能体通过 Visual Studio 在 fuciniCoverage.mcp.enabled 开启时运行的服务器来访问它们 —— 默认关闭,仅限 127.0.0.1,由你自己的令牌保护,并且不对网页开放。Copy MCP Server Configuration 会把客户端的配置条目放到剪贴板上。 - 与屏幕上相同的数字。这些工具根据已加载的运行来回答 —— 同样的排除,同样的重映射 —— 因此,被要求覆盖某个函数缺口的智能体,和看着边距的审阅者,谈论的是同一批行。
变更
- 密钥的方案在 Visual Studio 中决定的内容,与在 VS Code 中决定的相同。不包含某项功能的方案 —— MC/DC、HTML 报告、运行过某一行的测试的名称 —— 以前在 VS Code 中会去掉该功能,在这里却不会。现在两个版本读取同一张表:方案不包含的功能不予提供,其命令会说明这一点。
- 许可证服务器要求的最低版本在这里同样有效。从 2.2026.0 起,两个版本使用相同的版本号,因此低于该最低版本的构建会要求更新,与 VS Code 版本的做法相同。
Coverage Studio for VS Code 2.2026.0 —— 屏幕上的覆盖率,供 AI 智能体使用
2026-10-04
新增
- 屏幕上的覆盖率,供 AI 智能体使用。编写测试的智能体可以运行测试并读到一个百分比;却无法询问编辑器所知道的内容。六个工具用智能体可以据以行动的语言来回答:
coverage_summary、coverage_gaps、tests_for_line、patch_coverage、coverage_delta 和 test_run_command。VS Code 自己的智能体以语言模型工具的形式拥有它们,无需任何设置。其他所有支持 MCP 的智能体则通过扩展在 fuciniCoverage.mcp.enabled 开启时运行的服务器来访问它们 —— 默认关闭,仅限 127.0.0.1,由你自己的令牌保护,并且不对网页开放。Copy MCP Server Configuration 会把客户端的配置条目放到剪贴板上。 - 与屏幕上相同的数字。这些工具根据已加载的运行来回答 —— 同样的排除,同样的重映射 —— 因此,被要求覆盖某个函数缺口的智能体,和看着边距的审阅者,谈论的是同一批行。
Visual Studio 版 Coverage Studio 1.2026.22 —— 两个引擎测量的文件就是一个文件
2026-10-04
修复
- 两个引擎测量的文件就是一个文件。 llvm-cov 写出文件的完整路径;gcovr 写出的是相对于其报告所在构建目录的路径。相对路径会以报告自身的目录及其上级目录为根——但在那之前,解析器会先问这个路径是否就以当前的写法存在,而回答这个问题的是 Visual Studio 自身被启动的目录。只要那个目录里有这个文件,路径就仍然是相对的:文件有了两个名字,在 Coverage 窗口里列出两次,也在总数里计了两次。一棵 5,258 行的树读成了 5,836 行。不指明自身位置的路径不再被问及;它以报告写入的位置为根,行上也会这样显示。
VS Code 版 Coverage Studio 1.2026.23 —— 两个引擎测量的文件就是一个文件,你选择的边栏模式也不再写进设置
2026-10-04
修复
- 两个引擎测量的文件就是一个文件。 llvm-cov 写出文件的完整路径;gcovr 写出的是相对于其报告所在构建目录的路径。相对路径会以报告自身的目录及其上级目录为根——但在那之前,解析器会先问这个路径是否就以当前的写法存在,而回答这个问题的是扩展宿主被启动的目录,在
code . 之后就是你的项目根目录。于是路径仍然是相对的:文件有了两个名字,在 Coverage 视图里列出两次,也在总数里计了两次。一棵 5,258 行的树读成了 5,836 行。不指明自身位置的路径不再被问及;它以报告写入的位置为根,行上也会这样显示。 - 你选择的边栏模式在本次会话中有效,你的设置保持你写下的样子。 从状态栏、选择器或 Toggle Coverage Painting 选择模式,会把它写进
settings.json——在许多项目里这是纳入版本控制的文件,却被一个本就打算每分钟按两次的按钮改写。现在这个选择只在会话期间存在,而你写进设置里的模式在窗口打开时仍然优先。
Coverage Studio for Visual Studio 1.2026.21 —— 测试会察觉吗?在光标处运行变异测试
2026-10-03
新增
- Run Mutation Tests Here. 覆盖率说明某一行运行过;变异工具则说明如果这一行写错了,测试能否察觉。光标所在的函数 —— 或选中的行,或整个文件 —— 就是交给该文件夹的运行器去变异的内容,其报告会加载到屏幕上的覆盖率旁边:C# 用 Stryker.NET,JavaScript 和 TypeScript 用 StrykerJS,Java 用 PIT 配合 Maven。整个项目的变异运行要一个小时;一个函数只要一分钟。
Coverage Studio for VS Code 1.2026.22 —— 测试会察觉吗?在光标处运行变异测试
2026-10-03
新增
- Run Mutation Tests Here. 覆盖率说明某一行运行过;变异工具则说明如果这一行写错了,测试能否察觉。光标所在的函数 —— 或选中的行,或整个文件 —— 就是交给该文件夹的运行器去变异的内容,其报告会加载到屏幕上的覆盖率旁边:C# 用 Stryker.NET,JavaScript 和 TypeScript 用 StrykerJS,Java 用 PIT 配合 Maven。整个项目的变异运行要一个小时;一个函数只要一分钟。
Coverage Studio for Visual Studio 1.2026.20 —— 带覆盖率运行应用本身
2026-10-03
新增
- Run App with Coverage… 测量的是人实际走到的地方,而不仅是测试所做的事:文件夹中的 .NET 应用在 Microsoft 的
dotnet-coverage 之下、在它自己的控制台中启动,一直运行到被关闭为止。随后,操作中走过的部分会像任何一次运行那样被加载,在覆盖率会话中则累加到测试运行过的内容上。需要 dotnet tool install --global dotnet-coverage。
Coverage Studio for VS Code 1.2026.21 —— 带覆盖率运行应用本身
2026-10-03
新增
- Run App with Coverage… 测量的是人实际走到的地方,而不仅是测试所做的事:文件夹中的 .NET 应用在 Microsoft 的
dotnet-coverage 之下、在它自己的控制台中启动,一直运行到被关闭为止。随后,操作中走过的部分会像任何一次运行那样被加载,在覆盖率会话中则累加到测试运行过的内容上。需要 dotnet tool install --global dotnet-coverage。
Coverage Studio for Visual Studio 1.2026.19 —— 来自 GitHub 和 GitLab 的 zip 工件
2026-10-03
新增
- 来自 zip 工件的 CI 基线。GitHub 和 GitLab 把工件发布为归档。
baseline.report 指定了这样的归档时 —— 一个 URL,或磁盘上的一个 zip —— 它会被打开,并保留其中的报告:即 # 之后指定的成员(ci/artifact.zip#coverage/lcov.info),否则是归档中唯一的文件,再否则是其中唯一看起来像报告的文件。
Coverage Studio for VS Code 1.2026.20 —— 来自 GitHub 和 GitLab 的 zip 工件
2026-10-03
新增
- 来自 GitHub 和 GitLab 的 zip 工件。CI 发布工件,而工件是一个归档。现在获取到的 zip 会被打开,并保留其中的报告 —— 即 URL 的
# 之后指定的成员(…/zip#coverage/lcov.info),否则是归档中唯一的文件,再否则是其中唯一看起来像报告的文件。适用于 coverageFile.paths 中的 URL、baseline.report,以及磁盘上以 zip 形式存在的基线。
修复
- Cobertura 基线的文件在报告自己的
<source> 下找不到。比较结果显示 0 file(s) moved,旁边的合计却已变动。现在使用报告所指定的根目录,与对已加载报告的处理相同。
Coverage Studio for Visual Studio 1.2026.18 —— 按作者和按日期划分的新代码
2026-10-03
新增
- 按作者和按日期划分的新代码。新代码原本是指相对于某个 git 引用所更改的行。两个设置提出了引用无法回答的问题:
fuciniCoverage.gitDiff.author —— 某一个人写的行 —— 和 fuciniCoverage.gitDiff.since —— 自某一天以来写的行。两者都从 git blame 读取,并适用于差异覆盖率和新代码门禁。
Coverage Studio for VS Code 1.2026.19 —— 按作者和按日期划分的新代码
2026-10-03
新增
- 按作者和按日期划分的新代码。新代码原本是指相对于某个 git 引用所更改的行。两个设置提出了引用无法回答的问题:
fuciniCoverage.gitDiff.author —— 某一个人写的行 —— 和 fuciniCoverage.gitDiff.since —— 自某一天以来写的行。两者都从 git blame 读取,并适用于差异覆盖率和新代码门禁。
Coverage Studio for Visual Studio 1.2026.17 —— 在 Go 和 Rust 中带覆盖率运行单个测试
2026-10-02
新增
- Run This Test with Coverage 可读取 Go 和 Rust。在 Go 文件中,光标所在的
func TestXxx 会在它自己的包中按确切名称单独运行 —— go test ./pkg/calc -run "^TestTotal$"。在 Rust 文件中,#[test] 函数按其在 crate 中的路径以 --exact 运行;位于 mod 中时,运行该模块的测试;tests/ 下的集成测试则在它自己的二进制文件中运行。
Coverage Studio for VS Code 1.2026.18 —— 在 Go 和 Rust 中带覆盖率运行单个测试
2026-10-02
新增
- Run This Test with Coverage 可读取 Go 和 Rust。在 Go 文件中,光标所在的
func TestXxx 会在它自己的包中按确切名称单独运行 —— go test ./pkg/calc -run "^TestTotal$"。在 Rust 文件中,#[test] 函数按其在 crate 中的路径以 --exact 运行;位于 mod 中时,运行该模块的测试;tests/ 下的集成测试则在它自己的二进制文件中运行。
Coverage Studio for Visual Studio 1.2026.16 —— GCC 14 条件覆盖率,逐行显示
2026-10-02
新增
- GCC 14 的条件覆盖率,逐行显示。
-fcondition-coverage 以前被读取为每个文件两个计数;现在每个条件都标记在其所在行上,并在悬停提示中指明 —— 条件 1 从未为真,条件 0 两种结果都从未出现 —— 数据来自 gcov 的 JSON 及其文本清单。threshold.conditions 为它设置门禁,Copy Coverage Summary 有 Conditions 列,badge.metric 接受 conditions,搜索接受 conditions < 80。
修复
- 函数的分支数值把其条件的结果也算了进去。工具给出的是 6 个中的 4 个,显示的却是
branches 8/12。现在这里不再计入条件,与文件和运行的数值一致。
Coverage Studio for VS Code 1.2026.17 —— GCC 14 条件覆盖率,逐行显示
2026-10-02
新增
- GCC 14 的条件覆盖率,逐行显示。
-fcondition-coverage 以前被读取为每个文件两个计数;现在每个条件都标记在其所在行上,并在悬停提示中指明 —— 条件 1 从未为真,条件 0 两种结果都从未出现 —— 数据来自 gcov 的 JSON 及其文本清单。threshold.conditions 为它设置门禁,Copy Coverage Summary 有 Conditions 列,badge.metric 接受 conditions,搜索接受 conditions < 80。
修复
- 函数的分支数值把其条件的结果也算了进去。工具给出的是 6 个中的 4 个,显示的却是
branches 8/12。现在这里不再计入条件,与文件和运行的数值一致。
Coverage Studio for Visual Studio 1.2026.15 —— Coverage 视图跟随编辑器
2026-10-02
新增
- Coverage 视图跟随编辑器。你正在查看的文件会在树中高亮显示,其上级文件夹被展开,它所在的行被滚动到可见位置。
fuciniCoverage.coverageView.followActiveEditor 可将其关闭。
Coverage Studio for VS Code 1.2026.16 —— Coverage 视图跟随编辑器
2026-10-02
新增
- Coverage 视图跟随编辑器。你正在查看的文件会在树中高亮显示,其上级文件夹被展开,它所在的行被滚动到可见位置。
fuciniCoverage.coverageView.followActiveEditor 可将其关闭。
Coverage Studio for Visual Studio 1.2026.14 —— 仅针对分支的排除标记,以及 .NET 报告中的分支覆盖率
2026-10-02
新增
- 仅针对分支的排除标记和 gcovr 排除标记。
LCOV_EXCL_BR_LINE 以及 LCOV_EXCL_BR_START … LCOV_EXCL_BR_STOP 把所在行上的分支从计数中去掉,而行本身保留;LCOV_EXCL_EXCEPTION_BR_LINE 只去掉异常所到达的分支。每个标记也都能以 gcovr 的前缀读取:GCOVR_EXCL_LINE、GCOVR_EXCL_START、GCOV_EXCL_BR_LINE 等等。
修复
- .NET 报告不显示分支覆盖率。Coverlet 和
dotnet-coverage 把 Cobertura 行的 branch 属性写成 True,而以前只读取小写的 true —— 因此这类报告中的所有判定都被丢弃了。现在两种写法都能读取。数字会变动:.NET 项目的分支覆盖率会出现在原先没有的地方,其得分也随之变化。 - 由多个目录树合并而成的 Cobertura 报告只找到了第一个目录树的文件。这样的报告为每个目录树指定一个
<source>;现在会按报告中的顺序逐个尝试。
Coverage Studio for VS Code 1.2026.15 —— 仅针对分支的排除标记,以及 .NET 报告中的分支覆盖率
2026-10-02
新增
- 仅针对分支的排除标记和 gcovr 排除标记。
LCOV_EXCL_BR_LINE 以及 LCOV_EXCL_BR_START … LCOV_EXCL_BR_STOP 把所在行上的分支从计数中去掉,而行本身保留;LCOV_EXCL_EXCEPTION_BR_LINE 只去掉异常所到达的分支。每个标记也都能以 gcovr 的前缀读取:GCOVR_EXCL_LINE、GCOVR_EXCL_START、GCOV_EXCL_BR_LINE 等等。
修复
- .NET 报告不显示分支覆盖率。Coverlet 和
dotnet-coverage 把 Cobertura 行的 branch 属性写成 True,而以前只读取小写的 true —— 因此这类报告中的所有判定都被丢弃了。现在两种写法都能读取。数字会变动:.NET 项目的分支覆盖率会出现在原先没有的地方,其得分也随之变化。 - 由多个目录树合并而成的 Cobertura 报告只找到了第一个目录树的文件。这样的报告为每个目录树指定一个
<source>;现在会按报告中的顺序逐个尝试。
Coverage Studio for Visual Studio 1.2026.13 —— 仍能运行每一行的最少测试
2026-10-01
新增
- Show Minimal Test Set… 找出仍能运行测试套件所运行的每一行的最少测试,并在其下列出没有贡献任何独有行的测试。适用于提交前的快速运行,也适用于精简测试套件的人 —— 同时提醒:按行来看冗余,并不等于按测试所检查的内容来看也冗余。
Coverage Studio for VS Code 1.2026.14 —— 仍能运行每一行的最少测试
2026-10-01
新增
- Show Minimal Test Set… 找出仍能运行测试套件所运行的每一行的最少测试,并在其下列出没有贡献任何独有行的测试。适用于提交前的快速运行,也适用于精简测试套件的人 —— 同时提醒:按行来看冗余,并不等于按测试所检查的内容来看也冗余。
Coverage Studio for Visual Studio 1.2026.12 —— 说明原因的排除
2026-10-01
新增
- 带理由的排除。在代码中就地从计数里排除的代码可以说明原因 ——
// LCOV_EXCL_LINE: defensive, unreachable by construction、[ExcludeFromCodeCoverage(Justification = "…")] —— 这些原因会被报告出来:Export Coverage Report… 以 Markdown 和 CSV 列出各项排除及其理由。启用 fuciniCoverage.exclusions.requireReason 后,未给出原因的排除会在其所在行产生一条警告,并使 Check Coverage Thresholds 未通过。
Coverage Studio for VS Code 1.2026.13 —— 说明原因的排除
2026-10-01
新增
- 带理由的排除。在代码中就地从计数里排除的代码可以说明原因 ——
// LCOV_EXCL_LINE: defensive, unreachable by construction、[ExcludeFromCodeCoverage(Justification = "…")] —— 这些原因会被报告出来:Export Coverage Report… 以 Markdown 和 CSV 列出各项排除及其理由。启用 fuciniCoverage.exclusions.requireReason 后,未给出原因的排除会在其所在行产生一条警告,并使 Check Coverage Thresholds 未通过。
Coverage Studio for Visual Studio 1.2026.11 —— 针对新代码的门禁,以及未经编辑却发生变动的覆盖率
2026-10-01
新增
- 针对新代码的门禁,与针对整次运行的门禁并列。
fuciniCoverage.threshold.newCode 是相对于 gitDiff.baseRef 所更改行的最低行覆盖率,以百分比表示。Check Coverage Thresholds 会用单独的一句话判定它未通过 —— New code 72.00% < 80% (18 of 25 line(s) changed against origin/main ran) —— 而整次运行仍留在屏幕上。 - Show Indirect Coverage Changes… 列出无人编辑而覆盖率却发生变动的行 —— 因为某个测试没有了,或因为上游某个分支现在提前返回而不再运行的代码。
baseline.report 指定了 CI 基线时与它比较,否则与前一次运行比较。
Coverage Studio for VS Code 1.2026.12 —— 针对新代码的门禁,以及未经编辑却发生变动的覆盖率
2026-10-01
新增
- 针对新代码的门禁,与针对整次运行的门禁并列。
fuciniCoverage.threshold.newCode 是相对于 gitDiff.baseRef 所更改行的最低行覆盖率,以百分比表示。Check Coverage Thresholds 会用单独的一句话判定它未通过 —— New code 72.00% < 80% (18 of 25 line(s) changed against origin/main ran) —— 而整次运行仍留在屏幕上。 - Show Indirect Coverage Changes… 列出无人编辑而覆盖率却发生变动的行 —— 因为某个测试没有了,或因为上游某个分支现在提前返回而不再运行的代码。
baseline.report 指定了 CI 基线时与它比较,否则与前一次运行比较。
Coverage Studio for Visual Studio 1.2026.10 —— 只运行你的更改涉及的测试
2026-10-01
新增
- Run Tests Affected by My Changes… 列出运行过工作树相对于
fuciniCoverage.testImpact.baseRef(默认为 HEAD)所更改行的测试,运行更改最多的排在最前。选中某个测试即可打开它;如果报告来自按测试的运行(testRun.perTest),第一项会只运行这些测试。
修复
testRun.skipWhenTestsFail 在运行结束后依然有效。失败的运行写出的报告以前留在磁盘上,片刻之后就被监视器加载。现在它们会被删除。- TRX 记录器为覆盖率报告生成的副本绝不会被当作跟踪文件。
Coverage Studio for VS Code 1.2026.11 —— 只运行你的更改涉及的测试
2026-10-01
新增
- Run Tests Affected by My Changes… 列出运行过工作树相对于
fuciniCoverage.testImpact.baseRef(默认为 HEAD)所更改行的测试,运行更改最多的排在最前。选中某个测试即可打开它;如果报告来自按测试的运行(testRun.perTest),第一项会只运行这些测试。
修复
testRun.skipWhenTestsFail 在运行结束后依然有效。失败的运行写出的报告以前留在磁盘上,片刻之后就被监视器加载。现在它们会被删除。- TRX 记录器为覆盖率报告生成的副本绝不会被当作跟踪文件。
Coverage Studio for Visual Studio 1.2026.9 —— 标记上的通过与失败,以及 Visual Studio 自己的代码覆盖率文件
2026-09-30
新增
- 标记上的通过与失败。失败的测试运行过的行,其行首会出现一条红色竖条,悬停提示会列出失败的测试;Show Tests That Ran This Line 会说明其中哪些测试失败了。它需要一份记录了哪些测试运行过某一行的报告,以及运行器的结果文件 —— TRX 或 JUnit XML —— 该文件位于报告所在的文件夹中,或在
fuciniCoverage.testResults.paths 中指定。Run Tests with Coverage 现在会让 dotnet test 生成一份。 - 加载 Visual Studio 自己的代码覆盖率。Visual Studio 的 Analyze Code Coverage 写出的
.coverage 文件会用 dotnet-coverage 转换并自动加载:Coverage Studio 建立在内置收集器之上,而不是与它竞争。
Coverage Studio for VS Code 1.2026.10 —— 标记上的通过与失败
2026-09-30
新增
- 标记上的通过与失败。失败的测试运行过的行,其行首会出现一条红色竖条,悬停提示会列出失败的测试;Show Tests That Ran This Line 会说明其中哪些测试失败了。它需要一份记录了哪些测试运行过某一行的报告,以及运行器的结果文件 —— TRX 或 JUnit XML —— 该文件位于报告所在的文件夹中,或在
fuciniCoverage.testResults.paths 中指定。Run Tests with Coverage 现在会让 dotnet test 生成一份。
Coverage Studio for Visual Studio 1.2026.8 —— 重新加载后保留你的搜索、会话和上一次运行
2026-09-30
修复
- 覆盖率重新加载时,搜索框保留其查询和焦点。以前每次重新加载都会清空它,而且常常是在查询还在输入的时候。像
< 80% 这样的查询也会保留它匹配到的风险热点。 - 覆盖率会话不再把同一次运行计算两次。以前每次重新加载未更改的报告都会把它们再加一遍,所有命中次数都翻了倍。现在会话对每组报告只保留一次。
- CI 基线不再拖住加载。先绘制加载结果,比较随后进行。基线只准备一次,在其报告和设置保持不变期间一直保留;URL 无法访问时,使用之前获取的副本。
- “自上次运行以来”在重新加载未更改的报告后依然保留。以前,更改设置或刷新会使屏幕上的运行成为它自己的上一次运行,自前一次运行以来的所有变化随之消失。这样的重新读取现在也不再存入历史。
- 一次只进行一次加载。同时请求的两次重新加载曾并行运行,较慢的那次胜出。现在加载期间请求的重新加载会合并为该次加载之后的一次加载。
- 通过 HTTP 获取 CI 基线的方式与 VS Code 中相同。一个客户端,保留最后一份副本以备服务器无法访问时使用,
remote.headers 只发送到它所针对的地址 —— 绝不通过明文 HTTP 发送。 - 命令执行失败时会说明。以前命令或计时器中的失败被吞掉了;现在它会成为输出窗口中的一行。
- UI 线程上的工作更少。文件监视器在后台创建,错误列表条目每次加载只计算一次,日志成批写入,而不是逐行写入。
- 两个 Visual Studio 窗口不再损坏运行历史。其索引在两者共享的锁之下一步完成替换,丢失时则根据各次运行重新生成。
- Run Native Project with Coverage 构建项目自己的平台,并从编译器的 LLVM 中成对取用
llvm-cov 和 llvm-profdata。 - Coverage 窗口的警告、错误和通过颜色会跟随浅色主题,与跟随深色主题一样。
- 已打开且有未保存更改的设置文件不会被覆盖。设置页会提示先保存它。
变更
- 你选择的覆盖率文件以及测试运行写出的报告会替你记住,而不再写入
.vscode/settings.json。该文件常常会被提交,因此测试运行会在仓库中留下一处没人要求的更改。已在 coverageFile.paths 中的路径继续有效。
Coverage Studio for VS Code 1.2026.9 —— 重新加载后保留你的搜索、会话和上一次运行
2026-09-30
修复
- 覆盖率重新加载时,搜索框保留其查询和焦点。以前每次重新加载都会清空它,而且常常是在查询还在输入的时候。像
< 80% 这样的查询也会保留它匹配到的风险热点。 - 覆盖率会话不再把同一次运行计算两次。以前每次重新加载未更改的报告都会把它们再加一遍,所有命中次数都翻了倍。现在会话对每组报告只保留一次。
- CI 基线不再拖住加载。先绘制加载结果,比较随后进行。基线只准备一次,在其报告和设置保持不变期间一直保留;URL 无法访问时,使用之前获取的副本。
- 对报告文件更改的检查一次只运行一轮。在较慢的网络驱动器上,两轮检查看到了同一处更改,覆盖率被加载了两次。
- “自上次运行以来”在重新加载未更改的报告后依然保留。以前,更改设置或刷新会使屏幕上的运行成为它自己的上一次运行,自前一次运行以来的所有变化随之消失。这样的重新读取现在也不再存入历史。
变更
- 你选择的覆盖率文件以及测试运行写出的报告会替你记住,而不再写入
.vscode/settings.json。该文件常常会被提交,因此测试运行会在仓库中留下一处没人要求的更改。已在 coverageFile.paths 中的路径继续有效。
Coverage Studio for Visual Studio 1.2026.7 —— 精确运行所指定内容的测试运行
2026-09-30
修复
- 含有两个或更多测试项目的 .NET 解决方案不再只剩下一个项目的覆盖率。
dotnet test 为每个项目写出一份报告,而它们全都被移到同一个 coverage/coverage.cobertura.xml 上,因此只加载了最后一份。现在这样的文件夹会为每个测试项目运行一次 dotnet test,每份报告放入 coverage/<Project>/,运行某一个项目只会替换该项目的报告。 - 一次保存多个文件时,会运行每个已保存文件的测试。使用
testRun.onSave 时,以前只运行最后一个文件的测试;运行进行中发生的保存会被保留,待运行结束后一并运行。 - Run This Test with Coverage 和按测试的运行只精确运行所指定的内容。.NET 过滤器以前按子字符串匹配:
Total 也会运行 TotalTax。现在测试按其确切名称运行,类按其名称后加一个点运行,嵌套类中的测试也能找到(Outer+Inner)。 - 标题中含有
(、+ 或 $ 的 jest 或 vitest 测试可以运行了。标题被传给 -t,而它读取的是正则表达式,因此这样的测试什么也匹配不到,什么也没运行。 - Run This Test with Coverage 可读取 VB 和 F# 测试文件。
Public Sub 上方的 <Fact>,以及 let 或 member 上方的 [<Fact>],以前从未被识别。 - 取消测试运行会结束它启动的所有进程。以前只结束了 shell,
dotnet test 仍在它后面继续运行。关闭 Visual Studio 也会取消运行。 - 在保存后的运行期间输入内容,不再使标记错位。标记固定在该次运行所测量的文本上。
- 位于网络共享上的解决方案会在该位置运行测试。以前运行是在
C:\Windows 中启动的,因为命令 shell 不接受 \\server\share 路径作为其文件夹。
Coverage Studio for VS Code 1.2026.8 —— 精确运行所指定内容的测试运行
2026-09-30
修复
- 含有两个或更多测试项目的 .NET 解决方案不再只剩下一个项目的覆盖率。
dotnet test 为每个项目写出一份报告,而它们全都被移到同一个 coverage/coverage.cobertura.xml 上,因此只加载了最后一份。现在这样的文件夹会为每个测试项目运行一次 dotnet test,每份报告放入 coverage/<Project>/,运行某一个项目只会替换该项目的报告。 - 一次保存多个文件时,会运行每个已保存文件的测试。使用
testRun.onSave 时,以前只运行最后一个文件的测试;运行进行中发生的保存会被保留,待运行结束后一并运行。 - Run This Test with Coverage 和按测试的运行只精确运行所指定的内容。.NET 过滤器以前按子字符串匹配:
Total 也会运行 TotalTax。现在测试按其确切名称运行,类按其名称后加一个点运行,嵌套类中的测试也能找到(Outer+Inner)。 - 标题中含有
(、+ 或 $ 的 jest 或 vitest 测试可以运行了。标题被传给 -t,而它读取的是正则表达式,因此这样的测试什么也匹配不到,什么也没运行。 - 带引号的测试标题会完整地到达终端。引号内含有
\" 的命令在第一个引号处就断开了。 - Run This Test with Coverage 可读取 VB 和 F# 测试文件。
Public Sub 上方的 <Fact>,以及 let 或 member 上方的 [<Fact>],以前从未被识别。 - 未启动任何进程就结束的测试任务,不再让 Run Tests with Coverage 一直等下去。它会结束,并说明这次运行什么也没写出。
Coverage Studio for Visual Studio 1.2026.6 —— 哪些测试运行了某一行、每次保存后的覆盖率,以及 CI 基线
2026-09-29
新增
- 哪些测试运行了这一行。在报告记录了这一点的地方 —— 带
--show-contexts 的 coverage.py、OpenCover 的跟踪方法、按测试写出的 lcov 跟踪文件 —— 函数的 CodeLens 会显示有多少测试运行了它,Show Tests That Ran This Line 按运行次数从多到少列出这些测试,并打开你选中的那个。对于 dotnet test 运行,testRun.perTest 会逐个类运行测试,因此每份报告都能说明是哪个类写出的。
- 每次保存后的覆盖率。启用
testRun.onSave 后,保存源文件会带覆盖率运行覆盖它的测试,边栏随之更新。在 .NET 解决方案中,只运行引用了所保存文件所在项目的测试项目;连续多次保存只算一次运行。
- Run This Test with Coverage. 当光标位于测试方法、测试类或
describe 中,或位于测试文件中时,一条命令即可带覆盖率只运行这一部分 —— dotnet test --filter、jest/vitest -t 或 pytest 节点 ID —— 并加载其写出的结果。测试是从文本中读取的,因此无需语言服务即可用于 C#、VB、F#、JavaScript、TypeScript 和 Python。
- Exclude from Coverage,以及两个 .NET 过滤器。在覆盖率树的某一行上右键单击,或对打开的文件使用 Exclude This File from Coverage,会把该文件或文件夹加入
fuciniCoverage.ignore,它随即退出所有合计。ignore.namespaces 排除某个命名空间的文件(*.Migrations),ignore.attributes 排除带有某个特性的类、方法或属性 —— 默认是 ExcludeFromCodeCoverage,而 OpenCover、dotCover 和转换得到的 lcov 都不遵循它。
- Exclude Selection from Coverage. 选中若干行,从灯泡或编辑器的上下文菜单中执行:在 .NET 类、方法或属性上方写入
[ExcludeFromCodeCoverage] —— 如果文件已导入 System.Diagnostics.CodeAnalysis,则使用短形式 —— 在其他地方则用该语言自己的注释写入 LCOV_EXCL_LINE 或一对 LCOV_EXCL_START/STOP。已有的标记不会重复写入。
- 命名空间、类和方法。对于列出类名的 .NET 报告 —— Cobertura、Coverlet、OpenCover —— Folders / Namespaces 下拉列表可按命名空间、类和方法展示同一次运行,排序和过滤方式相同;方法行会在该方法处打开文件。编译器生成的类型,如
<>c 和 async 状态机,会并入为其生成的类中。
- 覆盖率树上方的搜索框。输入词语,保留名称或路径包含全部词语的行;输入比较式 ——
< 80%、lines >= 90、branches = 0 —— 保留数值满足条件的行;两者同时输入则须同时满足。方法行和风险热点也会被搜索;Escape 清除。
- Run Native Project with Coverage. 从 Tools 菜单对启动 C++ 项目执行:ClangCL 项目会使用 clang 的覆盖率插桩重新构建到
coverage/native/,然后运行并加载其报告;其他任何工具集在已安装 OpenCppCoverage 时于其下运行;两者都不可行时,会用一句话说明需要安装什么。
- 覆盖率会话与趋势。执行 Start Coverage Session 后,此后加载的每次运行都会累加到之前的运行上 —— 行、分支和函数都一样:任何一次运行执行过的都算已覆盖 —— 这样单元测试、集成测试和在应用中的一次手动操作就能显示它们合起来覆盖到了哪里。工具栏下方会把已保存历史的行覆盖率绘制成趋势,每次运行一个点。
- Compare Two History Runs,与 VS Code 中相同:选择两次保存的运行,两者之间发生变化的文件会按从旧到新的顺序列出,无论先选的是哪一次。
- Compare with CI Baseline.
baseline.report 指定主分支构建所发布的报告 —— 一个用 remote.headers 获取的 URL,或一个下载好的文件 —— 之后每次加载都与它对照:状态栏卡片显示本次运行所处的位置,Compare with CI Baseline 列出发生变化的文件。基线与本次运行经过同一份排除列表,因此合计是在同等条件下比较的。
- 在哪里找到它们。新命令位于 Tools > Coverage Studio 下和编辑器的上下文菜单中;Show Tests That Ran This Line 也可用 Ctrl+Shift+U, T 调用,Exclude Selection from Coverage 是一个灯泡操作。
修复
- 测试运行的报告不再带有你的用户名和计算机名。Microsoft 的 Code Coverage 收集器将报告命名为
<user>_<machine>_<stamp>.cobertura.xml,这个名字出现在树中以及它的每张截图里;现在报告在加载前会被重命名为 coverage.cobertura.xml。
- 生成的文件曾被说成是由
fuciniCoverage.ignore 排除的。现在每个被排除的文件都按排除它的设置来计数 —— ignore、ignore.generated 或 ignore.namespaces —— 因此显示的名称就是需要修改的那个。
- 按测试写出的 lcov 跟踪文件按每个文件一条记录读取,各测试段累加,与 VS Code 的读法相同;以前每个测试的记录都是一个单独的文件。
- 日志会说明解析器略过了什么。解析器找不到任何可插桩内容的文件(
FUCINI_PARSE_030)以及报告对自身缺漏的说明(FUCINI_PARSE_031,OpenCover 的 MissingPdb)会写入日志,与 VS Code 的写法相同。
- 只含宏的头文件不再以 100% 出现在树中。llvm-cov 和 gcov 会把宏的使用计到定义它的行上;位于已排除行上的分支和函数现在随这些行一起被去掉,没有任何可度量内容的文件会从运行中移除,并在输出中列出(
FUCINI_EXCLUDE_001)。
- 五种曾被当作不支持的格式而拒绝的报告现在能被识别。Kover 的 JaCoCo XML、Stryker.NET 报告、NCover 报告、旧版 SimpleCov resultset,以及含有大量空文件的 SonarQube 报告,现在都能通过其开头的内容识别。路径中含有
cobertura 一词的 Clover 或 SonarQube 报告,不再被当作 Cobertura 读取。
- 与写出它们的工具一致的数字。MC/DC 构建的分支数据与
llvm-cov report 一致;LCOV 2 的异常分支(BRDA:12,e0,1,3)会被计入;llvm-cov 的函数只在定义它的文件中声明;被两个测试二进制文件列出的 Go 块会累加其计数;由两个类报告的 Cobertura 判定和被列出两次的 JaCoCo 行会保留全部分支,且只计一次。
- 较小的修复。写到一半被截断的跟踪文件不再丢失文件;对多个
.gcda 文件运行 gcov -t 会为每个生成一个文件,模板实例只读取一次,gcov -H 中 1.20k 这样的计数会被保留;GNATcoverage 文件不再全部被报告为在覆盖率之后已更改;待定的 Stryker 变异体或中断的 PIT 运行不再拉低得分。
- 手动编辑设置文件后,保存时即会生效,与 VS Code 应用设置更改的方式相同。
Coverage Studio for VS Code 1.2026.7 —— 哪些测试运行了某一行、每次保存后的覆盖率,以及 CI 基线
2026-09-29
新增
- 哪些测试运行了这一行。在报告记录了这一点的地方 —— 带
--show-contexts 的 coverage.py、OpenCover 的跟踪方法、按测试写出的 lcov 跟踪文件 —— 函数的 CodeLens 会显示有多少测试运行了它,Show Tests That Ran This Line 按运行次数从多到少列出这些测试,并打开你选中的那个。对于 dotnet test 运行,testRun.perTest 会逐个类运行测试,因此每份报告都能说明是哪个类写出的。
- 每次保存后的覆盖率。启用
testRun.onSave 后,保存源文件会带覆盖率运行覆盖它的测试,边栏随之更新。在 .NET 解决方案中,只运行引用了所保存文件所在项目的测试项目;连续多次保存只算一次运行。
- Run This Test with Coverage. 当光标位于测试方法、测试类或
describe 中,或位于测试文件中时,一条命令即可带覆盖率只运行这一部分 —— dotnet test --filter、jest/vitest -t 或 pytest 节点 ID —— 并加载其写出的结果。测试是从文本中读取的,因此无需语言服务即可用于 C#、VB、F#、JavaScript、TypeScript 和 Python。
- Exclude from Coverage,以及两个 .NET 过滤器。在覆盖率树的某一行上右键单击,或对打开的文件使用 Exclude This File from Coverage,会把该文件或文件夹加入
fuciniCoverage.ignore,它随即退出所有合计。ignore.namespaces 排除某个命名空间的文件(*.Migrations),ignore.attributes 排除带有某个特性的类、方法或属性 —— 默认是 ExcludeFromCodeCoverage,而 OpenCover、dotCover 和转换得到的 lcov 都不遵循它。
- Exclude Selection from Coverage. 选中若干行,从灯泡或编辑器的上下文菜单中执行:在 .NET 类、方法或属性上方写入
[ExcludeFromCodeCoverage] —— 如果文件已导入 System.Diagnostics.CodeAnalysis,则使用短形式 —— 在其他地方则用该语言自己的注释写入 LCOV_EXCL_LINE 或一对 LCOV_EXCL_START/STOP。已有的标记不会重复写入。
- 命名空间、类和方法。对于列出类名的 .NET 报告 —— Cobertura、Coverlet、OpenCover —— Folders / Namespaces 下拉列表可按命名空间、类和方法展示同一次运行,排序和过滤方式相同;方法行会在该方法处打开文件。编译器生成的类型,如
<>c 和 async 状态机,会并入为其生成的类中。
- 覆盖率树上方的搜索框。输入词语,保留名称或路径包含全部词语的行;输入比较式 ——
< 80%、lines >= 90、branches = 0 —— 保留数值满足条件的行;两者同时输入则须同时满足。方法行和风险热点也会被搜索;Escape 清除。
- 覆盖率会话与趋势。执行 Start Coverage Session 后,此后加载的每次运行都会累加到之前的运行上 —— 行、分支和函数都一样:任何一次运行执行过的都算已覆盖 —— 这样单元测试、集成测试和在应用中的一次手动操作就能显示它们合起来覆盖到了哪里。工具栏下方会把已保存历史的行覆盖率绘制成趋势,每次运行一个点。
- Compare with CI Baseline.
baseline.report 指定主分支构建所发布的报告 —— 一个用 remote.headers 获取的 URL,或一个下载好的文件 —— 之后每次加载都与它对照:状态栏卡片显示本次运行所处的位置,Compare with CI Baseline 列出发生变化的文件。基线与本次运行经过同一份排除列表,因此合计是在同等条件下比较的。
修复
- 测试运行的报告不再带有你的用户名和计算机名。Microsoft 的 Code Coverage 收集器将报告命名为
<user>_<machine>_<stamp>.cobertura.xml,这个名字出现在树中以及它的每张截图里;现在报告在加载前会被重命名为 coverage.cobertura.xml。
- 终端为 PowerShell 时,Windows 上的测试运行会失败。
Code Coverage;Format=cobertura 两侧的引号在传给 pwsh 的途中丢失,; 被当作命令结束;现在配方按词逐个交给终端,并按其启动的 shell 加引号。
- 生成的文件曾被说成是由
fuciniCoverage.ignore 排除的。现在每个被排除的文件都按排除它的设置来计数 —— ignore、ignore.generated 或 ignore.namespaces —— 因此显示的名称就是需要修改的那个。
- 只含宏的头文件不再以 100% 出现在树中。llvm-cov 和 gcov 会把宏的使用计到定义它的行上;位于已排除行上的分支和函数现在随这些行一起被去掉,没有任何可度量内容的文件会从运行中移除,并在输出中列出(
FUCINI_EXCLUDE_001)。
- 五种曾被当作不支持的格式而拒绝的报告现在能被识别。Kover 的 JaCoCo XML、Stryker.NET 报告、NCover 报告、旧版 SimpleCov resultset,以及含有大量空文件的 SonarQube 报告,现在都能通过其开头的内容识别。路径中含有
cobertura 一词的 Clover 或 SonarQube 报告,不再被当作 Cobertura 读取。
- 与写出它们的工具一致的数字。MC/DC 构建的分支数据与
llvm-cov report 一致;LCOV 2 的异常分支(BRDA:12,e0,1,3)会被计入;llvm-cov 的函数只在定义它的文件中声明;被两个测试二进制文件列出的 Go 块会累加其计数;由两个类报告的 Cobertura 判定和被列出两次的 JaCoCo 行会保留全部分支,且只计一次。
- 较小的修复。写到一半被截断的跟踪文件不再丢失文件;对多个
.gcda 文件运行 gcov -t 会为每个生成一个文件,模板实例只读取一次,gcov -H 中 1.20k 这样的计数会被保留;GNATcoverage 文件不再全部被报告为在覆盖率之后已更改;待定的 Stryker 变异体或中断的 PIT 运行不再拉低得分。
变更
- 不再在每次加载时出现
FUCINI_ENCODING_001。没有字节顺序标记的报告按 UTF-8 读取,正如所有工具写出的那样,不再附带说明。
Coverage Studio for Visual Studio 1.2026.5 —— 在报告将要出现的位置监视
2026-09-28
新增
- 带通配符的相对条目会在任意深度搜索。
coverageFile.paths 中的 *.lcov.info 无论文件位于基准文件夹下的何处都能找到它,正如 VS Code 一直以来的读法;绝对路径的条目 —— ${workspaceFolder}/build/coverage-merged/*.lcov.info,** 表示任意深度 —— 则和以前一样,只在它所写的位置查找。
- 在报告将要出现的位置监视。 监视覆盖设置所指定的文件夹,无论那里是否已有报告:绝对路径文件所在的文件夹、通配符之前的文件夹 —— 当模式深入子文件夹时,连同其下的一切 —— 以及相对通配符的基准文件夹。构建写到那里的报告会自动加载;对这些文件夹中其他文件的写入则被忽略。
修复
- llvm-cov 的 JSON 报告被当作不支持的格式拒绝。 格式是从前 4096 个字符识别的,而 llvm-cov 把它的
"type": "llvm.coverage.json.export" 标记写在最末尾;一份首个文件记录带有大量分支和嵌套宏展开的导出,在这段开头里再没有别的可识别之处。这样的报告现在按它的开头 {"data":[{"files":[ 识别,没有其他格式是这样开头的。
gcov --json-format 也是如此。 gcov 先写文件的函数再写行,一个有十几个函数的文件在被检查的开头里同样没有行条目;现在由文档自身的 gcc_version 键来识别它。
Coverage Studio for VS Code 1.2026.6 —— 完整路径中的通配符,在报告将要出现的位置监视
2026-09-28
新增
- 绝对路径的
coverageFile.paths 条目中的通配符。 ${workspaceFolder}/build/coverage-merged/*.lcov.info 会加载该文件夹中所有这样的文件,** 表示任意深度:第一个通配符之前的文件夹是搜索范围,其余部分是这些文件夹下的模式,正如 Visual Studio 版本一直以来读取这类条目的方式。以前,绝对路径的条目按字面查找,因此带星号的条目什么也匹配不到 —— 而且因为它是通配符,也从不报告它什么都没匹配到。之后出现在那里的报告会由监视器或轮询加载,与字面条目一样;什么都没匹配到的通配符不予报告,因为它可能在等待构建。
修复
- llvm-cov 的 JSON 报告被当作不支持的格式拒绝。 格式是从前 4096 个字符识别的,而 llvm-cov 把它的
"type": "llvm.coverage.json.export" 标记写在最末尾;一份首个文件记录带有大量分支和嵌套宏展开的导出,在这段开头里再没有别的可识别之处。这样的报告现在按它的开头 {"data":[{"files":[ 识别,没有其他格式是这样开头的。
gcov --json-format 也是如此。 gcov 先写文件的函数再写行,一个有十几个函数的文件在被检查的开头里同样没有行条目;现在由文档自身的 gcc_version 键来识别它。
Coverage Studio for Visual Studio 1.2026.4 —— 两份报告,一个答案,已覆盖处显示绿色
2026-09-26
新增
- 为文件选择或合并报告。 在 Coverage 窗口中右键单击文件并选择 Choose Coverage Source...(当多份已加载的报告测量该文件时提供),或使用 Tools > Coverage Studio > Choose Coverage Source for This File...:列出每份报告及其各自的数值,随后是 Combine them — agree(只有每份报告都运行过的行才算已覆盖:一套代码,两个编译器)和 — union(任一报告运行过即算已覆盖:同一构建的多个测试套件),可应用于该文件、其文件夹或某个模式。各报告结果不一致的行在边距和 Annotated Source 中显示为青绿色,并注明每份报告的结果;文件所在行会列出这些报告和存在分歧的行数,状态栏和两张卡片都会说明数值来自何处。
- 红、琥珀色和绿色。 Gutter: Coverage 在红色和琥珀色之外,把每个已覆盖的行涂成绿色 —— 这一模式适合那些认为 100% 的文件就该是绿色的人。热力图的五种色阶是设置项(
heatmap.colors、heatmap.colorsDark),设置窗口会在选择时预览每种颜色。
修复
- 状态栏中文件的数值与其卡片上的一致。 没有内容的指标 —— 没有判定的文件上的 MC/DC —— 在状态栏项中计为 100%,而在它打开的卡片上则完全不计入。
- 只含常量的头文件不再显示 0% 或 100%。 当
excludeComments 开启时,预处理器指令与注释一样计为非代码。
Coverage Studio for VS Code 1.2026.5 —— 两份报告,一个答案,已覆盖处显示绿色
2026-09-26
新增
- 为文件选择或合并报告。
coverageFile.sources 按文件决定由多份已加载报告中的哪一份代表该文件 —— 或将它们合并:agree 只有每份报告都运行过的行才计为已覆盖,并以青绿色标记各报告不一致的行;union 则任一报告运行过即可。在 Coverage 视图的某一行上或针对打开的文件执行 Choose Coverage Source...,即可替您写好规则。属于付费套餐;在 Community 中由最新的报告决定。
- 红、琥珀色和绿色,以及一键切换的装订线模式。
coverage 模式把已覆盖的行涂成绿色;热力图的色阶是设置项,可在设置面板中实时预览;状态栏按钮和 Alt+G 让装订线在关闭、未覆盖、覆盖率和热力图之间切换。
修复
- 状态栏中文件的数值与其卡片上的一致。 没有内容的指标 —— 没有判定的文件上的 MC/DC —— 在状态栏项中计为 100%,而在它打开的卡片上则完全不计入。
- 只含常量的头文件不再显示 0% 或 100%。 当
excludeComments 开启时,预处理器指令与注释一样计为非代码。
Coverage Studio for Visual Studio 1.2026.3 —— 除了代码,无需选择
2026-09-24
变更
- Licence 对话框只询问代码。四个方案按钮已去掉:订阅码或邀请码指向一个池,池知道自己的方案,所以没有什么是人能比代码本身回答得更好的——而在仍选中 Pro 时粘贴的 Business 邀请码曾因方案不符被拒绝。粘贴代码,然后按 Activate。
Coverage Studio for VS Code 1.2026.4 —— 除了代码,无需选择
2026-09-24
变更
- Enter Subscription Code 只询问代码。方案问题已去掉:代码指向一个池,池知道自己的方案,所以余下的由服务器接手,不再以方案不符为由拒绝代码。邮件中的一键链接保持不变;激活邮件不再有“选择您的方案”这一步,同一个代码无需 VS Code 即可激活 Coverage Studio for Visual Studio。
Coverage Studio for Visual Studio 1.2026.2 —— 每次测试运行、每种报告,以及什么变动了
2026-09-24
新增
- 每次测试运行后都有覆盖率。Collect Coverage in Test Explorer… 会在解决方案旁放置一个带有 Microsoft Cobertura 收集器的
.runsettings —— 在 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 识别 dotnet test、vitest、jest、pytest、go、cargo、maven、gradle、phpunit 和 ctest,在 Output 窗口中开启覆盖率运行它们并加载写出的结果;没有 coverlet.collector 的测试项目用测试 SDK 自带的收集器运行。
- 自上次运行以来。每次加载都会与上一次比较:每一行开始运行或停止运行的地方在边栏中有一个三角形,分数旁有趋势,数字变动的文件则有 Compare with Last Run。
history.enabled 让运行记录跨重启保留;gitDiff.enabled 把运行缩减到您的分支改动的行。
- 门槛与 Error List。Check Coverage Thresholds 依据
threshold.* 评判本次运行;有了 compliance.diagnostics、problems.enabled、problems.perLine 或 deadCode.enabled,这些发现会与编译器自己的条目一起出现在 Error List 中,每条都会打开其文件。
- 报告、导出和徽章。Show Annotated Source 把当前文件作为一个页面在文档区中打开 —— 每一行都带着自己的颜色,发现列在旁边 —— 并与编辑器双向同步滚动。Open HTML Report 和 Generate Full HTML Report 把本次运行写入
htmlReport.outputDir 并打开浏览器。Export Coverage Report… 写出按文件或按函数的 CSV、Markdown、LCOV、Cobertura、SARIF、SVG 徽章或 Fucini JSON。Generate Coverage Badge 把徽章保存在仓库中,有了 badge.autoUpdate 则每次加载后都更新。
- Risk hotspots 与行筛选器进入 Coverage 窗口,与 VS Code 中相同:复杂代码与低覆盖率相遇的函数,最差的在前;以及排序旁的一个下拉框,可选全部文件、有缺口的文件、未测试的文件,或自上次运行以来更改过的文件。
- 解决方案根目录下的设置文件。解决方案旁的
fucini-coverage.json 在 .vscode/settings.json 之后读取,并在它是已存在的那个文件时由设置窗口写入 —— 供不愿保留 .vscode 文件夹的团队使用。两个版本都读取它。
- .NET 无需繁文缛节。
ignore.generated 把设计器文件、生成的文件、obj\ 和迁移文件排除在每个总计之外;testRun.skipWhenTestsFail 在运行以失败告终时把最后一次良好的覆盖率留在屏幕上。
此版本尚未包含
- Test Coverage 面板是 VS Code API,解决方案资源管理器无法显示徽章。Compare Two History Runs 将在订阅者提出需求时跟进。
Coverage Studio for VS Code 1.2026.3 —— 热点、筛选器,以及无需包的 .NET
2026-09-24
新增
- 显示哪些文件。Coverage 视图工具栏中排序旁的第二个下拉框:全部文件、有缺口的文件、未测试的文件,或自上一次运行以来数字变动的文件。文件夹跟随其文件并保留自己的数字。所有层级均可用。
- Risk hotspots。在树的下方:复杂代码与低覆盖率相遇的函数,最差的在前,每一项都会在该函数处打开其文件。函数依据 CRAP 分数入选 ——
hotspots.crapThreshold,默认为 30,即该指标的提出者所建议的数值 —— 或仅依据圈复杂度入选,hotspots.complexityThreshold,默认关闭。Community 看到数量和最差分数;排序后的列表属于 Pro。
- 无需包的
dotnet test。Run Tests with Coverage 先读取项目文件:若没有任何项目引用 Coverlet,运行就使用 Microsoft 自己的收集器 —— --collect:"Code Coverage;Format=cobertura",随 Microsoft.NET.Test.Sdk 一同提供 —— 其报告像 Coverlet 的一样被加载。
- 生成的 .NET 文件被排除。默认开启的
ignore.generated 会把 *.Designer.cs、*.g.cs、*.generated.cs、*.razor.g.cs、AssemblyInfo、全局 using、Migrations/ 下和 obj/ 下的一切从每个总计、页面和导出中去掉。没人测试的设计器文件不再让解决方案过不了门槛。
- 失败的运行保留最后一次良好的覆盖率。有了
testRun.skipWhenTestsFail,以失败测试告终的运行会让覆盖率保持原样留在屏幕上,并在 Output 窗格中说明。默认关闭。
变更
- Test Explorer 的运行会被自动找到。无需任何配置,众所周知的名称现在包括每个测试项目的
TestResults/<run>/ 文件夹,而不只是工作区文件夹自己的,以及 Coverlet 报告旁 Microsoft 收集器的 <user>_<machine>_<date>.cobertura.xml。在 Visual Studio 中运行过测试的 .NET 解决方案在首次打开时就会显示其覆盖率;每个运行文件夹都会加载,合并时对每个文件以最新一次运行为准。
Coverage Studio for Visual Studio 1.2026.1 —— 同样的覆盖率,在另一个 IDE 中
2026-09-23
新增
- 第二个扩展,面向 Visual Studio 2022 和 2026 —— Community、Professional 和 Enterprise。与 VS Code 版使用同一个读取器,因此同一份报告在两个编辑器里给出的数字精确到每一位都相同;同样的
fuciniCoverage.* 设置,从 .vscode/settings.json 读取,若机器上有 VS Code 也从其用户设置读取。它不使用 Visual Studio 自带的代码覆盖率:在 Visual Studio 2022 中那是 Enterprise 功能,而在 Community 和 Professional 上,这是该 IDE 唯一能显示的覆盖率。 - 在编辑器中:每行一条边栏条 —— 红色从未执行,琥珀色部分执行,按访问次数的热力图 —— 行内命中计数、每个函数上方一行显示其覆盖率、复杂度、CRAP 分数和 MC/DC、滚动条上的条纹、说明哪个分支没走过的悬停提示,以及报告之后您编辑过的行上的圆点。
- Coverage 窗口(View → Other Windows → Coverage):每个文件及其指标和一个总分,可排序,未测量的文件列在下方;状态栏的
Coverage 和 File 项各自打开完整卡片。 - 命令位于 Tools → Coverage Studio 下,配有
Ctrl+Shift+U 之后的两键和弦:N/P 转到下一个和上一个未覆盖的行,B 转到下一个部分测试的判定,R 重新加载。监视模式在构建写出的文件变化时重载。 - Getting Started,六个步骤各带按钮,18 种语言;第一次自动打开。
- 设置来自 Coverage 窗口工具栏上的齿轮,写入本版本的用户设置或文件夹的
.vscode/settings.json,并保留所编辑文件中的注释。 - 许可证:所有付费套餐均包含。已激活 Coverage Studio for VS Code 的机器无需再做任何事 —— 密钥会被自动找到;其他任何地方,Tools → Coverage Studio → Licence… 接受您激活邮件中的订阅代码。没有订阅就不会读取覆盖率:Visual Studio 中没有免费层级。
此版本尚未包含
- Run Tests with Coverage 和 Test Coverage 面板是 VS Code API;解决方案资源管理器无法显示徽章。Annotated Source 视图、HTML 报告和导出、Check Thresholds、Error List 条目、历史与趋势以及差异覆盖率将按订阅者提出需求的顺序推出。
Coverage Studio for VS Code 1.2026.2 —— 入门,以及一个订阅两个编辑器
2026-09-23
新增
- 一个演练。Get started with Coverage Studio —— 位于 Help → Welcome → Walkthroughs,安装后自动打开 —— 用六个步骤带新用户从覆盖率报告走到没人测试的代码行,每步都有其对应命令的按钮。全部十八种语言。
- 安装 ID 会留在 Coverage Studio for Visual Studio 读取的位置。Visual Studio 版按同一指纹验证
license.key 中的密钥,却无法读取本扩展的状态存储;现在每次激活时,ID 也会写到扩展全局存储旁边,因此在 VS Code 中激活的机器无需在 Visual Studio 中再次激活。一个随机 UUID,不与任何东西绑定,从不发送到任何地方。
变更
- 退款会终止订阅。获批的退款或拒付现在会立即取消订阅,其激活码不再签发密钥;每位客户一次退款。机器上已有的密钥照旧用到它自己的到期日。退款政策说明了确切的处理。
Coverage Studio for VS Code 1.2026.1 — 始终能看清的文件名
2026-09-21
修复
- Coverage 视图中的文件名在任何宽度下都能看清。 过去名称是一行里唯一会收缩的部分——在普通侧边栏里会缩到七个字符。现在名称完整绘制,指标列、得分和进度条从左侧滑到它下方,并在截断处渐隐,这样半个数字绝不会被读成完整的数字。每个数值仍然在该行的工具提示里。
- “文件已更改”标记会跟上文件的变化。 加载之后,它跟随第一次编辑和第一次还原,此后直到下一次加载都不再变化。现在每次保存和磁盘上的每次更改都会生效。
- Coverage 视图的工具栏不再把按钮标签拆成两行。 在狭窄的侧边栏里,工具栏现在在各控件之间换行,排序框移到单独一行。
- 覆盖率徽章在导出选择器里同样免费。 Generate Coverage Badge 一直在每个版本层级写出 SVG 徽章,而 Export Coverage Report… 在 Community 上拒绝同一个文件。现在两者都会写出。
- Show Worst-Covered Folders 与另外两个列表采用同样的授权方式。 在 Community 上没有任何变化——三者都免费且不计次——对任何已签发的密钥也没有变化。
新增
- 最低支持版本。 扩展现在大约每周一次从我们的许可证服务器读取一份小型签名策略。当某个构建版本比仍受支持的最旧版本还旧时,试用和免费层会停止并要求更新;付费许可证会被告知日期,并先在宽限期内继续工作。这次读取不会发送任何关于您或您的安装的信息,无法连接服务器的安装也绝不会因此被停止。目前未设置最低版本。
变更
- 从本版本起,许可证为专有许可。 此前扩展以 MIT 条款发布,这从来不适合一款按订阅销售的产品。您可以在套餐范围内安装和使用已发布的构建版本,包括商业用途;不得复制、修改、再分发或对其进行逆向工程。它根据您的数据生成的内容——报告、导出、徽章——归您所有,原先的署名条件已取消。早期版本的副本仍适用其随附的条款。
- 路径操作按钮(⋯)在您指向某一行之前不占空间。 它在每一行预留的 25 像素现在让给了文件名;悬停时它紧跟在名称后出现,行内没有任何东西移动。
Coverage Studio for VS Code 1.2026.0 — 条件、变异体,以及一行背后的测试
2026-09-20
修复
- LCOV 2 跟踪文件中每个函数只列出一次。
FN:<行>,<结束行>,<名称> 现在按 lcov 2.0 所写的方式读取——此前每个函数会出现两次,一次是从未调用,一次在第 0 行——lcov 2.2 的 FNL:/FNA: 组合也一并读取。
- C++ 模板不会再因为某一个实例化没运行就被整体标为从未执行;充满宏的函数也重新只算一个函数,而不是每个宏一个。
- 同意文本如实说明安装实际发送的内容:不再有每月一页的源代码,使用摘要携带的是签发你密钥时的请求码。
新增
- 条件覆盖率成为独立指标。
a && b 是一个判定、两个条件,测试可能走遍两条分支却从未见过 b 为假。它现在有了自己的行、列、导出、徽章、在得分中的权重(3,介于分支与 MC/DC 之间)和阈值——从 BullseyeCoverage、TRACE32 的 cond 导出以及 GCC 14 的 -fcondition-coverage 中读取。
- 变异体,就在它们所在之处。 PIT 与 Stryker 的报告按变异体逐个读取:存活的会标在编辑器中它自己的那一行,悬停显示改动以及运行过它的测试,并列入 HTML 报告和带注释的源代码。
- 哪些测试跑过这一行。 带
--show-contexts 的 coverage.py 与带 -coverbytest 的 OpenCover 都会记录哪些测试到达了某一行;命中次数的提示会列出它们。
- 已执行行中从未运行的那一部分会在编辑器中着色,C 与 C++ 的函数也会获得复杂度和 CRAP 分数,由 llvm-cov 本就携带的分支数据计算而来。
- JaCoCo、Cobertura 与 Coverlet 项目首次打开即可加载,无需任何配置——包括 Maven、Gradle 和
dotnet test 默认写入的位置。
- 任何宽度下,每个文件旁都有每项指标,按它在得分中的权重排序,放不下的会横向滚动而不是消失——当你在看别处时跟踪文件重新加载,Coverage 图标上会出现计数。
- 可以自愿加入的预发布通道,以及编辑器标题栏上的一个按钮:一键关闭覆盖率着色,再按一次原样还原。
变更
- Bullseye 与 TRACE32:分支覆盖率不再包含条件。判定归入分支覆盖率,条件归入条件覆盖率,因此这类项目的分支数值会变化,综合得分也随之变化。把
whmWeights.conditions 设为 0 即可回到从前的得分。
- 免费的 Community 层有了每周额度:每项计量操作每周五次(此前是每天二十次),达到上限时会提供订阅或 7 天通行证。已经在使用的安装会保留原有额度 30 天,并附日期提示一次。
- 试用期与免费层会向许可服务器保留一份用量台账:VS Code 机器 ID 的哈希、版本、评估开始的日期,以及计量操作的计数——仅此而已;付费许可从不记录,也从不等待它。以遥测换取的时长现在是一次性的 30 天。
- 每月一页源代码已经取消——对任何人都不再收集、保存或发送,之前版本留下的页面会在本版本首次启动时删除。
0.2026.82 — 适合您项目的阈值,以及报告所携带的一切信息
2026-09-17
修复
- 热力图在深色主题下的方向正确了。 它的色带原本从浅黄过渡到深棕,因此最热的循环反而显示最暗的条。深色主题现在有了自己的色带,从暗橄榄色过渡到鲜亮的橙色。
- MC/DC 悬停提示重新显示详细信息, llvm-cov 判定的条件数量也能正确统计。当前版本的 VS Code 会把悬停提示折叠成一行;而
(a && b) || c 曾只列出一个 100% 的条件,尽管标题正确地写着 3 对中的 2 对。 - C++ 函数按您编写的方式命名: 对于 llvm-cov、lcov 和 gcov,显示
clamp_to<int> 和 gearbox::next_gear,而不是链接器的 ??$clamp_to@H@@YAHHHH@Z。 - Istanbul 的行数与 nyc 一致, 可以读取
dotnet-coverage 的 XML,SimpleCov 的 :nocov: 行会被排除而不是出错,而只携带摘要的报告无论各报告按什么顺序读取,都会保留其数值。 - 多根工作区: HTML 报告不再把同一个文件夹名称写两遍,Coverage 视图以工作区文件夹的名称作为其标题,
pathRemap 规则现在既可以写 ${workspaceFolder},也可以写 ${workspaceRoot}。
新增
- 报告携带的一切都会显示出来。 函数调用、目标代码和变异得分在 Coverage 视图、HTML 报告以及 CSV 和 Markdown 导出中各有一列,在状态栏卡片中各有一行,在带注释的源代码中各有一个徽章——而报告未携带的指标会被省略,而不是显示为零。
- 复杂度与 CRAP。 当报告携带圈复杂度时(OpenCover、JaCoCo、Clover、Cobertura),每个函数的 CodeLens 上都会显示 CRAP 得分,每个文件会有一个链接到对应方法的 Max CRAP,HTML 报告还会列出 Riskiest Methods。
- 从每种格式中获取更多信息: 具名的分支臂、被排除的行、行内的列范围、生成报告的工具及其版本和日期,以及工具写入报告的警告。
- 可选权重, 用于综合评分中的目标代码和变异得分,除非您自行设置,否则两者均为
0。
变更
- 默认阈值不再是 100%。 您未设置的阈值现在为:行 80、函数 80、区域 75、分支 70、综合评分 75,而 MC/DC、实例化、函数调用和目标代码不设门禁——这是对普通项目的合理要求。
fuciniCoverage.threshold.profile: "safety" 会把每个门禁恢复为 100,与以前完全一样;而您自行设置的阈值优先于任何一个配置档。如果您依赖过去的默认值,那么在选择 safety 之前,您将受到更宽松的评判; 此前已运行过的安装会收到一次提示,并附带一个可直接完成该设置的按钮。 - 没有门禁的指标会显示一个中性的短横线, 在卡片中取代对勾或叉号,设置面板则会按实际生效的门禁预览判定结果。
0.2026.81 — 精确的百分比,以及可以发送的报告
2026-09-16
修复
- 有未保存更改的缓冲区中的覆盖率重新对齐。 在文件有未保存编辑时加载的运行,会把每个标记、悬停提示和 CodeLens 偏移这些编辑所推动的行数。现在会从磁盘上的文件恢复这些编辑,而在某行上方整行粘贴不再把该行算作已编辑。
- 合并与重复的 LCOV 记录正确累加。 较新的跟踪文件不再保留旧运行的分支和 MC/DC 汇总,同一跟踪文件中列出两次的文件会按 genhtml 的方式合并。
- 许可证密钥留在自己的机器上。 Settings Sync 不再把它带到其他安装上(在那里它会阻止覆盖率);过期的 Business、Enterprise 或 Pro Plus 密钥在过期后最多 45 天内自动续期。
- 远程跟踪文件的抓取更加谨慎。
remote.headers 在重定向过程中留在其源站,抓取在 30 秒后放弃,登录页面被拒绝而不是缓存,离线打开的窗口加载上次下载的副本。自更新只安装自己的版本。 - 解析器: llvm-cov 行计数与
llvm-cov show 一致,不同方法的 OpenCover 判定不再互相覆盖,xccov、TRACE32 和 EMMA 保留其行数据,共享一个文件的 Cobertura 类视为一个文件,JaCoCo 聚合报告可以解析,路径映射会解析 .. 并按整段匹配。 - 在编辑器中: 历史记录按工作区保存,标记留在真实文件上而不是差异编辑器的 HEAD 窗格,超出文件末尾的行不再绘制,Windows 上的资源管理器徽章支持
C:\… 路径,大型运行的查找更快。
新增
- 发送诊断报告。 加载、远程抓取、合并、历史比较或聊天失败的通知都会提供它。它精确预览将要发送的 JSON,可选附上 4 KB 文件样本、备注和回复地址,在你点击“发送”之前不会发送任何内容。
- 错误报告。 当 VS Code 的遥测级别为
all 或 error 时,FUCINI_* 错误会在不含文件内容、路径或名称的情况下上报。三条日志行有了自己的代码:FUCINI_REMOTE_002、FUCINI_REMOTE_003 和 FUCINI_GITDIFF_002,用户指南中均有说明。
变更
- 每个覆盖率百分比都有两位小数, 截断而非四舍五入:
87.43%,只有覆盖率恰好为 100 时才显示 100.00%。 - 阈值按精确值判定。 此前每个百分比都先四舍五入为整数,所以 89.6% 能通过 90% 的阈值。仅靠四舍五入通过的项目现在会显示 NON-COMPLIANT,直到覆盖率真正达到阈值。
- 遥测改为每日。 每个安装在 VS Code 遥测级别为
all 时每天发送一条小型许可证消息;开启 telemetry.enabled 后,使用摘要改为每日而非每月发送。为换取遥测而解锁功能的安装会在条款变更前被询问。
0.2026.80 — 看得见的更新
2026-09-14
新增
- Coverage 视图会提示有更新可用,并且一直提示。许可证横幅上方的一条栏会在你当前的版本旁显示新版本,并提供与更新通知相同的三个按钮:“下载 & 安装”“查看更新日志”和“跳过此版本”。活动栏中该视图的图标也会显示徽标,即使视图关闭也能看到。以前通知只在自动检查时出现一次,点击其他任何地方就会消失,直到一天后的下一次检查;现在这条栏会一直保留,直到更新被安装、被跳过,或
fuciniCoverage.update.checkForUpdates 被关闭,重新加载窗口后也仍然存在。
0.2026.79 — 每天一个 ping
2026-09-14
变更
- 小型 ping 现在合并发送,每天最多一次。更新、许可证变更、新的覆盖率格式以及无法解析的文件,过去各自单独发送一个 ping,一经发现立即发送——在某些安装上还会在每次会话中被重新发现:被撤销的席位每次启动都会报告撤销,在使用不同格式的工作区之间切换时,每次都会报告一个“新的”格式集合。现在它们会被收集起来,合并为一个 ping 发送,每天最多一次。没有可报告内容的日子不会发送任何东西。
- 只报告真正发生了变化的内容。一天之内变更后又恢复原状的许可证不会报告任何内容;格式是该安装曾经加载过的所有格式,而不只是最近一个工作区的格式。安装 ping 和卸载通知仍会立即发送,且不会收集任何新内容。
- VS Code 自身的遥测开关现在也适用于小型 ping。当
telemetry.telemetryLevel 设为 off 时,不会为每日 ping 收集任何内容,也不会发送任何内容;此前只有每月摘要和移除通知遵循该设置。一次性的安装 ping 保持不变。
- 在编辑器闲置期间结束的月份也会被报告。每月摘要以前只在加载覆盖率之后才检查,因此不再使用的安装永远不会发送它的最后一个月。现在只要 VS Code 处于打开状态,也会每小时检查一次——仍然只在开启遥测时进行,且仍然最多每 30 天一次。
修复
- 被服务器拒绝的 ping 不再算作已发送。以前服务器的任何响应(包括错误)都被当作送达,因此被拒绝的每日 ping 会丢失已收集的内容,被拒绝的安装 ping 也不会重试。现在只有成功的响应才算数;被拒绝的每日 ping 或每月摘要会被保留,并在一天后重试。
0.2026.78 — 全新的 14 天
2026-09-13
变更
- 每次评估都会一次性获得全新的 14 天。本版本首次启动时,所有没有付费许可证的 Pro 安装都会重新开放试用期——无论试用早已结束,还是尚余几天——并从当天起持续 14 天。发生时会显示一条简短通知。付费许可证不受影响;没有试用期的 Community 版本也保持不变。
- 付费许可证以绿色显示“已激活”。许可证横幅以前会向订阅用户显示“已激活 — 剩余 30 天”。订阅密钥有效至已付费周期结束,并随之续订,因此那个倒计时永远都会读起来像一个即将到期的试用期。标题现在只显示已激活,日期以“有效期至”列在详细信息中,倒计时只会在密钥到期前的最后一周回来,出现在原本就有的即将续订提示旁边。
0.2026.77 — 粘贴代码,仅此而已
2026-09-12
新增
- “Enter Subscription Code”——不再问别的。选择方案,粘贴购买邮件里的代码,确认,许可证密钥便为您签发并自动填好。此前从编辑器内部出发只有一条路:评估问卷——姓名、邮箱、账户类型、公司、一份调查——而这正是摆在已经付过钱的人面前的错误表单。另一条路是邮件里的
vscode:// 链接,对点击它心存戒备是稳妥而非胆小:这类链接可以由您访问的任何页面触发,而这恰恰就是激活要请您确认的原因。它在命令面板里,也是覆盖率面板许可证横幅上和激活对话框中的一个按钮——在任何状态下都有,因为许可证会在机器之间迁移,而在试用期中途购买是常态而非例外。
- 一条从试用期本身查看方案的路。定价页面可以从免费版的界面进入,却进不了激活对话框和许可证横幅——而那正是看着“剩余 3 天”的人真正会看的唯一位置。摆在这位读者面前的是一份问卷和一条
settings.json 提示,价格一个字也没有。
变更
- 激活对话框和许可证横幅不再以
FCK1 开头。两者以前都先给出您的请求代码和“把密钥粘贴到 settings.json”,而这是为我们的许可证服务器完全无法访问时准备的路。放在最前面,它就被读成了正式说明——于是手里拿着 FCB1… 订阅代码的客户被送往“Enter Activation Key”,那唯一必然拒收它的输入框。两者都还在,位于适合已经购买者的路径之下,并按其实际用途加以说明。
0.2026.76 — 邮件里提到的那条命令
2026-09-12
修复
- “Request Activation Key”现在真的是一条命令了。您的购买邮件——以及各语言版本的激活页面——都告诉您:如果一键链接没能通过您的邮件客户端,可以从命令面板运行 Fucini Coverage: Request Activation Key,选择方案并粘贴您的代码。可是这个名称属于面板的标题栏和链接本身,从来不属于任何命令,所以命令面板里根本搜不到它;而按名称最接近的 Enter Activation Key 接受的是我们服务器签发的
FCK1… 密钥,而不是邮件里那串 FCB1… 代码。照着说明操作,只会把您带到唯一那个必然拒收手里东西的输入框。现在它是一条真正的命令了。
- 试用期或密钥仍然有效时,激活对话框也会提供 申请许可证…。以前它要等到其中一项过期才出现,理由是能正常工作的安装没有理由联系许可证服务器。可是在试用期中途购买是常态而非例外,处于这种状态的买家从对话框里根本没有通往代码输入框的路:剩下的两个按钮要的是只有兑换代码之后才会产生的密钥。
0.2026.75 — 色盲友好配色
2026-09-12
新增
- 色盲友好配色。将
colorScale.preset 设为 colorblind,覆盖率将以朱红、橙色和蓝色(Okabe–Ito 配色)而非红、琥珀和绿来绘制——渐变、边栏条、行高亮、资源管理器徽章以及自上次运行以来的标记均适用。您自行设置的颜色优先。
0.2026.74 — 按测试筛选覆盖率
2026-09-12
新增
- 在 VS Code 自带的 Test Coverage 视图中按测试筛选覆盖率。 当跟踪文件为其测试命名时(lcov 的
TN: 段),每个测试都会成为 Test Explorer 中 Fucini Coverage 下的一个条目,Test Coverage 视图中的每个文件都会列出在其中执行过代码的测试,选择其中一个即可显示该测试到达的行。 - 路径设置中的
${command:…}。 ${command:cmake.buildDirectory}/coverage.info 会跟随所选的 CMake 工具包。该命令在每次发现之前运行,最多五秒,且仅在受信任的工作区中运行;执行失败的命令会让变量保持原样,并在输出中说明原因。 - 30 秒快速入门和与其他方案的比较现在位于 Marketplace 页面和主页的开头。
修复
- 按测试分别记录某个文件的跟踪文件,会按测试次数重复计算该文件。 现在这些记录会像 genhtml 读取时那样,在每个跟踪文件内相加:该文件在总计中只计一次,加载多个跟踪文件时也不会丢失任何测试的行。
0.2026.73 — 签名更新,以及切换版本后依然有效的密钥
2026-09-11
修复
- 安装 ID 现在会在任何功能使用它之前保存。 0.2026.72 内部版本 2 让 ID 不再在每次调用时重新计算,但启动时仍然没有等待它写入完成,因此打开后立即关闭的窗口仍可能丢失它——连同激活密钥所绑定的机器指纹一起丢失。现在启动时会等待写入完成。
- 从 Pro 切换到 Community 后,激活密钥依然有效。 每个版本都有自己的扩展存储,因此 Community 过去会以新的安装 ID 和新的指纹启动,而设置中的密钥(包括切换时刚为免费解锁申请的密钥)绑定的却是旧的。现在切换时会移交该 ID。
安全
- 来自 fucini.software 的更新经过签名,并在安装前验证。 更新源中的每个
.vsix 都带有 SHA-256 哈希和 Ed25519 签名,签名所用的密钥从不存放在网站服务器上。内置更新程序和切换到 Community 的流程都会用下载的文件验证这两者,并拒绝其他任何内容——代理的错误页面、被截断的下载、缓存中的旧版本,或不是我们发布的文件。仅靠 HTTPS 无法覆盖这种情况:进行 TLS 检查的企业代理会对经过它的每个连接重新签名。 - 每个版本都有自己的文件名。 更新源现在指向带版本号的
.vsix,而不是每次发布都会被覆盖的文件,因此忽略 Cache-Control 的缓存无法把上个月的版本当作本月的版本提供。下载页面上的链接保持不变。
0.2026.72 — 只测了一侧的判定
2026-09-10
新增
- 跳转到只测了一侧的判定。 Next Partly-Tested Decision及其上一处对应命令,会遍历那些部分分支执行过、部分从未执行的判定。这正是未覆盖行导航无法呈现的缺口:语句执行过的行就算已覆盖,无论它有多少分支从未走到,都保持已覆盖——
a 为假时只到达过一次的 if (a && b),行覆盖率 100%,测试只做了一半。按判定而非按分支停靠,因为 if/else 的分支可能相隔数页,跳到 switch 的第五个分支,远不如跳到 switch 本身说明问题。任何分支都未到达的判定留给未覆盖行命令处理,它们本来就会停在那里;而报告中根本没有分支数据的文件会如实说明,而不是声称每个判定都已双向测试。
Reload Coverage 会就地重读已加载的内容。 关闭监视时,重跑测试后回到新数字的唯一途径是Load Coverage,而它会重新执行发现流程,可能带回与屏幕上不同的一组文件。此命令精确重读当前已加载的内容,包括手动选取、发现流程再也找不到的跟踪文件。
Copy Coverage Summary 把本次运行写成 Markdown 表格。 覆盖率最低的文件排在最前,附合计行,可直接粘贴进 pull request。分支与 MC/DC 列仅在本次运行中确有测量时才出现:一整列破折号会被读成覆盖率为零,而不是未测量,那与事实正好相反。
修复
- 安装 ID 可能在会话之间发生变化——而许可证指纹正是由它生成的。 它在每次调用时重新计算,并且写入时无人等待,因此第二次调用,或启动后不久关闭的编辑器窗口,都可能产生一个新的 ID。ID 一变,激活密钥就不再匹配;同时它也虚增了所有按安装数统计的数字。现在每个会话只确定一次,并在任何使用之前完成保存。内部版本 2。
0.2026.71 — 这一行是哪个跟踪文件覆盖的
2026-09-08
新增
- 行级来源归属。 加载了多个跟踪文件时,执行次数的悬停提示现在以覆盖来源:结尾,列出在该行记录到执行的报告;在 Coverage 视图中点击某个跟踪文件行,现在会在每个打开的编辑器里点亮它贡献的那些行,就像此前点亮它测量过的文件一样。这是合并后的运行能回答、而单个报告回答不了的唯一问题:两个跟踪文件测量同一个文件时,对它的行是有分歧的,而此前合并把这种分歧抹平,从未展示过。合并仍然以文件为单位——最新的报告完整赢下共享文件——所以每行的来源在合并之前建立索引。只统计被覆盖的行:把某行记为
0 的报告并没有覆盖它。
- 终于读取 lcov 的
TN: 记录。 写明了测试套件的跟踪文件(TN:integration)在任何显示来源的位置都会显示为 coverage.info (integration),导出回 lcov 时这个名称也会保留,而不再写成空值。多数工具把 TN: 写成空,行为不变;会填写它的,恰恰是那些跟踪文件会被合并的工具,此时名称是唯一能说明谁是谁的东西。
fuciniCoverage.lineHighlight 为行本身着色。 off | uncovered | heatmap,默认关闭:在每一条未覆盖和部分覆盖的行背后加半透明底色,heatmap 还会在每一条已执行行背后加暖色,运行越多越暖。做成独立设置而不是 editorGutter.mode 的第四个取值,是因为两者需要不同的搭配:装订线保持干净而只给空白着色,或者只要条形而代码背后不着色。半透明是因为它位于文本下方;它着色的是空白而非已覆盖行,理由与装订线相同。
fuciniCoverage.overviewRuler 单独决定滚动条上的条纹。 follow(默认)保持一贯做法:装订线画未覆盖或部分覆盖条形的地方就画条纹,热力图则不画。uncovered 即使 editorGutter.mode 关闭也画——代码旁边什么都没有,只在滚动条上得到该文件的空白分布图。off 保留条形、去掉条纹。此前标尺与装订线是绑死的,这两种组合都无法实现。
修复
- 无法解析的跟踪文件现在会说明它是按什么读取的。“……格式不正确”让人无从判断文件是否被识别为自己以为的格式——被 VectorCAST 解析器拒绝的 Cobertura 文档,和真正被截断的 Cobertura 文档是两回事。当某个解析器接手了该文件时,提示现在以该文件按 cobertura 读取。结尾。若没有解析器接手,则不加这句:“不是本扩展能读取的格式”已经把话说完了。
0.2026.70 — 过时数据提示重新显示图标
2026-09-08
修复
- 状态栏悬停提示中的过时数据提示重新显示时钟图标,而不是文字
$(history)。 这条提示说明下方的数字描述的是文件的较早版本,它带有与状态栏本身相同的 $(history) 标记。 在状态栏中该标记会画成时钟图标,因为 StatusBarItem.text 会自行替换图标;而悬停提示是 MarkdownString,必须通过 supportThemeIcons 显式启用,而它从未启用过——于是唯一一处说明覆盖率为何不可信的文字,开头却是一段原始语法。 提示现在已启用它。
0.2026.69 — 装订线模式、远程跟踪文件、多根工作区与未测量文件
2026-09-08
新增
- 编辑器自身的装订线现在可以显示未覆盖的行,或命中次数热力图。 默认情况下它仍然只显示发现项——MC/DC 条、自上次运行以来的三角形、已编辑行的圆点——整个文件的彩色编码视图依旧是 Annotated Source。
fuciniCoverage.editorGutter.mode 可选择显示更多:uncovered 在每一条从未执行的行上放一个条,在每一条有分支臂从未走到的行上放一个琥珀色条,已覆盖的行上什么都不放,这样一片绿墙就不会把那三条红线藏起来;heatmap 再给每一条执行过的行加上暖色调,运行次数越多颜色越热。Choose Editor Gutter Mode... 可从命令面板或状态栏菜单在三者之间切换。README 以前直接宣称有“原生装订线”;现在它说的是实际存在的东西。 - 行内命中次数。
fuciniCoverage.hitCounts.inline 在每一条有语句开始的行后写上 ×12,也包括 ×0——这个数字一直都在悬停中显示,现在无需悬停。Toggle Inline Hit Counts 用于切换;状态栏菜单会视情况以“显示”或“隐藏”提供它。 - 所有路径设置都支持
${env:NAME}、${config:section.key}、${userHome} 和 ${workspaceFolderBasename},与原本已有的 ${workspaceFolder} 并列。扩展不认识的变量会原样保留,因此拼写错误会以它所查找的路径的形式出现在发现日志中,而不是凭空消失。 coverageFile.paths 条目可以是一个 http(s):// URL。 该工件会在每次加载时被抓取到扩展的存储中并从那里加载;Coverage 视图显示的是 URL,而不是缓存路径。每次抓取都是条件式的(ETag / Last-Modified),因此重新抓取一个未变化的工件不会下载任何内容;抓取失败时会改为加载上次下载的副本,原因写在输出中。fuciniCoverage.remote.headers 添加 Name: value 形式的标头,其中的变量会被展开——Authorization: Bearer ${env:CI_TOKEN} 让令牌不必写进 settings.json——fuciniCoverage.remote.refreshMinutes 则按定时器重新抓取。当 URL 本身不以文件名结尾时,请把 #lcov.info(或其他文件名)作为 URL 片段加上,以便识别格式。 - 加载和 Generate Full HTML Report 会显示进度,并且可以取消。 加载十个或更多跟踪文件,或它们的总量达到 8 MB 或更多时,会在带有 Cancel 按钮的进度通知下运行,通知中显示正在读取的文件和所处阶段(先读取,再检查源文件);较小的加载则和以前一样只转动状态栏。取消后上一次运行保持加载,并会如此说明。HTML 报告对每个渲染并写出的页面也是如此。
- 又多了两个重新加载的理由。 工作区之外的绝对
coverageFile.paths 条目——检出目录旁边的构建树、Bazel 输出根目录——现在也会被轮询,因此窗口打开之后出现在那里的文件会被加载,而不是再也不被查看;监视器以前只看得到工作区。此外,fuciniCoverage.watch.reloadAfterTasks 可指定若干任务(tasks.json 中的 label,或 Run Task 列表中所显示的 source: name,例如 npm: test),它们结束时会重新加载覆盖率,无论 watch.enabled 是否开启——适用于监视器无法跟踪的构建:替换符号链接输出树的运行、网络共享上的报告、对其文件做后处理的覆盖率步骤。 - 多根工作区。 工作区的每个文件夹现在都按自己的条件进行发现:
coverageFile.defaultLocation、coverageFile.paths、pathRemap、ignore、watch.*、remote.*、badge.*、报告目录、gitDiff.*、problems.perLine、editorGutter.mode 和 hitCounts.inline 都按文件夹读取,因此文件夹自己的 .vscode/settings.json 或其 .code-workspace 条目会生效;${workspaceFolder} 指的是该条目自己的文件夹;在每个文件夹中找到的跟踪文件合并为一次运行,Coverage 视图按文件夹对文件分组。pathRemap 规则中的 ${workspaceRoot} 会先尝试跟踪文件自己所在的文件夹,然后再尝试其他文件夹。凡是需要单个文件夹的地方——文件对话框、报告与徽章输出、git 元数据、Run Tests with Coverage——都取活动编辑器所在的文件夹;有多个文件夹而没有编辑器时,测试运行会询问用哪一个。向工作区添加或移除文件夹会自动重新加载覆盖率。在此之前,有十二处取的是第一个文件夹,第二个根目录的一切都拿到了错误的基准。 - 运行会发布到 VS Code 自己的 Test Coverage 视图。 开启
fuciniCoverage.testCoverage.publish(默认开启)后,每次加载的运行也会送往原生的 Test Coverage 面板、Explorer 中的逐文件百分比,以及编辑器自己的“Show Inline Coverage”开关——包括行、分支臂和函数,详情按需加载。Show in Test Coverage View 会发布活动运行并打开该面板,不论设置如何;状态栏菜单通过 quickActions.showTestCoverage 提供它。 - 文件不匹配时会给出路径重映射规则的建议。 最常见的“加载了却什么都不亮”,是跟踪文件的路径来自容器或 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 可按需运行同样的分析。不点击就不会写入任何内容。 fuciniCoverage.ignore:永远不计入的文件。 供应商文件、生成的文件或第三方文件(vendor/**、**/*.generated.ts、build/**)会在运行加载时被丢弃,因此 Coverage 视图、状态栏、阈值、徽章、CodeLens、历史记录和导出都在不含它们的情况下计数;加载结果会说明剔除了多少个,输出会列出它们的名字。模式匹配相对于工作区的路径和绝对路径;不含 / 的模式匹配任意深度的文件夹名或文件名,与 .gitignore 一样。这只针对整个文件——文件内部的行仍使用工具自己的排除标记。 - 逐行的 Problems 条目,可选开启。
fuciniCoverage.problems.perLine(off、uncovered 或 uncoveredAndPartial;默认关闭)会在每一段连续的从未执行的行上放一条 Information 诊断——一个四十行的死函数是一条,而不是四十条——在第二种模式下,还会在每一条有分支臂从未走到的行上放一条。只针对已打开的文档,因此两千个文件的运行不会淹没面板;条目随缓冲区的编辑跟着行移动,文档关闭时消失。problems.enabled 背后的逐文件条目保持不变。 - 供 README 使用的覆盖率徽章。 Generate Coverage Badge 为活动运行向工作区写出一个 shields 风格的 SVG(
fuciniCoverage.badge.outputPath,默认 coverage-badge.svg),README 用  嵌入即可,不需要任何托管服务。badge.metric 选择行、分支、MC/DC 或加权评分;颜色遵循 colorScale 的档位;badge.autoUpdate 在每次加载后重写它。Export Coverage Report 早已提供的 SVG 徽章现在共用同一个渲染器。 - 未测量与未覆盖。 没有任何测试加载过的文件根本不在跟踪文件里,因此扩展一直把它与命中次数为 0 的已测量文件区分开——并且不计入数字,而这正是一个一半模块没有测试的项目读出“92%”的方式。现在这个区别会显示出来:打开这样的文件时状态栏会显示
not measured,fuciniCoverage.unmeasured.mode 决定还会发生什么。list 会在 Coverage 视图中加入一个 Unmeasured(未测量)组,列出运行所测量种类中运行里没有的每个工作区文件,在加载结果中计数,在徽章开启时在 Explorer 中标为 ?,并允许 threshold.unmeasuredFiles 在超过所选数量时让 Check Coverage Thresholds 失败。count 更进一步:每个这样的文件以 0% 加入运行——每一行代码算作一条未覆盖行——因此状态栏、阈值、徽章、历史记录、导出和 Test Coverage 视图看到的都是诚实的数字;该文件在所有地方都被绘制为未测量,绝不会显示为“不再与其覆盖率匹配”。unmeasured.exclude 把头文件之类排除在外(默认 **/*.h、**/*.hpp、**/*.hh、**/*.inl、**/*.d.ts)。默认关闭;状态栏的状态是唯一始终开启的改变。 - 覆盖率视图会显示合并做了什么。 自 0.2026.63 起,加载在整个项目运行之上的模块单独重跑会替换该运行中该模块文件的数值,每一行也会注明其数据来自哪个报告——但数值覆盖了旧报告的行,看起来与多个报告中仅由一个测量的行完全一样,也没有任何地方说明一个报告有多少内容被覆盖。现在这样的行的跟踪文件徽章会带边框;树上方的每个跟踪文件行会统计合并对其文件做了什么(“42 个文件 · 7 个被较新报告覆盖”、“7 个文件 · 覆盖旧报告中的 7 个”);点击跟踪文件行会在完整的树中高亮它所测量的文件并淡化其余文件,直到再次点击。
fuciniCoverage.coverageView.mergedMarks(默认开启)可关闭边框和高亮;统计数保留。
0.2026.68 — 团队席位改为询问邀请码
2026-09-07
修复
- Business 或 Enterprise 用户现在被询问的是邀请码,而不是公司码。 自 9 月 2 日起,许可证服务器拒绝用共享的公司码激活 Business 或 Enterprise 席位:用它认领的席位不指向任何人,因此每个团队席位现在都绑定到收到邀请的邮箱地址,激活席位的是那封邮件中的
FCI1… 邀请码。问卷却仍把该字段标为“公司码”,提示去向经理索取,并显示 FCB1… 占位符——把人们引去粘贴那个唯一已经失效的码,留空时又要求输入公司码。在团队方案中,该字段现在显示为“邀请码”,提示说明码从何而来、共享的公司码无法激活席位,占位符显示 FCI1… 的形式,验证消息则要求输入邀请码。Pro 按其名称询问订阅码。Pro Plus 保持不变:它有意继续使用共享码。全部 17 种显示语言都已采用新措辞。
0.2026.67 — ${workspaceFolder} 在两个路径设置中都可用
2026-09-05
修复
${workspaceFolder} 现在也能在 coverageFile.paths 中使用,正如它在 coverageFile.defaultLocation 中一直可用那样。 这两个设置紧挨着,却只有一个说明了这个变量,于是人们在两处都写了它——而以 ${ 开头的条目并非绝对路径,所以它作为字面量进入基础文件夹下的发现 glob,什么也匹配不到,扩展便报告没有覆盖率。这样的条目现在会先被展开,从而成为绝对路径,然后直接检查是否存在。它在设置中保持原样,选中同一文件时不会以另一种形式再写一次,从 Coverage 视图卸载时也会自动从设置中移除。- 已配置却不存在的跟踪文件现在会在输出中说明。 指向错误路径的条目以唯一无人报告的方式失败:“未找到覆盖率”,与确实没有覆盖率的项目毫无区别。
[FUCINI_DISCOVERY] 现在会列出每个未找到文件的条目及其查找的路径,每个条目只报告一次,而不是每次重新加载都报告;带通配符的条目不予报告,因为它可能在等待构建写入内容。
0.2026.66 — 函数 CodeLens 上的分支、MC/DC 与评分
2026-08-29
新增
- 逐函数的 CodeLens 现在会显示分支、MC/DC 和综合评分,而不只是行数与命中次数——“add: 已覆盖 92% (12/13 行, 52 次命中, 评分 88%, 分支 3/4 (75%), MC/DC 2/3 (66%))”。当跟踪文件对某个函数没有相应内容可报告时——没有分支数据的纯 C 构建,或未用
-fcoverage-mcdc 插桩的构建——对应项会直接省略,而不是显示误导性的 0/0;评分同样只在另外两项至少有一项存在时才显示,因为当行是唯一指标时,它按定义就是镜头开头已经给出的那个数字。
- 来源徽章的悬停提示会说明每个跟踪文件是多久之前写入的,而不只是时间戳——“由 module.info 测量 (2026-08-15 14:32 · 3 小时前),取代了 lcov.info (2026-08-01 09:10) 对它的记录。”最细可到“刚刚”;超过 30 天则只显示绝对日期。
- 跟踪文件 mtime 相同时不再静默处理。 同一构建步骤中落地的两份报告,或 mtime 精度粗于一秒的文件系统,可能为两者都测量过的文件报告完全相同的时间戳——以前胜出者会退回到
coverageFile.paths 的顺序,而屏幕上没有任何说明。现在输出通道会指出这一点:[FUCINI_MERGE_TIE] 会列出两个跟踪文件以及它们共有的文件数量。
- “Show What Changed Since Last Run” 加入了文件行的
… 菜单,在存在可供比较的上一次运行时可用——它就是 Compare with Last Run 已经在计算的那份逐文件差异,只不过针对你询问的那一个文件,而不是整棵树。没有任何变动的文件会明确这样说,而不是什么都不给。
- Tune Colour Scale 命令:在提交之前,先在实时的 Coverage 视图上试用
colorScale.* 的颜色与阈值。每次编辑都直接写入设置——视图本来就会在任何 colorScale/threshold 变更时重绘,所以写入值就是预览——最后用“保留”或“恢复原始值”收尾。
- Problems 面板中的逐文件覆盖率缺口,每个低于
threshold.statement 的已加载源文件一条,由新的 fuciniCoverage.problems.enabled 控制(默认关闭——默认语句阈值为 100)。每条都概括未覆盖的内容(“已覆盖 62% 的行——14 行未覆盖,2 个函数未覆盖”),并附带一个快速修复,会打开已安装的任一聊天扩展(Copilot、Claude Code 等)并给出为该缺口编写测试的提示——逐行的诊断会在真实代码库上淹没 Problems,所以它保持在文件粒度,即读者真正能够采取行动的层级。
修复
- Coverage 视图中缺失/不匹配/已验证文件的原因现在可以选中并复制。 它以前只存在于行的原生
title 悬停提示中,而那是浏览器自己的提示,无法选中;想把确切原因粘贴进错误报告的人只能手动重新输入。现在悬停时会在一个真正的、带样式的面板中显示同样的文字,可以像页面上其他内容一样拖选。普通文件的悬停提示(只有路径)不受影响。
- 参数列表跨越多行的函数不再被误报为已移动。
detectMismatch 允许声明的记录行与实际找到其名称的位置最多相差两行——足以应付签名行、返回类型行和左花括号之间的常见分歧,却不够应付多行参数列表,它可以把两者拉开任意远。void LOG_Emit(...)——七个参数,每行一个——记录在其左花括号所在的第 163 行,却被报告为 "LOG_Emit" is at line 3:那是最近的文本匹配,碰巧是文件头部注释中提到的函数自己的名字,离第 163 行和第 156 行的真实声明都相去甚远。现在,只要名称与记录行之间的每一行都读起来像一个连续不断的声明——没有空行,也没有结束上一条语句或块的行——检查也会接受更靠前找到的名称;参数列表总是如此,而真正移动过的函数几乎从不如此。当不匹配确实存在时,报告的行现在是最接近记录行的匹配,而不总是文件中找到的第一个。
- 来源徽章不再显示“+N”。 在更大范围的运行之上加载某个模块自己的报告,会在文件的徽章上标出模块名称加上还有多少其他跟踪文件也覆盖了它——本意是“这么多份被取代了”,读起来却像“这些报告一致”,而且从树中无法看出它究竟指的是那 n 份中的哪一份。现在徽章只会写出其数字正显示在屏幕上的那个跟踪文件;悬停提示仍会说明哪些被取代了,以及在什么时候。
- 来源徽章不再把它旁边的文件名挤出面板边缘。 徽章的宽度是固定的(
flex: none),所以一旦某一行空间不足,文件名就会吸收全部差额并率先被省略,尽管徽章是两者中不那么重要的那个。现在徽章会在文件名丢失哪怕一个字符之前先让出自己的宽度;本来就优先于文件名的百分比和进度条不受影响。
0.2026.65 — 模块的重新运行取代更大范围运行的记录
2026-08-15
变更
- 模块自己的重新运行会取代更大范围运行对它的记录,而不是叠加上去。 先加载项目范围的报告,再在其上加载某个模块自己的报告,以前会把两者共有的每个文件的命中次数相加——只重新运行那个模块的测试,反而会把一次更大范围、如今已过时的运行早已报告的数字进一步抬高,而不是刷新它们。现在磁盘上 mtime 最新的跟踪文件对它测量的任何文件都完全胜出:语句、分支、声明以及逐文件汇总(分支、MC/DC、函数、函数调用、对象和变异摘要)全部只来自那份报告,无论两个路径在
coverageFile.paths 中处于什么位置——模块的重新运行胜出是因为它确实更新,而不是因为它碰巧最后加载。对某个文件完全不报告语句的跟踪文件——TRACE32 的目标代码导出,或与真实报告并排加载的 Stryker 变异报告——仍然只贡献它实际携带的摘要,不触动较早报告的行/分支细节;那种情形不受影响。这也消除了一个长期存在的缺陷:由两次运行测量的逐文件 MC/DC(或函数/函数调用/变异)汇总,其分母会随分子一起相加,从而低估真实百分比。来源徽章的悬停提示现在写的是“取代了 _ 对它的记录”,而不是“相加”。
修复
- Coverage 视图中的长文件名现在会省略而不是溢出。 行的名称 span 缺少
min-width: 0,而正是这一条声明才能让 flex 项的 overflow/text-overflow: ellipsis 真正生效——没有它,一旦面板窄到一定程度,长名称会保持全宽,从其后的来源徽章、百分比和进度条下面穿过去。
0.2026.64 — 按评分为 Coverage 视图排序
2026-08-01
新增
- Coverage 视图可以按评分排序,而不只是按名称。 每一行本来就带有 WHM 评分和逐指标的细分;但要在大树中找出最差的文件,只能沿着按字母排序的列表往下读。现在 Collapse all / Expand all 旁边的下拉框提供 文件名、综合评分、行、分支 和 MC/DC——除 文件名 之外的每种模式都会把文件夹和文件交错在一起,按该指标自身的百分比从最差开始排列,所以测试糟糕的文件夹会与测试糟糕的文件排在完全相同的位置,而不是被归到一边。对当前指标没有数据的文件(比如一种从不报告分支的格式)会排到底部,而不是被当作 0%。所做的选择会立即写入新的
fuciniCoverage.coverageView.sortBy 设置,因此在窗口重新加载后仍然保留,而不是每次都回到 文件名。
修复
- 多行的函数签名不再被误标为“已移动”。 Istanbul 的
fnMap 给每个函数两个行引用——名称所在的行和函数体开始的行——而解析器为后续在源文本中搜索名称的不匹配检查选用了函数体那一行。对于参数列表超过两行的任何函数(在按 100 列换行的代码库里很常见),名称的真实行离记录行太远,文件便在 Coverage 视图中变暗,并带着错误的“不再与其覆盖率匹配”警告。解析器现在优先使用名称自己的行,这正是不匹配检查一直在寻找的。
0.2026.63 — 每一行都标明它的覆盖率文件
2026-07-20
新增
- 每一行都标明是哪个覆盖率文件测量了它。 在整个项目的运行之上再加载某个模块自己的报告,就是同一批文件被测量了两次,而树中没有任何东西说明某一行读的是哪份报告。当加载了不止一个覆盖率文件时,每个文件行现在都会带上测量它的报告名称——若有多份,则是最近加载的那一份——并为其余每一份加上
+1,悬停提示会列出它们。合并会把它们的命中次数相加,而不是让某一份胜出,提示中也这样说明。只加载一个覆盖率文件时不会绘制任何内容,因为无从区分。
变更
- 扩展自己的页面列出了每一项设置及其真实默认值。 有二十项设置根本没有对应的条目——语言、三个阈值、一个权重以及十五个快捷操作开关——而遥测那一行还写着默认开启,实际上它已关闭很久了。现在有测试会把页面与清单逐项比对,默认值也包括在内。
修复
- 上一个版本加入的、对
files.watcherExclude 之下源文件的重新检查,现在与该检查的其余部分一样遵循 staleWarning.enabled,而不是自己另起的设置名。
0.2026.62 — 不再改动资源管理器,被静默的源文件也会重新检查
2026-07-06
变更
- 不再动资源管理器。 资源管理器中文件旁的覆盖率徽章 默认关闭。那一列属于正在使用它的人——VS Code 会在那里放 git 自己的 M 和 U,而且只放得下一个徽章——覆盖率视图会在为此而设的位置,以相同的数字列出相同的文件。
explorerBadges.enabled 可以原样打开它们。
修复
files.watcherExclude 之下的源文件也会重新检查。 文件与其覆盖率是否仍然吻合,靠保存和文件系统监视来驱动,而监视对被排除的一切保持沉默——尤其是 build/ 之下生成的源文件,那里最难察觉过期的标记。这些文件现在与覆盖率文件按同样的两秒节拍轮询,只有确实变动时才重新读取。超过两百个时,输出会给出说明,而不是把这一拍花在上面。
0.2026.61 — 关于测试运行器只问一次,而不是每次运行都问
2026-06-09
新增
- 关于测试运行器只问一次,而不是每次运行都问。 一个识别出多个运行器的工作区——比如既有 jest 配置又有
go.mod——会在每次 Run Tests with Coverage 前弹出选择框,为一个早已作出的决定索要一次按键。现在这个答案会为该工作区记住,提示中也会说明。Forget the Test Runner 会让它重新询问;而工作区中已不存在的、记住的运行器会被忽略而不是运行。
变更
- 扩展自己的页面列出了每一条命令。 三十四条中有十四条已从表格中流失——它们记录在这里和用户指南中,却不在人们安装前会读的那一页上。现在全部都列了出来,并有测试守着这一点。
0.2026.60 · 构建 3 — 撤销会重新去掉那些圆点
2026-06-01
修复
- 撤销会重新去掉已编辑行上的圆点。 自本次运行以来被编辑过的缓冲区,会在被改写的行上显示灰色圆点,覆盖率也从那些行上撤走。撤销这些编辑并不会让圆点消失:每一次更改都算数,包括把文本改回原样的那一次。现在会记住有人开始输入之前缓冲区的内容,一旦它再次成为那个内容,圆点就会消失,数字也重新适用。
- 发布号会互相校验。 清单、更新日志最上面的条目和发布标签都带着版本与构建号,三者都是手工输入的,而且此前已经出现过分歧。测试会比对它们,并检查条目按从新到旧排列、每条都带着真实的日期。
0.2026.59 — 卸载会一直有效
2026-05-12
变更
- 卸载掉的覆盖率文件会一直保持卸载。 在覆盖率视图里把某个文件移出列表,效力只持续到窗口关闭:在没有任何配置时,发现逻辑会退回到那些众所周知的文件名,第二天早上又找到了
lcov.info;而要说“别用那个”,唯一的办法竟是配置一条路径以便排除其中之一。现在这个决定会为该工作区记住。重新选择该文件,或在 coverageFile.paths 中写上它,就能撤销——设置里点名的文件永远不会被扣下,所以不会在无人开口的情况下少掉什么。
修复
- 已编辑缓冲区的重绘更快了。 被改写行的列表在每次重绘时都要从所有已记录的编辑重新算一遍,于是一个改了整个下午的长文件,为一个自上次按键以来根本没变的答案,付出了行数乘以编辑数的代价。现在每次按键只计算一次。
0.2026.58 · 构建 2 — 测试运行会记住它的覆盖率文件
2026-05-01
变更
- 测试运行会记住它的覆盖率文件,就像手动挑选那样。 Run Tests with Coverage 会加载这次运行写出的文件,然后询问是否把它加入
coverageFile.paths。自 0.2026.56 起,手动挑选的文件本就会自己写进去,而测试运行只是同一件事的另一条路径,因此现在它也照样写入。两者由同一项设置 coverageFile.rememberPicks 管辖;覆盖率视图中该文件所在的那一行,就是把任何一个再移除的地方。
修复
- 后台计时器会随扩展一起停止。 覆盖率文件监视器会随窗口一起释放,但它背后那个两秒一次的轮询,以及任何待处理的源文件复查,都是普通计时器,没有任何东西会释放它们。禁用扩展,或在扩展已禁用的情况下重新加载窗口,都会让它们继续运行,去读一个扩展早已无权过问的工作区。
0.2026.57 · 构建 4 — 带标签的实时预览、绘制的旗帜、选择对话框中的所有格式
2026-04-24
新增
- 实时预览会说明它预览的是什么。 设置面板的预览现在以运行:coverage/lcov.info · 12 个文件开头,当活动编辑器显示的是本次运行覆盖的文件时,还会在运行判定下方显示当前文件:src/a.c及该文件自身的判定。它跟随编辑器和每次加载,依据表单当前的内容——包括未保存的修改。面板位于前台时,在“覆盖率”视图中单击会把预览切换到该文件而不是打开它。
- 选择对话框列出每种格式。 先是所有覆盖率格式,然后是 LCOV;JSON(llvm-cov、Istanbul/nyc、coverage.py、SimpleCov、Coveralls、gcov、xccov、Stryker);XML(Cobertura、JaCoCo、Clover、OpenCover、GNATcoverage、Bullseye、SonarQube、VectorCAST、TRACE32、EMMA、UCIS/UCDB、NCover、dotCover、PIT);Go 覆盖率配置文件;gcov 列表和 Testwell CTC++——
.lcov、.gcov、.txt 和 .coveragexml 不再灰显。
变更
- 状态栏悬停使用颜色刻度。 运行和文件提示中的指标条采用
colorScale.* 的三种颜色,已配置阈值的指标按其自身阈值分级,其余按刻度断点分级;判定标签保留固定的状态颜色。
- 语言设置中的绘制旗帜。 0.2026.56 的旗帜表情在 Windows 上显示为两个字母。下拉列表现在用各语言自己的名称——Nederlands (nl)——并在其下方显示一排小型绘制旗帜,点击即可在下拉列表中选中。
0.2026.56 · 构建 3 — 记住所选文件、“覆盖率”视图中的跟踪文件、语言设置中的旗帜
2026-04-08
新增
- 所选文件会被记住。 用 Pick Coverage File 选择的文件过去只在选择它的窗口中有效。现在它会自动写入工作区设置的
coverageFile.paths——位于基础文件夹之下时为相对路径,否则为绝对路径——因此下一个窗口会加载它,监视器会重新加载它。coverageFile.rememberPicks(默认开启)可为需要者保留旧行为。该设置中的绝对路径条目现在可以指向任何位置的单个文件。
- “覆盖率”视图中的跟踪文件。 在树的上方,每个已加载的跟踪文件占一行,显示其文件数和一个卸载按钮,该按钮会将其从运行和设置中移除;旁边的“选择…”按钮可添加一个。卸载最后一个跟踪文件会清空运行。
- 语言设置中的旗帜。 设置面板的语言下拉列表过去只显示代码;现在每一项都带有旗帜和该语言的自称——🇳🇱 Nederlands (nl)、🇯🇵 日本語 (ja)、🌐 自动。
0.2026.55 — PHP 文件的最后一行不是超出文件末尾的覆盖
2026-03-27
修复
- PHP 文件的最后一行不再算作超出文件末尾的覆盖。 Xdebug 和 PCOV 把隐式的文件末尾 return 记录在最后一个换行之后的那一行,因此 php-code-coverage 会在 251 行的文件上写入“第 252 行”的命中——而不匹配检查曾把这当作矛盾,对每个以换行结尾的 PHP 文件都是如此。现在允许超出末尾换行一行;超出更多,或超出没有末尾换行的文件,仍然是矛盾。
0.2026.54 · 构建 2 — What Community Includes 中的试用行
2026-03-24
新增
- Community 版本中 What Community Includes 里的试用行。 该版本从未有过试用,因此其列表现在以开始 14 天 Pro 试用…开头,打开 Pro 页面;随后 Pro 版本的激活会提议移除 Community 版本。无论如何决定,Community 始终免费。
0.2026.53 — Show Worst-Covered Folders
2026-03-03
新增
- Show Worst-Covered Folders。 Show Worst-Covered Files 的文件夹级对应:每个文件夹按其下所有内容的覆盖率排序,最差的在前,数据来自绘制资源管理器徽章的同一索引;选中后在资源管理器中显示该文件夹。通过
quickActions.worstCoveredFolders 加入状态栏菜单。
0.2026.52 — “问题”面板中的阈值检查
2026-01-23
新增
- “问题”面板中的阈值检查。 开启
compliance.diagnostics 后,每个未达标的 threshold.* 指标在“问题”中显示为一条错误,挂在未达标的跟踪文件上,每次加载和 Check Coverage Thresholds 时刷新,检查通过时清除。 默认关闭,因为出厂语句阈值为 100。
变更
watch.enabled 的说明不再承诺提示。 它仍写着免费层级在重新加载前会被询问——在 0.2026.48 之前如此,之后不再。已在全部 18 种语言中重写。
0.2026.51 · 构建 2 — Run Tests with Coverage
2025-12-08
新增
- Run Tests with Coverage。 从工作区根目录识别 vitest、jest、pytest、go、cargo、dotnet、maven、gradle、phpunit 或 ctest,在终端任务中开启覆盖率运行,无论测试是否通过都加载其写出的内容,并一次性提议将该路径添加到
coverageFile.paths,此后由监视器负责加载。识别出多个运行器时提供选择;不会把你送去看配方。
0.2026.50 — 覆盖率跟随已编辑缓冲区中的文本
2025-10-23
新增
- 覆盖率跟随已编辑缓冲区中的文本。 自加载运行以来对每个打开缓冲区的编辑会被记录,所有读取运行行号的界面——悬停命中次数、MC/DC 条、自上次运行三角形、CodeLens、Next Uncovered——都通过这些记录读取:标记随其所在行移动,并从已重写的行上撤回,那里的小灰点说明原因。
dirtyMarks.enabled 可关闭灰点。
0.2026.49 — 自上次运行以来,在行槽中
2025-09-26
新增
- 自上次运行以来,在行槽中。 上次运行执行过而本次未执行的每一行在编辑器行槽中带有红色三角形,相反情况的每一行带有绿色三角形,各自在概览标尺上有一条色带,悬停时显示命中次数。未变化的行不显示任何内容。
sinceLastRun.enabled 可将其关闭。
变更
- “上次运行”的基线可跨越重启。 开启
history.enabled 后,窗口首次加载时由历史记录中最新的运行充当基线,因此在窗口打开前完成的构建仍会显示它改变了什么——在行槽中和 Compare with Last Run 中。
0.2026.48 · 构建 6 — 处处自动重新加载,标记跟随文件,悬停显示确切差异
2025-09-19
新增
- 对文件的判定在加载后保持最新。 过去文件只在加载跟踪文件时与其覆盖率核对一次,之后再也不核对:编辑一整个下午,行槽仍在绘制一个已不存在版本的数字。现在在编辑器中保存会立即重新检查该文件,而来自编辑器之外的更改——
git checkout、格式化工具、生成器——会稍后从磁盘重新检查。变得与运行结果矛盾的文件会得到标记;把测量版本换回来的检出会清除它。
- 悬停显示确切差异。 当文件不再与其覆盖率匹配时,“覆盖率”视图和资源管理器的提示会精确说明证据:跟踪文件保留了文本时,是该行现在的内容与报告记录的内容;保留了摘要时,是该行与失败的校验和;超出文件末尾的覆盖;不再位于报告所指位置的函数。同样的详情会写入输出通道,每个文件一行,加载结果上的显示哪些就指向那里。
- 资源管理器徽章的开关。
explorerBadges.enabled(默认开启)会隐藏资源管理器中每个已覆盖文件旁的分数、✓ 和 ⚠,以及按指标细分的悬停提示。行槽、状态栏和“覆盖率”视图不受影响。
变更
- 跟踪文件更改时,每个层级都会自动重新加载。 自 2026-09-02 起,免费层级会停在检测到新覆盖率——是否加载?的提示上,而付费许可证则静默重新加载。构建完成,数字是新的,打开了监视的人早已回答了这个问题——因此该提示在每个层级都已移除,解释它的通知也一并移除。
- 产品自行执行的加载不再计入免费层级的每日上限。 监视器的重新加载或启动时的发现并不是有人请求的加载;把它们计入会在一个上午的测试运行中耗尽 Community 安装的额度,然后把旧的运行结果留在屏幕上而无任何提示。上限现在只计量命令和文件选择器。
- 仅时间戳变化不再标记文件。 自本次运行以来 N 个文件已更改的警告取自每个源文件的 mtime,而
git pull 或格式化工具会改变所有 mtime,却不改变测量的内容。该警告连同其状态栏标记已移除。现在只有当文件内容与运行结果矛盾时才称其已更改,状态栏、加载结果和新的输出行 FUCINI_MISMATCH_001 都以此为准。staleWarning.enabled 保留其名称,现在准确描述内容检查。
- 监视
files.watcherExclude 下的文件夹会在输出中说明。 构建输出是人们最先从 VS Code 监视器中排除的内容,此后只有每 2 秒一次的轮询能注意到新的运行结果。输出通道现在会在监视器启动时指出该文件夹和 glob。
0.2026.47 · 构建 2 — 屏幕上显示未匹配路径、首次运行提示、再加两个快捷键
2025-08-09
新增
- 为没有可加载内容的工作区提供首次运行提示。 监视默认开启,启动加载是静默的,因此在尚无跟踪文件的项目中全新安装后什么都不会说。现在第一次空手而归的静默加载会说明这一点 — 仅此一次,永久有效 — 并给出两件值得做的事:手动选择覆盖率文件,或打开配方了解如何用您的工具链生成。手动触发的加载保留其原有消息。
- Toggle Annotated Source 和 Load Coverage 的快捷键。
Alt+A 在源码与其带注释视图之间切换活动标签页;Alt+Shift+R 重新发现并重新加载覆盖率(macOS 上为 Ctrl+Alt+A / Ctrl+Alt+R)。与 0.2026.45 添加的两个一样可重新映射。
变更
- 与工作区中任何文件都不匹配的路径会在屏幕上计数。 无法解析到任何工作区文件的跟踪文件路径会被加载但永远不会点亮 — 这是最常见的“它运行了但什么都没显示” — 而此前唯一的痕迹是输出通道中的一行
FUCINI_REMAP_001,附带能修复它的 pathRemap 规则,无人阅读。加载结果现在会统计它们,哪些? 显示名称和建议规则,打开 pathRemap 设置 则打开放置规则的位置。 - 状态栏菜单的文件选择器会列出它能读取的格式。 其描述仍列着首个版本的五种格式;现在写明二十五种,从 lcov、Cobertura 和 JaCoCo 到 gcov、llvm-cov、TRACE32 和变异报告。
0.2026.46 — 版本冲突的解决办法,以及更安静的上限提示
2025-08-06
变更
- 同时安装了两个版本:用两个按钮代替说明。 Pro 和 Community 同时存在时二者都无法激活 — 它们定义了相同的命令和视图 — 而此前的提示以指引你前往扩展视图收尾。两种解决办法各只需一条命令,因此现在都是按钮:保留此版本会卸载另一个版本并提议重新加载;在扩展中显示两者会在扩展视图中恰好打开这两个。若卸载失败,仍会提议重新加载 — 无论如何,决定哪个版本生效的都是重新加载。
- 使用上限只完整提示一次,之后仅在状态栏显示。 首次达到 Community 上限时值得完整的回答 — 数字、方案、遥测解锁、层级包含内容的列表。十分钟后的第五次则不值得。在同一会话中,再次触及同一上限只会在状态栏显示八秒钟的一行文字,不打断任何操作。输入密钥后重新开始,因为新的许可证意味着新的上限集合。
0.2026.45 — Next / Previous Uncovered 的快捷键
2025-07-26
新增
- Next / Previous Uncovered 有了快捷键。 这是阅读文件时反复按下的两条命令,而此前每次都要打开命令面板并输入名称。
Alt+N 跳到下一个未覆盖区域,Alt+P 跳到上一个(macOS 上为 Ctrl+Alt+N / Ctrl+Alt+P,因为 Option 会输入字符)。两者仅在获得焦点的文本编辑器中生效,并可像其他默认设置一样在 Keyboard Shortcuts 中重新映射。
0.2026.44 · 构建 3 — 免费层级的限制,一份清单
2025-07-24
新增
- Community 包含的内容,作为一份清单。 免费层级限制八项操作并保留十二项功能,而每一项决定都在各自的入口处执行 — 因此了解该层级形态的唯一方式就是在工作中途逐一撞上每一堵墙。新命令 What Community Includes 一次性展示全部内容:每项受限操作及其当日或当月已用量、每项被保留功能的名称,以及解除限制的两种方式 — 付费方案或遥测解锁。
- 凡是产生疑问的地方都会提供。 状态栏菜单中的一项、Coverage 视图许可证横幅中的一个按钮,以及 Community 安装撞墙时遇到的两条消息 — 已达到使用上限和此操作不包含 — 上的按钮。各行来自与门控所执行的同一权限集合,因此清单所说的就是将会发生的。
变更
- 监视模式说明它在免费层级会做什么。 状态栏条目向所有人承诺“自动重新加载覆盖率”,而在 Community 上这是监视器不会兑现的承诺 — 它会注意到并询问。该条目现在如实说明,命令也改名为 Toggle Tracefile Watch,因为“Toggle Watch”从未说明监视的是什么。行为本身未变。
0.2026.43 · 构建 3 — 加载失败会说明原因,隐藏文件会被计数
2025-06-25
变更
- 无法加载的跟踪文件现在会说明原因以及可以尝试的做法。 此前每次失败都产生同一条通知 — “no coverage could be parsed. See output.” — 原因则以代码和解析器消息的形式放在另一个通道中。通知现在以文件开头,并按实际情况归类拒绝原因:不是此扩展可读取的格式、格式不正确(通常是构建仍在写入)、格式正确但未记录任何内容(运行未执行任何插桩代码)或无法读取。解析器自己的话一并附上,多个文件会被计数,输出通道则放在显示输出按钮之后,而不是强制打开。
- 跟踪文件列出但无可测量内容的文件现在会在屏幕上计数。 仅含声明的头文件一直被排除在 Coverage 视图之外,而不是按 0/0 记为 100% — 它的名字只写入输出通道,别处没有。加载结果现在会说明N 个没有可插桩内容的文件未显示,并提供哪些?按钮打开包含名称的通道。
0.2025.42 · 构建 3 — NCover 与 dotCover:无处安放的 .NET 覆盖率
2025-06-08
新增
- NCover 与 JetBrains dotCover。 Coverlet 的 Cobertura 和 OpenCover 早已在此读取,覆盖了大部分新的 .NET 工作,却没有覆盖旧的那一类。仍在写出 NCover 的
Coverage.xml 的构建,或者用 dotCover 测量的团队,磁盘上有本扩展打不开的覆盖率数据。两种格式都不需要转换器:两者本就带有文件名和行号。 - 被排除的 NCover 数据点会被丢弃,而不是记为未命中。
excluded="true" 标记的是被刻意排除出度量之外的代码——带有 [ExcludeFromCodeCoverage] 的成员,或 NCoverExplorer 的过滤器。把它算作未覆盖,会让一次排除反而拉低它本应修正的那个数字。 - dotCover 需要
/ReportType=DetailedXML。 它的另一种 XML 报告是汇总报告,里面完全没有行号;这种报告会被识别出来并被拒绝,同时指出能解决问题的标志,而不是作为未知格式失败。dotCover 只按语句记录是与否,从不记录访问次数,因此一条被覆盖的语句只算一次命中。
0.2025.41 · 构建 4 — 变异测试:PIT 与 Stryker
2025-05-28
新增
- 变异测试。 覆盖率说明某行执行过;变异得分说明该行被改动时有东西失败了。一个测试套件可以执行文件中的每一行,却一个注入的缺陷也检测不出来,而任何覆盖率数字都不会告诉你这一点。PIT 覆盖 Java、Kotlin 与 Scala;Stryker 覆盖 JavaScript、TypeScript、C# 与 Scala。
- 它绝不会与覆盖率取平均。 把「这一行是否运行过」和「改动它时是否有东西察觉」混在一起,两个问题都回答不了,因此它在综合得分中不占任何权重,而是通过
fuciniCoverage.threshold.mutation 单独设门槛——默认是 0,因为变异得分是要提高的目标,而不是第一天就必须跨过的门槛。 - 从未获得公平运行的变异体不计入任何一边。 PIT 的
NON_VIABLE,以及 Stryker 的 CompileError 和 Ignored,都是工具无法制造出来的变异;把它们算作未检测到,等于因一个从未提供给测试套件的缺陷而惩罚它。
0.2025.40 — gcov 的纯文本清单:为早于 GCC 9 的编译器而生
2025-05-16
新增
- 带注释的
.gcov 清单。 gcov --json-format 是 GCC 9 才有的,而嵌入式交叉编译器往往老得多;此前的答案一直是先安装 lcov 或 gcovr。执行计数有五种写法,只有两种是数字,而 branch/call/function 注释归属于相邻行而非自身所在行——现在这一切都被正确读取。 - 调用注释转化为调用点覆盖率。
call N returned X% 正是 0.2025.38 中新增的函数调用指标,这种格式早在此处有地方安放它之前就已经携带这项数据了。
0.2025.39 · 构建 2 — 目标代码覆盖率,连带汇编代码
2025-04-27
新增
- 目标代码覆盖率——构建出的二进制文件中究竟有多少真正执行过。 这是这里唯一完全不从源码测量的指标:它来自调试器对真实目标上指令流的观测,对时序毫无探针影响。它也是对「这覆盖到汇编了吗」这个问题的诚实回答——手写汇编从不被插桩,这里其他任何指标都够不到它。
- 它是一项要求,而不是又一个权重。 目标代码覆盖率包含语句覆盖率——这里的 100% 意味着语句覆盖率的 100%,反过来则不成立——因此它在综合得分中不占权重,而是通过门槛来把关,这正是 DO-178C A 级在 MC/DC 之外所要求的方式。
- 差距本身才是交付物。 行覆盖率 100%、目标代码覆盖率不足 100% 的一次运行,恰好定位出了源码无法交代的编译器生成代码;合规卡片会说「312 字节从未执行,行覆盖率为 100%」,而不是把它埋没成「94%」。反过来的情况——源码未跑完却报告整个二进制都跑过了——会作为矛盾报告,而不是低分。
0.2025.38 · 构建 2 — 函数调用覆盖率,VectorCAST 与 TRACE32 就此完整
2025-04-01
新增
- 函数调用覆盖率——每个调用点是否都被执行过。 这与函数覆盖率是不同的问题:从三个调用点之一被调用过一次的函数,在「函数」下已算完整,而在这里只算完成三分之一。VectorCAST、TRACE32 和 Cantata 都报告过这项数据,只是这个模型此前没有地方安放这个数字。
- 这使 VectorCAST 与 TRACE32 得以完整。 早先的版本刻意拒绝把这些数据折叠进分支覆盖率,因为拉高分支百分比会拉高一个最终进入审计的数字。这两种格式现在都能载入它们一直在发送的数据了。
变更
- 合规门槛与加权得分现在识别七项指标,而非六项——两项新设置
fuciniCoverage.whmWeights.functionCalls 和 fuciniCoverage.threshold.functionCalls,在全部 17 种语言中都有说明。
0.2025.37 — 函数覆盖率不再只是位置,也是计数
2025-02-16
变更
- 即使工具不说明函数在哪里,函数覆盖率现在也会被计入。 TRACE32 的
func 导出、VectorCAST 自闭合的 <method> 元素,以及 EMMA 的 method, % 汇总,三者都明确给出了函数数量,却没有任何位置可以放置 CodeLens——三者此前在读入时都被丢弃了。声明在存在的地方仍是首选来源;在没有声明的地方,现在会以工具报告的数量作为退而求其次的方案。
0.2025.36 · 构建 4 — UCIS 与 Aldec UCDB,新增解析器逐行测试覆盖
2025-02-03
新增
- UCIS 与 UCDB XML——直接来自仿真器的 VHDL 与 Verilog。 有两种文档对应这个名字,项目手头有哪种取决于其仿真器写出的是哪种,因此两者都可读取:Accellera 的标准交换格式
<UCIS>,以及 Aldec 自有的 ux:ucdb(这正是 acdb2xml 从 Active-HDL 和 Riviera-PRO 实际生成的内容)。语句和分支覆盖率会被带入;翻转、有限状态机、断言与功能覆盖率不会被读取,只含有这些数据的文档会明确说明这一点,而不是空载入。 - 开源 VHDL 在这方面本就无需任何东西:GHDL 的 GCC 后端通过
-Wc,-ftest-coverage -Wc,-fprofile-arcs 插桩,结果经由 gcov、gcovr 或 lcov 处理。此版本是为商业仿真器而做的。
0.2025.35 · 构建 3 — EMMA XML,Delphi 终于有了入口
2025-01-22
新增
- EMMA XML。 Delphi 此前完全没有入口——既没有 lcov,也没有 Cobertura——而 DelphiCodeCoverage 用
-xml 写出的正是这种模式。这同时也是相当多老旧 Java 工具至今仍在输出的格式,因此一个解析器就能既打开一门语言,又清理了一段遗留问题。 - 加上
-xmllines,报告就会获得真正逐行的命中计数,于是行号旁的标记就能生效;不加的话就只有一个汇总百分比,此时会得到文件摘要而没有行标记,而不是靠猜测。带点号的包名只有在该文件是 Java 系语言源码时才会变成目录;在 Delphi 报告中,同一个字段其实是单元名,给它加上前缀只会凭空捏造出一个磁盘上谁都没有的文件夹。
0.2025.34 · 构建 3 — Lauterbach TRACE32:每次导出一项指标
2025-01-01
新增
- TRACE32 覆盖率导出。
COVerage.EXPORT.ListModule 写出的是调试器从目标机上的跟踪中测得的数据——不是插桩后的源码,而是处理器在真实目标上实际执行过的指令流,对时序毫无探针影响。一次导出一次只携带一项指标:stmt 变成行覆盖率;dec/cond 变成分支覆盖率;mcdc 变成 MC/DC。载入同一次运行的两次导出,它们会按模块名合并。 - 带有
func、call 或 object 覆盖率的导出此前会按名称被拒绝而不是空载入,并说明文件携带的是哪项指标——如今三者都各有归宿,分别在 0.2025.37、0.2025.38 和 0.2025.39 中。
0.2025.33 · 构建 4 — Testwell CTC++:因文本非空白分隔,按列读取
2024-12-19
新增
- Testwell CTC++ 执行概况清单。
ctcpost 把 MON.sym 和 MON.dat 转换成一份固定宽度的文本清单——这正是在欧洲嵌入式与安全评审中与 Bullseye 分庭抗礼、专测多条件覆盖率的工具。按列位置而非按空白拆分来读取,因为描述本身就可能以数字开头。 - 多条件不是 MC/DC,也不会被当作 MC/DC 报告。 CTC++ 统计的是条件组合,而 MC/DC 问的是每个条件是否被证明能独立影响结果。把这些数字塞进 MC/DC 的门槛后面,会让审计者拿到一个名不副实的数字,所以在这里它们如实呈现为分支覆盖率。
0.2025.32 · 构建 4 — VectorCAST XML,以及被悄悄丢弃的 MC/DC
2024-12-08
新增
- VectorCAST XML。 VectorCAST 一路写到 doctype 都是标准 Cobertura 报告,然后再加上普通 Cobertura 无法表达的属性。这意味着这些文件此前在这里就已经能加载,看起来也很完整——而
mcdcpair-coverage 却在读入时被悄悄丢弃了,恰恰丢给了那批专门为产出它而购买工具的用户。这些配对计数现在得以保留,会汇入 MC/DC 门槛、百分比与综合得分。 - 函数调用覆盖率被刻意地不去近似。 把它折叠进分支覆盖率,会拉高一个最终进入审计的数字;它在等待这个模型为它取个名字,而这在 0.2025.38 中实现了。
变更
- Cobertura 读取器现在会携带方言信息:
<coverage line-rate=…> 是一个格式家族,而非单一格式,正在读取的是哪种方言会随解析过程一起传递,而不是逐个元素去猜测。
0.2025.31 — Ada、Swift,以及会自动重新加载的覆盖率
2024-11-07
新增
- GNATcoverage XML —— Ada 终于可用。DO-178C 航电与 EN 50128 轨道团队正是本产品的安全加权评分与 MC/DC 支持所面向的用户,但在此之前,除非他们的
gnatcov 新到也能输出 Cobertura(而 Cobertura 会丢弃行以下的一切),否则在这里什么都加载不了。gnatcov coverage --annotate=xml 写出的是目录而非单个文件:请加载每个源文件对应的 *.xml —— 打开 index.xml 也会告诉你覆盖率究竟在哪里,而不是含糊地失败。部分覆盖的行仍是一行已覆盖的代码,只是其中的判定未被覆盖:缺口出现在分支与 MC/DC 覆盖率中,也就是它真正所属的位置。豁免区域会成为被排除的行,状态无法判定的义务按未覆盖而非已覆盖计入;使用 --level=stmt+mcdc 时,MC/DC 按条件计数,并驱动阈值与综合评分。
- BullseyeCoverage 与 Visual Studio 的
.coveragexml。Bullseye 是嵌入式与安全关键团队真正持有的商业 C/C++ 工具;运行它自带的 covxml 并加载结果即可。它的主要指标是条件/判定覆盖率而非行覆盖率,两者在这里保持分离——而且单结果探针按 1 而非 2 计分,因此一个已被完整测试的 switch 不会被报告为只覆盖一半。Visual Studio 的 .coveragexml 补全了使用 MSTest 与 vstest(而非 Coverlet)的 .NET 团队:请先用 dotnet-coverage convert 转换二进制 .coverage。两条路径都会保留部分覆盖的行。
- SonarQube 通用覆盖率 —— 以及关于 Xcode 的直接回答。两个元素、四个属性而已,但它之所以重要,是因为几乎任何无法输出其他格式的工具都能输出它:覆盖率工具从未被本扩展听说过的项目,如今也有了入口。它同时也是
xcresultparser 写出的格式,Swift 与 Objective-C 项目正是这样进来的:.xcresult 本身没有解析器,文档现在直接说明原因,而不是让你去猜 —— xccov 报告的是百分比而非逐行数据,而逐行数据的归档一次只能读取一个文件,且该文档从不写明它所描述的文件名。
- gzip 压缩的跟踪文件可直接加载。
gcov --json-format 默认写出 .gcov.json.gz,因此文档所宣传的格式恰恰是大多数人实际上无法加载的那一个。识别依据是文件自身的魔数而非文件名,所以丢掉 .gz 后缀的压缩报告同样可用 —— 并且现在任何受支持的格式都可以以压缩形式送达,不只是 gcov 的那一种。
- Swift 与 Objective-C,来自 Xcode 自己的报告。
xcrun xccov view --report --json 是 iOS 或 macOS 构建无需额外工具即可生成的唯一覆盖率文档。您可以得到按文件的百分比、按函数的执行次数以及 CodeLens。它不含逐行数据,Studio 也不会凭空编造,因此该格式下边栏保持空白 — 编造的边栏标记与实测的无法区分。若需逐行的 Swift 覆盖率,请使用 llvm-cov export -format=lcov 或 slather,两者一直都可用。
- Coveralls JSON — Elixir、Ruby、Python、Rust、Go 和 JavaScript 的上报工具都会写出这种格式。它是逐行的,所以边栏标记可用。
- 活跃天数、门禁拦截,以及汇总所属的许可证 — 为已开启遥测的安装,在每月使用摘要中新增这三项。
已移除
- 不再发送计算机名。
hostname 从一开始就在遥测的基础字段里——位于所有门禁之外,只要开启遥测的人都会发送。计算机名往往就是某个人的名字、一个工位号或客户的项目名,而在使用情况这件事上,它并不能回答操作系统答不了的问题。现在一次安装只由随机的安装 ID 标识。至此,任何指向您或您机器的信息都不会离开这台机器:计算机名、操作系统用户名、主目录、网络接口、文件路径、项目文件夹名,以及已登录的账号标识,都不会。留下的只有操作系统、版本和架构——是哪一类机器,而不是哪一台。
- 遥测数据现在最迟在 90 天内删除。 此前的政策只说“在有用期间保留”,那根本算不上一个期限。
变更
- 付费许可证现在会自动重新加载覆盖率。监视覆盖率文件一直意味着每次构建后都会被问“检测到新的覆盖率,是否加载?”—— 在所有层级都是如此,一个只有一个合理答案的问题,一小时要问好几次。该提示现在是免费 Community 层级的行为;付费许可证直接加载。Community 保留监视、检测以及它一直拥有的提示。
- 不再相符的文件会被指出,并附上证实它的检查 —— 在付费许可证下。检测本身没有被设限,将来也不会:告诉别人他们的覆盖率已不再描述自己的文件,这不是可以卖给他们的东西。Community 仍会得到这一结论,行也仍会变暗。付费许可证增加的是指向 —— 标记、资源管理器徽章,以及背后的行、函数或校验和。
- 遥测发送得更少,并说明它属于谁。每月摘要不再包含文件路径、您项目的文件夹名称或已登录的账户名。功能换遥测的交换现在会询问电子邮件地址,以便我们能告知同意者其安装发送了什么,并在其提出要求时删除。
- 修正了三处设置说明。
watch.enabled、staleWarning.enabled 和 telemetry.enabled 都与代码的实际行为有出入,其中 telemetry.enabled 最严重:它描述的发送内容远多于实际发送的内容。
修复
- 文件选择器不再隐藏它能读取的格式。Pick Coverage File此前只筛选
info、json 和 xml,因此 Go 的 coverage.out 和 gcov 的 .gcov.json.gz(两者都是本扩展能读取的格式)在那个恰恰要求你选择文件的对话框里是灰色的。
- 普通的 Community 安装不再发送其源代码页面。把关带标注源代码样本的检查,把每一个 Community 安装都当作已接受遥测交换,而不只是真正接受了的那些。
- 每次加载只有一条警告,而不是两条 —— 与覆盖率不再相符的文件几乎总是在运行之后也被编辑过,而两者各自单独上报。
- 卸载不再上报操作系统用户名和主目录 —— 对于许可证不允许的人而言。
0.2025.30 · 构建 3 — 你的构建本来就会写出的东西
2024-10-18
新增
- Go 覆盖率配置文件。
go test -coverprofile 是 Go 标准工具链唯一产出的覆盖率输出——没有像 Rust、Dart 和 Elixir 那样可以退而求其次的 lcov——因此 Go 项目没有任何本扩展能读取的东西。配置文件记录的是代码块而非行,块所跨越的每一行都取用它的计数,包括收尾的花括号,与 go tool cover -html 的高亮方式完全一致。coverage.out 加入了默认查找名单,因此未做任何配置的 Go 项目也能像 C 项目找到 lcov.info 那样找到自己的配置文件。
- Clover XML 与 OpenCover XML。PHP 项目手上真正有的是 Clover:
php-code-coverage 能输出 Cobertura,但它的默认格式是 Clover,几乎每一份 phpunit.xml 配置的也是它——于是 PHP 的覆盖率在这里无法读取,而旁边的 Cobertura 解析器却在等待几乎没人生成的输出。Istanbul 的 clover 报告器写出同样的文档,因此这样配置的 Jest 项目同样被覆盖。OpenCover 则是 .NET 这一侧的对应物:C# 与 VB.NET 早已以 Cobertura 的形式抵达,但 Cobertura 会把一个判定压扁成 condition-coverage="50% (1/2)" 这样的字符串,于是究竟走了哪个分支,在解析器看到之前就已经消失。OpenCover 为每个分支保留访问计数——这是「知道这个分支覆盖了一半」与「知道是哪一半」之间的差别。
- coverage.py 的 JSON,以及 gcov/gcovr 的 JSON。coverage.py 的 Cobertura 与 lcov 导出都只能把
# pragma: no cover 所在的行说成已覆盖或未覆盖,因为它们没有表示「刻意排除」的词——而本扩展有,正是它的 LCOV_EXCL 标记所设置的同一个标志。于是 Python 项目的 pragma 在这里的含义,与它们在 coverage.py 自己的报告中一致。而 GCC 的覆盖率此前只能经由 lcov 或 gcovr -x 抵达:为了转换 GCC 早已产出的数据,再跑一次第二个工具。gcov --json-format --stdout 与 gcovr --json 输出几乎相同的文档,如今一个解析器同时读取两者。
修复
- 注释按文件所用的语言来读取。非代码行扫描器是为 C 编写并套用到每个文件的,在本扩展读取的每一种格式都描述 C 系语言时,这是正确的。现在不再如此:C 扫描器遇到
# don't 时,会认为撇号开启了一个字符串,并且永远看不到它闭合,于是把注释行算作代码——数字悄悄地略有偏差,却没有任何东西提示这一点。现在,Python、Ruby、shell、Perl、R、Elixir 和 Julia 使用 #;三种形式都接受的 PHP 三种都用;其余一律使用 // 与 /* */,这也仍是未知扩展名的默认——#define 是代码,把它排除掉会在相反方向上出错。
0.2025.29 · 构建 4 — 每一项设置,都有说明
2024-10-15
新增
- 现在该面板容纳每一项
fuciniCoverage.* 设置,而不只是十三项合规设置。全部五十五项按照与已发布设置参考相同的分节、相同的顺序分组,因此你用来配置的页面与你阅读的页面对某项设置归属何处的看法是一致的。搜索框可按名称、键或说明筛选;跳转列表可在各节之间移动。表单在运行时从扩展自身打包的清单派生——类型、默认值、取值范围、枚举以及每一句文字——因此关于一项设置的信息不会被写下两遍,面板也不可能与它所编辑的扩展产生偏离。
- 说明文字遵循你固定的语言。VS Code 在扩展加载时根据编辑器的显示语言解析清单的本地化,并且没有提供按扩展覆盖该行为的方式——所以在英文编辑器中把
fuciniCoverage.language 设为德语,会翻译除设置之外的一切。由于面板自行读取并解析这些文件,它是唯一能够尊重该选择的地方。
- JSON 架构无法要求的控件。设置架构中没有任何东西把字符串标记为路径,因此原生界面无法为其提供选择器;三项保存目录的设置现在有了 浏览… 按钮。
coverageFile.paths 与 pathRemap 得到了真正的列表编辑器,而不是一个原始的 JSON 文本框;每个 colorScale 颜色则在十六进制值旁获得了色块。
变更
- 保存只写入你改动过的内容,别无其他。只有十三项设置时,保存写入全部十三项几乎无关紧要;到了五十五项,这就意味着一次编辑会把整个命名空间烙进一个原本只有两行的
settings.json。只有值确实变化的设置才会被写入,而等于默认值的设置会清除其覆盖项,而不是重述扩展本就提供的内容。
- 许可证密钥始终写入你的用户设置,该行也这样说明。
license.key 声明为应用程序范围,这意味着 VS Code 只会从那里读取它——把它写入工作区是一次看似成功却什么都没改变的保存。重置现在清除所选范围内的全部五十五个键而不是十三个,因此会先询问。而在面板之外所作的编辑也不再让你失去阅读位置:页面在重绘前会先比较,所以按下保存不会再把五十五行滚回顶部。
0.2025.28 · 构建 3 — 十三行设置,一个决定
2024-10-12
新增
- 合规模式、七个阈值门禁和六个综合得分权重,现在有了一个统一的编辑器。 在设置界面里它们是彼此无关的十三行,实际上却是同一个决定:除非当前生效的模式会读取它,阈值不起任何作用;除非由加权门禁作出判定,权重也不起任何作用。Fucini Coverage: Configure Coverage Compliance & Thresholds... 位于 Coverage 视图标题栏的齿轮按钮上,把三者放在一起,在选择模式的地方就解释每一种模式,并把那些会让门禁形同虚设的配置 —— 未设置任何逐指标阈值的严格模式、阈值为
0 的加权模式、全部为 0 的权重 —— 就在你眼前标为警告。
- 它预览判定结果,并通过 VS Code 写入。 未保存的表单针对已加载运行会得出的 COMPLIANT / NON-COMPLIANT,由扩展自身的合规引擎计算,而不是规则的第二份副本:一个可能与门禁给出不同答案的预览,比没有预览更糟。更改通过常规配置 API 写入
settings.json(用户或工作区,由你选择),因此文件的格式化和注释保留都交给 VS Code;手动修改或在另一个窗口中的修改会回流到打开的表单,无论是否加载了运行数据。无需许可证:Community 与 Pro 拥有同一个编辑器。
修复
- 更新通知的按钮显示为
Download && Install。 双写的与号是助记符转义,在 package.json 标题和模态对话框中是正确的 —— 但通知的操作按钮把标签当作纯文本,因此两个字符被原样打印出来,在全部 17 种语言中,呈现给每一位收到更新提示的用户。
0.2025.27 · 构建 7 — 由你自己选择的交换
2024-09-30
变更
- 遥测 默认关闭。它此前以默认开启的方式发布,理由是评估试用期需要这些数据。但当 Community 层级把开启遥测变成免费解锁全部 Pro 功能的条件时,这一理由便不再成立:交换只有在本人作出选择时才有意义,而无人选择的交换算不上交换。在您开启之前不会发送任何内容,而且无论如何 Community 都会继续以其标准功能集运行。
- 遥测设置说明它的用途,其余以链接给出。它的描述过去逐项列出每个上报字段,这意味着同一份清单存在两份——一份在设置里,一份在隐私政策里——本应永远保持一致,实际却没有。现在它说明开启后能获得什么,并链接到隐私政策查看字段清单,于是需要维护其正确性的清单从两份变成一份。
- 安装本版本会一次性重新开放您的评估期。试用期已经结束的用户将获得全新的 14 天,因为本版本改变了他们此前评估时所依据的条件:在遥测默认开启的情况下度过的试用,并不是对现在所提供产品的试用。它有意绑定到一次性令牌而非版本号——若每个版本都重置,就意味着对于持续更新的用户试用永远不会结束,那不是试用,而是多了几道手续的免费许可。令牌在首次激活时被消耗,随后恢复常规规则。付费许可证不受影响,因为密钥验证在试用被查询之前就已返回;Community 同样不受影响,因为该版本没有可重新开放的试用期。
- 许可证密钥不再以问卷为代价。激活提示、许可证密钥设置和试用结束对话框都把密钥呈现为用回答问题换来的东西。事实并非如此:密钥按申请自动签发,而反馈问卷是自愿的,且完全独立。
修复
- 仍有三处承诺试用“至 2026-12-31”。产品中从未存在这样的日期——试用期为 14 天,按安装分别自首次使用起计算。此前两个版本已在设置描述和 README 中纠正了这一说法;它却在本页自身的评估提示框、用户指南以及许可证工具的 README 中留存下来。三者中最严重的是用户指南:它声称该时间窗“对每次安装、在全球范围内、同时生效(而非按安装倒计时)”,恰好说反了;还称试用结束时覆盖率渲染会暂停,而实际上扩展会转入免费的 Community 层级。
- 遥测通知邮件从错误的域名发出。
From: 标头是 fucini.consulting 上的邮箱,而发送这些邮件的服务器是 fucini.software——正是该设置自身注释所警告的对齐问题,也是让邮件被静默过滤为垃圾邮件或直接遭到拒收的可靠途径。
0.2025.26 · 构建 2 — 变灰,而非消失
2024-08-27
变更
- 报告中列出但磁盘上不存在的文件,现在显示在它应在的位置,以灰色呈现,并说明原因。0.2025.25 不再为这类文件编造位置,这是对的,但仍让它们保留着一个根本算不上位置的相对路径——于是树仍旧用它的首段造出一个项目,某个子模块被删除的三个源文件便坐在一个幽灵般的
app 里,紧挨着它们真正来自的那个子模块。不一致是看得见的,这正是本意,但看见的地方不对,而且没有说明究竟哪里出了问题。
- 现在它出现在度量它的那个项目中,出现在报告给它的文件夹里——以主题的中灰色、斜体绘制,而不是普通的前景色。悬停时会给出它本该所在的路径,并说明那里什么也没有(很可能是在生成报告之后被重命名或删除),以及它的数字仍然计入统计。没有任何内容被丢弃,也没有任何总计发生变化:这一行就是报告对自身的陈述,而变灰正是让它不像一行可以打开的条目。
- 猜测只留在视图之内。文件记录的路径仍然完全是报告所说的那个,因为其余一切都以它为键——外部报告的增强要与它比对,遥测要把它相对化,带注释的视图要打开它——把一个推定位置交给它们,等于用已知换取臆造。只有树把两者合在一起,而且只针对本身不指明位置的路径:一个仅仅是不存在的绝对路径,仍保留报告所说的内容,并就地变灰。
0.2025.25 · 构建 4 — 在哪里度量的
2024-08-07
修复
- 子模块的覆盖率落到子模块真正所在的位置,其行也能打开了。git 子模块会在自己的代码树旁生成自己的报告,gcovr 在其中写下
<source>.</source>——"此文件所在的目录"——下面是 app/Application.cpp 这样的文件名。而那个 . 没有被锚定到任何地方:路径只在合并之后解析一次,那时运行已不知道每个文件来自哪个输入,唯一剩下的基准就是工作区根目录。尝试 <workspace>/app/Application.cpp 一无所获,所有路径都保持相对,覆盖率视图便把它们画成一个名为 app 的项目——名字取自一个从来就不是位置的路径的首段——其中每一行复制和打开的都是没有文件的地方。
- 现在路径在合并之前按跟踪文件逐个解析。相对的
sourceRoot 会锚定到其跟踪文件所在的目录,因此子模块 coverage.xml 旁边的 . 就是指那个子模块。若这样仍找不到源码,搜索会从跟踪文件向上查找——常见的 CMake 布局会把覆盖率写到 build/ 里数层之下,而项目采用哪一种形态在报告中无处记载,所以交给文件系统回答,而不是交给配置。向上查找止于工作区根目录:越过它,一个裸的 src/main.c 就可能解析到布局相同的相邻检出中——一个看起来正确的错误答案。已经是绝对路径且存在的路径原封不动,因此普通的 lcov 运行不受影响。
- 在覆盖率视图中,子模块仍是独立项目。如今在工作区内解析成功的文件,否则会被并入工作区自己的树——子模块的文件夹与父项目的交织在一起,其数字也会计入父项目的总计,仿佛同一份代码库被度量了两次。每个文件都记录自己是从哪个根度量的,视图据此分组,因此子模块即便位于打开的文件夹之内,也保留自己的标题和自己的总计。路径本就是绝对的运行没有这样的根,分组方式与以往完全一致。
- 报告中列出但已不存在的文件,仍会被报告为找不到。不会给它一个它并不在的貌似合理的路径:列出已被删除文件的报告是一份过期报告,把它们画在编造的位置上只会掩盖这一点。每一个都会在输出通道的
FUCINI_REMAP_001 下列出,并附上它本该所在的路径。
0.2025.24 · 构建 3 — 席位为何消失
2024-07-27
变更
- 消失的席位现在会说明原因。 以往每一次回收都显示同一行字 — 您在此方案中的席位已不再有效 — 读起来像是对错的人提出的指责。当团队订阅被下调到少于正在使用的席位数时,现在会在宽限期后释放超出的部分;失去席位的人除了是最久没有使用它的那位之外,什么也没做。当授权服务器有有用的信息可说时,扩展就会说出来:为适应下调后的订阅而被释放的席位会准确说明这一点,并指向管理订阅的人,同时仍然提供申请新密钥 — 因为回来的路是真实的:只要那个人腾出一个席位,池中就有空位。
- 已结束的订阅不再提供按钮。 已失效的订阅无法签发新密钥,因此那条通知上唯一的操作只能失败 — 这读起来像是扩展坏了,而不像订阅已经结束。现在它只说明发生了什么,到此为止。此版本无法识别的任何原因都保留通用措辞:授权服务器持续部署,而已安装的扩展不会,因此遇到陌生的原因是常态而非例外 — 绝不显示原始标识符,也绝不保持沉默。两条新消息均已翻译成全部十七种语言。
0.2025.23 · 构建 5 — 走出扩展
2024-07-17
新增
- 运行结果终于能出去了——多了六种格式。此前只有两个出口:除本扩展外无人读取的 Fucini JSON,以及机器完全无法读取的 HTML 报告。Export Coverage Report... 会打开格式选择器,把当前运行写成按文件的 CSV(行、分支、函数、MC/DC、区域和实例化的已覆盖数/总数/百分比,最差的排在最前,并带一行
TOTAL)、按函数的 CSV(命中次数、是否执行过、其中未覆盖的分支、MC/DC 对)、可粘贴进拉取请求的 Markdown 摘要、LCOV 跟踪文件、Cobertura XML、SARIF,或供 README 使用的自包含 SVG 徽章。它出现在命令面板、Covered Files 视图标题栏中 Generate Full HTML Report 旁边,以及开启 quickActions.exportReport 后的状态栏快捷菜单里。
- 它现在是转换器,而不只是查看器。扩展已经能读取 lcov、llvm-cov JSON、Cobertura、JaCoCo、Istanbul/nyc 和 SimpleCov;有了 LCOV 与 Cobertura 写入器,它也能反向输出。加载一份 JaCoCo 报告,或多份合并为一次运行的报告,即可输出 genhtml、Codecov、Coveralls 和 SonarQube 都接受的那一个跟踪文件——或者 Jenkins、GitLab 和 Azure DevOps 可原生读取的 XML。两者都会往返经过扩展自己的解析器,行范围按行展开,因此写出的
LF/LH 与屏幕上的百分比一致,而不是近似值。
- 每个写入器都说明自己丢弃了什么。除 CSV 外全部有损,而且是无声的:MC/DC、代码区域和 C++ 实例化在 LCOV、Cobertura 或 SARIF 中都没有对应表示,而 Cobertura 只记录一行中有多少条件被覆盖,不记录是哪一个分支。承载全部测量结果的格式,仍然是 Fucini JSON 和两个 CSV。在 CSV 中,本次运行不具备的指标其单元格留空而不是填零——空单元格表示"该工具未报告分支数据",
0 则表示"没有命中任何分支",事后电子表格无法区分二者。任何会被电子表格当作公式执行的内容——以 =、+、- 或 @ 开头的字段,也就是每一个带 npm 作用域的路径——都会在写出前加引号并解除威胁。
- SARIF 标注差异;徽章无需联网。未覆盖范围以
note 级别报告,而非 warning:未覆盖的代码说明的是测试套件的情况,而代码扫描会把警告视为应当阻断的问题——真正阻断的关卡仍是 Check Coverage Thresholds。徽章在本地绘制,而不是从 shields.io 获取,因此在隔离网络或本地部署的仓库中同样可用,其颜色取自与边槽和状态栏相同的 colorScale。在免费的 Community 版中选择器可以打开,两个 CSV 均可使用,与 Export Fucini JSON 一样每天上限 20 次;交换格式属于付费层,仍是这一版本一贯的界线——读取自己的数字免费,喂给 CI 流水线则不免费。
0.2025.22 · 构建 3 — 无可度量
2024-06-24
修复
- 没有任何可插桩内容的文件,不再被报告为 100% 覆盖。 只含声明的头文件——原型、一个宏、包含守卫——没有函数体,编译器不会为它生成任何覆盖率映射,而任何用零除以零的计算都会得出 100%。它就以绿色排在树里,紧挨着真正被测试过的代码。两个读取器现在都以工具自身的汇总作为该文件对自己的陈述——lcov 中的
LF/FNF/BRF,llvm-cov JSON 中的 summary 块——所有汇总均为零的文件会被排除在本次运行之外,而不是被打分。汇总之下的逐行记录被刻意忽略:宏的展开会归属到定义它的那一行,而计数属于在另一个文件中使用它的那一行;正是这条借来的行,让这样的头文件看起来像被测量过。运行总计也不再包含它,因此首要数字略有下降,却真实得多。每一个被排除的路径都会在输出通道中列出;若报告中所有文件都只含声明,则全部保留。
变更
- Pick Coverage File现在会追加到已加载的内容,而不是替换它。 按模块各写一份报告的构建没有单一文件可固定,而选择第二个模块的报告会悄悄卸载第一个。对话框现在可一次选择多个文件,每次选择都会加入集合,所选的全部内容合并为一次运行——在面板中按各自项目的名称分别绘制。监视覆盖全部文件,重新生成某一份报告也不会再把其他文件从屏幕上移走。Show Loaded Coverage Files 的末尾新增 卸载已选择的文件,可回到常规的自动查找。
- 支持有了产品自有域名的邮箱地址:
support@fucini.software。 当激活无法自行完成时,许可面板和请求码提示此前给出的是 fucini.consulting 地址——与扩展中其他所有链接都不同的域名,读起来像是另一家公司。license@fucini.software 保持不变:它负责发送密钥,并不是用来写信的信箱。
0.2025.21 — 这是谁的 src
2024-06-21
新增
- Coverage 视图中的每棵树现在都会说明它属于哪个项目。 0.2025.19 让合并运行按项目各得一个具名区块,但普通运行画出的仍是一棵光秃秃的树 —— 于是一个被裁剪到自身文件夹的工作区打开时只见
src,上方没有任何东西说明这是哪一个 src。现在每棵树都带着自己的根:通往项目的各级文件夹用弱化的颜色,项目自身的文件夹紧随其后、以完整颜色显示。被裁剪到工作区文件夹的树依然会说明它被裁剪到了哪里,合并进同一次运行的两个代码库也绝不会被读成一棵树。它是标题而不是行 —— 那里没有可展开的东西,下方的文件夹折叠方式与以前完全一致。面板较窄时,前面的目录先行缩短,因此真正为项目命名的那个文件夹最后才消失,悬停即可看到完整路径。
0.2025.20 · 构建 7 — 你期待的那个菜单
2024-06-08
新增
- Coverage 视图的每一行都有资源管理器自己的右键菜单。此前右键点击文件或文件夹打开的是 Webview 自带的剪切/复制/粘贴——三个在这一行上无事可做的条目。现在打开的是 VS Code 真正的菜单:打开、Open to the Side、打开方式…、Reveal in Explorer View、Reveal in File Explorer、Open in Integrated Terminal、文件夹上的在文件夹中查找…,以及Copy Path / Copy Relative Path——在两种写法确实不同的 Windows 上,正斜杠版本就排在旁边。
⋯ 按钮及其菜单保持不变,并作为新菜单的最后一项。
变更
- 覆盖率文件中没有数据的指标不再参与判定。构建里没有 MC/DC,却配置了 MC/DC 阈值,这原本会算作未通过——于是一个在构建实际测量的每项指标上都拿到 100% 的文件,却被标上"5 项中达成 3 项",对照的是这份覆盖率文件永远不可能跨过的门槛。没有数据的指标现在会在所有形成判定的地方被跳过:单文件状态栏、整次运行的卡片、带注释源代码上方的横幅,以及 HTML 报告。Check Coverage Thresholds仍会明确点名缺失的指标——那才是它该出现的地方。
- 没有任何可测量内容的文件不再出现在 Coverage 视图中。只有声明的头文件、只做再导出的文件、只有类型的模块:你写任何测试都不会改变它们的数字,打开后也根本看不到指标。0.2025.19 中它们显示为一个破折号;现在则干脆不列出,因此变空的文件夹也一并消失。若一次运行中没有任何内容可测量,仍会完整列出。
修复
- 盘符仍可能出现在树的顶端。当覆盖率数据的路径不在已打开的工作区之下时——来自其他项目的合并覆盖率文件,或者没有打开任何文件夹的窗口——树会从
W: 开始,在 Linux 和 macOS 上则是从一个完全没有名字的行开始:一行,只有一个子项,展开也毫无意义。现在无论路径是什么样子,都不会再绘制文件系统根节点,而每一行仍然带着自己真实的绝对路径,供菜单和编辑器使用。
0.2025.19 · 构建 6 — 只要路径,不要开场白
2024-05-16
新增
- Coverage 视图中每个文件和文件夹都有了行菜单。 行尾的按钮可以按编辑器、终端或提示词可能需要的四种形式中的任意一种复制该路径 —— 绝对路径或相对于工作区的路径,系统原生分隔符或正斜杠 —— 并提供Reveal in File Explorer和Open in Integrated Terminal,对文件而言终端会在其所在目录中打开。正斜杠条目仅在与原生形式不同的情况下才会列出,因此在 Linux 和 macOS 上菜单少两项。以前复制一个路径意味着要在资源管理器里再找一遍同一个文件。
- 树上方新增全部折叠与全部展开按钮。 先全部折叠、再打开你关心的那一个文件夹,是穿过大型树最快的方式,而此前每个文件夹都要点一次。用这种方式折叠的内容会像手动关闭的文件夹一样被记住,重新加载不会将其撤销。
- 跨越多个项目的合并运行现在会把每个项目分开绘制,各自以自己的名称标示。 以前,合并来自第二个代码库的跟踪文件会把它的文件夹挂在与工作区相同的树上,于是
src 出现两次却不说明原因,两个项目的目录还按字母顺序交错在一起。现在每个项目都有自己的具名区块,之间以横线分隔,工作区自身的排在最前。只覆盖单个项目的运行保持不变,也不带标题 —— 没有别的项目可与之区分。
修复
- 没有任何可执行内容的文件被报告为覆盖率 0%。 只包含
export * 再导出、或只包含类型声明的模块,编译后没有任何覆盖率工具能够度量的东西 —— 因此跟踪文件中不会为它记录任何语句。Coverage 视图把这算作 0%,将该文件标红,与真正未经测试的代码并列,可根本没有东西可以为它写测试;与此同时,资源管理器却给同一个文件打上绿色的 100%,因为空的总数读起来就是“无中之全部已覆盖”。这两个数字都不真实,如今两个都不再显示:面板中的行改为一个短横线和虚线轮廓,并用提示说明原因,资源管理器的徽章则直接省略。只包含这类文件的文件夹同样不予评分。对确实度量过的内容为 0% 的文件仍然显示 0% —— 短横线表示“无可度量”,而不是“度量了却没覆盖”。 - 来自合并项目的行指向了错误的位置。 它们的路径是按工作区根目录拼出来的,而不是它们自己的根目录,因此对于工作区之外的文件,行菜单复制的 —— 以及“Reveal in File Explorer”打开的 —— 是文件从未待过的路径。现在它们带的是自己真正的根目录。
变更
- Coverage 视图不再绘制工作区根目录。 树以前从文件系统根目录开始,逐层经过项目上方的每一个文件夹 —— 驱动器、存放你项目的目录、项目本身 —— 之后才轮到真正属于你的第一个文件夹。每一行都因此多出好几级缩进,说的却是窗口标题早已说过的话。路径现在从工作区文件夹开始。行菜单复制的、编辑器打开的,仍然是完整的绝对路径。
0.2025.18 · 构建 4 — 折叠后保持折叠
2024-04-30
修复
- 在 Coverage 视图中折叠的文件夹,每次重新加载都会再次展开。 监视默认开启,因此重新生成覆盖率的构建会重绘面板——而由于每个文件夹都以展开状态绘制,折叠只能维持到下一次构建。在大型树中,这意味着每小时要把同样的操作重复好几次。现在面板会记住您关闭了哪些文件夹,并让它们保持关闭。在之后的运行中首次出现的目录仍会像其他目录一样以展开状态显示:被记住的是有意关闭文件夹这一操作,而不是默认状态。
- 关闭遥测并不能阻止卸载时的 ping。 该 ping 由 VS Code 在卸载时运行的一个独立小脚本发送。它无法访问 VS Code API,也读不到您的设置,因此唯一能告诉它不要发送的,是扩展在遥测开启期间写入的一个文件不存在——而在您关闭遥测时,这个文件从未被删除。任何曾经开启、后来又关闭遥测的人,在卸载时仍会发送其操作系统用户名、主机名和主目录。现在,遥测一关闭,该文件就会被删除。
- Pro 续订可能会针对您刚刚替换掉的密钥报告成功。 静默续订会读取两次已配置的密钥:一次用于决定是否续订,之后再读一次用于决定是否显示消息。如果在续订进行期间粘贴了新密钥,第二次读取看到的就是另一个密钥,而“您的 Pro 订阅已续订”这条消息描述的却是已被替换的那个。现在只读取一次密钥。
变更
- 扩展中的每个模块现在都有自己的测试覆盖。 对一个全部工作就是告诉您测试实际覆盖到哪里的工具来说,这件事值得认真做好:54 个源文件中有 53 个在语句、分支、函数和行上均达到 100%,剩下的那个——VS Code 连接层——达到其函数的 95%。编写这些测试时发现了上述问题,另外还有二十多个永远不可能执行的防护:它们是位于已经排除了自身的检查之后的回退逻辑,看似安全网,实则什么也接不住。这些代码已被删除,而不是用一个不可能失败的测试来掩盖。
0.2025.17 — 在值得回答的时刻询问
2024-04-27
变更
- 可选的反馈问卷现在会等到你真正使用过扩展,并在更合适的时刻询问。 它此前按安装以来的自然日计数,衡量的是你多久以前安装了它,而不是你是否见过它工作——一个放置一个月未动的安装,会被要求评价一款从未向它展示过任何内容的产品。现在除了经过的时间,还需要真实的覆盖率加载,并且不再在编辑器启动时出现:它会等到一次加载成功之后。一年后还会有第三次也是最后一次邀请,因为同一季度内的两次会把当时恰好很忙的人永久排除在外。
- 荷兰语翻译不再使用敬语。 它通篇以「u」称呼你,对开发者工具而言显得生硬,也与产品其余的语气不符。所有荷兰语文本现在都使用「je」——逐句重写,因为这一改动会连带改变动词形式。
0.2025.16 — 是代码,不是公司
2024-04-23
变更
- 激活表单向独立开发者索取“company code”。 个人购买 Pro 或 Pro Plus 时,代码来自你自己的订阅——背后并没有公司,被问及公司只会让人以为走错了表单。该字段在 Pro 和 Pro Plus 中现已改为 Subscription code,在确实由团队共享的 Business 和 Enterprise 中仍为 Company code。下方的提示原本就按方案分别撰写,只有标签一直沿用通用说法。
0.2025.15 · 构建 3 — 按你设定的标准衡量
2024-03-25
修复
- 生成的 HTML 报告无论你设定了什么阈值,都按 100% 来判定代码。状态列把每个指标与一个隐藏的 100 相比较,于是把门槛设为 80 并已达标的项目,会在同一次运行、同一页面上看到绿色的 COMPLIANT 横幅,正好压在一列红叉之上。指标图例也一样。二者现在都使用你配置的阈值;在没有阈值适用之处,显示一个淡化的短横,而不是凭空给出判定。
- 合规横幅宣称的比它实际检查的更多。它始终写着"已满足所有已配置的阈值",在只检查加权分数的默认模式下也是如此 —— 于是一次运行可以宣称所有阈值均已满足,而下方表格里明明有一个未达标。现在每种模式都会说明它真正应用了哪条规则。
- README 说该扩展"可免费使用至 2026-12-31"。产品中并不存在这个日期。此前的版本已在设置说明中更正了这一说法,却漏掉了 README —— 那是任何人在 Marketplace 上最先读到的内容。现在它写的是真实情况:自首次使用起 14 天试用,之后进入免费的 Community 层级,没有任何"到期即停"的日期。
0.2025.14 — 一眼分得清
2024-03-15
变更
- 两个版本在 Marketplace 中不再一模一样。Pro 与 Community 从同一套源码构建,而在此之前这也包括图标——于是两条列表就是同一张图配不同标题,并排出现在同一批搜索结果里。现在每个版本都有自己的图标:同一幅图案,底部加一条色带,Pro 为青绿色,Community 为石板灰。图标放大显示时靠文字区分;在搜索结果行里文字太小读不出来,于是改由颜色承担这件事。
0.2025.13 — 就在你所在的地方可用
2024-02-26
修复
- 打开带注释视图后,不再无法再次打开它。带注释源码面板是 Webview 而不是文本编辑器,因此只要它拥有焦点,扩展就看不到"当前文件"——此时运行 Open Annotated Source 会回答"请先打开一个已加载覆盖率的文件",而对方正看着一个明明有覆盖率的文件的带注释视图。现在它会回退到你眼前这个面板背后的文件。同一段判断还悄悄跳过了第二次运行本就为之存在的重新检查:配置了 llvm-cov HTML 报告时,正是再次运行命令才会把面板切换到该报告自己的页面——所以如果你的覆盖率构建是在打开面板之后才完成的,从面板本身根本无从取用。
0.2025.12 · 构建 2 — 说真话
2024-02-15
新增
- 付费 Pro 订阅现在会自动续期。 每个激活密钥的有效期恰好等于实际付费的周期。团队方案会在下次签入时获取续期后的周期,但个人版 Pro 从不签入 — 它完全离线工作 — 因此没有任何机制把续期送达,月付订阅者的密钥无论多按时付款都会大约每月失效一次。现在扩展会在自身到期前后的几天内悄悄申请新密钥,并且仅在持有证明订阅已付款的激活码时才会这样做。在此期间离线不会有任何损失:密钥会一直有效到真正到期,之后的下一次尝试即可恢复。
- 从购买邮件激活只需一次点击。 链接会把方案和激活码直接交给扩展,无需打开 VS Code、查找命令并手动粘贴。占用席位前始终会请求确认。手动输入激活码仍与之前完全一样 — 链接只是捷径,绝非唯一途径 — 并且在 Community 版本中同样有效。
修复
- 某项设置的说明声称扩展"在 2026-12-31 之前免费"。 产品中根本不存在这个日期。实际情况是自首次使用起为期 14 天的试用,之后扩展会转入免费的 Community 层级。现在说明就是这么写的,所有语言均已更正。
- 阈值设置不再提及更改其默认值的那个版本 — 句子中间的版本号回答的是没有人在阅读设置说明时会问的问题。
- 多条翻译后的说明提到了任何翻译版 VS Code 都不会显示的命令名。 它们用英文名称指代激活命令,于是不使用英文工作的人会在命令面板中寻找一个根本不存在的字符串。
0.2025.11 · 构建 3 — 只统计该统计的
2023-12-26
修复
- 没有 MC/DC 判定的项目可能显示 0% 的总覆盖率。某些工具即使没有可测量的内容也会报告 MC/DC 部分,而这被理解为“已覆盖 0%”,而不是“没有需要覆盖的内容”。由于任何一项指标为零时总分就会降为零,一个完全覆盖的项目也可能显示 0%。没有可测量内容的指标现在完全不计入评分,其所在行也不再显示,而不是出现“0 / 0 条件已覆盖”。
- 许可状态现已翻译为全部 17 种语言。此前始终是英文,而且它嵌入在已翻译的句子中,因此状态栏、通知和“已覆盖文件”面板中会出现半中半英的一行。
- 带注释的源代码视图和覆盖率悬停信息也已翻译——合规明细表、导航按钮及其提示,以及分支和 MC/DC 的详细信息。
变更
- 付费 Pro 订阅现在可以使用自己的激活码激活。密钥申请中的方案列表新增了 Pro 选项,随 Pro 订阅提供的激活码终于有地方可以填写。个人 Pro 密钥仍然完全离线工作,激活后不会与服务器通信。
- 活动栏图标更大、更易辨认,与内置图标并排时也清晰可见。
- 切换到 Community 版现在从 fucini.software 安装。此前会尝试通过 Marketplace,而 Community 版并未在那里发布,因此切换后可能导致完全没有安装任何扩展。
0.2025.10 · 构建 5 — 更平缓的落地
2023-12-08
变更
- 已失效的订阅现在会落到免费层级 —— 个人激活密钥用尽后,扩展会无休止地提示您续订。选择不续订是订阅的正常结束,而不是故障,因此现在它会转入永久免费的 Community 层级。团队方案是有意不受影响的:已过期的 Pro Plus、Business 或 Enterprise 密钥仍会报告为已过期,因为那种情况下需要由管理员续订,而悄悄把整个公司降到免费层级会掩盖这一点。
修复
- 关闭遥测现在在所有情况下都会被遵守。 当扩展的内部详细诊断模式开启时,有一条代码路径可能会跳过该检查。该模式在每个已发布的构建中都处于关闭状态,因此从未有任何发行版出现过这种行为,但现在该检查是无条件执行的。
- 设置立即生效,无需等待重新加载。 修改路径重映射、注释排除、git-diff 过滤或被排除文件的合计,现在都会立刻重新加载覆盖率 —— 尤其是路径重映射,因为您正是在路径对不上时才会用到这项设置。
- “Unlock Full Features”和“Switch to Community”可能中途停止,而且不会给出任何提示。两者现在都会执行到底。
- 您的激活密钥会保持绑定到同一个机器标识。 在某些环境下,该标识此前可能在会话之间被重新生成,从而使已签发的密钥失效。
0.2025.9 — 完整翻译
2023-12-02
新增
- 全部 17 种已发布语言的完整翻译 —— 大约一百条较新的界面文本,包括激活与许可对话框、可选的反馈问卷、Community 解锁流程以及自更新通知,在所有非英语语言包中仍会回退为英文。现在全部 17 种语言都已覆盖该扩展完整的运行时界面。
变更
- 对源码注释、构建脚本文档和打包文件清单进行的内部整理。扩展中随附的文件集合未发生变化;没有任何功能性或行为上的改动。
0.2025.8 — 两个版本不会再冲突
2023-11-20
修复
- 同时安装 Pro 版和 Community 版可能导致其中之一在启动时崩溃 —— 它们注册了相同的命令和相同的覆盖率文件视图。现在会提前检测:如果另一个版本也已安装,激活会干净地停止并给出提示,告知您卸载其中之一,而不是出现无法解释的激活失败。
0.2025.7 — 内部整理
2023-10-30
内部整理版本;无功能性变更。
0.2024.6 — Community 层级与团队方案
2023-10-17
一个永久免费的层级、共享席位池的团队方案,以及扩展的独立 Community 版本。
新增
- 永久免费的 Community 层级 —— 14 天试用结束后不再直接中断,扩展现在会转入 Community:除 MC/DC 之外的全部功能、每月可有限体验的 Full HTML Report 与常驻的 Annotated Source 视图、对少数可自动化操作设置的宽松每日上限,其余一切均不受限制。
- 免费解锁全部功能 —— 新增的“Unlock Full Features”命令以详细的使用遥测换取完整、不受限制的授权,并可随时撤销。可选的应用内反馈问卷则会奖励一个为期 30 天的全功能密钥,没有任何附加条件。
- 团队方案:Pro Plus、Business 和 Enterprise —— 这些方案共享一个席位池(一个公司代码加上席位数量),而不是每台机器一个密钥;后台签到会保持席位授权为最新状态,并自动标记被回收或缩减的席位。
- Fucini Coverage Studio Community —— 一个由相同源码构建的独立专属发布版,其中付费层级的试用/激活/团队方案代码是真正不存在,而不仅仅是被隐藏。请参阅下载页面。
变更
- 在 Community 基线中,Full HTML Report 的生成以及常驻的 Annotated Source 视图(普通视图和并排视图)现在属于付费层级功能 —— 仅保留原地切换视图,并与以往一样按月限量。解锁后仍可获得全部功能。
- Community 层级的用量上限警告现在会在同一个提示中给出两条前进路径:查看付费方案,或通过遥测解锁。
修复
- 详细的、可能具有身份识别性的遥测数据(操作系统用户名、主目录、CPU/内存配置、网络接口,以及完整的报告/源码内容)现在只可能由 Community 或以遥测换取的免费授权发送 —— 无论本地遥测设置如何,付费的 Pro/Pro Plus/Business/Enterprise 许可证都绝不会发送这些数据。
- 已经在运行早期版本的安装,不会再仅仅因为升级就被赋予一个全新的试用期 —— 如果其旧的试用期已经用尽,现在会正确地转入 Community 层级。
- 更新通知、下载进度和错误消息现在显示简明的
Major.Year.Minor 版本号(与 VS Code 扩展视图中显示的一致),而不是泄露内部构建号,例如显示 0.2024.6 而不是 0.2024.6.2。
0.2024.5 — 精细化的许可证密钥
2023-09-03
激活密钥现在可以分别限制各项功能,许可证管理员也可以从管理面板手动签发一个精细调整过的密钥。
新增
- 按功能设置用量上限 —— 激活密钥现在可以对每项功能/操作分别设限(例如,HTML 报告导出每月 1 次),而不是共用一个覆盖率加载上限。现有密钥继续照常使用。
- 手动签发密钥 —— 许可证管理员现在可以针对在编辑器内问卷之外收到的请求码手动签发密钥,精确选择要授予的功能、有效期以及各功能的上限;如果提供了邮箱地址,密钥会自动通过邮件发送。
0.2024.4 — 更新源的可靠性
2023-07-24
修复了一个缓存缺陷,该缺陷可能导致某些企业代理后的用户看不到新版本。
修复
- 自更新源的可靠性 —— 更新清单现在会带着严格的 no-cache 响应头提供,因此位于 fucini.software 与读取方之间的缓存代理再也无法返回隐藏新版本的陈旧副本。
0.2024.3 — 小修复与性能改进
2023-07-13
一次小型维护发布:包含一些小的错误修复和性能改进。
修复
- 错误修复 — 小的错误修复和稳定性改进。
- 性能 — 覆盖率加载与渲染方面的小幅性能改进。
0.2024.2 — 自动激活
2023-06-20
激活密钥现已自动签发并应用——无需再等待邮件。
评估版本。每次安装均可获得自首次使用起计算、全功能解锁的免费 14 天试用期;之后会转入免费的 Community 层级,而不是停止工作。许可证密钥可按申请自动签发。了解更多 →
变更
- 自动激活 — 现在请求密钥会提交一份简短问卷,并自动将收到的密钥应用到您的设置中,无需通过邮件往返。
- 更快的续期 — 续期请求只询问使用情况和期望问题;之前请求中的联系方式会被重复使用,不会再次询问。
- 固定的评估窗口 — 试用期现在对所有人统一持续至2026年12月31日,取代此前按安装时间单独倒计时的14天试用期。
- 本地化的激活流程 — 续订问卷和激活确认信息现已翻译为所有支持的 18 种语言,与扩展的其余部分一致。
0.2024.1 · 构建 3 — 更智能的更新检查
2023-06-02
该扩展现在会同时检查 fucini.software 和 VS Code 应用市场的更新,并始终提供较新的版本。
修复
- 双来源检查 — 现在会同时查询 fucini.software 和 VS Code 应用市场,并提供较新的版本。
0.2024.0 — 首次发布
2023-04-26
Fucini Coverage Studio 的首个公开版本 —— 原生 VS Code 覆盖率工具,可接收行业标准跟踪文件,将其规范化为统一的规范模型,确定性地合并多次运行,并通过 VS Code 内置的 Test Coverage API 进行报告。
新增
- 多格式接入 —— LCOV、llvm-cov JSON、Cobertura XML、JaCoCo XML、Istanbul/nyc 和 SimpleCov JSON,自动检测。
- 确定性合并 —— 将多个跟踪文件合并为一次运行,并记录来源信息,不受加载顺序影响,结果始终稳定。
- 原生覆盖率界面 —— 行/分支/函数装订线标记、概览标尺,以及内置的 Test Coverage 面板。
- MC/DC 覆盖率 —— 悬停时按判定分解显示,并提供可选的彩色边距装订线。
- 综合评分 —— 基于 SIL 加权的加权调和平均值,涵盖行、分支、函数、区域、MC/DC 和 C++ 实例化。
- 合规判定 —— 支持
strict、whm、both 和 either 模式的 COMPLIANT / NON-COMPLIANT 门控。
- 路径重映射、差异覆盖率、Explorer 徽章以及全局状态栏。
- 编辑器内分析 —— 函数 CodeLens、分支悬停提示、死代码警告、过期覆盖率警告,以及 Next/Previous Uncovered。
- 已覆盖文件视图、HTML 报告、历史记录与趋势、watch 模式以及 Fucini JSON 导出。