From 628978c494651fca6036c80af096fba2f91a2ece Mon Sep 17 00:00:00 2001 From: Dana Sherson Date: Wed, 4 Mar 2020 01:42:23 +1100 Subject: [PATCH 1/5] Add subprocess handling to simplecov Using Process.fork (whether using the Parallel gem or directly) creates code that was invisible to SimpleCov. by starting SimpleCov within the subprocess with its own command name and etc we can see that code :) This also adds documentation for what to do when using Process.spawn or similar. fixes: #414 --- CHANGELOG.md | 6 +++++ README.md | 44 ++++++++++++++++++++++++++++++++++ lib/simplecov.rb | 1 + lib/simplecov/configuration.rb | 34 ++++++++++++++++++++++++++ lib/simplecov/process.rb | 19 +++++++++++++++ spec/simplecov_spec.rb | 39 ++++++++++++++++++++++++------ 6 files changed, 136 insertions(+), 7 deletions(-) create mode 100644 lib/simplecov/process.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 367942ce..bdbca923 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +Unreleased +========== + +## Enhancements +* observe forked processes (configure with SimpleCov.at_fork) + 0.18.5 (2020-02-25) =================== diff --git a/README.md b/README.md index 196c8d3c..1a682f33 100644 --- a/README.md +++ b/README.md @@ -614,6 +614,50 @@ namespace :coverage do end ``` +## Running simplecov against subprocesses + +SimpleCov will cover code run using `Process.fork` automatically, appending `" (subprocess #{pid})"` +to the `SimpleCov.command_name`, with results that can be merged together using SimpleCov's merging feature. + +To configure this, use `.at_fork`. + +```ruby +SimpleCov.at_fork do |pid| + # This needs a unique name so it won't be ovewritten + SimpleCov.command_name "#{SimpleCov.command_name} (subprocess: #{pid})" + # be quiet, the parent process will be in charge of using the regular formatter and checking coverage totals + SimpleCov.print_error_status = false + SimpleCov.formatter = SimpleCov::Formatter::SimpleFormatter + SimpleCov.minimum_coverage 0 + # start + SimpleCov.start +end +``` + +NOTE: SimpleCov must have already been started before `Process.fork` was called. + +### Running simplecov against spawned subprocesses + +Perhaps you're testing a ruby script with `PTY.spawn` or `Open3.popen`, or `Process.spawn` or etc. +SimpleCov can cover this too. + +Add a .simplecov_spawn file to your project root +```ruby +# .simplecov_spawn +require 'simplecov' # this will also pick up whatever config is in .simplecov + # so ensure it just contains configuration, and doesn't call SimpleCov.start. +SimpleCov.at_fork.call(Process.pid) +SimpleCov.start +``` +Then, instead of calling your script directly, like: +```ruby +PTY.spawn('my_script.rb') do # ... +``` +Use bin/ruby to require the new .simplecov_spawn file, then your script +```ruby +PTY.spawn('ruby -r.simplecov_spawn my_script.rb') do # ... +``` + ## Running coverage only on demand The Ruby STDLIB Coverage library that SimpleCov builds upon is *very* fast (on a ~10 min Rails test suite, the speed diff --git a/lib/simplecov.rb b/lib/simplecov.rb index 32bdab3d..9bf71843 100644 --- a/lib/simplecov.rb +++ b/lib/simplecov.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "English" +require_relative "simplecov/process" # Coverage may be inaccurate under JRUBY. if defined?(JRUBY_VERSION) && defined?(JRuby) diff --git a/lib/simplecov/configuration.rb b/lib/simplecov/configuration.rb index bba523a5..f2fd2571 100644 --- a/lib/simplecov/configuration.rb +++ b/lib/simplecov/configuration.rb @@ -196,6 +196,40 @@ def at_exit(&block) @at_exit ||= proc { SimpleCov.result.format! } end + # + # Gets or sets the behavior to start a new forked Process. + # + # By default, it will add " (Process #{pid})" to the command_name, and start SimpleCov in quiet mode + # + # Configure with: + # + # SimpleCov.at_fork do |pid| + # SimpleCov.start do + # # This needs a unique name so it won't be ovewritten + # SimpleCov.command_name "#{SimpleCov.command_name} (subprocess: #{pid})" + # # be quiet, the parent process will be in charge of using the regular formatter and checking coverage totals + # SimpleCov.print_error_status = false + # SimpleCov.formatter = SimpleCov::Formatter::SimpleFormatter + # SimpleCov.minimum_coverage 0 + # # start + # SimpleCov.start + # end + # end + # + def at_fork(&block) + @at_fork = block if block_given? + @at_fork ||= lambda { |pid| + # This needs a unique name so it won't be ovewritten + SimpleCov.command_name "#{SimpleCov.command_name} (subprocess: #{pid})" + # be quiet, the parent process will be in charge of using the regular formatter and checking coverage totals + SimpleCov.print_error_status = false + SimpleCov.formatter = SimpleCov::Formatter::SimpleFormatter + SimpleCov.minimum_coverage 0 + # start + SimpleCov.start + } + end + # # Returns the project name - currently assuming the last dirname in # the SimpleCov.root is this. diff --git a/lib/simplecov/process.rb b/lib/simplecov/process.rb new file mode 100644 index 00000000..9667e8f6 --- /dev/null +++ b/lib/simplecov/process.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Process + class << self + def fork_with_simplecov(&block) + if SimpleCov.running + fork_without_simplecov do + SimpleCov.at_fork.call(Process.pid) + block.call if block_given? + end + else + fork_without_simplecov(&block) + end + end + + alias fork_without_simplecov fork + alias fork fork_with_simplecov + end +end diff --git a/spec/simplecov_spec.rb b/spec/simplecov_spec.rb index a3cca6d8..84f61a45 100644 --- a/spec/simplecov_spec.rb +++ b/spec/simplecov_spec.rb @@ -270,6 +270,31 @@ end end + context "with_reports_to_clear_up" do + after do + clear_mergeable_reports + end + + def a_void_method_call_that_wont_warn + true + end + + it "starts coverage of subprocesses" do + SimpleCov.command_name "RSpec" + SimpleCov.start + + a_void_method_call_that_wont_warn # this process + + pid = Process.fork do + a_void_method_call_that_wont_warn # that process + end + + Process.wait(pid) # timings! + + expect(SimpleCov.result.command_name).to eq "RSpec, RSpec (subprocess: #{pid})" + end + end + context "when files to be merged" do before do expect(SimpleCov).to receive(:run_exit_tasks!) @@ -322,14 +347,14 @@ def create_mergeable_report(name, resultset) SimpleCov::ResultMerger.store_result(result) FileUtils.mv resultset_path, "#{resultset_path}#{name}.final" end + end - def clear_mergeable_reports(*names) - SimpleCov.clear_result - SimpleCov::ResultMerger.clear_resultset - FileUtils.rm resultset_path - FileUtils.rm "#{resultset_path}.lock" - names.each { |name| FileUtils.rm "#{resultset_path}#{name}.final" } - end + def clear_mergeable_reports(*names) + SimpleCov.clear_result + SimpleCov::ResultMerger.clear_resultset + FileUtils.rm resultset_path + FileUtils.rm "#{resultset_path}.lock" + names.each { |name| FileUtils.rm "#{resultset_path}#{name}.final" } end end From 33084cce0be746c57588cac858a3ff26f4fcde70 Mon Sep 17 00:00:00 2001 From: Dana Sherson Date: Wed, 4 Mar 2020 08:11:35 +1100 Subject: [PATCH 2/5] Subprocesses is off by default Can be enabled with enable_for_subprocesses Also moved the testing to a feature test --- CHANGELOG.md | 2 +- README.md | 6 ++- .../config_enable_for_subprocesses.feature | 37 ++++++++++++++++++ lib/simplecov.rb | 3 +- lib/simplecov/configuration.rb | 1 + lib/simplecov/process.rb | 2 +- spec/simplecov_spec.rb | 39 ++++--------------- test_projects/subprocesses/.simplecov | 1 + .../subprocesses/.simplecov_spawn.rb | 5 +++ test_projects/subprocesses/lib/command | 7 ++++ .../subprocesses/lib/subprocesses.rb | 21 ++++++++++ .../subprocesses/spec/simple_spec.rb | 7 ++++ test_projects/subprocesses/spec/spawn_spec.rb | 8 ++++ .../subprocesses/spec/spec_helper.rb | 6 +++ 14 files changed, 108 insertions(+), 37 deletions(-) create mode 100644 features/config_enable_for_subprocesses.feature create mode 100644 test_projects/subprocesses/.simplecov create mode 100644 test_projects/subprocesses/.simplecov_spawn.rb create mode 100755 test_projects/subprocesses/lib/command create mode 100644 test_projects/subprocesses/lib/subprocesses.rb create mode 100644 test_projects/subprocesses/spec/simple_spec.rb create mode 100644 test_projects/subprocesses/spec/spawn_spec.rb create mode 100644 test_projects/subprocesses/spec/spec_helper.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index bdbca923..434952ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ Unreleased ========== ## Enhancements -* observe forked processes (configure with SimpleCov.at_fork) +* observe forked processes (enable with SimpleCov.enable_for_subprocesses) 0.18.5 (2020-02-25) =================== diff --git a/README.md b/README.md index 1a682f33..ff65ab3c 100644 --- a/README.md +++ b/README.md @@ -616,16 +616,18 @@ end ## Running simplecov against subprocesses -SimpleCov will cover code run using `Process.fork` automatically, appending `" (subprocess #{pid})"` +`SimpleCov.enable_for_subprocesses` will allow SimpleCov to observe subprocesses starting using `Process.fork`. +This modifies ruby's core Process.fork method so that SimpleCov can see into it, appending `" (subprocess #{pid})"` to the `SimpleCov.command_name`, with results that can be merged together using SimpleCov's merging feature. To configure this, use `.at_fork`. ```ruby +SimpleCov.enable_for_subprocesses = true SimpleCov.at_fork do |pid| # This needs a unique name so it won't be ovewritten SimpleCov.command_name "#{SimpleCov.command_name} (subprocess: #{pid})" - # be quiet, the parent process will be in charge of using the regular formatter and checking coverage totals + # be quiet, the parent process will be in charge of output and checking coverage totals SimpleCov.print_error_status = false SimpleCov.formatter = SimpleCov::Formatter::SimpleFormatter SimpleCov.minimum_coverage 0 diff --git a/features/config_enable_for_subprocesses.feature b/features/config_enable_for_subprocesses.feature new file mode 100644 index 00000000..ea0523b1 --- /dev/null +++ b/features/config_enable_for_subprocesses.feature @@ -0,0 +1,37 @@ +@rspec + +Feature: + Coverage should include code run by subprocesses + + Background: + Given I'm working on the project "subprocesses" + + Scenario: Coverage has seen the subprocess line + When I open the coverage report generated with `bundle exec rspec spec/simple_spec.rb` + Then I should see the groups: + | name | coverage | files | + | All Files | 100.0% | 1 | + + Scenario: The at_fork proc + Given a file named ".simplecov" with: + """ + SimpleCov.enable_for_subprocesses = true + SimpleCov.command_name "parent process name" + SimpleCov.at_fork do |_pid| + SimpleCov.command_name "child process name" + SimpleCov.start + end + """ + When I open the coverage report generated with `bundle exec rspec spec/simple_spec.rb` + Then I should see the groups: + | name | coverage | files | + | All Files | 100.0% | 1 | + And the report should be based upon: + | child process name | + | parent process name | + + Scenario: The documentation on .simplecov_spawn + When I open the coverage report generated with `bundle exec rspec spec/spawn_spec.rb` + Then I should see the groups: + | name | coverage | files | + | All Files | 100.0% | 1 | diff --git a/lib/simplecov.rb b/lib/simplecov.rb index 9bf71843..4172c134 100644 --- a/lib/simplecov.rb +++ b/lib/simplecov.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "English" -require_relative "simplecov/process" # Coverage may be inaccurate under JRUBY. if defined?(JRUBY_VERSION) && defined?(JRuby) @@ -53,6 +52,8 @@ class << self def start(profile = nil, &block) require "coverage" initial_setup(profile, &block) + require_relative "./simplecov/process" if SimpleCov.enable_for_subprocesses + @result = nil self.pid = Process.pid diff --git a/lib/simplecov/configuration.rb b/lib/simplecov/configuration.rb index f2fd2571..923ae50c 100644 --- a/lib/simplecov/configuration.rb +++ b/lib/simplecov/configuration.rb @@ -12,6 +12,7 @@ module SimpleCov # module Configuration # rubocop:disable Metrics/ModuleLength attr_writer :filters, :groups, :formatter, :print_error_status + attr_accessor :enable_for_subprocesses # # The root for the project. This defaults to the diff --git a/lib/simplecov/process.rb b/lib/simplecov/process.rb index 9667e8f6..fbe59068 100644 --- a/lib/simplecov/process.rb +++ b/lib/simplecov/process.rb @@ -3,7 +3,7 @@ module Process class << self def fork_with_simplecov(&block) - if SimpleCov.running + if defined?(SimpleCov) && SimpleCov.running fork_without_simplecov do SimpleCov.at_fork.call(Process.pid) block.call if block_given? diff --git a/spec/simplecov_spec.rb b/spec/simplecov_spec.rb index 84f61a45..a3cca6d8 100644 --- a/spec/simplecov_spec.rb +++ b/spec/simplecov_spec.rb @@ -270,31 +270,6 @@ end end - context "with_reports_to_clear_up" do - after do - clear_mergeable_reports - end - - def a_void_method_call_that_wont_warn - true - end - - it "starts coverage of subprocesses" do - SimpleCov.command_name "RSpec" - SimpleCov.start - - a_void_method_call_that_wont_warn # this process - - pid = Process.fork do - a_void_method_call_that_wont_warn # that process - end - - Process.wait(pid) # timings! - - expect(SimpleCov.result.command_name).to eq "RSpec, RSpec (subprocess: #{pid})" - end - end - context "when files to be merged" do before do expect(SimpleCov).to receive(:run_exit_tasks!) @@ -347,14 +322,14 @@ def create_mergeable_report(name, resultset) SimpleCov::ResultMerger.store_result(result) FileUtils.mv resultset_path, "#{resultset_path}#{name}.final" end - end - def clear_mergeable_reports(*names) - SimpleCov.clear_result - SimpleCov::ResultMerger.clear_resultset - FileUtils.rm resultset_path - FileUtils.rm "#{resultset_path}.lock" - names.each { |name| FileUtils.rm "#{resultset_path}#{name}.final" } + def clear_mergeable_reports(*names) + SimpleCov.clear_result + SimpleCov::ResultMerger.clear_resultset + FileUtils.rm resultset_path + FileUtils.rm "#{resultset_path}.lock" + names.each { |name| FileUtils.rm "#{resultset_path}#{name}.final" } + end end end diff --git a/test_projects/subprocesses/.simplecov b/test_projects/subprocesses/.simplecov new file mode 100644 index 00000000..68299dc3 --- /dev/null +++ b/test_projects/subprocesses/.simplecov @@ -0,0 +1 @@ +SimpleCov.enable_for_subprocesses = true diff --git a/test_projects/subprocesses/.simplecov_spawn.rb b/test_projects/subprocesses/.simplecov_spawn.rb new file mode 100644 index 00000000..42927408 --- /dev/null +++ b/test_projects/subprocesses/.simplecov_spawn.rb @@ -0,0 +1,5 @@ +require 'bundler/setup' +require 'simplecov' +SimpleCov.enable_for_subprocesses = true +SimpleCov.at_fork.call(Process.pid) +SimpleCov.start diff --git a/test_projects/subprocesses/lib/command b/test_projects/subprocesses/lib/command new file mode 100755 index 00000000..11091537 --- /dev/null +++ b/test_projects/subprocesses/lib/command @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby + +require_relative './subprocesses' + +Subprocesses.new.run + +puts 'done' diff --git a/test_projects/subprocesses/lib/subprocesses.rb b/test_projects/subprocesses/lib/subprocesses.rb new file mode 100644 index 00000000..877d4c56 --- /dev/null +++ b/test_projects/subprocesses/lib/subprocesses.rb @@ -0,0 +1,21 @@ +class Subprocesses + def run + method_called_in_parent_process + + pid = Process.fork do + method_called_by_subprocess + end + + Process.wait(pid) + + true + end + + def method_called_in_parent_process + true + end + + def method_called_by_subprocess + true + end +end diff --git a/test_projects/subprocesses/spec/simple_spec.rb b/test_projects/subprocesses/spec/simple_spec.rb new file mode 100644 index 00000000..e289817a --- /dev/null +++ b/test_projects/subprocesses/spec/simple_spec.rb @@ -0,0 +1,7 @@ +require_relative "spec_helper" + +describe Subprocesses do + it "call things" do + expect(subject.run).to be true + end +end diff --git a/test_projects/subprocesses/spec/spawn_spec.rb b/test_projects/subprocesses/spec/spawn_spec.rb new file mode 100644 index 00000000..c9bdb7ea --- /dev/null +++ b/test_projects/subprocesses/spec/spawn_spec.rb @@ -0,0 +1,8 @@ +require 'spec_helper' +require 'open3' +describe 'spawn' do + it 'calls things' do + stdout, exitstatus = Open3.capture2("ruby -r#{__dir__}/../.simplecov_spawn #{__dir__}/../lib/command") + expect(stdout.chomp).to eq 'done' + end +end diff --git a/test_projects/subprocesses/spec/spec_helper.rb b/test_projects/subprocesses/spec/spec_helper.rb new file mode 100644 index 00000000..34172054 --- /dev/null +++ b/test_projects/subprocesses/spec/spec_helper.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +require "simplecov" +SimpleCov.start + +require_relative "../lib/subprocesses.rb" From c6a65c657b92deba9898633b86164393eae9bc4f Mon Sep 17 00:00:00 2001 From: Dana Sherson Date: Wed, 4 Mar 2020 15:53:07 +1100 Subject: [PATCH 3/5] Fix test to work for ruby 2.4 also --- test_projects/subprocesses/.simplecov | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test_projects/subprocesses/.simplecov b/test_projects/subprocesses/.simplecov index 68299dc3..162f163c 100644 --- a/test_projects/subprocesses/.simplecov +++ b/test_projects/subprocesses/.simplecov @@ -1 +1,5 @@ SimpleCov.enable_for_subprocesses = true +# different versions of ruby were tracking different numbers of files. idk why. +# lets only worry about one file. +SimpleCov.add_filter /command/ +SimpleCov.add_filter /spawn/ From d59fd44a524b66cba230a2237ad035cfdc61de10 Mon Sep 17 00:00:00 2001 From: Dana Sherson Date: Wed, 4 Mar 2020 17:33:20 +1100 Subject: [PATCH 4/5] Have spawn doc match closer to spec --- README.md | 11 ++++++----- test_projects/subprocesses/.simplecov_spawn.rb | 2 +- test_projects/subprocesses/spec/spawn_spec.rb | 6 ++++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ff65ab3c..32260e09 100644 --- a/README.md +++ b/README.md @@ -643,13 +643,14 @@ NOTE: SimpleCov must have already been started before `Process.fork` was called. Perhaps you're testing a ruby script with `PTY.spawn` or `Open3.popen`, or `Process.spawn` or etc. SimpleCov can cover this too. -Add a .simplecov_spawn file to your project root +Add a .simplecov_spawn.rb file to your project root ```ruby -# .simplecov_spawn +# .simplecov_spawn.rb require 'simplecov' # this will also pick up whatever config is in .simplecov # so ensure it just contains configuration, and doesn't call SimpleCov.start. -SimpleCov.at_fork.call(Process.pid) -SimpleCov.start +SimpleCov.command_name 'spawn' # As this is not for a test runner directly, script doesn't have a pre-defined base command_name +SimpleCov.at_fork.call(Process.pid) # Use the per-process setup described previously +SimpleCov.start # only now can we start. ``` Then, instead of calling your script directly, like: ```ruby @@ -657,7 +658,7 @@ PTY.spawn('my_script.rb') do # ... ``` Use bin/ruby to require the new .simplecov_spawn file, then your script ```ruby -PTY.spawn('ruby -r.simplecov_spawn my_script.rb') do # ... +PTY.spawn('ruby -r./.simplecov_spawn my_script.rb') do # ... ``` ## Running coverage only on demand diff --git a/test_projects/subprocesses/.simplecov_spawn.rb b/test_projects/subprocesses/.simplecov_spawn.rb index 42927408..14c9b5af 100644 --- a/test_projects/subprocesses/.simplecov_spawn.rb +++ b/test_projects/subprocesses/.simplecov_spawn.rb @@ -1,5 +1,5 @@ require 'bundler/setup' require 'simplecov' -SimpleCov.enable_for_subprocesses = true +SimpleCov.command_name 'spawn' SimpleCov.at_fork.call(Process.pid) SimpleCov.start diff --git a/test_projects/subprocesses/spec/spawn_spec.rb b/test_projects/subprocesses/spec/spawn_spec.rb index c9bdb7ea..37824edc 100644 --- a/test_projects/subprocesses/spec/spawn_spec.rb +++ b/test_projects/subprocesses/spec/spawn_spec.rb @@ -2,7 +2,9 @@ require 'open3' describe 'spawn' do it 'calls things' do - stdout, exitstatus = Open3.capture2("ruby -r#{__dir__}/../.simplecov_spawn #{__dir__}/../lib/command") - expect(stdout.chomp).to eq 'done' + Dir.chdir(File.expand_path('..', __dir__)) do + stdout, exitstatus = Open3.capture2("ruby -r./.simplecov_spawn lib/command") + expect(stdout.chomp).to eq 'done' + end end end From fa0f73d6f7997ecffcf73adfe50bd871433186c6 Mon Sep 17 00:00:00 2001 From: Dana Sherson Date: Fri, 6 Mar 2020 21:10:56 +1100 Subject: [PATCH 5/5] Remove unnecessary = Also Gem::Version.new comparisons please. Also don't run this test on jruby, Process.fork is NotImplementedError --- README.md | 4 ++-- features/config_enable_for_subprocesses.feature | 4 ++-- features/support/env.rb | 10 +++++++--- lib/simplecov.rb | 2 +- lib/simplecov/configuration.rb | 17 ++++++++++++++--- test_projects/subprocesses/.simplecov | 2 +- 6 files changed, 27 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 32260e09..d92fc71b 100644 --- a/README.md +++ b/README.md @@ -623,13 +623,13 @@ to the `SimpleCov.command_name`, with results that can be merged together using To configure this, use `.at_fork`. ```ruby -SimpleCov.enable_for_subprocesses = true +SimpleCov.enable_for_subprocesses true SimpleCov.at_fork do |pid| # This needs a unique name so it won't be ovewritten SimpleCov.command_name "#{SimpleCov.command_name} (subprocess: #{pid})" # be quiet, the parent process will be in charge of output and checking coverage totals SimpleCov.print_error_status = false - SimpleCov.formatter = SimpleCov::Formatter::SimpleFormatter + SimpleCov.formatter SimpleCov::Formatter::SimpleFormatter SimpleCov.minimum_coverage 0 # start SimpleCov.start diff --git a/features/config_enable_for_subprocesses.feature b/features/config_enable_for_subprocesses.feature index ea0523b1..5d78b6b5 100644 --- a/features/config_enable_for_subprocesses.feature +++ b/features/config_enable_for_subprocesses.feature @@ -1,4 +1,4 @@ -@rspec +@rspec @process_fork Feature: Coverage should include code run by subprocesses @@ -15,7 +15,7 @@ Feature: Scenario: The at_fork proc Given a file named ".simplecov" with: """ - SimpleCov.enable_for_subprocesses = true + SimpleCov.enable_for_subprocesses true SimpleCov.command_name "parent process name" SimpleCov.at_fork do |_pid| SimpleCov.command_name "child process name" diff --git a/features/support/env.rb b/features/support/env.rb index 36279d3c..c59526dc 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -47,9 +47,13 @@ end Before("@rails6") do - # Rails 6 only supports Ruby 2.5+ and amazingly because string comparison - # goes beginning to end the string comparison _should_ work - skip_this_scenario if RUBY_VERSION < "2.5" + # Rails 6 only supports Ruby 2.5+ + skip_this_scenario if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.5") +end + +Before("@process_fork") do + # Process.fork is NotImplementedError in jruby + skip_this_scenario if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby" end Aruba.configure do |config| diff --git a/lib/simplecov.rb b/lib/simplecov.rb index 4172c134..a278134f 100644 --- a/lib/simplecov.rb +++ b/lib/simplecov.rb @@ -52,7 +52,7 @@ class << self def start(profile = nil, &block) require "coverage" initial_setup(profile, &block) - require_relative "./simplecov/process" if SimpleCov.enable_for_subprocesses + require_relative "./simplecov/process" if SimpleCov.enabled_for_subprocesses? @result = nil self.pid = Process.pid diff --git a/lib/simplecov/configuration.rb b/lib/simplecov/configuration.rb index 923ae50c..1b881c4d 100644 --- a/lib/simplecov/configuration.rb +++ b/lib/simplecov/configuration.rb @@ -12,7 +12,6 @@ module SimpleCov # module Configuration # rubocop:disable Metrics/ModuleLength attr_writer :filters, :groups, :formatter, :print_error_status - attr_accessor :enable_for_subprocesses # # The root for the project. This defaults to the @@ -197,6 +196,18 @@ def at_exit(&block) @at_exit ||= proc { SimpleCov.result.format! } end + # gets or sets the enabled_for_subprocess configuration + # when true, this will inject SimpleCov code into Process.fork + def enable_for_subprocesses(value = nil) + @enable_for_subprocesses = value unless value.nil? + @enable_for_subprocesses || false + end + + # gets the enabled_for_subprocess configuration + def enabled_for_subprocesses? + enable_for_subprocesses + end + # # Gets or sets the behavior to start a new forked Process. # @@ -210,7 +221,7 @@ def at_exit(&block) # SimpleCov.command_name "#{SimpleCov.command_name} (subprocess: #{pid})" # # be quiet, the parent process will be in charge of using the regular formatter and checking coverage totals # SimpleCov.print_error_status = false - # SimpleCov.formatter = SimpleCov::Formatter::SimpleFormatter + # SimpleCov.formatter SimpleCov::Formatter::SimpleFormatter # SimpleCov.minimum_coverage 0 # # start # SimpleCov.start @@ -224,7 +235,7 @@ def at_fork(&block) SimpleCov.command_name "#{SimpleCov.command_name} (subprocess: #{pid})" # be quiet, the parent process will be in charge of using the regular formatter and checking coverage totals SimpleCov.print_error_status = false - SimpleCov.formatter = SimpleCov::Formatter::SimpleFormatter + SimpleCov.formatter SimpleCov::Formatter::SimpleFormatter SimpleCov.minimum_coverage 0 # start SimpleCov.start diff --git a/test_projects/subprocesses/.simplecov b/test_projects/subprocesses/.simplecov index 162f163c..4e3d9215 100644 --- a/test_projects/subprocesses/.simplecov +++ b/test_projects/subprocesses/.simplecov @@ -1,4 +1,4 @@ -SimpleCov.enable_for_subprocesses = true +SimpleCov.enable_for_subprocesses true # different versions of ruby were tracking different numbers of files. idk why. # lets only worry about one file. SimpleCov.add_filter /command/