Skip to content

Commit

Permalink
Support coverage for eval
Browse files Browse the repository at this point in the history
Since Ruby 3.2, coverage.so can measure coverage of code that evaluated
by `Kernel#eval`. Typically, this would be useful for ERB.

https://bugs.ruby-lang.org/issues/19008

This change adds a new API for SimpleCov to enable the feature.

```ruby
SimpleCov.start do
  enable_coverage_for_eval
end
```
  • Loading branch information
mame committed Dec 3, 2022
1 parent 0f1c69a commit 71c4057
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ tmp
.yardoc
spec/fixtures/coverage
spec/fixtures/frameworks/coverage
spec/fixtures/eval_test/coverage
test_projects/**/coverage
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,18 @@ Primary coverage determines what will come in first all output, and the type of
Note that coverage must first be enabled for non-default coverage types.
## Coverage for eval
You can measure coverage for code that is evaluated by `Kernel#eval`. Supported in CRuby versions 3.2+.
```ruby
SimpleCov.start do
enable_coverage_for_eval
end
```
This is typically useful for ERB. Set `ERB#filename=` to make it possible for SimpleCov to trace the original .erb source file.
## Filters
Filters can be used to remove selected files from your coverage data. By default, a filter is applied that removes all
Expand Down
2 changes: 2 additions & 0 deletions lib/simplecov.rb
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,8 @@ def start_coverage_with_criteria
[lookup_corresponding_ruby_coverage_name(criterion), true]
end.to_h

start_arguments[:eval] = true if coverage_for_eval_enabled?

Coverage.start(start_arguments) unless Coverage.running?
end

Expand Down
17 changes: 17 additions & 0 deletions lib/simplecov/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,23 @@ def branch_coverage_supported?
coverage_start_arguments_supported? && RUBY_ENGINE != "jruby"
end

def coverage_for_eval_supported?
require "coverage"
defined?(Coverage.supported?) && Coverage.supported?(:eval)
end

def coverage_for_eval_enabled?
@coverage_for_eval_enabled ||= false
end

def enable_coverage_for_eval
if coverage_for_eval_supported?
@coverage_for_eval_enabled = true
else
raise "Coverage for eval is not available! Use Ruby 3.2.0 or later"
end
end

private

def raise_if_criterion_disabled(criterion)
Expand Down
26 changes: 26 additions & 0 deletions spec/coverage_for_eval_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

require "helper"

RSpec.describe "coverage for eval" do
if SimpleCov.coverage_for_eval_supported?
around do |test|
Dir.chdir(File.join(File.dirname(__FILE__), "fixtures", "eval_test")) do
FileUtils.rm_rf("./coverage")
test.call
end
end

before do
@stdout, @stderr, @status = Open3.capture3(command)
end

context "foo" do
let(:command) { "ruby eval_test.rb" }

it "records coverage for erb" do
expect(@stdout).to include(" 2 / 3 LOC")
end
end
end
end
5 changes: 5 additions & 0 deletions spec/fixtures/eval_test/eval_test.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<% if 1 + 1 == 2 %>
covered
<% else %>
not covered
<% end %>
8 changes: 8 additions & 0 deletions spec/fixtures/eval_test/eval_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
require "simplecov"
SimpleCov.enable_coverage_for_eval
SimpleCov.start "rails"

file = File.join(__dir__, "eval_test.erb")
erb = ERB.new(File.read(file))
erb.filename = file
erb.run

0 comments on commit 71c4057

Please sign in to comment.