Skip to content

Commit 3a6dad0

Browse files
committed
Drop leading / from project_filename
The paths returned by `SourceFile#project_filename` are described as "relative to the projects directory," but they began with a `/` because stripping `SimpleCov.root` left the separator behind. Consumers of `coverage.json` (and the `minimum_coverage_by_file` error line) can reasonably interpret a `/`-prefixed path as absolute and resolve it incorrectly. Strip the leading `/` or `\` in `project_filename`, adjust the built-in regex profiles (`hidden_filter`, `test_frameworks`, `rails`) and `StringFilter#segment_pattern` to match segment boundaries without requiring a leading slash, refresh the JSON fixtures and specs, and remove the now-unnecessary `shortenFilename` helper from the HTML frontend (which also sidesteps any Windows backslash concern). Anchored user-supplied RegexFilters that relied on a leading `/`, like `%r{^/lib/}` need to be rewritten as `%r{\Alib/}`. Noted in CHANGELOG.
1 parent f953a80 commit 3a6dad0

18 files changed

Lines changed: 39 additions & 43 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Unreleased
55
* JSON formatter: group stats changed from `{ "covered_percent": 80.0 }` to full stats shape `{ "covered": 8, "missed": 2, "total": 10, "percent": 80.0, "strength": 0.0 }`. The key `covered_percent` is renamed to `percent`.
66
* JSON formatter: `simplecov_json_formatter` gem is now built in. `require "simplecov_json_formatter"` continues to work via a shim.
77
* `StringFilter` now matches at path-segment boundaries. `"lib"` matches `/lib/` but no longer matches `/library/`. Use a `Regexp` filter for substring matching.
8+
* `SourceFile#project_filename` now returns a truly relative path with no leading separator (e.g. `lib/foo.rb` instead of `/lib/foo.rb`). This also removes the leading `/` from file path keys in `coverage.json` and from the filename in `minimum_coverage_by_file` error messages. Anchored `RegexFilter`s that relied on a leading `/` (e.g. `%r{^/lib/}`) should be rewritten (e.g. `%r{\Alib/}`).
89
* Removed `docile` gem dependency. The `SimpleCov.configure` DSL block is now evaluated via `instance_exec` with instance variable proxying.
910

1011
## Enhancements

features/minimum_coverage_by_file.feature

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Feature:
1818

1919
When I run `bundle exec rake test`
2020
Then the exit status should not be 0
21-
And the output should contain "Line coverage by file (75.00%) is below the expected minimum coverage (75.01%) in /lib/faked_project/framework_specific.rb."
21+
And the output should contain "Line coverage by file (75.00%) is below the expected minimum coverage (75.01%) in lib/faked_project/framework_specific.rb."
2222
And the output should contain "SimpleCov failed with exit 2"
2323

2424
Scenario: Just passing it
@@ -48,8 +48,8 @@ Feature:
4848

4949
When I run `bundle exec rake test`
5050
Then the exit status should not be 0
51-
And the output should contain "Line coverage by file (80.00%) is below the expected minimum coverage (90.00%) in /lib/faked_project/some_class.rb."
52-
And the output should contain "Branch coverage by file (50.00%) is below the expected minimum coverage (70.00%) in /lib/faked_project/some_class.rb."
51+
And the output should contain "Line coverage by file (80.00%) is below the expected minimum coverage (90.00%) in lib/faked_project/some_class.rb."
52+
And the output should contain "Branch coverage by file (50.00%) is below the expected minimum coverage (70.00%) in lib/faked_project/some_class.rb."
5353
And the output should contain "SimpleCov failed with exit 2"
5454

5555
@branch_coverage
@@ -67,6 +67,6 @@ Feature:
6767

6868
When I run `bundle exec rake test`
6969
Then the exit status should not be 0
70-
And the output should contain "Branch coverage by file (50.00%) is below the expected minimum coverage (70.00%) in /lib/faked_project/some_class.rb."
70+
And the output should contain "Branch coverage by file (50.00%) is below the expected minimum coverage (70.00%) in lib/faked_project/some_class.rb."
7171
And the output should not contain "Line coverage ("
7272
And the output should contain "SimpleCov failed with exit 2"

features/step_definitions/json_steps.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
json_report = JSON.parse(File.read("coverage/coverage.json"))
66
coverage_hash = json_report.fetch "coverage"
77

8-
faked_project = coverage_hash.fetch("/lib/faked_project.rb")
8+
faked_project = coverage_hash.fetch("lib/faked_project.rb")
99
expect(faked_project["lines"]).to eq [nil, nil, 1, 1, 1, nil, nil, nil, 5, 3, nil, nil, 1]
1010
expect(faked_project["lines_covered_percent"]).to be_a(Float)
1111

12-
some_class = coverage_hash.fetch("/lib/faked_project/some_class.rb")
12+
some_class = coverage_hash.fetch("lib/faked_project/some_class.rb")
1313
expect(some_class["lines"]).to eq [nil, nil, 1, 1, 1, nil, 1, 2, nil, nil, 1, 1, nil, nil, 1, 1, 1, nil, 0, nil, nil, 0, nil, nil, 1, nil, 1, 0, nil, nil]
1414
expect(some_class["lines_covered_percent"]).to be_a(Float)
1515
end

html_frontend/src/app.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -272,11 +272,6 @@ function fmtPct(pct: number): string {
272272
return (Math.floor(pct * 100) / 100).toFixed(2);
273273
}
274274

275-
function shortenFilename(filename: string): string {
276-
// Paths in the JSON output are already root-relative with a leading `/`.
277-
return filename.replace(/^\//, '');
278-
}
279-
280275
function fileId(filename: string): string {
281276
return md5Hex(filename);
282277
}
@@ -416,7 +411,6 @@ function buildMissedMethodLines(methods: MethodEntry[] | undefined): Set<number>
416411

417412
function renderSourceFile(filename: string, data: FileCoverage, branchCoverage: boolean, methodCoverage: boolean): string {
418413
const id = fileId(filename);
419-
const shortName = shortenFilename(filename);
420414
const coveredLines = data.covered_lines;
421415
const missedLines = data.missed_lines;
422416
const totalLines = coveredLines + missedLines;
@@ -433,7 +427,7 @@ function renderSourceFile(filename: string, data: FileCoverage, branchCoverage:
433427

434428
let html = `<div class="source_table" id="${id}">`;
435429
html += '<div class="header">';
436-
html += `<h2>${escapeHTML(shortName)}</h2>`;
430+
html += `<h2>${escapeHTML(filename)}</h2>`;
437431
html += renderCoverageSummary(coveredLines, totalLines, coveredBranches, totalBranches, coveredMethods, totalMethods, branchCoverage, methodCoverage, showMethodToggle);
438432

439433
if (showMethodToggle) {
@@ -534,7 +528,6 @@ function renderFileList(
534528
for (const fn of filenames) {
535529
const f = allCoverage[fn];
536530
if (!f) continue;
537-
const shortName = shortenFilename(fn);
538531
const id = fileId(fn);
539532
const coveredLines = f.covered_lines;
540533
const relevantLines = coveredLines + f.missed_lines;
@@ -548,7 +541,7 @@ function renderFileList(
548541
}
549542

550543
html += `<tr class="t-file" ${dataAttrs}>`;
551-
html += `<td class="strong t-file__name"><a href="#${id}" class="src_link" title="${escapeHTML(shortName)}">${escapeHTML(shortName)}</a></td>`;
544+
html += `<td class="strong t-file__name"><a href="#${id}" class="src_link" title="${escapeHTML(fn)}">${escapeHTML(fn)}</a></td>`;
552545
html += renderCoverageCells(f.lines_covered_percent, coveredLines, relevantLines, 'line', false);
553546
if (branchCoverage) {
554547
html += renderCoverageCells(f.branches_covered_percent || 100.0, f.covered_branches || 0, f.total_branches || 0, 'branch', false);

lib/simplecov/filter.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,18 +65,20 @@ def matches?(source_file)
6565
def segment_pattern
6666
@segment_pattern ||= begin
6767
normalized = filter_argument.delete_prefix("/")
68+
escaped = Regexp.escape(normalized)
69+
boundary = '(?:\A|/)'
6870
if normalized.include?(".")
6971
# Contains a dot — looks like a filename pattern. Allow substring
7072
# match within the last path segment (e.g. "test.rb" matches
71-
# "faked_test.rb") while still anchoring to a "/" boundary.
72-
%r{/[^/]*#{Regexp.escape(normalized)}}
73+
# "faked_test.rb") while still anchoring to a segment boundary.
74+
/#{boundary}[^\/]*#{escaped}/
7375
elsif normalized.end_with?("/")
7476
# Trailing slash signals directory-only matching
75-
%r{/#{Regexp.escape(normalized)}}
77+
/#{boundary}#{escaped}/
7678
else
7779
# No dot — looks like a directory or path. Require segment-boundary
78-
# match so "lib" matches "/lib/" but not "/library/".
79-
%r{/#{Regexp.escape(normalized)}(?=[/.]|$)}
80+
# match so "lib" matches "lib/" but not "library/".
81+
/#{boundary}#{escaped}(?=[\/.]|\z)/
8082
end
8183
end
8284
end

lib/simplecov/formatter/html_formatter/public/application.js

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22

33
SimpleCov.profiles.define "hidden_filter" do
4-
add_filter %r{^/\..*}
4+
add_filter %r{\A\..*}
55
end

lib/simplecov/profiles/rails.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
SimpleCov.profiles.define "rails" do
44
load_profile "test_frameworks"
55

6-
add_filter %r{^/config/}
7-
add_filter %r{^/db/}
6+
add_filter %r{\Aconfig/}
7+
add_filter %r{\Adb/}
88

99
add_group "Controllers", "app/controllers"
1010
add_group "Channels", "app/channels"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22

33
SimpleCov.profiles.define "test_frameworks" do
4-
add_filter %r{^/(test|features|spec|autotest)/}
4+
add_filter %r{\A(test|features|spec|autotest)/}
55
end

lib/simplecov/source_file.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def initialize(filename, coverage_data, loaded: true)
2424

2525
# The path to this source file relative to the projects directory
2626
def project_filename
27-
@filename.delete_prefix(SimpleCov.root)
27+
@filename.delete_prefix(SimpleCov.root).sub(%r{\A[/\\]}, "")
2828
end
2929

3030
# The source code for this file. Aliased as :source

0 commit comments

Comments
 (0)