From 71c40576021ea6f95d73472b8a52ab1df1f4eef2 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Sat, 3 Dec 2022 13:28:37 +0900 Subject: [PATCH] Support coverage for eval 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 ``` --- .gitignore | 1 + README.md | 12 ++++++++++++ lib/simplecov.rb | 2 ++ lib/simplecov/configuration.rb | 17 +++++++++++++++++ spec/coverage_for_eval_spec.rb | 26 ++++++++++++++++++++++++++ spec/fixtures/eval_test/eval_test.erb | 5 +++++ spec/fixtures/eval_test/eval_test.rb | 8 ++++++++ 7 files changed, 71 insertions(+) create mode 100644 spec/coverage_for_eval_spec.rb create mode 100644 spec/fixtures/eval_test/eval_test.erb create mode 100644 spec/fixtures/eval_test/eval_test.rb diff --git a/.gitignore b/.gitignore index 91d75687..43711f56 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,5 @@ tmp .yardoc spec/fixtures/coverage spec/fixtures/frameworks/coverage +spec/fixtures/eval_test/coverage test_projects/**/coverage diff --git a/README.md b/README.md index deaaf69a..8db3fd1f 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/lib/simplecov.rb b/lib/simplecov.rb index 5881846a..12202c9e 100644 --- a/lib/simplecov.rb +++ b/lib/simplecov.rb @@ -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 diff --git a/lib/simplecov/configuration.rb b/lib/simplecov/configuration.rb index fb45061f..0b701bf2 100644 --- a/lib/simplecov/configuration.rb +++ b/lib/simplecov/configuration.rb @@ -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) diff --git a/spec/coverage_for_eval_spec.rb b/spec/coverage_for_eval_spec.rb new file mode 100644 index 00000000..7677b3a3 --- /dev/null +++ b/spec/coverage_for_eval_spec.rb @@ -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 diff --git a/spec/fixtures/eval_test/eval_test.erb b/spec/fixtures/eval_test/eval_test.erb new file mode 100644 index 00000000..dff78675 --- /dev/null +++ b/spec/fixtures/eval_test/eval_test.erb @@ -0,0 +1,5 @@ +<% if 1 + 1 == 2 %> + covered +<% else %> + not covered +<% end %> diff --git a/spec/fixtures/eval_test/eval_test.rb b/spec/fixtures/eval_test/eval_test.rb new file mode 100644 index 00000000..36b3d689 --- /dev/null +++ b/spec/fixtures/eval_test/eval_test.rb @@ -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