From 693af604ff118c94f9fdbad55870229e6d07c516 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Sat, 22 Aug 2020 13:08:23 +0300 Subject: [PATCH 01/34] add some todos --- lib/simplecov.rb | 5 ++++- lib/simplecov/combine/results_combiner.rb | 1 + lib/simplecov/configuration.rb | 1 + lib/simplecov/file_list.rb | 1 + lib/simplecov/result.rb | 4 +++- lib/simplecov/simulate_coverage.rb | 1 + lib/simplecov/source_file.rb | 1 + spec/combine/results_combiner_spec.rb | 1 + spec/configuration_spec.rb | 1 + spec/file_list_spec.rb | 1 + spec/simplecov_spec.rb | 1 + spec/source_file/branch_spec.rb | 1 + spec/source_file_spec.rb | 1 + spec/useless_results_remover_spec.rb | 1 + 14 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/simplecov.rb b/lib/simplecov.rb index fe68b6fe..b061845e 100644 --- a/lib/simplecov.rb +++ b/lib/simplecov.rb @@ -355,7 +355,8 @@ def start_coverage_with_criteria CRITERION_TO_RUBY_COVERAGE = { branch: :branches, - line: :lines + line: :lines, + method: :methods }.freeze def lookup_corresponding_ruby_coverage_name(criterion) CRITERION_TO_RUBY_COVERAGE.fetch(criterion) @@ -444,6 +445,7 @@ def probably_running_parallel_tests? require_relative "simplecov/profiles" require_relative "simplecov/source_file/line" require_relative "simplecov/source_file/branch" +# require_relative "simplecov/source_file/method" require_relative "simplecov/source_file" require_relative "simplecov/file_list" require_relative "simplecov/result" @@ -457,6 +459,7 @@ def probably_running_parallel_tests? require_relative "simplecov/result_adapter" require_relative "simplecov/combine" require_relative "simplecov/combine/branches_combiner" +# require_relative "simplecov/combine/methods_combiner" require_relative "simplecov/combine/files_combiner" require_relative "simplecov/combine/lines_combiner" require_relative "simplecov/combine/results_combiner" diff --git a/lib/simplecov/combine/results_combiner.rb b/lib/simplecov/combine/results_combiner.rb index dd359302..9f3896e6 100644 --- a/lib/simplecov/combine/results_combiner.rb +++ b/lib/simplecov/combine/results_combiner.rb @@ -16,6 +16,7 @@ module ResultsCombiner # ==> FileCombiner: collect result of next combine levels lines and branches. # ===> LinesCombiner: combine lines results. # ===> BranchesCombiner: combine branches results. + # TODO: add method cov # # @return [Hash] # diff --git a/lib/simplecov/configuration.rb b/lib/simplecov/configuration.rb index 94f662c9..4f3078e9 100644 --- a/lib/simplecov/configuration.rb +++ b/lib/simplecov/configuration.rb @@ -360,6 +360,7 @@ def add_group(group_name, filter_argument = nil, &filter_proc) groups[group_name] = parse_filter(filter_argument, &filter_proc) end + # TODO: add method cov SUPPORTED_COVERAGE_CRITERIA = %i[line branch].freeze DEFAULT_COVERAGE_CRITERION = :line # diff --git a/lib/simplecov/file_list.rb b/lib/simplecov/file_list.rb index d4c9bba9..c8872ae9 100644 --- a/lib/simplecov/file_list.rb +++ b/lib/simplecov/file_list.rb @@ -100,6 +100,7 @@ def branch_covered_percent private + # TODO: add method cov def compute_coverage_statistics total_coverage_statistics = @files.each_with_object(line: [], branch: []) do |file, together| together[:line] << file.coverage_statistics[:line] diff --git a/lib/simplecov/result.rb b/lib/simplecov/result.rb index 36eb1f9f..d153bb01 100644 --- a/lib/simplecov/result.rb +++ b/lib/simplecov/result.rb @@ -20,7 +20,9 @@ class Result # Explicitly set the command name that was used for this coverage result. Defaults to SimpleCov.command_name attr_writer :command_name - def_delegators :files, :covered_percent, :covered_percentages, :least_covered_file, :covered_strength, :covered_lines, :missed_lines, :total_branches, :covered_branches, :missed_branches, :coverage_statistics + def_delegators :files, :covered_percent, :covered_percentages, :least_covered_file, :covered_strength, + :covered_lines, :missed_lines, :total_branches, :covered_branches, :missed_branches, + :coverage_statistics def_delegator :files, :lines_of_code, :total_lines # Initialize a new SimpleCov::Result from given Coverage.result (a Hash of filenames each containing an array of diff --git a/lib/simplecov/simulate_coverage.rb b/lib/simplecov/simulate_coverage.rb index 04443865..387cfcd4 100644 --- a/lib/simplecov/simulate_coverage.rb +++ b/lib/simplecov/simulate_coverage.rb @@ -23,6 +23,7 @@ def call(absolute_path) # we don't want to parse branches ourselves... # requiring files can have side effects and we don't want to trigger that "branches" => {} + # TODO: add method cov? } end end diff --git a/lib/simplecov/source_file.rb b/lib/simplecov/source_file.rb index 4cb9f632..c3c394e6 100644 --- a/lib/simplecov/source_file.rb +++ b/lib/simplecov/source_file.rb @@ -34,6 +34,7 @@ def coverage_statistics { **line_coverage_statistics, **branch_coverage_statistics + # TODO: add method cov } end diff --git a/spec/combine/results_combiner_spec.rb b/spec/combine/results_combiner_spec.rb index 05e1b55e..a0af4081 100644 --- a/spec/combine/results_combiner_spec.rb +++ b/spec/combine/results_combiner_spec.rb @@ -9,6 +9,7 @@ source_fixture("sample.rb") => { "lines" => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], "branches" => {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}} + # TODO: add method cov? }, source_fixture("app/models/user.rb") => { "lines" => [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil], diff --git a/spec/configuration_spec.rb b/spec/configuration_spec.rb index ca2e8ccb..44d8c3f1 100644 --- a/spec/configuration_spec.rb +++ b/spec/configuration_spec.rb @@ -74,6 +74,7 @@ expect(config.minimum_coverage).to eq line: 85.0 end + # TODO: add method cov it "sets the right coverage when called with a hash of just branch" do config.enable_coverage :branch config.minimum_coverage branch: 85.0 diff --git a/spec/file_list_spec.rb b/spec/file_list_spec.rb index f0d33629..7de0eac6 100644 --- a/spec/file_list_spec.rb +++ b/spec/file_list_spec.rb @@ -8,6 +8,7 @@ source_fixture("sample.rb") => { "lines" => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], "branches" => {} + # TODO: add method cov }, source_fixture("app/models/user.rb") => { "lines" => [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil], diff --git a/spec/simplecov_spec.rb b/spec/simplecov_spec.rb index 1ab1aaed..74fe7de6 100644 --- a/spec/simplecov_spec.rb +++ b/spec/simplecov_spec.rb @@ -172,6 +172,7 @@ end end + # TODO: add method cov context "branch coverage" do before do allow(SimpleCov).to receive(:minimum_coverage).and_return(branch: 90) diff --git a/spec/source_file/branch_spec.rb b/spec/source_file/branch_spec.rb index 048cc12b..99016c7e 100644 --- a/spec/source_file/branch_spec.rb +++ b/spec/source_file/branch_spec.rb @@ -2,6 +2,7 @@ require "helper" +# TODO: add method cov describe SimpleCov::SourceFile::Branch do let(:if_branch) do described_class.new(start_line: 1, end_line: 3, coverage: 0, inline: false, type: :then) diff --git a/spec/source_file_spec.rb b/spec/source_file_spec.rb index 86f62b3a..bb35d2b9 100644 --- a/spec/source_file_spec.rb +++ b/spec/source_file_spec.rb @@ -69,6 +69,7 @@ end end + # TODO: add method cov describe "branch coverage" do it "has total branches count 0" do expect(subject.total_branches.size).to eq(0) diff --git a/spec/useless_results_remover_spec.rb b/spec/useless_results_remover_spec.rb index 223b8f55..cafa56b5 100644 --- a/spec/useless_results_remover_spec.rb +++ b/spec/useless_results_remover_spec.rb @@ -11,6 +11,7 @@ gem_file_path => { "lines" => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], "branches" => {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}} + # TODO: add method cov? }, source_path => { "lines" => [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil], From 2521b5c547cef5b72a473dc4bb58467732426aec Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Sat, 22 Aug 2020 14:22:10 +0300 Subject: [PATCH 02/34] add method coverage criterion --- lib/simplecov.rb | 2 +- lib/simplecov/configuration.rb | 10 +++++++--- spec/configuration_spec.rb | 31 +++++++++++++++++++++++++++++-- spec/simplecov_spec.rb | 10 +++++++++- spec/source_file_spec.rb | 16 ++++++++-------- 5 files changed, 54 insertions(+), 15 deletions(-) diff --git a/lib/simplecov.rb b/lib/simplecov.rb index b061845e..83263b2e 100644 --- a/lib/simplecov.rb +++ b/lib/simplecov.rb @@ -356,7 +356,7 @@ def start_coverage_with_criteria CRITERION_TO_RUBY_COVERAGE = { branch: :branches, line: :lines, - method: :methods + method: :methods, }.freeze def lookup_corresponding_ruby_coverage_name(criterion) CRITERION_TO_RUBY_COVERAGE.fetch(criterion) diff --git a/lib/simplecov/configuration.rb b/lib/simplecov/configuration.rb index 4f3078e9..2ba53b33 100644 --- a/lib/simplecov/configuration.rb +++ b/lib/simplecov/configuration.rb @@ -360,8 +360,7 @@ def add_group(group_name, filter_argument = nil, &filter_proc) groups[group_name] = parse_filter(filter_argument, &filter_proc) end - # TODO: add method cov - SUPPORTED_COVERAGE_CRITERIA = %i[line branch].freeze + SUPPORTED_COVERAGE_CRITERIA = %i[line branch method].freeze DEFAULT_COVERAGE_CRITERION = :line # # Define which coverage criterion should be evaluated. @@ -404,6 +403,10 @@ def branch_coverage? branch_coverage_supported? && coverage_criterion_enabled?(:branch) end + def method_coverage? + method_coverage_supported? && coverage_criterion_enabled?(:method) + end + def coverage_start_arguments_supported? # safe to cache as within one process this value should never # change @@ -416,6 +419,7 @@ def coverage_start_arguments_supported? end alias branch_coverage_supported? coverage_start_arguments_supported? + alias method_coverage_supported? coverage_start_arguments_supported? private @@ -423,7 +427,7 @@ def raise_if_criterion_disabled(criterion) raise_if_criterion_unsupported(criterion) # rubocop:disable Style/IfUnlessModifier unless coverage_criterion_enabled?(criterion) - raise "Coverage criterion #{criterion}, is disabled! Please enable it first through enable_coverage #{criterion} (if supported)" + raise "Coverage criterion #{criterion} is disabled! Please enable it first through enable_coverage #{criterion} (if supported)" end # rubocop:enable Style/IfUnlessModifier end diff --git a/spec/configuration_spec.rb b/spec/configuration_spec.rb index 44d8c3f1..1bbfec78 100644 --- a/spec/configuration_spec.rb +++ b/spec/configuration_spec.rb @@ -74,7 +74,6 @@ expect(config.minimum_coverage).to eq line: 85.0 end - # TODO: add method cov it "sets the right coverage when called with a hash of just branch" do config.enable_coverage :branch config.minimum_coverage branch: 85.0 @@ -82,13 +81,21 @@ expect(config.minimum_coverage).to eq branch: 85.0 end - it "sets the right coverage when called withboth line and branch" do + it "sets the right coverage when called with both line and branch" do config.enable_coverage :branch config.minimum_coverage branch: 85.0, line: 95.4 expect(config.minimum_coverage).to eq branch: 85.0, line: 95.4 end + it "sets the right coverage when called with line, branch and method" do + config.enable_coverage :branch + config.enable_coverage :method + config.minimum_coverage branch: 85.0, line: 95.4, method: 91.5 + + expect(config.minimum_coverage).to eq branch: 85.0, line: 95.4, method: 91.5 + end + it "raises when trying to set branch coverage but not enabled" do expect do config.minimum_coverage branch: 42 @@ -131,6 +138,12 @@ expect(config.coverage_criterion).to eq :branch end + it "works fine with :method" do + config.coverage_criterion :method + + expect(config.coverage_criterion).to eq :method + end + it "works fine setting it back and forth" do config.coverage_criterion :branch config.coverage_criterion :line @@ -184,5 +197,19 @@ expect(config).not_to be_branch_coverage end end + + describe "#method_coverage?", if: SimpleCov.method_coverage_supported? do + it "returns true of method coverage is being measured" do + config.enable_coverage :method + + expect(config).to be_method_coverage + end + + it "returns false for line coverage" do + config.coverage_criterion :line + + expect(config).not_to be_method_coverage + end + end end end diff --git a/spec/simplecov_spec.rb b/spec/simplecov_spec.rb index 74fe7de6..17962702 100644 --- a/spec/simplecov_spec.rb +++ b/spec/simplecov_spec.rb @@ -291,12 +291,20 @@ def clear_mergeable_reports(*names) SimpleCov.send :start_coverage_measurement end - it "starts coverage with lines and branches if branches is activated" do + it "starts coverage with lines and branches if branch coverage is activated" do expect(Coverage).to receive(:start).with(lines: true, branches: true) SimpleCov.enable_coverage :branch SimpleCov.send :start_coverage_measurement end + + it "starts coverage with lines and methods if method coverage is activated" do + expect(Coverage).to receive(:start).with(lines: true, methods: true) + + SimpleCov.enable_coverage :method + + SimpleCov.send :start_coverage_measurement + end end end diff --git a/spec/source_file_spec.rb b/spec/source_file_spec.rb index bb35d2b9..c9a518cb 100644 --- a/spec/source_file_spec.rb +++ b/spec/source_file_spec.rb @@ -4,7 +4,7 @@ describe SimpleCov::SourceFile do COVERAGE_FOR_SAMPLE_RB = { - "lines" => [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil, nil, 1, 0, nil, nil, nil], + "lines" => [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil, nil, 1, 0, nil, nil, nil], "branches" => {} }.freeze @@ -95,7 +95,7 @@ context "file with branches" do COVERAGE_FOR_BRANCHES_RB = { - "lines" => [1, 1, 1, nil, 1, nil, 1, 0, nil, 1, nil, nil, nil], + "lines" => [1, 1, 1, nil, 1, nil, 1, 0, nil, 1, nil, nil, nil], "branches" => { [:if, 0, 3, 4, 3, 21] => {[:then, 1, 3, 4, 3, 10] => 0, [:else, 2, 3, 4, 3, 21] => 1}, @@ -185,7 +185,7 @@ context "A file that has inline branches" do COVERAGE_FOR_INLINE = { - "lines" => [1, 1, 1, nil, 1, 1, 0, nil, 1, nil, nil, nil, nil], + "lines" => [1, 1, 1, nil, 1, 1, 0, nil, 1, nil, nil, nil, nil], "branches" => { [:if, 0, 3, 11, 3, 33] => {[:then, 1, 3, 23, 3, 27] => 1, [:else, 2, 3, 30, 3, 33] => 0}, @@ -331,7 +331,7 @@ context "a file with more complex skipping" do COVERAGE_FOR_NOCOV_COMPLEX_RB = { - "lines" => [nil, nil, 1, 1, nil, 1, nil, nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, 1, nil, 0, nil, nil, 1, nil, nil, nil, nil], + "lines" => [nil, nil, 1, 1, nil, 1, nil, nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, 1, nil, 0, nil, nil, 1, nil, nil, nil, nil], "branches" => { [:if, 0, 6, 4, 11, 7] => {[:then, 1, 7, 6, 7, 7] => 0, [:else, 2, 10, 6, 10, 7] => 1}, @@ -392,7 +392,7 @@ context "a file with nested branches" do COVERAGE_FOR_NESTED_BRANCHES_RB = { - "lines" => [nil, nil, 1, 1, 1, 1, 1, 1, nil, nil, 0, nil, nil, nil, nil], + "lines" => [nil, nil, 1, 1, 1, 1, 1, 1, nil, nil, 0, nil, nil, nil, nil], "branches" => { [:while, 0, 7, 8, 7, 31] => {[:body, 1, 7, 8, 7, 16] => 2}, @@ -428,7 +428,7 @@ context "a file with case" do COVERAGE_FOR_CASE_STATEMENT_RB = { - "lines" => [1, 1, 1, nil, 0, nil, 1, nil, 0, nil, 0, nil, nil, nil], + "lines" => [1, 1, 1, nil, 0, nil, 1, nil, 0, nil, 0, nil, nil, nil], "branches" => { [:case, 0, 3, 4, 12, 7] => { [:when, 1, 5, 6, 5, 10] => 0, @@ -471,7 +471,7 @@ context "a file with case without else" do COVERAGE_FOR_CASE_WITHOUT_ELSE_STATEMENT_RB = { - "lines" => [1, 1, 1, nil, 0, nil, 1, nil, 0, nil, nil, nil], + "lines" => [1, 1, 1, nil, 0, nil, 1, nil, 0, nil, nil, nil], "branches" => { [:case, 0, 3, 4, 10, 7] => { [:when, 1, 5, 6, 5, 10] => 0, @@ -556,7 +556,7 @@ context "the branch tester script" do COVERAGE_FOR_BRANCH_TESTER_RB = { - "lines" => [nil, nil, 1, 1, nil, 1, nil, 1, 1, nil, nil, 1, 0, nil, nil, 1, 0, nil, 1, nil, nil, 1, 1, 1, nil, nil, 1, 0, nil, nil, 1, 1, nil, 0, nil, 1, 1, 0, 0, 1, 5, 0, 0, nil, 0, nil, 0, nil, nil, nil], + "lines" => [nil, nil, 1, 1, nil, 1, nil, 1, 1, nil, nil, 1, 0, nil, nil, 1, 0, nil, 1, nil, nil, 1, 1, 1, nil, nil, 1, 0, nil, nil, 1, 1, nil, 0, nil, 1, 1, 0, 0, 1, 5, 0, 0, nil, 0, nil, 0, nil, nil, nil], "branches" => { [:if, 0, 4, 0, 4, 19] => {[:then, 1, 4, 12, 4, 15] => 0, [:else, 2, 4, 18, 4, 19] => 1}, From d68a977a049f313f28cd887983bb7f22a5bca3fb Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Sat, 22 Aug 2020 14:22:24 +0300 Subject: [PATCH 03/34] add some temp stuff --- Gemfile | 2 +- Gemfile.lock | 7 +++++- features/method_coverage.feature | 37 +++++++++++++++++++++++++++++ lib/simplecov/source_file/method.rb | 33 +++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 features/method_coverage.feature create mode 100644 lib/simplecov/source_file/method.rb diff --git a/Gemfile b/Gemfile index 9688762b..4422fd79 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source "https://rubygems.org" # Uncomment this to use local copy of simplecov-html in development when checked out -# gem "simplecov-html", path: File.dirname(__FILE__) + "/../simplecov-html" +gem "simplecov-html", path: File.dirname(__FILE__) + "/../simplecov-html" # Uncomment this to use development version of html formatter from github # gem "simplecov-html", github: "colszowka/simplecov-html" diff --git a/Gemfile.lock b/Gemfile.lock index 5ceb1e75..4b581c5c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,6 +5,11 @@ PATH docile (~> 1.1) simplecov-html (~> 0.11) +PATH + remote: ../simplecov-html + specs: + simplecov-html (0.12.2) + GEM remote: https://rubygems.org/ specs: @@ -136,7 +141,6 @@ GEM rubocop-ast (0.3.0) parser (>= 2.7.1.4) ruby-progressbar (1.10.1) - simplecov-html (0.12.2) spoon (0.0.6) ffi sys-uname (1.2.1) @@ -174,6 +178,7 @@ DEPENDENCIES rspec (~> 3.2) rubocop simplecov! + simplecov-html! test-unit BUNDLED WITH diff --git a/features/method_coverage.feature b/features/method_coverage.feature new file mode 100644 index 00000000..9d10b4a3 --- /dev/null +++ b/features/method_coverage.feature @@ -0,0 +1,37 @@ +@rspec @method_coverage +Feature: + + Simply executing method coverage gives ok results. + + Background: + Given I'm working on the project "faked_project" + + Scenario: + Given SimpleCov for RSpec is configured with: + """ + require 'simplecov' + SimpleCov.start do + enable_coverage :method + end + """ + When I open the coverage report generated with `bundle exec rspec spec` + Then I should see the groups: + | name | coverage | files | + | All Files | 91.8% | 7 | + # And I should see a line coverage summary of 56/61 + # And I should see a branch coverage summary of 2/4 + # And I should see the source files: + # | name | coverage | branch coverage | + # | lib/faked_project.rb | 100.00 % | 100.00 % | + # | lib/faked_project/some_class.rb | 80.00 % | 50.00 % | + # | lib/faked_project/framework_specific.rb | 75.00 % | 100.00 % | + # | lib/faked_project/meta_magic.rb | 100.00 % | 100.00 % | + # | spec/forking_spec.rb | 100.00 % | 50.00 % | + # | spec/meta_magic_spec.rb | 100.00 % | 100.00 % | + # | spec/some_class_spec.rb | 100.00 % | 100.00 % | + + # When I open the detailed view for "lib/faked_project/some_class.rb" + # Then I should see a line coverage summary of 12/15 for the file + # And I should see a branch coverage summary of 1/2 for the file + # And I should see coverage branch data like "then: 1" + # And I should see coverage branch data like "else: 0" diff --git a/lib/simplecov/source_file/method.rb b/lib/simplecov/source_file/method.rb new file mode 100644 index 00000000..0daf983a --- /dev/null +++ b/lib/simplecov/source_file/method.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module SimpleCov + class SourceFile + class Method + attr_reader :source_file, :coverage + attr_reader :klass, :method, :start_line, :start_col, :end_line, :end_col + + def initialize(source_file, info, coverage) + @source_file = source_file + @klass, @method, @start_line, @start_col, @end_line, @end_col = info + @coverage = coverage + end + + def covered? + !skipped? && coverage.positive? + end + + def skipped? + return @skipped if defined?(@skipped) + @skipped = lines.all?(&:skipped?) + end + + def lines + @lines ||= source_file.lines[(start_line - 1)..(end_line - 1)] + end + + def to_s + "#{klass}##{method}" + end + end + end +end From 1f40180ac5902cb7c27e28ab57848edf5f4fdb8c Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Sat, 22 Aug 2020 15:31:03 +0300 Subject: [PATCH 04/34] add basic method coverage support --- lib/simplecov.rb | 3 +- lib/simplecov/file_list.rb | 7 +- lib/simplecov/result.rb | 22 ++--- lib/simplecov/result_serialization.rb | 112 ++++++++++++++++++++++++++ lib/simplecov/source_file.rb | 38 +++++++-- lib/simplecov/source_file/method.rb | 4 + 6 files changed, 167 insertions(+), 19 deletions(-) create mode 100644 lib/simplecov/result_serialization.rb diff --git a/lib/simplecov.rb b/lib/simplecov.rb index 83263b2e..e7a1572c 100644 --- a/lib/simplecov.rb +++ b/lib/simplecov.rb @@ -445,7 +445,7 @@ def probably_running_parallel_tests? require_relative "simplecov/profiles" require_relative "simplecov/source_file/line" require_relative "simplecov/source_file/branch" -# require_relative "simplecov/source_file/method" +require_relative "simplecov/source_file/method" require_relative "simplecov/source_file" require_relative "simplecov/file_list" require_relative "simplecov/result" @@ -454,6 +454,7 @@ def probably_running_parallel_tests? require_relative "simplecov/last_run" require_relative "simplecov/lines_classifier" require_relative "simplecov/result_merger" +require_relative "simplecov/result_serialization" require_relative "simplecov/command_guesser" require_relative "simplecov/version" require_relative "simplecov/result_adapter" diff --git a/lib/simplecov/file_list.rb b/lib/simplecov/file_list.rb index c8872ae9..2b20fc49 100644 --- a/lib/simplecov/file_list.rb +++ b/lib/simplecov/file_list.rb @@ -98,17 +98,20 @@ def branch_covered_percent coverage_statistics[:branch]&.percent end + # TODO: add method cov methods for html report + private - # TODO: add method cov def compute_coverage_statistics - total_coverage_statistics = @files.each_with_object(line: [], branch: []) do |file, together| + total_coverage_statistics = @files.each_with_object(line: [], branch: [], method: []) do |file, together| together[:line] << file.coverage_statistics[:line] together[:branch] << file.coverage_statistics[:branch] if SimpleCov.branch_coverage? + together[:method] << file.coverage_statistics[:method] if SimpleCov.method_coverage? end coverage_statistics = {line: CoverageStatistics.from(total_coverage_statistics[:line])} coverage_statistics[:branch] = CoverageStatistics.from(total_coverage_statistics[:branch]) if SimpleCov.branch_coverage? + coverage_statistics[:method] = CoverageStatistics.from(total_coverage_statistics[:method]) if SimpleCov.method_coverage? coverage_statistics end end diff --git a/lib/simplecov/result.rb b/lib/simplecov/result.rb index d153bb01..b9c74ebe 100644 --- a/lib/simplecov/result.rb +++ b/lib/simplecov/result.rb @@ -64,12 +64,12 @@ def command_name # Returns a hash representation of this Result that can be used for marshalling it into JSON def to_hash - { - command_name => { - "coverage" => coverage, - "timestamp" => created_at.to_i - } - } + SimpleCov::ResultSerialization.serialize(self) + end + + # Loads a SimpleCov::Result#to_hash dump + def self.from_hash(hash) + SimpleCov::ResultSerialization.deserialize(hash) end # Loads a SimpleCov::Result#to_hash dump @@ -83,6 +83,11 @@ def self.from_hash(hash) result end + def coverage + keys = original_result.keys & filenames + Hash[keys.zip(original_result.values_at(*keys))] + end + private # We changed the format of the raw result data in simplecov, as people are likely @@ -110,11 +115,6 @@ def adapt_pre_simplecov_0_18_result(result) end end - def coverage - keys = original_result.keys & filenames - Hash[keys.zip(original_result.values_at(*keys))] - end - # Applies all configured SimpleCov filters on this result's source files def filter! @files = SimpleCov.filtered(files) diff --git a/lib/simplecov/result_serialization.rb b/lib/simplecov/result_serialization.rb new file mode 100644 index 00000000..baeab5c8 --- /dev/null +++ b/lib/simplecov/result_serialization.rb @@ -0,0 +1,112 @@ +# frozen_string_literal: true + +module SimpleCov + class ResultSerialization + class << self + def serialize(result) + coverage = {} + + result.coverage.each do |file_path, file_data| + serializable_file_data = {} + + file_data.each do |key, value| + serializable_file_data[key] = serialize_value(key, value) + end + + coverage[file_path] = serializable_file_data + end + + data = {"coverage" => coverage, "timestamp" => result.created_at.to_i} + {result.command_name => data} + end + + def deserialize(hash) # rubocop:disable Metrics/MethodLength + command_name, data = hash.first + + coverage = {} + + data["coverage"].each do |file_name, file_data| + parsed_file_data = {} + + file_data.each do |key, value| + key = key.to_sym + parsed_file_data[key] = deserialize_value(key, value) + end + + coverage[file_name] = parsed_file_data + end + + result = SimpleCov::Result.new(coverage) + result.command_name = command_name + result.created_at = Time.at(data["timestamp"]) + result + end + + private + + def serialize_value(key, value) # rubocop:disable Metrics/MethodLength + case key + when :branches + value.map { |k, v| [k, v.to_a] } + when :methods + value.map do |methods_data, coverage| + klass, *info = methods_data + # Replace all memory addresses with 0 since they are inconsistent between test runs + serialized_klass = klass.to_s.sub(/0x[0-9a-f]{16}/, "0x0000000000000000") + serialized_methods_data = [serialized_klass, *info] + [serialized_methods_data, coverage] + end + else + value + end + end + + def deserialize_value(key, value) + case key + when :branches + deserialize_branches(value) + when :methods + deserialize_methods(value) + else + value + end + end + + def deserialize_branches(value) + result = {} + + value.each do |serialized_root, serialized_coverage_data| + root = deserialize_branch_info(serialized_root) + coverage_data = {} + + serialized_coverage_data.each do |serialized_branch, coverage| + branch = deserialize_branch_info(serialized_branch) + coverage_data[branch] = coverage + end + + result[root] = coverage_data + end + + result + end + + def deserialize_branch_info(value) + type, *info = value + [type.to_sym, *info] + end + + def deserialize_methods(value) + result = Hash.new { |hash, key| hash[key] = 0 } + + value.each do |serialized_info, coverage| + klass, method_name, *info = serialized_info + info = [klass, method_name.to_sym, *info] + # Info keys might be non-unique since we replace memory addresses with 0 + result[info] += coverage + end + + result + end + end + end +end diff --git a/lib/simplecov/source_file.rb b/lib/simplecov/source_file.rb index c3c394e6..a99975f2 100644 --- a/lib/simplecov/source_file.rb +++ b/lib/simplecov/source_file.rb @@ -33,8 +33,8 @@ def coverage_statistics @coverage_statistics ||= { **line_coverage_statistics, - **branch_coverage_statistics - # TODO: add method cov + **branch_coverage_statistics, + **method_coverage_statistics, } end @@ -155,6 +155,18 @@ def line_with_missed_branch?(line_number) branches_for_line(line_number).select { |_type, count| count.zero? }.any? end + def methods + @methods ||= build_methods + end + + def covered_methods + methods.select(&:covered?) + end + + def missed_methods + methods.select(&:missed?) + end + private # no_cov_chunks is zero indexed to work directly with the array holding the lines @@ -293,6 +305,7 @@ def process_skipped_branches(branches) # See #801 # def restore_ruby_data_structure(structure) + return structure # TODO[@tycooon]: remove # Tests use the real data structures (except for integration tests) so no need to # put them through here. return structure if structure.is_a?(Array) @@ -328,12 +341,18 @@ def build_branch(branch_data, hit_count, condition_start_line) ) end + def build_methods + coverage_data.fetch("methods", []).map do |info, coverage| + SourceFile::Method.new(self, info, coverage) + end + end + def line_coverage_statistics { line: CoverageStatistics.new( total_strength: lines_strength, - covered: covered_lines.size, - missed: missed_lines.size + covered: covered_lines.size, + missed: missed_lines.size ) } end @@ -342,7 +361,16 @@ def branch_coverage_statistics { branch: CoverageStatistics.new( covered: covered_branches.size, - missed: missed_branches.size + missed: missed_branches.size + ) + } + end + + def method_coverage_statistics + { + method: CoverageStatistics.new( + covered: covered_methods.size, + missed: missed_methods.size ) } end diff --git a/lib/simplecov/source_file/method.rb b/lib/simplecov/source_file/method.rb index 0daf983a..f30f7d77 100644 --- a/lib/simplecov/source_file/method.rb +++ b/lib/simplecov/source_file/method.rb @@ -21,6 +21,10 @@ def skipped? @skipped = lines.all?(&:skipped?) end + def missed? + !skipped? && coverage.zero? + end + def lines @lines ||= source_file.lines[(start_line - 1)..(end_line - 1)] end From d609d16e122d5e6a4a9681173a07bc024964da9f Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Sat, 22 Aug 2020 15:53:46 +0300 Subject: [PATCH 05/34] fix serialization --- lib/simplecov/result.rb | 15 +++------------ lib/simplecov/result_merger.rb | 2 +- lib/simplecov/source_file.rb | 8 ++++---- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/lib/simplecov/result.rb b/lib/simplecov/result.rb index b9c74ebe..582d01c3 100644 --- a/lib/simplecov/result.rb +++ b/lib/simplecov/result.rb @@ -30,9 +30,11 @@ class Result def initialize(original_result) result = adapt_result(original_result) @original_result = result.freeze + @files = SimpleCov::FileList.new(result.map do |filename, coverage| - SimpleCov::SourceFile.new(filename, JSON.parse(JSON.dump(coverage))) if File.file?(filename) + SimpleCov::SourceFile.new(filename, coverage) if File.file?(filename) end.compact.sort_by(&:filename)) + filter! end @@ -72,17 +74,6 @@ def self.from_hash(hash) SimpleCov::ResultSerialization.deserialize(hash) end - # Loads a SimpleCov::Result#to_hash dump - def self.from_hash(hash) - command_name, data = hash.first - - result = SimpleCov::Result.new(data["coverage"]) - - result.command_name = command_name - result.created_at = Time.at(data["timestamp"]) - result - end - def coverage keys = original_result.keys & filenames Hash[keys.zip(original_result.values_at(*keys))] diff --git a/lib/simplecov/result_merger.rb b/lib/simplecov/result_merger.rb index f0d1338d..2f506a7b 100644 --- a/lib/simplecov/result_merger.rb +++ b/lib/simplecov/result_merger.rb @@ -72,7 +72,7 @@ def merge_and_store(*results) # coverage data and the command_name for the result consisting of a join # on all source result's names def merge_results(*results) - parsed_results = JSON.parse(JSON.dump(results.map(&:original_result))) + parsed_results = results.map(&:original_result) combined_result = SimpleCov::Combine::ResultsCombiner.combine(*parsed_results) result = SimpleCov::Result.new(combined_result) # Specify the command name diff --git a/lib/simplecov/source_file.rb b/lib/simplecov/source_file.rb index a99975f2..a112a5be 100644 --- a/lib/simplecov/source_file.rb +++ b/lib/simplecov/source_file.rb @@ -234,9 +234,9 @@ def ensure_remove_undefs(file_lines) end def build_lines - coverage_exceeding_source_warn if coverage_data["lines"].size > src.size + coverage_exceeding_source_warn if coverage_data.fetch(:lines).size > src.size lines = src.map.with_index(1) do |src, i| - SimpleCov::SourceFile::Line.new(src, i, coverage_data["lines"][i - 1]) + SimpleCov::SourceFile::Line.new(src, i, coverage_data.fetch(:lines)[i - 1]) end process_skipped_lines(lines) end @@ -278,7 +278,7 @@ def build_branches_report # @return [Array] # def build_branches - coverage_branch_data = coverage_data.fetch("branches", {}) + coverage_branch_data = coverage_data.fetch(:branches, {}) branches = coverage_branch_data.flat_map do |condition, coverage_branches| build_branches_from(condition, coverage_branches) end @@ -342,7 +342,7 @@ def build_branch(branch_data, hit_count, condition_start_line) end def build_methods - coverage_data.fetch("methods", []).map do |info, coverage| + coverage_data.fetch(:methods, []).map do |info, coverage| SourceFile::Method.new(self, info, coverage) end end From f00fdf2c0bc79732be9d23b63843396993599f43 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Wed, 2 Sep 2020 19:02:24 +0300 Subject: [PATCH 06/34] some fixes and fix all specs --- lib/simplecov/combine/files_combiner.rb | 11 +++- lib/simplecov/result.rb | 2 +- lib/simplecov/result_adapter.rb | 2 +- lib/simplecov/simulate_coverage.rb | 6 +-- lib/simplecov/source_file.rb | 32 +++-------- spec/combine/results_combiner_spec.rb | 72 +++++++++++++------------ spec/file_list_spec.rb | 12 ++--- spec/result_merger_spec.rb | 24 ++++----- spec/result_spec.rb | 8 +-- spec/simplecov_spec.rb | 4 +- spec/source_file_spec.rb | 64 +++++++++++----------- spec/useless_results_remover_spec.rb | 10 ++-- 12 files changed, 120 insertions(+), 127 deletions(-) diff --git a/lib/simplecov/combine/files_combiner.rb b/lib/simplecov/combine/files_combiner.rb index 32df1184..b70429d6 100644 --- a/lib/simplecov/combine/files_combiner.rb +++ b/lib/simplecov/combine/files_combiner.rb @@ -15,8 +15,15 @@ module FilesCombiner # @return [Hash] # def combine(coverage_a, coverage_b) - combination = {"lines" => Combine.combine(LinesCombiner, coverage_a["lines"], coverage_b["lines"])} - combination["branches"] = Combine.combine(BranchesCombiner, coverage_a["branches"], coverage_b["branches"]) if SimpleCov.branch_coverage? + combination = {} + combination[:lines] = Combine.combine(LinesCombiner, coverage_a[:lines], coverage_b[:lines]) + + if SimpleCov.branch_coverage? + combination[:branches] = Combine.combine(BranchesCombiner, coverage_a[:branches], coverage_b[:branches]) + end + + # TODO: add method cov + combination end end diff --git a/lib/simplecov/result.rb b/lib/simplecov/result.rb index 582d01c3..f9f6fcc0 100644 --- a/lib/simplecov/result.rb +++ b/lib/simplecov/result.rb @@ -102,7 +102,7 @@ def pre_simplecov_0_18_result?(result) def adapt_pre_simplecov_0_18_result(result) result.transform_values do |line_coverage_data| - {"lines" => line_coverage_data} + {lines: line_coverage_data} end end diff --git a/lib/simplecov/result_adapter.rb b/lib/simplecov/result_adapter.rb index 4b7f07f9..79cf8e6f 100644 --- a/lib/simplecov/result_adapter.rb +++ b/lib/simplecov/result_adapter.rb @@ -20,7 +20,7 @@ def adapt result.each_with_object({}) do |(file_name, cover_statistic), adapted_result| if cover_statistic.is_a?(Array) - adapted_result.merge!(file_name => {"lines" => cover_statistic}) + adapted_result.merge!(file_name => {lines: cover_statistic}) else adapted_result.merge!(file_name => cover_statistic) end diff --git a/lib/simplecov/simulate_coverage.rb b/lib/simplecov/simulate_coverage.rb index 387cfcd4..bc95bfe5 100644 --- a/lib/simplecov/simulate_coverage.rb +++ b/lib/simplecov/simulate_coverage.rb @@ -19,11 +19,11 @@ def call(absolute_path) lines = File.foreach(absolute_path) { - "lines" => LinesClassifier.new.classify(lines), + lines: LinesClassifier.new.classify(lines), # we don't want to parse branches ourselves... # requiring files can have side effects and we don't want to trigger that - "branches" => {} - # TODO: add method cov? + branches: {}, + methods: {}, } end end diff --git a/lib/simplecov/source_file.rb b/lib/simplecov/source_file.rb index a112a5be..583495db 100644 --- a/lib/simplecov/source_file.rb +++ b/lib/simplecov/source_file.rb @@ -234,9 +234,9 @@ def ensure_remove_undefs(file_lines) end def build_lines - coverage_exceeding_source_warn if coverage_data.fetch(:lines).size > src.size + coverage_exceeding_source_warn if lines_data.size > src.size lines = src.map.with_index(1) do |src, i| - SimpleCov::SourceFile::Line.new(src, i, coverage_data.fetch(:lines)[i - 1]) + SimpleCov::SourceFile::Line.new(src, i, lines_data[i - 1]) end process_skipped_lines(lines) end @@ -254,9 +254,13 @@ def lines_strength lines.map(&:coverage).compact.reduce(:+) end + def lines_data + coverage_data.fetch(:lines) + end + # Warning to identify condition from Issue #56 def coverage_exceeding_source_warn - warn "Warning: coverage data provided by Coverage [#{coverage_data['lines'].size}] exceeds number of lines in #{filename} [#{src.size}]" + warn "Warning: coverage data provided by Coverage [#{lines_data.size}] exceeds number of lines in #{filename} [#{src.size}]" end # @@ -296,35 +300,15 @@ def process_skipped_branches(branches) branches end - # Since we are dumping to and loading from JSON, and we have arrays as keys those - # don't make their way back to us intact e.g. just as a string - # - # We should probably do something different here, but as it stands these are - # our data structures that we write so eval isn't _too_ bad. - # - # See #801 - # - def restore_ruby_data_structure(structure) - return structure # TODO[@tycooon]: remove - # Tests use the real data structures (except for integration tests) so no need to - # put them through here. - return structure if structure.is_a?(Array) - - # rubocop:disable Security/Eval - eval structure - # rubocop:enable Security/Eval - end - def build_branches_from(condition, branches) # the format handed in from the coverage data is like this: # # [:then, 4, 6, 6, 6, 10] # # which is [type, id, start_line, start_col, end_line, end_col] - _condition_type, _condition_id, condition_start_line, * = restore_ruby_data_structure(condition) + _condition_type, _condition_id, condition_start_line, * = condition branches.map do |branch_data, hit_count| - branch_data = restore_ruby_data_structure(branch_data) build_branch(branch_data, hit_count, condition_start_line) end end diff --git a/spec/combine/results_combiner_spec.rb b/spec/combine/results_combiner_spec.rb index a0af4081..df32ad68 100644 --- a/spec/combine/results_combiner_spec.rb +++ b/spec/combine/results_combiner_spec.rb @@ -7,39 +7,39 @@ let(:resultset1) do { source_fixture("sample.rb") => { - "lines" => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], - "branches" => {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}} + lines: [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], + branches: {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}} # TODO: add method cov? }, source_fixture("app/models/user.rb") => { - "lines" => [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil], - "branches" => {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}} + lines: [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil], + branches: {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}} }, - source_fixture("app/controllers/sample_controller.rb") => {"lines" => [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]}, - source_fixture("resultset1.rb") => {"lines" => [1, 1, 1, 1]}, - source_fixture("parallel_tests.rb") => {"lines" => [nil, 0, nil, 0]}, - source_fixture("conditionally_loaded_1.rb") => {"lines" => [nil, 0, 1]}, # loaded only in the first resultset - source_fixture("three.rb") => {"lines" => [nil, 1, 1]} + source_fixture("app/controllers/sample_controller.rb") => {lines: [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]}, + source_fixture("resultset1.rb") => {lines: [1, 1, 1, 1]}, + source_fixture("parallel_tests.rb") => {lines: [nil, 0, nil, 0]}, + source_fixture("conditionally_loaded_1.rb") => {lines: [nil, 0, 1]}, # loaded only in the first resultset + source_fixture("three.rb") => {lines: [nil, 1, 1]} } end let(:resultset2) do { - source_fixture("sample.rb") => {"lines" => [1, nil, 1, 1, nil, nil, 1, 1, nil, nil]}, + source_fixture("sample.rb") => {lines: [1, nil, 1, 1, nil, nil, 1, 1, nil, nil]}, source_fixture("app/models/user.rb") => { - "lines" => [nil, 1, 5, 1, nil, nil, 1, 0, nil, nil], - "branches" => {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 1, [:else, 5, 8, 6, 8, 36] => 2}} + lines: [nil, 1, 5, 1, nil, nil, 1, 0, nil, nil], + branches: {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 1, [:else, 5, 8, 6, 8, 36] => 2}} }, - source_fixture("app/controllers/sample_controller.rb") => {"lines" => [nil, 3, 1, nil, nil, nil, 1, 0, nil, nil]}, - source_fixture("resultset2.rb") => {"lines" => [nil, 1, 1, nil]}, - source_fixture("parallel_tests.rb") => {"lines" => [nil, nil, 0, 0]}, - source_fixture("conditionally_loaded_2.rb") => {"lines" => [nil, 0, 1]}, # loaded only in the second resultset - source_fixture("three.rb") => {"lines" => [nil, 1, 4]} + source_fixture("app/controllers/sample_controller.rb") => {lines: [nil, 3, 1, nil, nil, nil, 1, 0, nil, nil]}, + source_fixture("resultset2.rb") => {lines: [nil, 1, 1, nil]}, + source_fixture("parallel_tests.rb") => {lines: [nil, nil, 0, 0]}, + source_fixture("conditionally_loaded_2.rb") => {lines: [nil, 0, 1]}, # loaded only in the second resultset + source_fixture("three.rb") => {lines: [nil, 1, 4]} } end let(:resultset3) do - {source_fixture("three.rb") => {"lines" => [nil, 1, 2]}} + {source_fixture("three.rb") => {lines: [nil, 1, 2]}} end after do @@ -56,70 +56,72 @@ end it "has proper results for sample.rb" do - expect(subject[source_fixture("sample.rb")]["lines"]).to eq([1, 1, 2, 2, nil, nil, 2, 2, nil, nil]) + expect(subject[source_fixture("sample.rb")][:lines]).to eq([1, 1, 2, 2, nil, nil, 2, 2, nil, nil]) + + # TODO: add method cov # gotta configure max line so it doesn't get ridiculous # rubocop:disable Style/IfUnlessModifier if SimpleCov.branch_coverage_supported? - expect(subject[source_fixture("sample.rb")]["branches"][[:if, 3, 8, 6, 8, 36]][[:then, 4, 8, 6, 8, 12]]).to eq(47) + expect(subject[source_fixture("sample.rb")][:branches][[:if, 3, 8, 6, 8, 36]][[:then, 4, 8, 6, 8, 12]]).to eq(47) end # rubocop:enable Style/IfUnlessModifier end it "has proper results for user.rb" do - expect(subject[source_fixture("app/models/user.rb")]["lines"]).to eq([nil, 2, 6, 2, nil, nil, 2, 0, nil, nil]) + expect(subject[source_fixture("app/models/user.rb")][:lines]).to eq([nil, 2, 6, 2, nil, nil, 2, 0, nil, nil]) if SimpleCov.branch_coverage_supported? - expect(subject[source_fixture("app/models/user.rb")]["branches"][[:if, 3, 8, 6, 8, 36]][[:then, 4, 8, 6, 8, 12]]).to eq(48) - expect(subject[source_fixture("app/models/user.rb")]["branches"][[:if, 3, 8, 6, 8, 36]][[:else, 5, 8, 6, 8, 36]]).to eq(26) + expect(subject[source_fixture("app/models/user.rb")][:branches][[:if, 3, 8, 6, 8, 36]][[:then, 4, 8, 6, 8, 12]]).to eq(48) + expect(subject[source_fixture("app/models/user.rb")][:branches][[:if, 3, 8, 6, 8, 36]][[:else, 5, 8, 6, 8, 36]]).to eq(26) end end it "has proper results for sample_controller.rb" do - expect(subject[source_fixture("app/controllers/sample_controller.rb")]["lines"]).to eq([nil, 4, 2, 1, nil, nil, 2, 0, nil, nil]) + expect(subject[source_fixture("app/controllers/sample_controller.rb")][:lines]).to eq([nil, 4, 2, 1, nil, nil, 2, 0, nil, nil]) end it "has proper results for resultset1.rb" do - expect(subject[source_fixture("resultset1.rb")]["lines"]).to eq([1, 1, 1, 1]) + expect(subject[source_fixture("resultset1.rb")][:lines]).to eq([1, 1, 1, 1]) end it "has proper results for resultset2.rb" do - expect(subject[source_fixture("resultset2.rb")]["lines"]).to eq([nil, 1, 1, nil]) + expect(subject[source_fixture("resultset2.rb")][:lines]).to eq([nil, 1, 1, nil]) end it "has proper results for parallel_tests.rb" do - expect(subject[source_fixture("parallel_tests.rb")]["lines"]).to eq([nil, nil, nil, 0]) + expect(subject[source_fixture("parallel_tests.rb")][:lines]).to eq([nil, nil, nil, 0]) end it "has proper results for conditionally_loaded_1.rb" do - expect(subject[source_fixture("conditionally_loaded_1.rb")]["lines"]).to eq([nil, 0, 1]) + expect(subject[source_fixture("conditionally_loaded_1.rb")][:lines]).to eq([nil, 0, 1]) end it "has proper results for conditionally_loaded_2.rb" do - expect(subject[source_fixture("conditionally_loaded_2.rb")]["lines"]).to eq([nil, 0, 1]) + expect(subject[source_fixture("conditionally_loaded_2.rb")][:lines]).to eq([nil, 0, 1]) end it "has proper results for three.rb" do - expect(subject[source_fixture("three.rb")]["lines"]).to eq([nil, 3, 7]) + expect(subject[source_fixture("three.rb")][:lines]).to eq([nil, 3, 7]) end end end it "merges frozen resultsets" do resultset1 = { - source_fixture("sample.rb").freeze => {"lines" => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil]}, - source_fixture("app/models/user.rb").freeze => {"lines" => [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]} + source_fixture("sample.rb").freeze => {lines: [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil]}, + source_fixture("app/models/user.rb").freeze => {lines: [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]} } resultset2 = { - source_fixture("sample.rb").freeze => {"lines" => [1, nil, 1, 1, nil, nil, 1, 1, nil, nil]} + source_fixture("sample.rb").freeze => {lines: [1, nil, 1, 1, nil, nil, 1, 1, nil, nil]} } merged_result = SimpleCov::Combine::ResultsCombiner.combine(resultset1, resultset2) expect(merged_result.keys).to eq(resultset1.keys) expect(merged_result.values.map(&:frozen?)).to eq([false, false]) - expect(merged_result[source_fixture("sample.rb")]["lines"]).to eq([1, 1, 2, 2, nil, nil, 2, 2, nil, nil]) - expect(merged_result[source_fixture("app/models/user.rb")]["lines"]).to eq([nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]) + expect(merged_result[source_fixture("sample.rb")][:lines]).to eq([1, 1, 2, 2, nil, nil, 2, 2, nil, nil]) + expect(merged_result[source_fixture("app/models/user.rb")][:lines]).to eq([nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]) end end diff --git a/spec/file_list_spec.rb b/spec/file_list_spec.rb index 7de0eac6..03325cbb 100644 --- a/spec/file_list_spec.rb +++ b/spec/file_list_spec.rb @@ -6,17 +6,17 @@ subject do original_result = { source_fixture("sample.rb") => { - "lines" => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], - "branches" => {} + lines: [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], + branches: {} # TODO: add method cov }, source_fixture("app/models/user.rb") => { - "lines" => [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil], - "branches" => {} + lines: [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil], + branches: {} }, source_fixture("app/controllers/sample_controller.rb") => { - "lines" => [nil, 2, 2, 0, nil, nil, 0, nil, nil, nil], - "branches" => {} + lines: [nil, 2, 2, 0, nil, nil, 0, nil, nil, nil], + branches: {} } } SimpleCov::Result.new(original_result).files diff --git a/spec/result_merger_spec.rb b/spec/result_merger_spec.rb index 42234513..5f2223a9 100644 --- a/spec/result_merger_spec.rb +++ b/spec/result_merger_spec.rb @@ -13,21 +13,21 @@ describe "with two faked coverage resultsets" do before do @resultset1 = { - source_fixture("sample.rb") => {"lines" => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil]}, - source_fixture("app/models/user.rb") => {"lines" => [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]}, - source_fixture("app/controllers/sample_controller.rb") => {"lines" => [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]}, - source_fixture("resultset1.rb") => {"lines" => [1, 1, 1, 1]}, - source_fixture("parallel_tests.rb") => {"lines" => [nil, 0, nil, 0]}, - source_fixture("conditionally_loaded_1.rb") => {"lines" => [nil, 0, 1]} # loaded only in the first resultset + source_fixture("sample.rb") => {lines: [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil]}, + source_fixture("app/models/user.rb") => {lines: [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]}, + source_fixture("app/controllers/sample_controller.rb") => {lines: [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]}, + source_fixture("resultset1.rb") => {lines: [1, 1, 1, 1]}, + source_fixture("parallel_tests.rb") => {lines: [nil, 0, nil, 0]}, + source_fixture("conditionally_loaded_1.rb") => {lines: [nil, 0, 1]} # loaded only in the first resultset } @resultset2 = { - source_fixture("sample.rb") => {"lines" => [1, nil, 1, 1, nil, nil, 1, 1, nil, nil]}, - source_fixture("app/models/user.rb") => {"lines" => [nil, 1, 5, 1, nil, nil, 1, 0, nil, nil]}, - source_fixture("app/controllers/sample_controller.rb") => {"lines" => [nil, 3, 1, nil, nil, nil, 1, 0, nil, nil]}, - source_fixture("resultset2.rb") => {"lines" => [nil, 1, 1, nil]}, - source_fixture("parallel_tests.rb") => {"lines" => [nil, nil, 0, 0]}, - source_fixture("conditionally_loaded_2.rb") => {"lines" => [nil, 0, 1]} # loaded only in the second resultset + source_fixture("sample.rb") => {lines: [1, nil, 1, 1, nil, nil, 1, 1, nil, nil]}, + source_fixture("app/models/user.rb") => {lines: [nil, 1, 5, 1, nil, nil, 1, 0, nil, nil]}, + source_fixture("app/controllers/sample_controller.rb") => {lines: [nil, 3, 1, nil, nil, nil, 1, 0, nil, nil]}, + source_fixture("resultset2.rb") => {lines: [nil, 1, 1, nil]}, + source_fixture("parallel_tests.rb") => {lines: [nil, nil, 0, 0]}, + source_fixture("conditionally_loaded_2.rb") => {lines: [nil, 0, 1]} # loaded only in the second resultset } end diff --git a/spec/result_spec.rb b/spec/result_spec.rb index 462a6787..4d367bb8 100644 --- a/spec/result_spec.rb +++ b/spec/result_spec.rb @@ -21,9 +21,9 @@ let(:original_result) do { - source_fixture("sample.rb") => {"lines" => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil]}, - source_fixture("app/models/user.rb") => {"lines" => [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]}, - source_fixture("app/controllers/sample_controller.rb") => {"lines" => [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]} + source_fixture("sample.rb") => {lines: [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil]}, + source_fixture("app/models/user.rb") => {lines: [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]}, + source_fixture("app/controllers/sample_controller.rb") => {lines: [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]} } end @@ -212,7 +212,7 @@ old_resultset = {source_fixture("three.rb") => [nil, 1, 2]} expect(described_class.new(old_resultset).original_result).to eq( - source_fixture("three.rb") => {"lines" => [nil, 1, 2]} + source_fixture("three.rb") => {lines: [nil, 1, 2]} ) end end diff --git a/spec/simplecov_spec.rb b/spec/simplecov_spec.rb index 17962702..4306b4de 100644 --- a/spec/simplecov_spec.rb +++ b/spec/simplecov_spec.rb @@ -192,11 +192,11 @@ describe ".collate" do let(:resultset1) do - {source_fixture("sample.rb") => {"lines" => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil]}} + {source_fixture("sample.rb") => {lines: [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil]}} end let(:resultset2) do - {source_fixture("sample.rb") => {"lines" => [1, nil, 1, 1, nil, nil, 1, 1, nil, nil]}} + {source_fixture("sample.rb") => {lines: [1, nil, 1, 1, nil, nil, 1, 1, nil, nil]}} end let(:resultset_path) { SimpleCov::ResultMerger.resultset_path } diff --git a/spec/source_file_spec.rb b/spec/source_file_spec.rb index c9a518cb..6ae17ac5 100644 --- a/spec/source_file_spec.rb +++ b/spec/source_file_spec.rb @@ -4,12 +4,12 @@ describe SimpleCov::SourceFile do COVERAGE_FOR_SAMPLE_RB = { - "lines" => [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil, nil, 1, 0, nil, nil, nil], - "branches" => {} + lines: [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil, nil, 1, 0, nil, nil, nil], + branches: {} }.freeze COVERAGE_FOR_SAMPLE_RB_WITH_MORE_LINES = { - "lines" => [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil, nil, nil, nil, nil, nil, nil, nil] + lines: [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil, nil, nil, nil, nil, nil, nil, nil] }.freeze context "a source file initialized with some coverage data" do @@ -95,8 +95,8 @@ context "file with branches" do COVERAGE_FOR_BRANCHES_RB = { - "lines" => [1, 1, 1, nil, 1, nil, 1, 0, nil, 1, nil, nil, nil], - "branches" => { + lines: [1, 1, 1, nil, 1, nil, 1, 0, nil, 1, nil, nil, nil], + branches: { [:if, 0, 3, 4, 3, 21] => {[:then, 1, 3, 4, 3, 10] => 0, [:else, 2, 3, 4, 3, 21] => 1}, [:if, 3, 5, 4, 5, 26] => @@ -185,8 +185,8 @@ context "A file that has inline branches" do COVERAGE_FOR_INLINE = { - "lines" => [1, 1, 1, nil, 1, 1, 0, nil, 1, nil, nil, nil, nil], - "branches" => { + lines: [1, 1, 1, nil, 1, 1, 0, nil, 1, nil, nil, nil, nil], + branches: { [:if, 0, 3, 11, 3, 33] => {[:then, 1, 3, 23, 3, 27] => 1, [:else, 2, 3, 30, 3, 33] => 0}, [:if, 3, 6, 6, 10, 9] => @@ -217,7 +217,7 @@ end context "a file that is never relevant" do - COVERAGE_FOR_NEVER_RB = {"lines" => [nil, nil], "branches" => {}}.freeze + COVERAGE_FOR_NEVER_RB = {lines: [nil, nil], branches: {}}.freeze subject do SimpleCov::SourceFile.new(source_fixture("never.rb"), COVERAGE_FOR_NEVER_RB) @@ -237,7 +237,7 @@ end context "a file where nothing is ever executed mixed with skipping #563" do - COVERAGE_FOR_SKIPPED_RB = {"lines" => [nil, nil, nil, nil]}.freeze + COVERAGE_FOR_SKIPPED_RB = {lines: [nil, nil, nil, nil]}.freeze subject do SimpleCov::SourceFile.new(source_fixture("skipped.rb"), COVERAGE_FOR_SKIPPED_RB) @@ -253,7 +253,7 @@ end context "a file where everything is skipped and missed #563" do - COVERAGE_FOR_SKIPPED_RB_2 = {"lines" => [nil, nil, 0, nil]}.freeze + COVERAGE_FOR_SKIPPED_RB_2 = {lines: [nil, nil, 0, nil]}.freeze subject do SimpleCov::SourceFile.new(source_fixture("skipped.rb"), COVERAGE_FOR_SKIPPED_RB_2) @@ -275,8 +275,8 @@ context "a file where everything is skipped/irrelevant but executed #563" do COVERAGE_FOR_SKIPPED_AND_EXECUTED_RB = { - "lines" => [nil, nil, 1, 1, 0, 0, nil, 0, nil, nil, nil, nil], - "branches" => { + lines: [nil, nil, 1, 1, 0, 0, nil, 0, nil, nil, nil, nil], + branches: { [:if, 0, 5, 4, 9, 7] => {[:then, 1, 6, 6, 6, 7] => 1, [:else, 2, 8, 6, 8, 7] => 0} } @@ -331,8 +331,8 @@ context "a file with more complex skipping" do COVERAGE_FOR_NOCOV_COMPLEX_RB = { - "lines" => [nil, nil, 1, 1, nil, 1, nil, nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, 1, nil, 0, nil, nil, 1, nil, nil, nil, nil], - "branches" => { + lines: [nil, nil, 1, 1, nil, 1, nil, nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, 1, nil, 0, nil, nil, 1, nil, nil, nil, nil], + branches: { [:if, 0, 6, 4, 11, 7] => {[:then, 1, 7, 6, 7, 7] => 0, [:else, 2, 10, 6, 10, 7] => 1}, [:if, 3, 13, 4, 13, 24] => @@ -392,8 +392,8 @@ context "a file with nested branches" do COVERAGE_FOR_NESTED_BRANCHES_RB = { - "lines" => [nil, nil, 1, 1, 1, 1, 1, 1, nil, nil, 0, nil, nil, nil, nil], - "branches" => { + lines: [nil, nil, 1, 1, 1, 1, 1, 1, nil, nil, 0, nil, nil, nil, nil], + branches: { [:while, 0, 7, 8, 7, 31] => {[:body, 1, 7, 8, 7, 16] => 2}, [:if, 2, 6, 6, 9, 9] => @@ -428,8 +428,8 @@ context "a file with case" do COVERAGE_FOR_CASE_STATEMENT_RB = { - "lines" => [1, 1, 1, nil, 0, nil, 1, nil, 0, nil, 0, nil, nil, nil], - "branches" => { + lines: [1, 1, 1, nil, 0, nil, 1, nil, 0, nil, 0, nil, nil, nil], + branches: { [:case, 0, 3, 4, 12, 7] => { [:when, 1, 5, 6, 5, 10] => 0, [:when, 2, 7, 6, 7, 10] => 1, @@ -471,8 +471,8 @@ context "a file with case without else" do COVERAGE_FOR_CASE_WITHOUT_ELSE_STATEMENT_RB = { - "lines" => [1, 1, 1, nil, 0, nil, 1, nil, 0, nil, nil, nil], - "branches" => { + lines: [1, 1, 1, nil, 0, nil, 1, nil, 0, nil, nil, nil], + branches: { [:case, 0, 3, 4, 10, 7] => { [:when, 1, 5, 6, 5, 10] => 0, [:when, 2, 7, 6, 7, 10] => 1, @@ -518,8 +518,8 @@ context "a file with if/elsif" do COVERAGE_FOR_ELSIF_RB = { - "lines" => [1, 1, 1, 0, 1, 0, 1, 1, nil, 0, nil, nil, nil], - "branches" => { + lines: [1, 1, 1, 0, 1, 0, 1, 1, nil, 0, nil, nil, nil], + branches: { [:if, 0, 7, 4, 10, 10] => {[:then, 1, 8, 6, 8, 10] => 1, [:else, 2, 10, 6, 10, 10] => 0}, [:if, 3, 5, 4, 10, 10] => @@ -556,8 +556,8 @@ context "the branch tester script" do COVERAGE_FOR_BRANCH_TESTER_RB = { - "lines" => [nil, nil, 1, 1, nil, 1, nil, 1, 1, nil, nil, 1, 0, nil, nil, 1, 0, nil, 1, nil, nil, 1, 1, 1, nil, nil, 1, 0, nil, nil, 1, 1, nil, 0, nil, 1, 1, 0, 0, 1, 5, 0, 0, nil, 0, nil, 0, nil, nil, nil], - "branches" => { + lines: [nil, nil, 1, 1, nil, 1, nil, 1, 1, nil, nil, 1, 0, nil, nil, 1, 0, nil, 1, nil, nil, 1, 1, 1, nil, nil, 1, 0, nil, nil, 1, 1, nil, 0, nil, 1, 1, 0, 0, 1, 5, 0, 0, nil, 0, nil, 0, nil, nil, nil], + branches: { [:if, 0, 4, 0, 4, 19] => {[:then, 1, 4, 12, 4, 15] => 0, [:else, 2, 4, 18, 4, 19] => 1}, [:unless, 3, 6, 0, 6, 23] => @@ -610,8 +610,8 @@ context "a file entirely ignored with a single # :nocov:" do COVERAGE_FOR_SINGLE_NOCOV_RB = { - "lines" => [nil, 1, 1, 1, 0, 1, 0, 1, 1, nil, 0, nil, nil, nil], - "branches" => { + lines: [nil, 1, 1, 1, 0, 1, 0, 1, 1, nil, 0, nil, nil, nil], + branches: { [:if, 0, 8, 4, 11, 10] => {[:then, 1, 9, 6, 9, 10] => 1, [:else, 2, 11, 6, 11, 10] => 0}, [:if, 3, 6, 4, 11, 10] => @@ -655,8 +655,8 @@ context "a file with an uneven usage of # :nocov:s" do COVERAGE_FOR_UNEVEN_NOCOV_RB = { - "lines" => [1, 1, nil, 1, 0, 1, 0, nil, 1, 1, nil, nil, 0, nil, nil, nil], - "branches" => { + lines: [1, 1, nil, 1, 0, 1, 0, nil, 1, 1, nil, nil, 0, nil, nil, nil], + branches: { [:if, 0, 9, 4, 13, 10] => {[:then, 1, 10, 6, 10, 10] => 1, [:else, 2, 13, 6, 13, 10] => 0}, [:if, 3, 6, 4, 13, 10] => @@ -698,9 +698,9 @@ end context "a file contains non-ASCII characters" do - COVERAGE_FOR_SINGLE_LINE = {"lines" => [nil]}.freeze - COVERAGE_FOR_DOUBLE_LINES = {"lines" => [nil, 1]}.freeze - COVERAGE_FOR_TRIPLE_LINES = {"lines" => [nil, nil, 1]}.freeze + COVERAGE_FOR_SINGLE_LINE = {lines: [nil]}.freeze + COVERAGE_FOR_DOUBLE_LINES = {lines: [nil, 1]}.freeze + COVERAGE_FOR_TRIPLE_LINES = {lines: [nil, nil, 1]}.freeze DEGREE_135_LINE = "puts \"135°C\"\n" shared_examples_for "converting to UTF-8" do @@ -766,7 +766,7 @@ describe "empty euc-jp file" do subject do - SimpleCov::SourceFile.new(source_fixture("empty_euc-jp.rb"), "lines" => []) + SimpleCov::SourceFile.new(source_fixture("empty_euc-jp.rb"), lines: []) end it "has empty lines" do diff --git a/spec/useless_results_remover_spec.rb b/spec/useless_results_remover_spec.rb index cafa56b5..f4b107cd 100644 --- a/spec/useless_results_remover_spec.rb +++ b/spec/useless_results_remover_spec.rb @@ -9,13 +9,13 @@ let(:result_set) do { gem_file_path => { - "lines" => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], - "branches" => {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}} + lines: [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], + branches: {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}} # TODO: add method cov? }, source_path => { - "lines" => [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil], - "branches" => {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}} + lines: [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil], + branches: {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}} } } end @@ -31,6 +31,6 @@ it "still retains the app path" do expect(subject).to have_key(source_path) - expect(subject[source_path]["lines"]).to be_kind_of(Array) + expect(subject[source_path][:lines]).to be_kind_of(Array) end end From 31b95e7536d585500f6ee336ca35a918cf4c5dd7 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Wed, 2 Sep 2020 19:14:12 +0300 Subject: [PATCH 07/34] add methods combiner --- Gemfile | 2 +- Gemfile.lock | 7 +---- lib/simplecov.rb | 4 +-- lib/simplecov/combine/files_combiner.rb | 3 +-- lib/simplecov/combine/methods_combiner.rb | 31 +++++++++++++++++++++++ lib/simplecov/combine/results_combiner.rb | 2 +- lib/simplecov/file_list.rb | 17 ++++++++----- lib/simplecov/simulate_coverage.rb | 2 +- lib/simplecov/source_file.rb | 2 +- lib/simplecov/source_file/method.rb | 4 +-- spec/combine/results_combiner_spec.rb | 16 +++++++----- 11 files changed, 60 insertions(+), 30 deletions(-) create mode 100644 lib/simplecov/combine/methods_combiner.rb diff --git a/Gemfile b/Gemfile index 4422fd79..9688762b 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source "https://rubygems.org" # Uncomment this to use local copy of simplecov-html in development when checked out -gem "simplecov-html", path: File.dirname(__FILE__) + "/../simplecov-html" +# gem "simplecov-html", path: File.dirname(__FILE__) + "/../simplecov-html" # Uncomment this to use development version of html formatter from github # gem "simplecov-html", github: "colszowka/simplecov-html" diff --git a/Gemfile.lock b/Gemfile.lock index 4b581c5c..5ceb1e75 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,11 +5,6 @@ PATH docile (~> 1.1) simplecov-html (~> 0.11) -PATH - remote: ../simplecov-html - specs: - simplecov-html (0.12.2) - GEM remote: https://rubygems.org/ specs: @@ -141,6 +136,7 @@ GEM rubocop-ast (0.3.0) parser (>= 2.7.1.4) ruby-progressbar (1.10.1) + simplecov-html (0.12.2) spoon (0.0.6) ffi sys-uname (1.2.1) @@ -178,7 +174,6 @@ DEPENDENCIES rspec (~> 3.2) rubocop simplecov! - simplecov-html! test-unit BUNDLED WITH diff --git a/lib/simplecov.rb b/lib/simplecov.rb index e7a1572c..aa96c809 100644 --- a/lib/simplecov.rb +++ b/lib/simplecov.rb @@ -356,7 +356,7 @@ def start_coverage_with_criteria CRITERION_TO_RUBY_COVERAGE = { branch: :branches, line: :lines, - method: :methods, + method: :methods }.freeze def lookup_corresponding_ruby_coverage_name(criterion) CRITERION_TO_RUBY_COVERAGE.fetch(criterion) @@ -460,7 +460,7 @@ def probably_running_parallel_tests? require_relative "simplecov/result_adapter" require_relative "simplecov/combine" require_relative "simplecov/combine/branches_combiner" -# require_relative "simplecov/combine/methods_combiner" +require_relative "simplecov/combine/methods_combiner" require_relative "simplecov/combine/files_combiner" require_relative "simplecov/combine/lines_combiner" require_relative "simplecov/combine/results_combiner" diff --git a/lib/simplecov/combine/files_combiner.rb b/lib/simplecov/combine/files_combiner.rb index b70429d6..f4a5725f 100644 --- a/lib/simplecov/combine/files_combiner.rb +++ b/lib/simplecov/combine/files_combiner.rb @@ -20,10 +20,9 @@ def combine(coverage_a, coverage_b) if SimpleCov.branch_coverage? combination[:branches] = Combine.combine(BranchesCombiner, coverage_a[:branches], coverage_b[:branches]) + combination[:methods] = Combine.combine(MethodsCombiner, coverage_a[:methods], coverage_b[:methods]) end - # TODO: add method cov - combination end end diff --git a/lib/simplecov/combine/methods_combiner.rb b/lib/simplecov/combine/methods_combiner.rb new file mode 100644 index 00000000..b842c423 --- /dev/null +++ b/lib/simplecov/combine/methods_combiner.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module SimpleCov + module Combine + # + # Combine different method coverage results on single file. + # + # Should be called through `SimpleCov.combine`. + module MethodsCombiner + module_function + + # + # TODO[@tycooon]: add description + # + # @return [Hash] + # + def combine(coverage_a, coverage_b) + result_coverage = {} + + keys = (coverage_a.keys + coverage_b.keys).uniq + + keys.each do |method_name| + result_coverage[method_name] = + coverage_a.fetch(method_name, 0) + coverage_b.fetch(method_name, 0) + end + + result_coverage + end + end + end +end diff --git a/lib/simplecov/combine/results_combiner.rb b/lib/simplecov/combine/results_combiner.rb index 9f3896e6..2ebf8edc 100644 --- a/lib/simplecov/combine/results_combiner.rb +++ b/lib/simplecov/combine/results_combiner.rb @@ -16,7 +16,7 @@ module ResultsCombiner # ==> FileCombiner: collect result of next combine levels lines and branches. # ===> LinesCombiner: combine lines results. # ===> BranchesCombiner: combine branches results. - # TODO: add method cov + # ===> MethodsCombiner: combine methods results. # # @return [Hash] # diff --git a/lib/simplecov/file_list.rb b/lib/simplecov/file_list.rb index 2b20fc49..d48e7202 100644 --- a/lib/simplecov/file_list.rb +++ b/lib/simplecov/file_list.rb @@ -98,21 +98,24 @@ def branch_covered_percent coverage_statistics[:branch]&.percent end - # TODO: add method cov methods for html report + # TODO: add method cov methods for html report private def compute_coverage_statistics - total_coverage_statistics = @files.each_with_object(line: [], branch: [], method: []) do |file, together| - together[:line] << file.coverage_statistics[:line] - together[:branch] << file.coverage_statistics[:branch] if SimpleCov.branch_coverage? - together[:method] << file.coverage_statistics[:method] if SimpleCov.method_coverage? - end - + total_coverage_statistics = compute_total_coverage_statistics coverage_statistics = {line: CoverageStatistics.from(total_coverage_statistics[:line])} coverage_statistics[:branch] = CoverageStatistics.from(total_coverage_statistics[:branch]) if SimpleCov.branch_coverage? coverage_statistics[:method] = CoverageStatistics.from(total_coverage_statistics[:method]) if SimpleCov.method_coverage? coverage_statistics end + + def compute_total_coverage_statistics + @files.each_with_object(line: [], branch: [], method: []) do |file, together| + together[:line] << file.coverage_statistics[:line] + together[:branch] << file.coverage_statistics[:branch] if SimpleCov.branch_coverage? + together[:method] << file.coverage_statistics[:method] if SimpleCov.method_coverage? + end + end end end diff --git a/lib/simplecov/simulate_coverage.rb b/lib/simplecov/simulate_coverage.rb index bc95bfe5..f75122db 100644 --- a/lib/simplecov/simulate_coverage.rb +++ b/lib/simplecov/simulate_coverage.rb @@ -23,7 +23,7 @@ def call(absolute_path) # we don't want to parse branches ourselves... # requiring files can have side effects and we don't want to trigger that branches: {}, - methods: {}, + methods: {} } end end diff --git a/lib/simplecov/source_file.rb b/lib/simplecov/source_file.rb index 583495db..3adb7f3d 100644 --- a/lib/simplecov/source_file.rb +++ b/lib/simplecov/source_file.rb @@ -34,7 +34,7 @@ def coverage_statistics { **line_coverage_statistics, **branch_coverage_statistics, - **method_coverage_statistics, + **method_coverage_statistics } end diff --git a/lib/simplecov/source_file/method.rb b/lib/simplecov/source_file/method.rb index f30f7d77..3096dad4 100644 --- a/lib/simplecov/source_file/method.rb +++ b/lib/simplecov/source_file/method.rb @@ -3,8 +3,7 @@ module SimpleCov class SourceFile class Method - attr_reader :source_file, :coverage - attr_reader :klass, :method, :start_line, :start_col, :end_line, :end_col + attr_reader :source_file, :coverage, :klass, :method, :start_line, :start_col, :end_line, :end_col def initialize(source_file, info, coverage) @source_file = source_file @@ -18,6 +17,7 @@ def covered? def skipped? return @skipped if defined?(@skipped) + @skipped = lines.all?(&:skipped?) end diff --git a/spec/combine/results_combiner_spec.rb b/spec/combine/results_combiner_spec.rb index df32ad68..abc605cc 100644 --- a/spec/combine/results_combiner_spec.rb +++ b/spec/combine/results_combiner_spec.rb @@ -9,11 +9,11 @@ source_fixture("sample.rb") => { lines: [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], branches: {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}} - # TODO: add method cov? }, source_fixture("app/models/user.rb") => { lines: [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil], - branches: {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}} + branches: {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}}, + methods: {["#", "foo", 4, 2, 6, 5] => 1} }, source_fixture("app/controllers/sample_controller.rb") => {lines: [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]}, source_fixture("resultset1.rb") => {lines: [1, 1, 1, 1]}, @@ -28,7 +28,8 @@ source_fixture("sample.rb") => {lines: [1, nil, 1, 1, nil, nil, 1, 1, nil, nil]}, source_fixture("app/models/user.rb") => { lines: [nil, 1, 5, 1, nil, nil, 1, 0, nil, nil], - branches: {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 1, [:else, 5, 8, 6, 8, 36] => 2}} + branches: {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 1, [:else, 5, 8, 6, 8, 36] => 2}}, + methods: {["#", "foo", 4, 2, 6, 5] => 5, ["#", "bar", 1, 2, 3, 4] => 3} }, source_fixture("app/controllers/sample_controller.rb") => {lines: [nil, 3, 1, nil, nil, nil, 1, 0, nil, nil]}, source_fixture("resultset2.rb") => {lines: [nil, 1, 1, nil]}, @@ -58,14 +59,11 @@ it "has proper results for sample.rb" do expect(subject[source_fixture("sample.rb")][:lines]).to eq([1, 1, 2, 2, nil, nil, 2, 2, nil, nil]) - # TODO: add method cov - # gotta configure max line so it doesn't get ridiculous - # rubocop:disable Style/IfUnlessModifier if SimpleCov.branch_coverage_supported? expect(subject[source_fixture("sample.rb")][:branches][[:if, 3, 8, 6, 8, 36]][[:then, 4, 8, 6, 8, 12]]).to eq(47) + expect(subject[source_fixture("sample.rb")][:methods]).to eq(nil) end - # rubocop:enable Style/IfUnlessModifier end it "has proper results for user.rb" do @@ -74,6 +72,10 @@ if SimpleCov.branch_coverage_supported? expect(subject[source_fixture("app/models/user.rb")][:branches][[:if, 3, 8, 6, 8, 36]][[:then, 4, 8, 6, 8, 12]]).to eq(48) expect(subject[source_fixture("app/models/user.rb")][:branches][[:if, 3, 8, 6, 8, 36]][[:else, 5, 8, 6, 8, 36]]).to eq(26) + expect(subject[source_fixture("app/models/user.rb")][:methods]).to eq( + ["#", "foo", 4, 2, 6, 5] => 6, + ["#", "bar", 1, 2, 3, 4] => 3 + ) end end From fa3902aa9bdf93f42cf8b0a03ceee2c820320cb0 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Wed, 2 Sep 2020 19:27:11 +0300 Subject: [PATCH 08/34] update ci config --- .github/workflows/stable.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stable.yml b/.github/workflows/stable.yml index 6593643e..ad3f2d7e 100644 --- a/.github/workflows/stable.yml +++ b/.github/workflows/stable.yml @@ -4,8 +4,9 @@ on: pull_request: push: - branches: - - master + # TODO[@tycooon]: uncomment + # branches: + # - master jobs: test: From a78b5eda8fce24d16ca28f3308bf20b640b8dd3b Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Thu, 3 Sep 2020 13:17:05 +0300 Subject: [PATCH 09/34] add some backwards compability to result serialization --- Gemfile | 2 +- Gemfile.lock | 7 +- features/branch_coverage.feature | 2 +- features/step_definitions/html_steps.rb | 2 +- lib/simplecov/result_serialization.rb | 7 ++ spec/result_spec.rb | 137 +++++++++++++++++++++--- 6 files changed, 136 insertions(+), 21 deletions(-) diff --git a/Gemfile b/Gemfile index ccbbb9f9..49d8952f 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source "https://rubygems.org" # Uncomment this to use local copy of simplecov-html in development when checked out -# gem "simplecov-html", path: File.dirname(__FILE__) + "/../simplecov-html" +gem "simplecov-html", path: File.dirname(__FILE__) + "/../simplecov-html" # Uncomment this to use development version of html formatter from github # gem "simplecov-html", github: "simplecov-ruby/simplecov-html" diff --git a/Gemfile.lock b/Gemfile.lock index dc1772d6..226539d3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,6 +5,11 @@ PATH docile (~> 1.1) simplecov-html (~> 0.11) +PATH + remote: ../simplecov-html + specs: + simplecov-html (0.12.2) + GEM remote: https://rubygems.org/ specs: @@ -136,7 +141,6 @@ GEM rubocop-ast (0.3.0) parser (>= 2.7.1.4) ruby-progressbar (1.10.1) - simplecov-html (0.12.2) spoon (0.0.6) ffi sys-uname (1.2.1) @@ -174,6 +178,7 @@ DEPENDENCIES rspec (~> 3.2) rubocop simplecov! + simplecov-html! test-unit BUNDLED WITH diff --git a/features/branch_coverage.feature b/features/branch_coverage.feature index 55f0d096..622cd780 100644 --- a/features/branch_coverage.feature +++ b/features/branch_coverage.feature @@ -21,7 +21,7 @@ Feature: And I should see a line coverage summary of 56/61 And I should see a branch coverage summary of 2/4 And I should see the source files: - | name | coverage | branch coverage | + | name | coverage | branch coverage | | lib/faked_project.rb | 100.00 % | 100.00 % | | lib/faked_project/some_class.rb | 80.00 % | 50.00 % | | lib/faked_project/framework_specific.rb | 75.00 % | 100.00 % | diff --git a/features/step_definitions/html_steps.rb b/features/step_definitions/html_steps.rb index a2cffa7b..3e0f993d 100644 --- a/features/step_definitions/html_steps.rb +++ b/features/step_definitions/html_steps.rb @@ -25,7 +25,7 @@ expected_files = table.hashes available_source_files = all(".t-file", visible: true) - expect(expected_files.length).to eq(available_source_files.count) + expect(available_source_files.count).to eq(expected_files.length) include_branch_coverage = table.column_names.include?("branch coverage") # Find all filenames and their coverage present in coverage report diff --git a/lib/simplecov/result_serialization.rb b/lib/simplecov/result_serialization.rb index 79b138ce..eeb4361e 100644 --- a/lib/simplecov/result_serialization.rb +++ b/lib/simplecov/result_serialization.rb @@ -27,6 +27,8 @@ def deserialize(hash) # rubocop:disable Metrics/MethodLength data["coverage"].each do |file_name, file_data| parsed_file_data = {} + file_data = {lines: file_data} if file_data.is_a?(Array) + file_data.each do |key, value| key = key.to_sym parsed_file_data[key] = deserialize_value(key, value) @@ -91,6 +93,7 @@ def deserialize_branches(value) end def deserialize_branch_info(value) + value = adapt_old_style_branch_info(value) if value.is_a?(Symbol) type, *info = value [type.to_sym, *info] end @@ -107,6 +110,10 @@ def deserialize_methods(value) result end + + def adapt_old_style_branch_info(value) + eval(value.to_s) # rubocop:disable Security/Eval + end end end end diff --git a/spec/result_spec.rb b/spec/result_spec.rb index 296eb0ed..6b540709 100644 --- a/spec/result_spec.rb +++ b/spec/result_spec.rb @@ -207,32 +207,135 @@ end describe ".from_hash" do - let(:other_result) do - { - source_fixture("sample.rb") => {lines: [nil, 1, 1, 1, nil, nil, 0, 0, nil, nil]} - } - end let(:created_at) { Time.now.to_i } - it "can consume multiple commands" do - input = { + let(:input) do + { "rspec" => { "coverage" => original_result, "timestamp" => created_at - }, - "cucumber" => { - "coverage" => other_result, - "timestamp" => created_at } } + end - result = described_class.from_hash(input) + let(:expected_branch_coverage) do + { + [:unless, 0, 8, 4, 8, 90] => { + [:else, 1, 8, 4, 8, 90] => 0, + [:then, 2, 8, 4, 8, 35] => 1 + } + } + end - expect(result.size).to eq 2 - sorted = result.sort_by(&:command_name) - expect(sorted.map(&:command_name)).to eq %w[cucumber rspec] - expect(sorted.map(&:created_at).map(&:to_i)).to eq [created_at, created_at] - expect(sorted.map(&:original_result)).to eq [other_result, original_result] + context "multiple commands" do + let(:other_result) do + { + source_fixture("sample.rb") => {lines: [nil, 1, 1, 1, nil, nil, 0, 0, nil, nil]} + } + end + + let(:input) do + { + "rspec" => { + "coverage" => original_result, + "timestamp" => created_at + }, + "cucumber" => { + "coverage" => other_result, + "timestamp" => created_at + } + } + end + + it "can consume multiple commands" do + result = described_class.from_hash(input) + + expect(result.size).to eq 2 + sorted = result.sort_by(&:command_name) + expect(sorted.map(&:command_name)).to eq %w[cucumber rspec] + expect(sorted.map(&:created_at).map(&:to_i)).to eq [created_at, created_at] + expect(sorted.map(&:original_result)).to eq [other_result, original_result] + end + end + + context "branch and method coverage present" do + let(:original_result) do + { + source_fixture("sample.rb") => { + "lines" => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], + "branches" => [ + [ + ["unless", 0, 8, 4, 8, 90], + [ + [["else", 1, 8, 4, 8, 90], 0], + [["then", 2, 8, 4, 8, 35], 1] + ] + ] + ], + "methods" => [ + [["RSpec::ExampleGroups::SomeClass::LetDefinitions", "subject", 6, 10, 6, 34], 2] + ] + } + } + end + + it "parses that properly" do + result = described_class.from_hash(input) + + expect(result.size).to eq(1) + expect(result.first.original_result.size).to eq(1) + + expect(result.first.original_result.values.last).to eq( + lines: [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], + branches: expected_branch_coverage, + methods: { + ["RSpec::ExampleGroups::SomeClass::LetDefinitions", :subject, 6, 10, 6, 34] => 2 + } + ) + end + end + + context "old style line coverage format" do + let(:original_result) do + { source_fixture("sample.rb") => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil] } + end + + it "parses that properly" do + result = described_class.from_hash(input) + + expect(result.size).to eq(1) + expect(result.first.original_result.size).to eq(1) + + expect(result.first.original_result.values.last).to eq( + lines: [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], + ) + end + end + + context "old style branch coverage format" do + let(:original_result) do + { + source_fixture("sample.rb") => { + "branches" => { + "[:unless, 0, 8, 4, 8, 90]": { + "[:else, 1, 8, 4, 8, 90]": 0, + "[:then, 2, 8, 4, 8, 35]": 1 + } + } + } + } + end + + it "parses that properly" do + result = described_class.from_hash(input) + + expect(result.size).to eq(1) + expect(result.first.original_result.size).to eq(1) + + expect(result.first.original_result.values.last).to eq( + branches: expected_branch_coverage + ) + end end end end From b16b6e527c9adaa37353456bfe113f380a5b1105 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Thu, 3 Sep 2020 18:15:21 +0300 Subject: [PATCH 10/34] add some methods for html report --- lib/simplecov/combine/branches_combiner.rb | 2 +- lib/simplecov/combine/methods_combiner.rb | 2 +- lib/simplecov/file_list.rb | 19 +++- lib/simplecov/source_file.rb | 8 ++ spec/file_list_spec.rb | 10 +- spec/result_spec.rb | 118 ++++++++++++++------- spec/simplecov_spec.rb | 1 - spec/source_file/branch_spec.rb | 1 - spec/source_file/method_spec.rb | 7 ++ spec/source_file_spec.rb | 2 +- spec/useless_results_remover_spec.rb | 7 +- 11 files changed, 127 insertions(+), 50 deletions(-) create mode 100644 spec/source_file/method_spec.rb diff --git a/lib/simplecov/combine/branches_combiner.rb b/lib/simplecov/combine/branches_combiner.rb index 320f648f..2f0f4acd 100644 --- a/lib/simplecov/combine/branches_combiner.rb +++ b/lib/simplecov/combine/branches_combiner.rb @@ -10,7 +10,7 @@ module BranchesCombiner module_function # - # Return merged branches or the existed brach if other is missing. + # Return merged branches or the existing branch if other is missing. # # Branches inside files are always same if they exist, the difference only in coverage count. # Branch coverage report for any conditional case is built from hash, it's key is a condition and diff --git a/lib/simplecov/combine/methods_combiner.rb b/lib/simplecov/combine/methods_combiner.rb index b842c423..67604285 100644 --- a/lib/simplecov/combine/methods_combiner.rb +++ b/lib/simplecov/combine/methods_combiner.rb @@ -10,7 +10,7 @@ module MethodsCombiner module_function # - # TODO[@tycooon]: add description + # Combine method coverage from 2 sources # # @return [Hash] # diff --git a/lib/simplecov/file_list.rb b/lib/simplecov/file_list.rb index d48e7202..61f81d3b 100644 --- a/lib/simplecov/file_list.rb +++ b/lib/simplecov/file_list.rb @@ -98,7 +98,24 @@ def branch_covered_percent coverage_statistics[:branch]&.percent end - # TODO: add method cov methods for html report + # Return total count of methods in all files + def total_methods + coverage_statistics[:method]&.total + end + + # Return total count of covered methods + def covered_methods + coverage_statistics[:method]&.covered + end + + # Return total count of covered methods + def missed_methods + coverage_statistics[:method]&.missed + end + + def method_covered_percent + coverage_statistics[:method]&.percent + end private diff --git a/lib/simplecov/source_file.rb b/lib/simplecov/source_file.rb index 3adb7f3d..1c5bff55 100644 --- a/lib/simplecov/source_file.rb +++ b/lib/simplecov/source_file.rb @@ -159,6 +159,10 @@ def methods @methods ||= build_methods end + def total_methods + @total_methods ||= covered_methods + missed_methods + end + def covered_methods methods.select(&:covered?) end @@ -167,6 +171,10 @@ def missed_methods methods.select(&:missed?) end + def methods_coverage_percent + coverage_statistics[:method]&.percent + end + private # no_cov_chunks is zero indexed to work directly with the array holding the lines diff --git a/spec/file_list_spec.rb b/spec/file_list_spec.rb index 03325cbb..10033216 100644 --- a/spec/file_list_spec.rb +++ b/spec/file_list_spec.rb @@ -7,16 +7,18 @@ original_result = { source_fixture("sample.rb") => { lines: [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], - branches: {} - # TODO: add method cov + branches: {}, + methods: {} }, source_fixture("app/models/user.rb") => { lines: [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil], - branches: {} + branches: {}, + methods: {} }, source_fixture("app/controllers/sample_controller.rb") => { lines: [nil, 2, 2, 0, nil, nil, 0, nil, nil, nil], - branches: {} + branches: {}, + methods: {} } } SimpleCov::Result.new(original_result).files diff --git a/spec/result_spec.rb b/spec/result_spec.rb index 6b540709..e46416de 100644 --- a/spec/result_spec.rb +++ b/spec/result_spec.rb @@ -206,13 +206,58 @@ end end + describe "#to_hash" do + subject { SimpleCov::Result.new(original_result) } + + let(:original_result) do + { + source_fixture("sample.rb") => { + lines: [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], + branches: { + [:unless, 0, 8, 4, 8, 90] => { + [:else, 1, 8, 4, 8, 90] => 0, + [:then, 2, 8, 4, 8, 35] => 1 + } + }, + methods: { + ["# 2 + } + } + } + end + + it "dumps all coverage types properly" do + expect(subject.to_hash).to match( + "RSpec" => { + "coverage" => { + source_fixture("sample.rb") => { + lines: [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], + branches: [ + [ + [:unless, 0, 8, 4, 8, 90], [ + [[:else, 1, 8, 4, 8, 90], 0], + [[:then, 2, 8, 4, 8, 35], 1] + ] + ] + ], + methods: [ + [["# be_a(Integer), + } + ) + end + end + describe ".from_hash" do let(:created_at) { Time.now.to_i } let(:input) do { "rspec" => { - "coverage" => original_result, + "coverage" => dumped_result, "timestamp" => created_at } } @@ -227,46 +272,14 @@ } end - context "multiple commands" do - let(:other_result) do - { - source_fixture("sample.rb") => {lines: [nil, 1, 1, 1, nil, nil, 0, 0, nil, nil]} - } - end - - let(:input) do - { - "rspec" => { - "coverage" => original_result, - "timestamp" => created_at - }, - "cucumber" => { - "coverage" => other_result, - "timestamp" => created_at - } - } - end - - it "can consume multiple commands" do - result = described_class.from_hash(input) - - expect(result.size).to eq 2 - sorted = result.sort_by(&:command_name) - expect(sorted.map(&:command_name)).to eq %w[cucumber rspec] - expect(sorted.map(&:created_at).map(&:to_i)).to eq [created_at, created_at] - expect(sorted.map(&:original_result)).to eq [other_result, original_result] - end - end - context "branch and method coverage present" do - let(:original_result) do + let(:dumped_result) do { source_fixture("sample.rb") => { "lines" => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], "branches" => [ [ - ["unless", 0, 8, 4, 8, 90], - [ + ["unless", 0, 8, 4, 8, 90], [ [["else", 1, 8, 4, 8, 90], 0], [["then", 2, 8, 4, 8, 35], 1] ] @@ -296,7 +309,7 @@ end context "old style line coverage format" do - let(:original_result) do + let(:dumped_result) do { source_fixture("sample.rb") => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil] } end @@ -313,7 +326,7 @@ end context "old style branch coverage format" do - let(:original_result) do + let(:dumped_result) do { source_fixture("sample.rb") => { "branches" => { @@ -337,6 +350,37 @@ ) end end + + context "multiple commands" do + let(:other_result) do + { + source_fixture("sample.rb") => {lines: [nil, 1, 1, 1, nil, nil, 0, 0, nil, nil]} + } + end + + let(:input) do + { + "rspec" => { + "coverage" => original_result, + "timestamp" => created_at + }, + "cucumber" => { + "coverage" => other_result, + "timestamp" => created_at + } + } + end + + it "can consume multiple commands" do + result = described_class.from_hash(input) + + expect(result.size).to eq 2 + sorted = result.sort_by(&:command_name) + expect(sorted.map(&:command_name)).to eq %w[cucumber rspec] + expect(sorted.map(&:created_at).map(&:to_i)).to eq [created_at, created_at] + expect(sorted.map(&:original_result)).to eq [other_result, original_result] + end + end end end diff --git a/spec/simplecov_spec.rb b/spec/simplecov_spec.rb index 4306b4de..409f5371 100644 --- a/spec/simplecov_spec.rb +++ b/spec/simplecov_spec.rb @@ -172,7 +172,6 @@ end end - # TODO: add method cov context "branch coverage" do before do allow(SimpleCov).to receive(:minimum_coverage).and_return(branch: 90) diff --git a/spec/source_file/branch_spec.rb b/spec/source_file/branch_spec.rb index 99016c7e..048cc12b 100644 --- a/spec/source_file/branch_spec.rb +++ b/spec/source_file/branch_spec.rb @@ -2,7 +2,6 @@ require "helper" -# TODO: add method cov describe SimpleCov::SourceFile::Branch do let(:if_branch) do described_class.new(start_line: 1, end_line: 3, coverage: 0, inline: false, type: :then) diff --git a/spec/source_file/method_spec.rb b/spec/source_file/method_spec.rb new file mode 100644 index 00000000..a8c4d8a1 --- /dev/null +++ b/spec/source_file/method_spec.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require "helper" + +describe SimpleCov::SourceFile::Method do + # TODO[@tycooon]: add specs +end diff --git a/spec/source_file_spec.rb b/spec/source_file_spec.rb index 6ae17ac5..599ccee0 100644 --- a/spec/source_file_spec.rb +++ b/spec/source_file_spec.rb @@ -69,7 +69,7 @@ end end - # TODO: add method cov + # TODO[@tycooon]: add method cov describe "branch coverage" do it "has total branches count 0" do expect(subject.total_branches.size).to eq(0) diff --git a/spec/useless_results_remover_spec.rb b/spec/useless_results_remover_spec.rb index f4b107cd..b24e96ed 100644 --- a/spec/useless_results_remover_spec.rb +++ b/spec/useless_results_remover_spec.rb @@ -10,12 +10,13 @@ { gem_file_path => { lines: [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], - branches: {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}} - # TODO: add method cov? + branches: {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}}, + methods: {} }, source_path => { lines: [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil], - branches: {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}} + branches: {[:if, 3, 8, 6, 8, 36] => {[:then, 4, 8, 6, 8, 12] => 47, [:else, 5, 8, 6, 8, 36] => 24}}, + methods: {} } } end From 66e6e0be0705b1ab7373e06c9518bc336f9ce13c Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Tue, 22 Sep 2020 13:55:25 +0300 Subject: [PATCH 11/34] revert simplecov-html version --- Gemfile | 13 ++++++++----- Gemfile.lock | 7 +------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Gemfile b/Gemfile index 49d8952f..95a2357f 100644 --- a/Gemfile +++ b/Gemfile @@ -2,11 +2,14 @@ source "https://rubygems.org" -# Uncomment this to use local copy of simplecov-html in development when checked out -gem "simplecov-html", path: File.dirname(__FILE__) + "/../simplecov-html" - -# Uncomment this to use development version of html formatter from github -# gem "simplecov-html", github: "simplecov-ruby/simplecov-html" +case ENV["SIMPLECOV_HTML_MODE"] +when "local" + # Use local copy of simplecov-html in development when checked out + gem "simplecov-html", path: File.dirname(__FILE__) + "/../simplecov-html" +when "github" + # Use development version of html formatter from github + gem "simplecov-html", github: "simplecov-ruby/simplecov-html" +end group :development do gem "apparition", "~> 0.6.0" diff --git a/Gemfile.lock b/Gemfile.lock index 226539d3..dc1772d6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,11 +5,6 @@ PATH docile (~> 1.1) simplecov-html (~> 0.11) -PATH - remote: ../simplecov-html - specs: - simplecov-html (0.12.2) - GEM remote: https://rubygems.org/ specs: @@ -141,6 +136,7 @@ GEM rubocop-ast (0.3.0) parser (>= 2.7.1.4) ruby-progressbar (1.10.1) + simplecov-html (0.12.2) spoon (0.0.6) ffi sys-uname (1.2.1) @@ -178,7 +174,6 @@ DEPENDENCIES rspec (~> 3.2) rubocop simplecov! - simplecov-html! test-unit BUNDLED WITH From d79cb80843cf01c21efc4962d81f3d5bc26f7a22 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Tue, 22 Sep 2020 14:06:53 +0300 Subject: [PATCH 12/34] fix rubocop issues --- Gemfile | 4 +++- spec/result_spec.rb | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 95a2357f..680c54ae 100644 --- a/Gemfile +++ b/Gemfile @@ -2,14 +2,16 @@ source "https://rubygems.org" +# rubocop:disable Bundler/DuplicatedGem case ENV["SIMPLECOV_HTML_MODE"] when "local" # Use local copy of simplecov-html in development when checked out - gem "simplecov-html", path: File.dirname(__FILE__) + "/../simplecov-html" + gem "simplecov-html", path: "#{File.dirname(__FILE__)}/../simplecov-html" when "github" # Use development version of html formatter from github gem "simplecov-html", github: "simplecov-ruby/simplecov-html" end +# rubocop:enable Bundler/DuplicatedGem group :development do gem "apparition", "~> 0.6.0" diff --git a/spec/result_spec.rb b/spec/result_spec.rb index e46416de..195babf1 100644 --- a/spec/result_spec.rb +++ b/spec/result_spec.rb @@ -245,7 +245,7 @@ ] } }, - "timestamp" => be_a(Integer), + "timestamp" => be_a(Integer) } ) end @@ -310,7 +310,7 @@ context "old style line coverage format" do let(:dumped_result) do - { source_fixture("sample.rb") => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil] } + {source_fixture("sample.rb") => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil]} end it "parses that properly" do @@ -320,7 +320,7 @@ expect(result.first.original_result.size).to eq(1) expect(result.first.original_result.values.last).to eq( - lines: [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil], + lines: [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil] ) end end From 4904192d753bf5a2a95768a949b927920dce4986 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Tue, 22 Sep 2020 14:18:24 +0300 Subject: [PATCH 13/34] fix flacky specs --- spec/command_guesser_spec.rb | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/spec/command_guesser_spec.rb b/spec/command_guesser_spec.rb index 9817f3f2..4fbb1e0e 100644 --- a/spec/command_guesser_spec.rb +++ b/spec/command_guesser_spec.rb @@ -5,44 +5,44 @@ describe SimpleCov::CommandGuesser do subject { SimpleCov::CommandGuesser } it 'correctly guesses "Unit Tests" for unit tests' do - subject.original_run_command = "/some/path/test/units/foo_bar_test.rb" + allow(subject).to receive(:original_run_command) { "/some/path/test/units/foo_bar_test.rb" } expect(subject.guess).to eq("Unit Tests") - subject.original_run_command = "test/units/foo.rb" + allow(subject).to receive(:original_run_command) { "test/units/foo.rb" } expect(subject.guess).to eq("Unit Tests") - subject.original_run_command = "test/foo.rb" + allow(subject).to receive(:original_run_command) { "test/foo.rb" } expect(subject.guess).to eq("Unit Tests") - subject.original_run_command = "test/{models,helpers,unit}/**/*_test.rb" + allow(subject).to receive(:original_run_command) { "test/{models,helpers,unit}/**/*_test.rb" } expect(subject.guess).to eq("Unit Tests") end it 'correctly guesses "Functional Tests" for functional tests' do - subject.original_run_command = "/some/path/test/functional/foo_bar_controller_test.rb" + allow(subject).to receive(:original_run_command) { "/some/path/test/functional/foo_bar_controller_test.rb" } expect(subject.guess).to eq("Functional Tests") - subject.original_run_command = "test/{controllers,mailers,functional}/**/*_test.rb" + allow(subject).to receive(:original_run_command) { "test/{controllers,mailers,functional}/**/*_test.rb" } expect(subject.guess).to eq("Functional Tests") end it 'correctly guesses "Integration Tests" for integration tests' do - subject.original_run_command = "/some/path/test/integration/foo_bar_controller_test.rb" + allow(subject).to receive(:original_run_command) { "/some/path/test/integration/foo_bar_controller_test.rb" } expect(subject.guess).to eq("Integration Tests") - subject.original_run_command = "test/integration/**/*_test.rb" + allow(subject).to receive(:original_run_command) { "test/integration/**/*_test.rb" } expect(subject.guess).to eq("Integration Tests") end it 'correctly guesses "Cucumber Features" for cucumber features' do - subject.original_run_command = "features" + allow(subject).to receive(:original_run_command) { "features" } expect(subject.guess).to eq("Cucumber Features") - subject.original_run_command = "cucumber" + allow(subject).to receive(:original_run_command) { "cucumber" } expect(subject.guess).to eq("Cucumber Features") end it 'correctly guesses "RSpec" for RSpec' do - subject.original_run_command = "/some/path/spec/foo.rb" + allow(subject).to receive(:original_run_command) { "/some/path/spec/foo.rb" } expect(subject.guess).to eq("RSpec") end it "defaults to RSpec because RSpec constant is defined" do - subject.original_run_command = "some_arbitrary_command with arguments" + allow(subject).to receive(:original_run_command) { "some_arbitrary_command with arguments" } expect(subject.guess).to eq("RSpec") end end From 3eff8b79337355455b0eebe543c60d0947788c09 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Fri, 23 Apr 2021 17:24:57 +0300 Subject: [PATCH 14/34] minor refactor --- .gitignore | 1 + lib/simplecov/combine/files_combiner.rb | 13 ++++++++----- lib/simplecov/configuration.rb | 12 ++++-------- spec/combine/results_combiner_spec.rb | 1 + 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 91d75687..903961cf 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ tmp ## PROJECT::SPECIFIC .yardoc +.ruby-version spec/fixtures/coverage spec/fixtures/frameworks/coverage test_projects/**/coverage diff --git a/lib/simplecov/combine/files_combiner.rb b/lib/simplecov/combine/files_combiner.rb index f4a5725f..c19b79d2 100644 --- a/lib/simplecov/combine/files_combiner.rb +++ b/lib/simplecov/combine/files_combiner.rb @@ -14,13 +14,16 @@ module FilesCombiner # # @return [Hash] # - def combine(coverage_a, coverage_b) + def combine(cov_a, cov_b) combination = {} - combination[:lines] = Combine.combine(LinesCombiner, coverage_a[:lines], coverage_b[:lines]) + combination[:lines] = Combine.combine(LinesCombiner, cov_a[:lines], cov_b[:lines]) - if SimpleCov.branch_coverage? - combination[:branches] = Combine.combine(BranchesCombiner, coverage_a[:branches], coverage_b[:branches]) - combination[:methods] = Combine.combine(MethodsCombiner, coverage_a[:methods], coverage_b[:methods]) + if SimpleCov.branch_coverage? # rubocop:disable Style/IfUnlessModifier + combination[:branches] = Combine.combine(BranchesCombiner, cov_a[:branches], cov_b[:branches]) + end + + if SimpleCov.method_coverage? # rubocop:disable Style/IfUnlessModifier + combination[:methods] = Combine.combine(MethodsCombiner, cov_a[:methods], cov_b[:methods]) end combination diff --git a/lib/simplecov/configuration.rb b/lib/simplecov/configuration.rb index c6ed242f..719ed22d 100644 --- a/lib/simplecov/configuration.rb +++ b/lib/simplecov/configuration.rb @@ -409,8 +409,7 @@ def method_coverage? end def coverage_start_arguments_supported? - # safe to cache as within one process this value should never - # change + # safe to cache as within one process this value should never change return @coverage_start_arguments_supported if defined?(@coverage_start_arguments_supported) @coverage_start_arguments_supported = begin @@ -426,19 +425,16 @@ def coverage_start_arguments_supported? def raise_if_criterion_disabled(criterion) raise_if_criterion_unsupported(criterion) - # rubocop:disable Style/IfUnlessModifier - unless coverage_criterion_enabled?(criterion) + + unless coverage_criterion_enabled?(criterion) # rubocop:disable Style/IfUnlessModifier raise "Coverage criterion #{criterion} is disabled! Please enable it first through enable_coverage #{criterion} (if supported)" end - # rubocop:enable Style/IfUnlessModifier end def raise_if_criterion_unsupported(criterion) - # rubocop:disable Style/IfUnlessModifier - unless SUPPORTED_COVERAGE_CRITERIA.member?(criterion) + unless SUPPORTED_COVERAGE_CRITERIA.member?(criterion) # rubocop:disable Style/IfUnlessModifier raise "Unsupported coverage criterion #{criterion}, supported values are #{SUPPORTED_COVERAGE_CRITERIA}" end - # rubocop:enable Style/IfUnlessModifier end def minimum_possible_coverage_exceeded(coverage_option) diff --git a/spec/combine/results_combiner_spec.rb b/spec/combine/results_combiner_spec.rb index abc605cc..2e4e2759 100644 --- a/spec/combine/results_combiner_spec.rb +++ b/spec/combine/results_combiner_spec.rb @@ -49,6 +49,7 @@ before do SimpleCov.enable_coverage :branch + SimpleCov.enable_coverage :method end context "a merge" do From 9fafd3cb49e763dad2d6d3e24fb7b5ce42ce502b Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Fri, 23 Apr 2021 19:13:12 +0300 Subject: [PATCH 15/34] fix results collation --- Gemfile | 3 - Gemfile.lock | 2 +- features/method_coverage.feature | 37 ----------- lib/simplecov/combine/files_combiner.rb | 1 + lib/simplecov/result.rb | 12 ++-- lib/simplecov/result_merger.rb | 85 ++++++------------------- spec/result_merger_spec.rb | 2 +- spec/simplecov_spec.rb | 7 +- 8 files changed, 30 insertions(+), 119 deletions(-) delete mode 100644 features/method_coverage.feature diff --git a/Gemfile b/Gemfile index 397e9269..bf062f2f 100644 --- a/Gemfile +++ b/Gemfile @@ -2,7 +2,6 @@ source "https://rubygems.org" -# rubocop:disable Bundler/DuplicatedGem case ENV["SIMPLECOV_HTML_MODE"] when "local" # Use local copy of simplecov-html in development when checked out @@ -11,8 +10,6 @@ when "github" # Use development version of html formatter from github gem "simplecov-html", github: "simplecov-ruby/simplecov-html" end -# rubocop:enable Bundler/DuplicatedGem - group :development do gem "apparition", "~> 0.6.0" gem "aruba", "~> 1.0" diff --git a/Gemfile.lock b/Gemfile.lock index 359c9964..b1acad64 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -179,4 +179,4 @@ DEPENDENCIES webrick BUNDLED WITH - 2.2.8 + 2.2.16 diff --git a/features/method_coverage.feature b/features/method_coverage.feature deleted file mode 100644 index 9d10b4a3..00000000 --- a/features/method_coverage.feature +++ /dev/null @@ -1,37 +0,0 @@ -@rspec @method_coverage -Feature: - - Simply executing method coverage gives ok results. - - Background: - Given I'm working on the project "faked_project" - - Scenario: - Given SimpleCov for RSpec is configured with: - """ - require 'simplecov' - SimpleCov.start do - enable_coverage :method - end - """ - When I open the coverage report generated with `bundle exec rspec spec` - Then I should see the groups: - | name | coverage | files | - | All Files | 91.8% | 7 | - # And I should see a line coverage summary of 56/61 - # And I should see a branch coverage summary of 2/4 - # And I should see the source files: - # | name | coverage | branch coverage | - # | lib/faked_project.rb | 100.00 % | 100.00 % | - # | lib/faked_project/some_class.rb | 80.00 % | 50.00 % | - # | lib/faked_project/framework_specific.rb | 75.00 % | 100.00 % | - # | lib/faked_project/meta_magic.rb | 100.00 % | 100.00 % | - # | spec/forking_spec.rb | 100.00 % | 50.00 % | - # | spec/meta_magic_spec.rb | 100.00 % | 100.00 % | - # | spec/some_class_spec.rb | 100.00 % | 100.00 % | - - # When I open the detailed view for "lib/faked_project/some_class.rb" - # Then I should see a line coverage summary of 12/15 for the file - # And I should see a branch coverage summary of 1/2 for the file - # And I should see coverage branch data like "then: 1" - # And I should see coverage branch data like "else: 0" diff --git a/lib/simplecov/combine/files_combiner.rb b/lib/simplecov/combine/files_combiner.rb index c19b79d2..390bd0d6 100644 --- a/lib/simplecov/combine/files_combiner.rb +++ b/lib/simplecov/combine/files_combiner.rb @@ -16,6 +16,7 @@ module FilesCombiner # def combine(cov_a, cov_b) combination = {} + combination[:lines] = Combine.combine(LinesCombiner, cov_a[:lines], cov_b[:lines]) if SimpleCov.branch_coverage? # rubocop:disable Style/IfUnlessModifier diff --git a/lib/simplecov/result.rb b/lib/simplecov/result.rb index 5b308c5b..89e7cf83 100644 --- a/lib/simplecov/result.rb +++ b/lib/simplecov/result.rb @@ -73,18 +73,14 @@ def to_hash # Loads a SimpleCov::Result#to_hash dump def self.from_hash(hash) SimpleCov::ResultSerialization.deserialize(hash) - # hash.map do |command_name, data| - # new(data.fetch("coverage"), command_name: command_name, created_at: Time.at(data["timestamp"])) - # end end private - # TODO[@tycooon]: remove? - # def coverage - # keys = original_result.keys & filenames - # Hash[keys.zip(original_result.values_at(*keys))] - # end + def coverage + keys = original_result.keys & filenames + Hash[keys.zip(original_result.values_at(*keys))] + end # Applies all configured SimpleCov filters on this result's source files def filter! diff --git a/lib/simplecov/result_merger.rb b/lib/simplecov/result_merger.rb index a6b2e92e..15155eb6 100644 --- a/lib/simplecov/result_merger.rb +++ b/lib/simplecov/result_merger.rb @@ -31,20 +31,14 @@ def merge_results(*file_paths, ignore_timeout: false) # In big CI setups you might deal with 100s of CI jobs and each one producing Megabytes # of data. Reading them all in easily produces Gigabytes of memory consumption which # we want to avoid. - # - # For similar reasons a SimpleCov::Result is only created in the end as that'd create - # even more data especially when it also reads in all source files. - initial_memo = valid_results(file_paths.shift, ignore_timeout: ignore_timeout) - - command_names, coverage = file_paths.reduce(initial_memo) do |memo, file_path| - merge_coverage(memo, valid_results(file_path, ignore_timeout: ignore_timeout)) - end - create_result(command_names, coverage) + results = file_paths.map { |path| valid_results(path, ignore_timeout: ignore_timeout) } + merge_coverage(results) end def valid_results(file_path, ignore_timeout: false) - results = parse_file(file_path) + raw_results = parse_file(file_path) + results = Result.from_hash(raw_results) merge_valid_results(results, ignore_timeout: ignore_timeout) end @@ -72,42 +66,25 @@ def parse_json(content) end def merge_valid_results(results, ignore_timeout: false) - results = results.select { |_command_name, data| within_merge_timeout?(data) } unless ignore_timeout - - command_plus_coverage = results.map do |command_name, data| - [[command_name], adapt_result(data.fetch("coverage"))] - end - - # one file itself _might_ include multiple test runs - merge_coverage(*command_plus_coverage) + results = results.select { |x| within_merge_timeout?(x) } unless ignore_timeout + merge_coverage(results) end - def within_merge_timeout?(data) - time_since_result_creation(data) < SimpleCov.merge_timeout + def within_merge_timeout?(result) + Time.now - result.created_at < SimpleCov.merge_timeout end - def time_since_result_creation(data) - Time.now - Time.at(data.fetch("timestamp")) - end - - def create_result(command_names, coverage) - return nil unless coverage - - command_name = command_names.reject(&:empty?).sort.join(", ") - SimpleCov::Result.new(coverage, command_name: command_name) - end + def merge_coverage(results) + results = results.compact - def merge_coverage(*results) - return [[""], nil] if results.empty? + return nil if results.size.zero? return results.first if results.size == 1 - results.reduce do |(memo_command, memo_coverage), (command, coverage)| - # timestamp is dropped here, which is intentional (we merge it, it gets a new time stamp as of now) - merged_coverage = Combine.combine(Combine::ResultsCombiner, memo_coverage, coverage) - merged_command = memo_command + command - - [merged_command, merged_coverage] - end + parsed_results = results.map(&:original_result) + combined_result = SimpleCov::Combine::ResultsCombiner.combine(*parsed_results) + result = SimpleCov::Result.new(combined_result) + result.command_name = results.map(&:command_name).reject(&:empty?).sort.join(", ") + result end # @@ -118,9 +95,8 @@ def merged_result # conceptually this is just doing `merge_results(resultset_path)` # it's more involved to make syre `synchronize_resultset` is only used around reading resultset_hash = read_resultset - command_names, coverage = merge_valid_results(resultset_hash) - - create_result(command_names, coverage) + results = Result.from_hash(resultset_hash) + merge_valid_results(results) end def read_resultset @@ -164,31 +140,6 @@ def synchronize_resultset @resultset_locked = false end end - - # We changed the format of the raw result data in simplecov, as people are likely - # to have "old" resultsets lying around (but not too old so that they're still - # considered we can adapt them). - # See https://github.com/simplecov-ruby/simplecov/pull/824#issuecomment-576049747 - def adapt_result(result) - if pre_simplecov_0_18_result?(result) - adapt_pre_simplecov_0_18_result(result) - else - result - end - end - - # pre 0.18 coverage data pointed from file directly to an array of line coverage - def pre_simplecov_0_18_result?(result) - _key, data = result.first - - data.is_a?(Array) - end - - def adapt_pre_simplecov_0_18_result(result) - result.transform_values do |line_coverage_data| - {"lines" => line_coverage_data} - end - end end end end diff --git a/spec/result_merger_spec.rb b/spec/result_merger_spec.rb index 4518d5c4..ee2320cb 100644 --- a/spec/result_merger_spec.rb +++ b/spec/result_merger_spec.rb @@ -123,7 +123,7 @@ it "has the result stored" do SimpleCov::ResultMerger.merge_and_store(resultset1_path, resultset2_path) - expect_resultset_1_and_2_merged(SimpleCov::ResultMerger.read_resultset) + expect_resultset_1_and_2_merged(SimpleCov::ResultMerger.merged_result.to_hash) end end diff --git a/spec/simplecov_spec.rb b/spec/simplecov_spec.rb index 63e6dd31..62dfa829 100644 --- a/spec/simplecov_spec.rb +++ b/spec/simplecov_spec.rb @@ -207,7 +207,7 @@ "result1, result2" => { "coverage" => { source_fixture("sample.rb") => { - "lines" => [1, 1, 2, 2, nil, nil, 2, 2, nil, nil] + lines: [1, 1, 2, 2, nil, nil, 2, 2, nil, nil] } } } @@ -215,7 +215,10 @@ end let(:collated) do - JSON.parse(File.read(resultset_path)).transform_values { |v| v.reject { |k| k == "timestamp" } } + JSON.parse(File.read(resultset_path)).transform_values do |data| + data["coverage"].values.first.transform_keys!(&:to_sym) + data.reject { |k| k == "timestamp" } + end end context "when no files to be merged" do From 64206882943ad3083689c40590278baaddf29d2a Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Fri, 23 Apr 2021 19:44:56 +0300 Subject: [PATCH 16/34] update test app gemfile --- Gemfile | 1 + test_projects/rails/rspec_rails/Gemfile.lock | 157 +++++++++---------- 2 files changed, 78 insertions(+), 80 deletions(-) diff --git a/Gemfile b/Gemfile index bf062f2f..236df0a8 100644 --- a/Gemfile +++ b/Gemfile @@ -10,6 +10,7 @@ when "github" # Use development version of html formatter from github gem "simplecov-html", github: "simplecov-ruby/simplecov-html" end + group :development do gem "apparition", "~> 0.6.0" gem "aruba", "~> 1.0" diff --git a/test_projects/rails/rspec_rails/Gemfile.lock b/test_projects/rails/rspec_rails/Gemfile.lock index b586e8ef..36274504 100644 --- a/test_projects/rails/rspec_rails/Gemfile.lock +++ b/test_projects/rails/rspec_rails/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: ../../.. specs: - simplecov (0.20.0) + simplecov (0.21.2) docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) @@ -9,65 +9,60 @@ PATH GEM remote: https://rubygems.org/ specs: - actioncable (6.1.0) - actionpack (= 6.1.0) - activesupport (= 6.1.0) + actioncable (6.1.3.1) + actionpack (= 6.1.3.1) + activesupport (= 6.1.3.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.1.0) - actionpack (= 6.1.0) - activejob (= 6.1.0) - activerecord (= 6.1.0) - activestorage (= 6.1.0) - activesupport (= 6.1.0) + actionmailbox (6.1.3.1) + actionpack (= 6.1.3.1) + activejob (= 6.1.3.1) + activerecord (= 6.1.3.1) + activestorage (= 6.1.3.1) + activesupport (= 6.1.3.1) mail (>= 2.7.1) - actionmailer (6.1.0) - actionpack (= 6.1.0) - actionview (= 6.1.0) - activejob (= 6.1.0) - activesupport (= 6.1.0) + actionmailer (6.1.3.1) + actionpack (= 6.1.3.1) + actionview (= 6.1.3.1) + activejob (= 6.1.3.1) + activesupport (= 6.1.3.1) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.1.0) - actionview (= 6.1.0) - activesupport (= 6.1.0) + actionpack (6.1.3.1) + actionview (= 6.1.3.1) + activesupport (= 6.1.3.1) rack (~> 2.0, >= 2.0.9) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.1.0) - actionpack (= 6.1.0) - activerecord (= 6.1.0) - activestorage (= 6.1.0) - activesupport (= 6.1.0) + actiontext (6.1.3.1) + actionpack (= 6.1.3.1) + activerecord (= 6.1.3.1) + activestorage (= 6.1.3.1) + activesupport (= 6.1.3.1) nokogiri (>= 1.8.5) - actionview (6.1.0) - activesupport (= 6.1.0) + actionview (6.1.3.1) + activesupport (= 6.1.3.1) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.1.0) - activesupport (= 6.1.0) + activejob (6.1.3.1) + activesupport (= 6.1.3.1) globalid (>= 0.3.6) - activemodel (6.1.0) - activesupport (= 6.1.0) - activerecord (6.1.0) - activemodel (= 6.1.0) - activesupport (= 6.1.0) - activerecord-jdbc-adapter (61.0-java) - activerecord (~> 6.1.0) - activerecord-jdbcsqlite3-adapter (61.0-java) - activerecord-jdbc-adapter (= 61.0) - jdbc-sqlite3 (~> 3.8, < 3.30) - activestorage (6.1.0) - actionpack (= 6.1.0) - activejob (= 6.1.0) - activerecord (= 6.1.0) - activesupport (= 6.1.0) - marcel (~> 0.3.1) - mimemagic (~> 0.3.2) - activesupport (6.1.0) + activemodel (6.1.3.1) + activesupport (= 6.1.3.1) + activerecord (6.1.3.1) + activemodel (= 6.1.3.1) + activesupport (= 6.1.3.1) + activestorage (6.1.3.1) + actionpack (= 6.1.3.1) + activejob (= 6.1.3.1) + activerecord (= 6.1.3.1) + activesupport (= 6.1.3.1) + marcel (~> 1.0.0) + mini_mime (~> 1.0.2) + activesupport (6.1.3.1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -90,68 +85,69 @@ GEM rack-test (>= 0.6.3) regexp_parser (~> 1.5) xpath (~> 3.2) - concurrent-ruby (1.1.7) + concurrent-ruby (1.1.8) crass (1.0.6) diff-lcs (1.4.4) - docile (1.3.3) + docile (1.3.5) erubi (1.10.0) globalid (0.4.2) activesupport (>= 4.2.0) - i18n (1.8.5) + i18n (1.8.10) concurrent-ruby (~> 1.0) jbuilder (2.10.1) activesupport (>= 5.0.0) - jdbc-sqlite3 (3.28.0) - loofah (2.8.0) + loofah (2.9.1) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) - marcel (0.3.3) - mimemagic (~> 0.3.2) + marcel (1.0.1) method_source (1.0.0) - mimemagic (0.3.5) - mini_mime (1.0.2) - mini_portile2 (2.4.0) - minitest (5.14.2) + mini_mime (1.0.3) + mini_portile2 (2.5.0) + minitest (5.14.4) msgpack (1.3.3) msgpack (1.3.3-java) - nio4r (2.5.4) - nio4r (2.5.4-java) - nokogiri (1.10.10) - mini_portile2 (~> 2.4.0) - nokogiri (1.10.10-java) + nio4r (2.5.7) + nio4r (2.5.7-java) + nokogiri (1.11.3) + mini_portile2 (~> 2.5.0) + racc (~> 1.4) + nokogiri (1.11.3-java) + racc (~> 1.4) public_suffix (4.0.6) puma (5.1.1) nio4r (~> 2.0) puma (5.1.1-java) nio4r (~> 2.0) + racc (1.5.2) + racc (1.5.2-java) rack (2.2.3) rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.1.0) - actioncable (= 6.1.0) - actionmailbox (= 6.1.0) - actionmailer (= 6.1.0) - actionpack (= 6.1.0) - actiontext (= 6.1.0) - actionview (= 6.1.0) - activejob (= 6.1.0) - activemodel (= 6.1.0) - activerecord (= 6.1.0) - activestorage (= 6.1.0) - activesupport (= 6.1.0) + rails (6.1.3.1) + actioncable (= 6.1.3.1) + actionmailbox (= 6.1.3.1) + actionmailer (= 6.1.3.1) + actionpack (= 6.1.3.1) + actiontext (= 6.1.3.1) + actionview (= 6.1.3.1) + activejob (= 6.1.3.1) + activemodel (= 6.1.3.1) + activerecord (= 6.1.3.1) + activestorage (= 6.1.3.1) + activesupport (= 6.1.3.1) bundler (>= 1.15.0) - railties (= 6.1.0) + railties (= 6.1.3.1) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) - railties (6.1.0) - actionpack (= 6.1.0) - activesupport (= 6.1.0) + railties (6.1.3.1) + actionpack (= 6.1.3.1) + activesupport (= 6.1.3.1) method_source rake (>= 0.8.7) thor (~> 1.0) @@ -184,7 +180,8 @@ GEM actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) - thor (1.0.1) + sqlite3 (1.4.2) + thor (1.1.0) tzinfo (2.0.4) concurrent-ruby (~> 1.0) tzinfo-data (1.2020.4) @@ -209,7 +206,6 @@ PLATFORMS universal-java-1.8 DEPENDENCIES - activerecord-jdbcsqlite3-adapter (~> 61.0) bootsnap (>= 1.4.4) byebug capybara (>= 3.26) @@ -219,8 +215,9 @@ DEPENDENCIES rspec-rails simplecov! spring + sqlite3 (~> 1.4) tzinfo-data web-console (>= 4.1.0) BUNDLED WITH - 2.2.2 + 2.2.16 From ddccb3c7e52f72447f3b8f003bb7a23c401be612 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Fri, 23 Apr 2021 20:29:08 +0300 Subject: [PATCH 17/34] add specs --- spec/fixtures/coverer.rb | 5 +- spec/fixtures/methods.rb | 18 +++++ spec/source_file/method_spec.rb | 45 ++++++++++++- spec/source_file_spec.rb | 112 ++++++++++++++++++++++++++++---- 4 files changed, 163 insertions(+), 17 deletions(-) create mode 100644 spec/fixtures/methods.rb diff --git a/spec/fixtures/coverer.rb b/spec/fixtures/coverer.rb index b6d9e53b..381bdeb0 100644 --- a/spec/fixtures/coverer.rb +++ b/spec/fixtures/coverer.rb @@ -2,8 +2,5 @@ require "coverage" Coverage.start(:all) -require_relative "uneven_nocovs" - -UnevenNocov.call(42) - +require_relative "methods" p Coverage.result diff --git a/spec/fixtures/methods.rb b/spec/fixtures/methods.rb new file mode 100644 index 00000000..de753ef3 --- /dev/null +++ b/spec/fixtures/methods.rb @@ -0,0 +1,18 @@ +class A + def method1 + puts "hello from method1" + method2 + end + +private + + def method2 + puts "hello from method2" + end + + def method3 + puts "hello from method3" + end +end + +A.new.method1 diff --git a/spec/source_file/method_spec.rb b/spec/source_file/method_spec.rb index a8c4d8a1..bebee569 100644 --- a/spec/source_file/method_spec.rb +++ b/spec/source_file/method_spec.rb @@ -3,5 +3,48 @@ require "helper" describe SimpleCov::SourceFile::Method do - # TODO[@tycooon]: add specs + subject { described_class.new(source_file, info, coverage) } + + let(:source_file) do + SimpleCov::SourceFile.new(source_fixture("methods.rb"), lines: {}) + end + + let(:info) { ["A", :method1, 2, 2, 5, 5] } + let(:coverage) { 1 } + + it "is covered" do + expect(subject.covered?).to eq(true) + end + + it "is not skipped" do + expect(subject.skipped?).to eq(false) + end + + it "is not missed" do + expect(subject.missed?).to eq(false) + end + + it "has 4 lines" do + expect(subject.lines.size).to eq(4) + end + + it "converts to string properly" do + expect(subject.to_s).to eq("A#method1") + end + + context "uncovered method" do + let(:coverage) { 0 } + + it "is not covered" do + expect(subject.covered?).to eq(false) + end + + it "is not skipped" do + expect(subject.skipped?).to eq(false) + end + + it "is missed" do + expect(subject.missed?).to eq(true) + end + end end diff --git a/spec/source_file_spec.rb b/spec/source_file_spec.rb index 599ccee0..1aa30561 100644 --- a/spec/source_file_spec.rb +++ b/spec/source_file_spec.rb @@ -69,7 +69,6 @@ end end - # TODO[@tycooon]: add method cov describe "branch coverage" do it "has total branches count 0" do expect(subject.total_branches.size).to eq(0) @@ -91,23 +90,43 @@ expect(subject.branches_report).to eq({}) end end + + describe "method coverage" do + it "has total methods count 0" do + expect(subject.total_methods.size).to eq(0) + end + + it "has covered methods count 0" do + expect(subject.covered_methods.size).to eq(0) + end + + it "has missed methods count 0" do + expect(subject.missed_methods.size).to eq(0) + end + + it "is considered 100% methods covered" do + expect(subject.methods_coverage_percent).to eq(100.0) + end + end end context "file with branches" do - COVERAGE_FOR_BRANCHES_RB = { - lines: [1, 1, 1, nil, 1, nil, 1, 0, nil, 1, nil, nil, nil], - branches: { - [:if, 0, 3, 4, 3, 21] => - {[:then, 1, 3, 4, 3, 10] => 0, [:else, 2, 3, 4, 3, 21] => 1}, - [:if, 3, 5, 4, 5, 26] => - {[:then, 4, 5, 16, 5, 20] => 1, [:else, 5, 5, 23, 5, 26] => 0}, - [:if, 6, 7, 4, 11, 7] => - {[:then, 7, 8, 6, 8, 10] => 0, [:else, 8, 10, 6, 10, 9] => 1} + let(:coverage_for_branches_rb) do + { + lines: [1, 1, 1, nil, 1, nil, 1, 0, nil, 1, nil, nil, nil], + branches: { + [:if, 0, 3, 4, 3, 21] => + {[:then, 1, 3, 4, 3, 10] => 0, [:else, 2, 3, 4, 3, 21] => 1}, + [:if, 3, 5, 4, 5, 26] => + {[:then, 4, 5, 16, 5, 20] => 1, [:else, 5, 5, 23, 5, 26] => 0}, + [:if, 6, 7, 4, 11, 7] => + {[:then, 7, 8, 6, 8, 10] => 0, [:else, 8, 10, 6, 10, 9] => 1} + } } - }.freeze + end subject do - SimpleCov::SourceFile.new(source_fixture("branches.rb"), COVERAGE_FOR_BRANCHES_RB) + SimpleCov::SourceFile.new(source_fixture("branches.rb"), coverage_for_branches_rb) end describe "branch coverage" do @@ -164,6 +183,60 @@ end end + context "file with methods" do + let(:coverage_for_methods_rb) do + { + lines: [1, 1, 1, 1, nil, nil, 1, nil, 1, 1, nil, nil, 1, 0, nil, nil, nil, 1], + branches: {}, + methods: { + ["A", :method3, 13, 2, 15, 5] => 0, + ["A", :method2, 9, 2, 11, 5] => 1, + ["A", :method1, 2, 2, 5, 5] => 1 + } + } + end + + subject do + SimpleCov::SourceFile.new(source_fixture("methods.rb"), coverage_for_methods_rb) + end + + describe "method coverage" do + it "has total methods count 0" do + expect(subject.total_methods.size).to eq(3) + end + + it "has covered methods count 0" do + expect(subject.covered_methods.size).to eq(2) + end + + it "has missed methods count 0" do + expect(subject.missed_methods.size).to eq(1) + end + + it "is considered 66.(6)% methods covered" do + expect(subject.methods_coverage_percent).to eq(66.66666666666667) + end + end + + describe "line coverage" do + it "has line coverage" do + expect(subject.covered_percent).to eq 90.0 + end + + it "has 9 covered lines" do + expect(subject.covered_lines.size).to eq 9 + end + + it "has 1 missed line" do + expect(subject.missed_lines.size).to eq 1 + end + + it "has 10 relevant lines" do + expect(subject.relevant_lines).to eq 10 + end + end + end + context "simulating potential Ruby 1.9 defect -- see Issue #56" do subject do SimpleCov::SourceFile.new(source_fixture("sample.rb"), COVERAGE_FOR_SAMPLE_RB_WITH_MORE_LINES) @@ -234,6 +307,10 @@ it "has 100.0 branch coverage" do expect(subject.branches_coverage_percent).to eq(100.00) end + + it "has 100.0 method coverage" do + expect(subject.methods_coverage_percent).to eq(100.00) + end end context "a file where nothing is ever executed mixed with skipping #563" do @@ -327,6 +404,17 @@ expect(subject.covered_branches.size).to eq 0 end end + + describe "method coverage" do + it "has no methods" do + expect(subject.total_methods.size).to eq 0 + end + + it "does has neither covered nor missed methods" do + expect(subject.missed_methods.size).to eq 0 + expect(subject.covered_methods.size).to eq 0 + end + end end context "a file with more complex skipping" do From 15c03b27519b98b8070513bef88d37e7c1a93357 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Sat, 24 Apr 2021 13:51:20 +0300 Subject: [PATCH 18/34] optimize result merger --- lib/simplecov/result_merger.rb | 11 ++++++++--- lib/simplecov/result_serialization.rb | 4 ++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/simplecov/result_merger.rb b/lib/simplecov/result_merger.rb index 15155eb6..78dbcc7c 100644 --- a/lib/simplecov/result_merger.rb +++ b/lib/simplecov/result_merger.rb @@ -32,11 +32,16 @@ def merge_results(*file_paths, ignore_timeout: false) # of data. Reading them all in easily produces Gigabytes of memory consumption which # we want to avoid. - results = file_paths.map { |path| valid_results(path, ignore_timeout: ignore_timeout) } - merge_coverage(results) + file_paths = file_paths.dup + initial_result = merge_file_results(file_paths.shift, ignore_timeout: ignore_timeout) + + file_paths.reduce(initial_result) do |memo, path| + file_result = merge_file_results(path, ignore_timeout: ignore_timeout) + merge_coverage([memo, file_result]) + end end - def valid_results(file_path, ignore_timeout: false) + def merge_file_results(file_path, ignore_timeout:) raw_results = parse_file(file_path) results = Result.from_hash(raw_results) merge_valid_results(results, ignore_timeout: ignore_timeout) diff --git a/lib/simplecov/result_serialization.rb b/lib/simplecov/result_serialization.rb index eeb4361e..2a5f6e71 100644 --- a/lib/simplecov/result_serialization.rb +++ b/lib/simplecov/result_serialization.rb @@ -24,7 +24,7 @@ def deserialize(hash) # rubocop:disable Metrics/MethodLength hash.map do |command_name, data| coverage = {} - data["coverage"].each do |file_name, file_data| + data.fetch("coverage").each do |file_name, file_data| parsed_file_data = {} file_data = {lines: file_data} if file_data.is_a?(Array) @@ -39,7 +39,7 @@ def deserialize(hash) # rubocop:disable Metrics/MethodLength result = SimpleCov::Result.new(coverage) result.command_name = command_name - result.created_at = Time.at(data["timestamp"]) + result.created_at = Time.at(data.fetch("timestamp")) result end end From 9a8b3246ade78691ed219c47c20a61276695d752 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Sat, 24 Apr 2021 14:24:11 +0300 Subject: [PATCH 19/34] add specs for method cov merging --- spec/result_merger_spec.rb | 67 ++++++++++++++++++++++++++++++++++++++ spec/source_file_spec.rb | 4 +-- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/spec/result_merger_spec.rb b/spec/result_merger_spec.rb index ee2320cb..21547ada 100644 --- a/spec/result_merger_spec.rb +++ b/spec/result_merger_spec.rb @@ -165,6 +165,73 @@ expect_resultset_1_and_2_merged(result_hash) end end + + describe "method coverage", if: SimpleCov.method_coverage_supported? do + before do + SimpleCov.enable_coverage :method + store_result(result3, path: resultset3_path) + end + + after do + SimpleCov.clear_coverage_criteria + end + + let(:resultset1) do + { + source_fixture("methods.rb") => { + methods: { + ["A", :method1, 2, 2, 5, 5] => 1, + ["A", :method2, 9, 2, 11, 5] => 0, + ["A", :method3, 13, 2, 15, 5] => 0 + } + } + } + end + + let(:resultset2) do + { + source_fixture("methods.rb") => { + methods: { + ["A", :method1, 2, 2, 5, 5] => 0, + ["A", :method2, 9, 2, 11, 5] => 1, + ["A", :method3, 13, 2, 15, 5] => 0 + } + } + } + end + + let(:resultset3) do + { + source_fixture("methods.rb") => { + methods: { + ["B", :method1, 2, 2, 5, 5] => 1, + ["B", :method2, 9, 2, 11, 5] => 0, + ["B", :method3, 13, 2, 15, 5] => 0 + } + } + } + end + + let(:result3) { SimpleCov::Result.new(resultset3, command_name: "result3") } + let(:resultset3_path) { "#{resultset_prefix}3.json" } + + it "correctly merges the 3 results" do + result = SimpleCov::ResultMerger.merge_and_store( + resultset1_path, resultset2_path, resultset3_path + ) + + merged_coverage = result.original_result.fetch(source_fixture("methods.rb")) + + expect(merged_coverage.fetch(:methods)).to eq( + ["A", :method1, 2, 2, 5, 5] => 1, + ["A", :method2, 9, 2, 11, 5] => 1, + ["A", :method3, 13, 2, 15, 5] => 0, + ["B", :method1, 2, 2, 5, 5] => 1, + ["B", :method2, 9, 2, 11, 5] => 0, + ["B", :method3, 13, 2, 15, 5] => 0 + ) + end + end end context "pre 0.18 result format" do diff --git a/spec/source_file_spec.rb b/spec/source_file_spec.rb index 1aa30561..43609c77 100644 --- a/spec/source_file_spec.rb +++ b/spec/source_file_spec.rb @@ -189,9 +189,9 @@ lines: [1, 1, 1, 1, nil, nil, 1, nil, 1, 1, nil, nil, 1, 0, nil, nil, nil, 1], branches: {}, methods: { - ["A", :method3, 13, 2, 15, 5] => 0, + ["A", :method1, 2, 2, 5, 5] => 1, ["A", :method2, 9, 2, 11, 5] => 1, - ["A", :method1, 2, 2, 5, 5] => 1 + ["A", :method3, 13, 2, 15, 5] => 0 } } end From dc754e45991c624a322e948fc754761093ecacfc Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Fri, 30 Apr 2021 18:58:20 +0300 Subject: [PATCH 20/34] add feature specs for method coverage --- Gemfile | 2 ++ Gemfile.lock | 15 +++++++++- features/method_coverage.feature | 39 +++++++++++++++++++++++++ features/step_definitions/html_steps.rb | 8 +++++ 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 features/method_coverage.feature diff --git a/Gemfile b/Gemfile index 236df0a8..97673e29 100644 --- a/Gemfile +++ b/Gemfile @@ -9,6 +9,8 @@ when "local" when "github" # Use development version of html formatter from github gem "simplecov-html", github: "simplecov-ruby/simplecov-html" +when "methods" + gem "simplecov-html", github: "umbrellio/simplecov-html", branch: "add-method-coverage-support" end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index b1acad64..e686a04b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,10 @@ +GIT + remote: https://github.com/umbrellio/simplecov-html.git + revision: fc9c7a1beaa75bad3a925d1296b94fcd0c96b126 + branch: add-method-coverage-support + specs: + simplecov-html (0.12.3) + PATH remote: . specs: @@ -101,6 +108,10 @@ GEM pry (0.13.1) coderay (~> 1.1) method_source (~> 1.0) + pry (0.13.1-java) + coderay (~> 1.1) + method_source (~> 1.0) + spoon (~> 0.0) public_suffix (4.0.6) racc (1.5.2) racc (1.5.2-java) @@ -136,8 +147,9 @@ GEM rubocop-ast (1.4.1) parser (>= 2.7.1.5) ruby-progressbar (1.11.0) - simplecov-html (0.12.3) simplecov_json_formatter (0.1.2) + spoon (0.0.6) + ffi sys-uname (1.2.2) ffi (~> 1.1) test-unit (3.3.6) @@ -175,6 +187,7 @@ DEPENDENCIES rspec (~> 3.2) rubocop simplecov! + simplecov-html! test-unit webrick diff --git a/features/method_coverage.feature b/features/method_coverage.feature new file mode 100644 index 00000000..aa52ba0d --- /dev/null +++ b/features/method_coverage.feature @@ -0,0 +1,39 @@ +@rspec @method_coverage +Feature: + + Simply executing method coverage gives ok results. + + Background: + Given I'm working on the project "faked_project" + + Scenario: + Given SimpleCov for RSpec is configured with: + """ + require 'simplecov' + SimpleCov.start do + enable_coverage :method + end + """ + When I open the coverage report generated with `bundle exec rspec spec` + Then I should see the groups: + | name | coverage | files | + | All Files | 91.8% | 7 | + And I should see a line coverage summary of 56/61 + And I should see a method coverage summary of 10/13 + And I should see the source files: + | name | coverage | method coverage | + | lib/faked_project.rb | 100.00 % | 100.00 % | + | lib/faked_project/some_class.rb | 80.00 % | 75.00 % | + | lib/faked_project/framework_specific.rb | 75.00 % | 33.33 % | + | lib/faked_project/meta_magic.rb | 100.00 % | 100.00 % | + | spec/forking_spec.rb | 100.00 % | 100.00 % | + | spec/meta_magic_spec.rb | 100.00 % | 100.00 % | + | spec/some_class_spec.rb | 100.00 % | 100.00 % | + + When I open the detailed view for "lib/faked_project/framework_specific.rb" + Then I should see a line coverage summary of 6/8 for the file + And I should see a method coverage summary of 1/3 for the file + And I should see missed methods list: + | name | + | ##test_unit | + | ##cucumber | diff --git a/features/step_definitions/html_steps.rb b/features/step_definitions/html_steps.rb index f4f080e7..69b5d42a 100644 --- a/features/step_definitions/html_steps.rb +++ b/features/step_definitions/html_steps.rb @@ -25,6 +25,7 @@ available_source_files = all(".t-file", visible: true, count: expected_files.count) include_branch_coverage = table.column_names.include?("branch coverage") + include_method_coverage = table.column_names.include?("method coverage") # Find all filenames and their coverage present in coverage report files = available_source_files.map do |file_row| @@ -35,6 +36,7 @@ } coverage_data["branch coverage"] = file_row.find(".t-file__branch-coverage").text if include_branch_coverage + coverage_data["method coverage"] = file_row.find(".t-file__method-coverage").text if include_method_coverage coverage_data end @@ -68,3 +70,9 @@ Then /^I should see coverage branch data like "(.+)"$/ do |text| expect(find(".hits", visible: true, text: text)).to be_truthy end + +Then /^I should see missed methods list:$/ do |table| + expected_list = table.hashes.map { |x| x.fetch("name") } + list = all(".t-missed-method-summary li", visible: true).map(&:text) + expect(list).to eq(expected_list) +end From b5c29b4414ff5d9c887b61f94418016b1095fe31 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Fri, 30 Apr 2021 19:03:44 +0300 Subject: [PATCH 21/34] fix indentation in features --- features/method_coverage.feature | 3 ++- features/step_definitions/simplecov_steps.rb | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/features/method_coverage.feature b/features/method_coverage.feature index aa52ba0d..98af2ddb 100644 --- a/features/method_coverage.feature +++ b/features/method_coverage.feature @@ -10,8 +10,9 @@ Feature: Given SimpleCov for RSpec is configured with: """ require 'simplecov' + SimpleCov.start do - enable_coverage :method + enable_coverage :method end """ When I open the coverage report generated with `bundle exec rspec spec` diff --git a/features/step_definitions/simplecov_steps.rb b/features/step_definitions/simplecov_steps.rb index 4e3081a0..d4e07137 100644 --- a/features/step_definitions/simplecov_steps.rb +++ b/features/step_definitions/simplecov_steps.rb @@ -22,7 +22,7 @@ steps %( Given a file named "#{framework_dir}/simplecov_config.rb" with: """ - #{config_body} +#{config_body.indent(6)} """ ) end From bb5aad1d74432ff7b964bb5c530fd2c9b8d75fab Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Fri, 30 Apr 2021 19:05:53 +0300 Subject: [PATCH 22/34] skip method coverage features if not supported --- features/support/env.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/features/support/env.rb b/features/support/env.rb index e5d3fb3a..75e39e29 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -28,6 +28,10 @@ skip_this_scenario unless SimpleCov.branch_coverage_supported? end +Before("@method_coverage") do + skip_this_scenario unless SimpleCov.method_coverage_supported? +end + Before("@rails6") do # Rails 6 only supports Ruby 2.5+ skip_this_scenario if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.5") From 0501b733836e278b5626575eeda09925c2c8f8fd Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Fri, 30 Apr 2021 19:25:15 +0300 Subject: [PATCH 23/34] fix build --- .github/workflows/stable.yml | 6 +++--- features/maximum_coverage_drop.feature | 1 - features/minimum_coverage.feature | 1 - features/minimum_coverage_by_file.feature | 1 - 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/stable.yml b/.github/workflows/stable.yml index 3234a65a..3a86f2ec 100644 --- a/.github/workflows/stable.yml +++ b/.github/workflows/stable.yml @@ -10,6 +10,9 @@ jobs: matrix: ruby: [2.5.8, 2.6.6, 2.7.2, 3.0.0, jruby-9.2.14.0] + env: + SIMPLECOV_HTML_MODE: methods + steps: - uses: actions/checkout@v2 @@ -21,9 +24,6 @@ jobs: - name: Get sqlite for Rails test projects run: sudo apt-get install libsqlite3-dev - - name: Install bundler - run: gem i bundler - - name: Install dependencies run: | bundle config set --local without benchmark diff --git a/features/maximum_coverage_drop.feature b/features/maximum_coverage_drop.feature index 5566a79c..7a8b60c5 100644 --- a/features/maximum_coverage_drop.feature +++ b/features/maximum_coverage_drop.feature @@ -314,7 +314,6 @@ Feature: When I run `bundle exec rake test` Then the exit status should not be 0 - And the output should not contain "Line coverage" And the output should contain "Branch coverage has dropped by 50.00% since the last time (maximum allowed: 0.00%)." And the output should contain "SimpleCov failed with exit 3" diff --git a/features/minimum_coverage.feature b/features/minimum_coverage.feature index ba1b8c60..6d38c869 100644 --- a/features/minimum_coverage.feature +++ b/features/minimum_coverage.feature @@ -84,5 +84,4 @@ Feature: When I run `bundle exec rake test` Then the exit status should not be 0 And the output should contain "Branch coverage (50.00%) is below the expected minimum coverage (80.00%)." - And the output should not contain "Line coverage" And the output should contain "SimpleCov failed with exit 2" diff --git a/features/minimum_coverage_by_file.feature b/features/minimum_coverage_by_file.feature index e4540ef9..49442a33 100644 --- a/features/minimum_coverage_by_file.feature +++ b/features/minimum_coverage_by_file.feature @@ -68,5 +68,4 @@ Feature: When I run `bundle exec rake test` Then the exit status should not be 0 And the output should contain "Branch coverage by file (50.00%) is below the expected minimum coverage (70.00%)." - And the output should not contain "Line coverage" And the output should contain "SimpleCov failed with exit 2" From ed40a9d8f50d1cbe8557a6efa7521cff2d0fa591 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Tue, 16 Nov 2021 23:32:48 +0300 Subject: [PATCH 24/34] add SimpleCov::Utils --- Gemfile.lock | 2 +- lib/simplecov.rb | 11 ++-------- .../exit_codes/maximum_coverage_drop_check.rb | 11 +++++----- .../minimum_coverage_by_file_check.rb | 10 +++++----- .../minimum_overall_coverage_check.rb | 8 ++++---- lib/simplecov/utils.rb | 20 +++++++++++++++++++ 6 files changed, 37 insertions(+), 25 deletions(-) create mode 100644 lib/simplecov/utils.rb diff --git a/Gemfile.lock b/Gemfile.lock index e686a04b..c3d7b5b2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -192,4 +192,4 @@ DEPENDENCIES webrick BUNDLED WITH - 2.2.16 + 2.2.30 diff --git a/lib/simplecov.rb b/lib/simplecov.rb index 7ac5c219..c90e21bc 100644 --- a/lib/simplecov.rb +++ b/lib/simplecov.rb @@ -285,18 +285,10 @@ def wait_for_other_processes def write_last_run(result) SimpleCov::LastRun.write(result: result.coverage_statistics.transform_values do |stats| - round_coverage(stats.percent) + SimpleCov::Utils.round_coverage(stats.percent) end) end - # - # @api private - # - # Rounding down to be extra strict, see #679 - def round_coverage(coverage) - coverage.floor(2) - end - private def initial_setup(profile, &block) @@ -467,6 +459,7 @@ def probably_running_parallel_tests? require_relative "simplecov/combine/results_combiner" require_relative "simplecov/useless_results_remover" require_relative "simplecov/simulate_coverage" +require_relative "simplecov/utils" # Load default config require_relative "simplecov/defaults" unless ENV["SIMPLECOV_NO_DEFAULTS"] diff --git a/lib/simplecov/exit_codes/maximum_coverage_drop_check.rb b/lib/simplecov/exit_codes/maximum_coverage_drop_check.rb index 7b65b96b..b1f3cdd1 100644 --- a/lib/simplecov/exit_codes/maximum_coverage_drop_check.rb +++ b/lib/simplecov/exit_codes/maximum_coverage_drop_check.rb @@ -17,10 +17,11 @@ def failing? def report coverage_drop_violations.each do |violation| $stderr.printf( - "%s coverage has dropped by %.2f%% since the last time (maximum allowed: %.2f%%).\n", + "%s coverage has dropped by %s since the last time " \ + "(maximum allowed: %s).\n", criterion: violation[:criterion].capitalize, - drop_percent: SimpleCov.round_coverage(violation[:drop_percent]), - max_drop: violation[:max_drop] + drop_percent: SimpleCov::Utils.render_coverage(violation[:drop_percent]), + max_drop: SimpleCov::Utils.render_coverage(violation[:max_drop]) ) end end @@ -60,9 +61,7 @@ def compute_coverage_drop_data MAX_DROP_ACCURACY = 10 def drop_percent(criterion) drop = last_coverage(criterion) - - SimpleCov.round_coverage( - result.coverage_statistics.fetch(criterion).percent - ) + SimpleCov::Utils.round_coverage(result.coverage_statistics.fetch(criterion).percent) # floats, I tell ya. # irb(main):001:0* 80.01 - 80.0 diff --git a/lib/simplecov/exit_codes/minimum_coverage_by_file_check.rb b/lib/simplecov/exit_codes/minimum_coverage_by_file_check.rb index a276d275..cf617201 100644 --- a/lib/simplecov/exit_codes/minimum_coverage_by_file_check.rb +++ b/lib/simplecov/exit_codes/minimum_coverage_by_file_check.rb @@ -15,10 +15,10 @@ def failing? def report minimum_violations.each do |violation| $stderr.printf( - "%s coverage by file (%.2f%%) is below the expected minimum coverage (%.2f%%).\n", - covered: SimpleCov.round_coverage(violation.fetch(:actual)), - minimum_coverage: violation.fetch(:minimum_expected), - criterion: violation.fetch(:criterion).capitalize + "%s coverage by file (%s) is below the expected minimum coverage (%s).\n", + criterion: violation.fetch(:criterion).capitalize, + covered: SimpleCov::Utils.render_coverage(violation.fetch(:actual)), + minimum_coverage: SimpleCov::Utils.render_coverage(violation.fetch(:minimum_expected)) ) end end @@ -44,7 +44,7 @@ def compute_minimum_coverage_data { criterion: criterion, minimum_expected: expected_percent, - actual: SimpleCov.round_coverage(actual_coverage.percent) + actual: SimpleCov::Utils.round_coverage(actual_coverage.percent) } end end diff --git a/lib/simplecov/exit_codes/minimum_overall_coverage_check.rb b/lib/simplecov/exit_codes/minimum_overall_coverage_check.rb index ea3a0ea9..5fd4fa3e 100644 --- a/lib/simplecov/exit_codes/minimum_overall_coverage_check.rb +++ b/lib/simplecov/exit_codes/minimum_overall_coverage_check.rb @@ -15,10 +15,10 @@ def failing? def report minimum_violations.each do |violation| $stderr.printf( - "%s coverage (%.2f%%) is below the expected minimum coverage (%.2f%%).\n", - covered: SimpleCov.round_coverage(violation.fetch(:actual)), - minimum_coverage: violation.fetch(:minimum_expected), - criterion: violation.fetch(:criterion).capitalize + "%s coverage (%s) is below the expected minimum coverage (%s).\n", + criterion: violation.fetch(:criterion).capitalize, + covered: SimpleCov::Utils.render_coverage(violation.fetch(:actual)), + minimum_coverage: SimpleCov::Utils.render_coverage(violation.fetch(:minimum_expected)) ) end end diff --git a/lib/simplecov/utils.rb b/lib/simplecov/utils.rb new file mode 100644 index 00000000..116351f1 --- /dev/null +++ b/lib/simplecov/utils.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module SimpleCov + # Functionally for rounding coverage results + module Utils + module_function + + # + # @api private + # + # Rounding down to be extra strict, see #679 + def round_coverage(coverage) + coverage.floor(2) + end + + def render_coverage(coverage) + format("%.2f%%", round_coverage(coverage)) + end + end +end From a9978b05199afe09797a0edde2a352c8aa59e4a0 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Wed, 17 Nov 2021 00:23:08 +0300 Subject: [PATCH 25/34] update bundler --- Gemfile.lock | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index c3d7b5b2..4c04536e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,10 +1,3 @@ -GIT - remote: https://github.com/umbrellio/simplecov-html.git - revision: fc9c7a1beaa75bad3a925d1296b94fcd0c96b126 - branch: add-method-coverage-support - specs: - simplecov-html (0.12.3) - PATH remote: . specs: @@ -147,6 +140,7 @@ GEM rubocop-ast (1.4.1) parser (>= 2.7.1.5) ruby-progressbar (1.11.0) + simplecov-html (0.12.3) simplecov_json_formatter (0.1.2) spoon (0.0.6) ffi @@ -187,9 +181,8 @@ DEPENDENCIES rspec (~> 3.2) rubocop simplecov! - simplecov-html! test-unit webrick BUNDLED WITH - 2.2.30 + 2.2.31 From 5cdbe219beb58ecfb8795161f7641b7579e9402a Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Sat, 7 Jan 2023 15:58:41 +0600 Subject: [PATCH 26/34] update nokogiri --- Gemfile.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4c04536e..c9a5336b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -81,13 +81,13 @@ GEM method_source (1.0.0) middleware (0.1.0) mini_mime (1.0.2) - mini_portile2 (2.5.0) + mini_portile2 (2.8.1) minitest (5.14.3) multi_test (0.1.2) - nokogiri (1.11.1) - mini_portile2 (~> 2.5.0) + nokogiri (1.13.10) + mini_portile2 (~> 2.8.0) racc (~> 1.4) - nokogiri (1.11.1-java) + nokogiri (1.13.10-java) racc (~> 1.4) parallel (1.20.1) parser (3.0.0.0) @@ -106,8 +106,8 @@ GEM method_source (~> 1.0) spoon (~> 0.0) public_suffix (4.0.6) - racc (1.5.2) - racc (1.5.2-java) + racc (1.6.2) + racc (1.6.2-java) rack (2.2.3) rack-test (1.1.0) rack (>= 1.0, < 3) @@ -185,4 +185,4 @@ DEPENDENCIES webrick BUNDLED WITH - 2.2.31 + 2.4.3 From a07dd23a063370409ea7492b81ea527578bc84b4 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Sat, 7 Jan 2023 16:11:56 +0600 Subject: [PATCH 27/34] update gemfiles --- Gemfile.lock | 11 +++++++++-- test_projects/rails/rspec_rails/Gemfile.lock | 14 +++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 66c4301d..2bf999dd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,6 +6,13 @@ GIT capybara (~> 3.13, < 4) websocket-driver (>= 0.6.5) +GIT + remote: https://github.com/umbrellio/simplecov-html.git + revision: fc9c7a1beaa75bad3a925d1296b94fcd0c96b126 + branch: add-method-coverage-support + specs: + simplecov-html (0.12.3) + PATH remote: . specs: @@ -147,7 +154,6 @@ GEM rubocop-ast (1.15.1) parser (>= 3.0.1.1) ruby-progressbar (1.11.0) - simplecov-html (0.12.3) simplecov_json_formatter (0.1.3) spoon (0.0.6) ffi @@ -189,8 +195,9 @@ DEPENDENCIES rspec (~> 3.2) rubocop simplecov! + simplecov-html! test-unit webrick BUNDLED WITH - 2.3.4 + 2.4.3 diff --git a/test_projects/rails/rspec_rails/Gemfile.lock b/test_projects/rails/rspec_rails/Gemfile.lock index 56f5d142..713a7ecd 100644 --- a/test_projects/rails/rspec_rails/Gemfile.lock +++ b/test_projects/rails/rspec_rails/Gemfile.lock @@ -106,24 +106,24 @@ GEM matrix (0.4.2) method_source (1.0.0) mini_mime (1.1.2) - mini_portile2 (2.5.3) + mini_portile2 (2.8.1) minitest (5.15.0) msgpack (1.3.3) msgpack (1.3.3-java) nio4r (2.5.4) nio4r (2.5.4-java) - nokogiri (1.11.0) - mini_portile2 (~> 2.5.0) + nokogiri (1.13.10) + mini_portile2 (~> 2.8.0) racc (~> 1.4) - nokogiri (1.11.0-java) + nokogiri (1.13.10-java) racc (~> 1.4) public_suffix (4.0.7) puma (5.1.1) nio4r (~> 2.0) puma (5.1.1-java) nio4r (~> 2.0) - racc (1.6.0) - racc (1.6.0-java) + racc (1.6.2) + racc (1.6.2-java) rack (2.2.3) rack-test (1.1.0) rack (>= 1.0, < 3) @@ -222,4 +222,4 @@ DEPENDENCIES web-console (>= 4.1.0) BUNDLED WITH - 2.3.4 + 2.4.3 From bb0fd38cfa34249906c8f7c673da3a23d22e69f6 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Sat, 7 Jan 2023 16:19:40 +0600 Subject: [PATCH 28/34] fix gh workflow --- .github/workflows/stable.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/stable.yml b/.github/workflows/stable.yml index 9e0d7bd9..696339a1 100644 --- a/.github/workflows/stable.yml +++ b/.github/workflows/stable.yml @@ -13,9 +13,7 @@ jobs: env: BUNDLE_WITHOUT: "benchmark" JRUBY_OPTS: "--debug" - - env: - SIMPLECOV_HTML_MODE: methods + SIMPLECOV_HTML_MODE: "methods" steps: - uses: actions/checkout@v3 From ed4fb86a21f0e051eedf335d81fce34c311a4895 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Sat, 7 Jan 2023 16:25:04 +0600 Subject: [PATCH 29/34] fix spec --- spec/coverage_for_eval_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/coverage_for_eval_spec.rb b/spec/coverage_for_eval_spec.rb index 7677b3a3..5e582cb9 100644 --- a/spec/coverage_for_eval_spec.rb +++ b/spec/coverage_for_eval_spec.rb @@ -19,7 +19,7 @@ let(:command) { "ruby eval_test.rb" } it "records coverage for erb" do - expect(@stdout).to include(" 2 / 3 LOC") + expect(@stdout).to include("Line coverage: 2 / 3") end end end From 15ab7902d4f2cd88b3490c4e78a3e662d14d58b2 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Mon, 9 Jan 2023 14:04:25 +0600 Subject: [PATCH 30/34] add some todos --- .github/workflows/stable.yml | 2 +- Gemfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stable.yml b/.github/workflows/stable.yml index 696339a1..7bddcb4d 100644 --- a/.github/workflows/stable.yml +++ b/.github/workflows/stable.yml @@ -13,7 +13,7 @@ jobs: env: BUNDLE_WITHOUT: "benchmark" JRUBY_OPTS: "--debug" - SIMPLECOV_HTML_MODE: "methods" + SIMPLECOV_HTML_MODE: "methods" # TODO: remove after simplecov-html release steps: - uses: actions/checkout@v3 diff --git a/Gemfile b/Gemfile index 42b94000..b1545b32 100644 --- a/Gemfile +++ b/Gemfile @@ -9,7 +9,7 @@ when "local" when "github" # Use development version of html formatter from github gem "simplecov-html", github: "simplecov-ruby/simplecov-html" -when "methods" +when "methods" # TODO: remove after simplecov-html release gem "simplecov-html", github: "umbrellio/simplecov-html", branch: "add-method-coverage-support" end From c13f0b1c5017cfacb12b4d6a37151f1d551ec710 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Mon, 25 Dec 2023 19:03:01 +0300 Subject: [PATCH 31/34] fix rubocop issue --- lib/simplecov/result_merger.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/simplecov/result_merger.rb b/lib/simplecov/result_merger.rb index 78dbcc7c..fbaf5439 100644 --- a/lib/simplecov/result_merger.rb +++ b/lib/simplecov/result_merger.rb @@ -82,7 +82,7 @@ def within_merge_timeout?(result) def merge_coverage(results) results = results.compact - return nil if results.size.zero? + return nil if results.empty? return results.first if results.size == 1 parsed_results = results.map(&:original_result) From 037a493dd84119027557a8c89f4fb90a75ea03dd Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Mon, 25 Dec 2023 19:06:27 +0300 Subject: [PATCH 32/34] revert bundler version --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 51a82e3b..99eda27e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -208,4 +208,4 @@ DEPENDENCIES webrick BUNDLED WITH - 2.5.3 + 2.4.20 From 8ede952b825683bf3bff34fdfca068c53a614860 Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Mon, 25 Dec 2023 19:13:00 +0300 Subject: [PATCH 33/34] update simplecov-html --- .github/workflows/stable.yml | 1 - Gemfile.lock | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/stable.yml b/.github/workflows/stable.yml index 2239bef1..5557333f 100644 --- a/.github/workflows/stable.yml +++ b/.github/workflows/stable.yml @@ -22,7 +22,6 @@ jobs: uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} - rubygems: latest bundler-cache: true # 'bundle install' and cache - name: Run tests diff --git a/Gemfile.lock b/Gemfile.lock index 99eda27e..a62b117b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -8,7 +8,7 @@ GIT GIT remote: https://github.com/umbrellio/simplecov-html.git - revision: dea7be12fce6364e9d7a7529a4fcd52075c18af8 + revision: 54879bd1080865cf8013bcda12e0c03ac687d7a9 branch: add-method-coverage-support specs: simplecov-html (0.12.3) From 2811cc1dd90a8801b096b12087887dd90954d7fb Mon Sep 17 00:00:00 2001 From: Yuri Smirnov Date: Tue, 4 Nov 2025 13:14:51 +0300 Subject: [PATCH 34/34] update branch --- .github/workflows/push_gem.yml | 37 +++ .github/workflows/stable.yml | 45 ++- .github/workflows/unstable.yml | 31 +- .gitignore | 1 - .rubocop.yml | 4 + Gemfile | 33 ++- Gemfile.lock | 279 +++++++++--------- README.md | 10 +- Rakefile | 1 + features/parallel_tests.feature | 2 +- features/step_definitions/simplecov_steps.rb | 2 +- features/step_definitions/web_steps.rb | 6 +- features/support/env.rb | 24 +- features/warnings.feature | 3 +- lib/minitest/simplecov_plugin.rb | 2 +- lib/simplecov.rb | 24 +- lib/simplecov/combine/files_combiner.rb | 2 +- lib/simplecov/combine/lines_combiner.rb | 12 +- lib/simplecov/command_guesser.rb | 4 +- lib/simplecov/configuration.rb | 10 +- lib/simplecov/defaults.rb | 2 +- lib/simplecov/formatter/simple_formatter.rb | 4 +- lib/simplecov/load_global_config.rb | 2 +- lib/simplecov/process.rb | 2 +- lib/simplecov/result.rb | 2 +- lib/simplecov/source_file.rb | 8 +- lib/simplecov/source_file/branch.rb | 2 +- lib/simplecov/source_file/line.rb | 3 +- lib/simplecov/useless_results_remover.rb | 2 +- simplecov.gemspec | 3 +- spec/combine/results_combiner_spec.rb | 4 + spec/command_guesser_spec.rb | 1 + spec/config_loader_spec.rb | 2 +- spec/configuration_spec.rb | 28 +- spec/coverage_for_eval_spec.rb | 4 +- .../maximum_coverage_drop_check_spec.rb | 5 +- .../minimum_coverage_by_file_check_spec.rb | 4 +- .../minimum_overall_coverage_check_spec.rb | 4 +- spec/filters_spec.rb | 14 +- spec/fixtures/branches.rb | 2 +- spec/fixtures/frameworks/rspec_bad.rb | 2 +- spec/fixtures/frameworks/rspec_good.rb | 2 +- spec/fixtures/nocov_complex.rb | 4 +- spec/last_run_spec.rb | 2 +- spec/result_merger_spec.rb | 10 +- spec/result_spec.rb | 12 +- spec/return_codes_spec.rb | 7 + spec/simplecov_spec.rb | 10 +- spec/source_file/line_spec.rb | 1 + spec/support/fail_rspec_on_ruby_warning.rb | 4 +- spec/useless_results_remover_spec.rb | 12 +- test_projects/rails/rspec_rails/Gemfile | 11 +- test_projects/rails/rspec_rails/Gemfile.lock | 226 -------------- .../rails/rspec_rails/config/application.rb | 1 + 54 files changed, 425 insertions(+), 509 deletions(-) create mode 100644 .github/workflows/push_gem.yml delete mode 100644 test_projects/rails/rspec_rails/Gemfile.lock diff --git a/.github/workflows/push_gem.yml b/.github/workflows/push_gem.yml new file mode 100644 index 00000000..4f09f6e0 --- /dev/null +++ b/.github/workflows/push_gem.yml @@ -0,0 +1,37 @@ +name: Push Gem + +on: + workflow_dispatch: + +permissions: + contents: read + +jobs: + push: + if: github.repository == 'simplecov-ruby/simplecov' + runs-on: ubuntu-latest + + environment: + name: rubygems.org + url: https://rubygems.org/gems/simplecov + + permissions: + contents: write + id-token: write + + steps: + # Set up + - name: Harden Runner + uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + with: + egress-policy: audit + + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - name: Set up Ruby + uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0 + with: + bundler-cache: true + ruby-version: ruby + + # Release + - uses: rubygems/release-gem@a25424ba2ba8b387abc8ef40807c2c85b96cbe32 # v1 diff --git a/.github/workflows/stable.yml b/.github/workflows/stable.yml index 5557333f..35cad2ae 100644 --- a/.github/workflows/stable.yml +++ b/.github/workflows/stable.yml @@ -3,26 +3,51 @@ name: stable on: [push, pull_request] jobs: - test: + tests: runs-on: ubuntu-latest - strategy: - matrix: - ruby: [2.7, '3.0', 3.1, 3.2, ruby-head, jruby-9.4] - env: BUNDLE_WITHOUT: "benchmark" JRUBY_OPTS: "--debug" SIMPLECOV_HTML_MODE: "methods" # TODO: remove after simplecov-html release + strategy: + fail-fast: false + + matrix: + ruby-version: + - '2.5' + - '2.6' + - '2.7' + - '3.0' + - '3.1' + - '3.2' + - '3.3' + - '3.4' + - jruby-9.4 + - truffleruby steps: - uses: actions/checkout@v4 - - name: Setup ruby - uses: ruby/setup-ruby@v1 + - run: rm Gemfile.lock + + - uses: ruby/setup-ruby@v1 with: - ruby-version: ${{ matrix.ruby }} - bundler-cache: true # 'bundle install' and cache + ruby-version: ${{ matrix.ruby-version }} + rubygems: ${{ (matrix.ruby_version < '2.6' && '3.3.26') || 'default' }} + bundler-cache: true + + - name: Run Rubocop + run: bundle exec rake rubocop + # code style is enough to check once (and might even take some time on JRuby) + if: matrix.ruby-version == '3.3' - name: Run tests - run: bundle exec rake + run: bundle exec rake test + if: matrix.ruby-version != 'truffleruby' + + # Run only `rake spec` on truffleruby, because just `rake` runs cucumber + # which fails because it uses an old childprocess which depends on fork. + - name: Run specs (truffleruby) + run: bundle exec rake spec + if: matrix.ruby-version == 'truffleruby' diff --git a/.github/workflows/unstable.yml b/.github/workflows/unstable.yml index e57276ef..43d4abb1 100644 --- a/.github/workflows/unstable.yml +++ b/.github/workflows/unstable.yml @@ -5,25 +5,34 @@ on: - cron: '0 0 * * *' jobs: - test: + tests: runs-on: ubuntu-latest - - strategy: - matrix: - ruby: [ruby-head, jruby-head] - env: BUNDLE_WITHOUT: "benchmark" JRUBY_OPTS: "--debug" + strategy: + fail-fast: false + + matrix: + ruby-version: + - ruby-head + - jruby-head + - truffleruby-head steps: - uses: actions/checkout@v4 - - name: Setup ruby - uses: ruby/setup-ruby@v1 + - uses: ruby/setup-ruby@v1 with: - ruby-version: ${{ matrix.ruby }} - bundler-cache: true # 'bundle install' and cache + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true - name: Run tests - run: bundle exec rake + run: bundle exec rake test + if: matrix.ruby-version != 'truffleruby-head' + + # Run only `rake spec` on truffleruby, because just `rake` runs cucumber + # which fails because it uses an old childprocess which depends on fork. + - name: Run specs (truffleruby) + run: bundle exec rake spec + if: matrix.ruby-version == 'truffleruby-head' diff --git a/.gitignore b/.gitignore index ba3d114e..43711f56 100644 --- a/.gitignore +++ b/.gitignore @@ -26,7 +26,6 @@ tmp ## PROJECT::SPECIFIC .yardoc -.ruby-version spec/fixtures/coverage spec/fixtures/frameworks/coverage spec/fixtures/eval_test/coverage diff --git a/.rubocop.yml b/.rubocop.yml index b170ace2..c040c7d6 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -11,6 +11,7 @@ AllCops: - "vendor/bundle/**/*" - "vendor/bundle/**/.*" TargetRubyVersion: 2.5 + NewCops: enable # we might wanna adopt rspec and rake but it's a bit annoying for now SuggestExtensions: false @@ -238,6 +239,9 @@ Style/DocumentDynamicEvalDefinition: Style/EndlessMethod: Enabled: true +Style/EnvHome: + Enabled: false + Style/ExplicitBlockArgument: # capturing as a proc has a performance hit, so is a case by case choice Enabled: false diff --git a/Gemfile b/Gemfile index 707853b9..0199d8d2 100644 --- a/Gemfile +++ b/Gemfile @@ -2,31 +2,42 @@ source "https://rubygems.org" -case ENV["SIMPLECOV_HTML_MODE"] +case ENV.fetch("SIMPLECOV_HTML_MODE", nil) when "local" # Use local copy of simplecov-html in development when checked out gem "simplecov-html", path: File.join(__dir__, "../simplecov-html") when "github" # Use development version of html formatter from github - gem "simplecov-html", github: "simplecov-ruby/simplecov-html" + gem "simplecov-html", git: "https://github.com/simplecov-ruby/simplecov-html.git" when "methods" # TODO: remove after simplecov-html release - gem "simplecov-html", github: "umbrellio/simplecov-html", branch: "add-method-coverage-support" + gem "simplecov-html", git: "https://github.com/umbrellio/simplecov-html.git", branch: "add-method-coverage-support-update" end +gem "base64" +gem "bigdecimal" gem "matrix" +gem "mutex_m" +gem "ostruct" group :development do - gem "apparition", github: "twalpole/apparition" # LOCKED: When this is released, use a released version https://github.com/twalpole/apparition/pull/79 - gem "aruba", "~> 1.0" - gem "capybara", "~> 3.31" - gem "rackup" - gem "cucumber", "~> 4.0" + gem "apparition", git: "https://github.com/twalpole/apparition.git" + gem "activesupport", "~> 6.1" + gem "aruba" + gem "capybara" + if RUBY_VERSION < "2.7" + gem "rack", "< 3" + else + gem "rackup" + end + gem "cucumber" gem "minitest" - gem "rake", "~> 13.0" - gem "rspec", "~> 3.2" + gem "rake" + gem "rspec" gem "pry" - gem "rubocop" + gem "rubocop", "~> 1.70.0" if RUBY_VERSION > "3.2" gem "test-unit" + gem "logger" + gem "power_assert", "~> 2.0" if RUBY_VERSION < "3.0" # Explicitly add webrick because it has been removed from stdlib in Ruby 3.0 gem "webrick" end diff --git a/Gemfile.lock b/Gemfile.lock index a62b117b..dd6d7863 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -8,10 +8,10 @@ GIT GIT remote: https://github.com/umbrellio/simplecov-html.git - revision: 54879bd1080865cf8013bcda12e0c03ac687d7a9 - branch: add-method-coverage-support + revision: cd5c2a4f9f183d245b409436047034258205ee2f + branch: add-method-coverage-support-update specs: - simplecov-html (0.12.3) + simplecov-html (0.13.2) PATH remote: . @@ -24,188 +24,201 @@ PATH GEM remote: https://rubygems.org/ specs: - activesupport (6.1.4.4) + activesupport (6.1.7.10) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) zeitwerk (~> 2.3) - addressable (2.8.5) - public_suffix (>= 2.0.2, < 6.0) - aruba (1.1.2) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + aruba (2.3.2) bundler (>= 1.17, < 3.0) - childprocess (>= 2.0, < 5.0) contracts (>= 0.16.0, < 0.18.0) - cucumber (>= 2.4, < 7.0) - rspec-expectations (~> 3.4) + cucumber (>= 8.0, < 11.0) + rspec-expectations (>= 3.4, < 5.0) thor (~> 1.0) - ast (2.4.2) - benchmark-ips (2.9.2) - builder (3.2.4) - capybara (3.39.2) + ast (2.4.3) + base64 (0.3.0) + benchmark-ips (2.14.0) + bigdecimal (3.3.1) + builder (3.3.0) + capybara (3.40.0) addressable matrix mini_mime (>= 0.1.3) - nokogiri (~> 1.8) + nokogiri (~> 1.11) rack (>= 1.6.0) rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - childprocess (4.1.0) coderay (1.1.3) - concurrent-ruby (1.1.9) - contracts (0.16.1) - cucumber (4.1.0) - builder (~> 3.2, >= 3.2.3) - cucumber-core (~> 7.1, >= 7.1.0) - cucumber-create-meta (~> 1.0.0, >= 1.0.0) - cucumber-cucumber-expressions (~> 10.1, >= 10.1.0) - cucumber-gherkin (~> 14.0, >= 14.0.1) - cucumber-html-formatter (~> 7.0, >= 7.0.0) - cucumber-messages (~> 12.2, >= 12.2.0) - cucumber-wire (~> 3.1, >= 3.1.0) - diff-lcs (~> 1.3, >= 1.3, < 1.4) - multi_test (~> 0.1, >= 0.1.2) - sys-uname (~> 1.0, >= 1.0.2) - cucumber-core (7.1.0) - cucumber-gherkin (~> 14.0, >= 14.0.1) - cucumber-messages (~> 12.2, >= 12.2.0) - cucumber-tag-expressions (~> 2.0, >= 2.0.4) - cucumber-create-meta (1.0.0) - cucumber-messages (~> 12.2, >= 12.2.0) - sys-uname (~> 1.2, >= 1.2.1) - cucumber-cucumber-expressions (10.3.0) - cucumber-gherkin (14.2.0) - cucumber-messages (~> 12.4, >= 12.4.0) - cucumber-html-formatter (7.2.0) - cucumber-messages (~> 12.4, >= 12.4.0) - cucumber-messages (12.4.0) - protobuf-cucumber (~> 3.10, >= 3.10.8) - cucumber-tag-expressions (2.0.4) - cucumber-wire (3.1.0) - cucumber-core (~> 7.1, >= 7.1.0) - cucumber-cucumber-expressions (~> 10.1, >= 10.1.0) - cucumber-messages (~> 12.2, >= 12.2.0) - diff-lcs (1.3) - docile (1.4.0) - ffi (1.15.5) - ffi (1.15.5-java) - i18n (1.8.11) + concurrent-ruby (1.3.5) + contracts (0.17.2) + cucumber (10.1.1) + base64 (~> 0.2) + builder (~> 3.2) + cucumber-ci-environment (> 9, < 11) + cucumber-core (> 15, < 17) + cucumber-cucumber-expressions (> 17, < 19) + cucumber-html-formatter (> 20.3, < 22) + diff-lcs (~> 1.5) + logger (~> 1.6) + mini_mime (~> 1.1) + multi_test (~> 1.1) + sys-uname (~> 1.3) + cucumber-ci-environment (10.0.1) + cucumber-core (15.3.0) + cucumber-gherkin (> 27, < 35) + cucumber-messages (> 26, < 30) + cucumber-tag-expressions (> 5, < 9) + cucumber-cucumber-expressions (18.0.1) + bigdecimal + cucumber-gherkin (34.0.0) + cucumber-messages (> 25, < 29) + cucumber-html-formatter (21.15.1) + cucumber-messages (> 19, < 28) + cucumber-messages (27.2.0) + cucumber-tag-expressions (8.0.0) + diff-lcs (1.6.2) + docile (1.4.1) + ffi (1.17.2-aarch64-linux-gnu) + ffi (1.17.2-aarch64-linux-musl) + ffi (1.17.2-arm-linux-gnu) + ffi (1.17.2-arm-linux-musl) + ffi (1.17.2-arm64-darwin) + ffi (1.17.2-x86_64-darwin) + ffi (1.17.2-x86_64-linux-gnu) + ffi (1.17.2-x86_64-linux-musl) + i18n (1.14.7) concurrent-ruby (~> 1.0) - json (2.6.3) - json (2.6.3-java) - matrix (0.4.2) - method_source (1.0.0) - middleware (0.1.0) + json (2.15.2) + language_server-protocol (3.17.0.5) + logger (1.7.0) + matrix (0.4.3) + memoist3 (1.0.0) + method_source (1.1.0) mini_mime (1.1.5) - mini_portile2 (2.8.4) - minitest (5.15.0) - multi_test (0.1.2) - nokogiri (1.15.4) - mini_portile2 (~> 2.8.2) + minitest (5.26.0) + multi_test (1.1.0) + mutex_m (0.3.0) + nokogiri (1.18.10-aarch64-linux-gnu) + racc (~> 1.4) + nokogiri (1.18.10-aarch64-linux-musl) + racc (~> 1.4) + nokogiri (1.18.10-arm-linux-gnu) + racc (~> 1.4) + nokogiri (1.18.10-arm-linux-musl) + racc (~> 1.4) + nokogiri (1.18.10-arm64-darwin) racc (~> 1.4) - nokogiri (1.15.4-java) + nokogiri (1.18.10-x86_64-darwin) racc (~> 1.4) - parallel (1.22.1) - parser (3.1.3.0) + nokogiri (1.18.10-x86_64-linux-gnu) + racc (~> 1.4) + nokogiri (1.18.10-x86_64-linux-musl) + racc (~> 1.4) + ostruct (0.6.3) + parallel (1.27.0) + parser (3.3.10.0) ast (~> 2.4.1) - power_assert (2.0.1) - protobuf-cucumber (3.10.8) - activesupport (>= 3.2) - middleware - thor - thread_safe - pry (0.14.1) + racc + power_assert (3.0.0) + prism (1.6.0) + pry (0.15.2) coderay (~> 1.1) method_source (~> 1.0) - pry (0.14.1-java) - coderay (~> 1.1) - method_source (~> 1.0) - spoon (~> 0.0) - public_suffix (5.0.3) - racc (1.7.1) - racc (1.7.1-java) - rack (3.0.8) - rack-test (2.1.0) + public_suffix (6.0.2) + racc (1.8.1) + rack (3.2.4) + rack-test (2.2.0) rack (>= 1.3) - rackup (2.0.0) + rackup (2.2.1) rack (>= 3) - webrick rainbow (3.1.1) - rake (13.0.6) - regexp_parser (2.8.1) - rexml (3.2.5) - rspec (3.10.0) - rspec-core (~> 3.10.0) - rspec-expectations (~> 3.10.0) - rspec-mocks (~> 3.10.0) - rspec-core (3.10.1) - rspec-support (~> 3.10.0) - rspec-expectations (3.10.1) + rake (13.3.1) + regexp_parser (2.11.3) + rspec (3.13.2) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.6) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.5) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.10.0) - rspec-mocks (3.10.2) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.7) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.10.0) - rspec-support (3.10.3) - rubocop (1.42.0) + rspec-support (~> 3.13.0) + rspec-support (3.13.6) + rubocop (1.70.0) json (~> 2.3) + language_server-protocol (>= 3.17.0) parallel (~> 1.10) - parser (>= 3.1.2.1) + parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.24.1, < 2.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.36.2, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.24.1) - parser (>= 3.1.1.0) - ruby-progressbar (1.11.0) - simplecov_json_formatter (0.1.3) - spoon (0.0.6) - ffi - sys-uname (1.2.2) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.47.1) + parser (>= 3.3.7.2) + prism (~> 1.4) + ruby-progressbar (1.13.0) + simplecov_json_formatter (0.1.4) + sys-uname (1.4.1) ffi (~> 1.1) - test-unit (3.5.3) + memoist3 (~> 1.0.0) + test-unit (3.7.1) power_assert - thor (1.2.1) - thread_safe (0.3.6) - thread_safe (0.3.6-java) - tzinfo (2.0.4) + thor (1.4.0) + tzinfo (2.0.6) concurrent-ruby (~> 1.0) - unicode-display_width (2.3.0) - webrick (1.7.0) - websocket-driver (0.7.5) - websocket-extensions (>= 0.1.0) - websocket-driver (0.7.5-java) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.1.0) + webrick (1.9.1) + websocket-driver (0.8.0) + base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.5.3) + zeitwerk (2.7.3) PLATFORMS - java - ruby - universal-java-1.8 + aarch64-linux-gnu + aarch64-linux-musl + arm-linux-gnu + arm-linux-musl + arm64-darwin + x86_64-darwin + x86_64-linux-gnu + x86_64-linux-musl DEPENDENCIES + activesupport (~> 6.1) apparition! - aruba (~> 1.0) + aruba + base64 benchmark-ips - capybara (~> 3.31) - cucumber (~> 4.0) + bigdecimal + capybara + cucumber + logger matrix minitest + mutex_m + ostruct pry rackup - rake (~> 13.0) - rspec (~> 3.2) - rubocop + rake + rspec + rubocop (~> 1.70.0) simplecov! simplecov-html! test-unit webrick BUNDLED WITH - 2.4.20 + 2.7.2 diff --git a/README.md b/README.md index ea872b97..a22b17c6 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ SimpleCov [![Gem Version](https://badge.fury.io/rb/simplecov.svg)](https://badge * [Rubygem] * [Continuous Integration] -[Coverage]: https://docs.ruby-lang.org/en/3.2/Coverage.html "API doc for Ruby's Coverage library" +[Coverage]: https://docs.ruby-lang.org/en/master/Coverage.html "API doc for Ruby's Coverage library" [Source Code]: https://github.com/simplecov-ruby/simplecov "Source Code @ GitHub" [API documentation]: http://rubydoc.info/gems/simplecov/frames "RDoc API Documentation at Rubydoc.info" [Configuration]: http://rubydoc.info/gems/simplecov/SimpleCov/Configuration "Configuration options API documentation" @@ -350,7 +350,7 @@ SimpleCov.start do end ``` -Primary coverage determines what will come in first all output, and the type of coverage to check if you don't specify the type of coverage when customizing exit behavior (`SimpleCov.minimum_coverage 90`). +Primary coverage determines what will come first in all output, and the type of coverage to check if you don't specify the type of coverage when customizing exit behavior (`SimpleCov.minimum_coverage 90`). Note that coverage must first be enabled for non-default coverage types. @@ -861,10 +861,10 @@ As of SimpleCov 0.9, you can specify multiple result formats. Formatters besides ```ruby require "simplecov-html" -SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new([ +SimpleCov.formatters = [ SimpleCov::Formatter::HTMLFormatter, SimpleCov::Formatter::CSVFormatter, -]) +] ``` ## JSON formatter @@ -889,7 +889,7 @@ SimpleCov.formatter = SimpleCov::Formatter::JSONFormatter ## Ruby version compatibility -SimpleCov is built in [Continuous Integration] on Ruby 2.7+ as well as JRuby 9.3+. +SimpleCov is built in [Continuous Integration] on Ruby 2.5+ as well as JRuby 9.2+. Note for JRuby => You need to pass JRUBY_OPTS="--debug" or create .jrubyrc and add debug.fullTrace=true diff --git a/Rakefile b/Rakefile index 9e8336ed..e9c2273b 100644 --- a/Rakefile +++ b/Rakefile @@ -29,4 +29,5 @@ Cucumber::Rake::Task.new do |t| t.cucumber_opts = %w[--retry 3 --no-strict-flaky] end +task test: %i[spec cucumber] task default: %i[rubocop spec cucumber] diff --git a/features/parallel_tests.feature b/features/parallel_tests.feature index cef36cfd..3422ada9 100644 --- a/features/parallel_tests.feature +++ b/features/parallel_tests.feature @@ -66,4 +66,4 @@ Feature: end """ When I successfully run `bundle exec parallel_rspec spec` - Then the output should not match /+cover.+below.+minimum/ + Then the output should not match /.*cover.+below.+minimum/ diff --git a/features/step_definitions/simplecov_steps.rb b/features/step_definitions/simplecov_steps.rb index 3422b516..2761b2a9 100644 --- a/features/step_definitions/simplecov_steps.rb +++ b/features/step_definitions/simplecov_steps.rb @@ -21,7 +21,7 @@ steps %( Given a file named "#{framework_dir}/simplecov_config.rb" with: """ -#{config_body.indent(6)} +#{config_body.gsub(/^/, ' ' * 6)} """ ) end diff --git a/features/step_definitions/web_steps.rb b/features/step_definitions/web_steps.rb index 6a3bedba..d50cbb2d 100644 --- a/features/step_definitions/web_steps.rb +++ b/features/step_definitions/web_steps.rb @@ -46,14 +46,14 @@ def with_scope(locator) Then /^(?:|I )should not see "([^"]*)"(?: within "([^"]*)")?$/ do |text, selector| with_scope(selector) do - expect(page).to have_no_content(text) + expect(page).not_to have_content(text) end end Then /^(?:|I )should not see \/([^\/]*)\/(?: within "([^"]*)")?$/ do |regexp, selector| regexp = Regexp.new(regexp) with_scope(selector) do - expect(page).to have_no_xpath("//*", text: regexp) + expect(page).not_to have_xpath("//*", text: regexp) end end @@ -65,7 +65,7 @@ def with_scope(locator) end Then "{string} should not be visible" do |text| - expect(page).to have_no_content(:visible, text) + expect(page).not_to have_content(:visible, text) end Then /^show me the page$/ do diff --git a/features/support/env.rb b/features/support/env.rb index 75e39e29..082365a5 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -5,12 +5,22 @@ require "bundler" Bundler.setup -require "aruba/cucumber" -require "aruba/config/jruby" if RUBY_ENGINE == "jruby" require "capybara/cucumber" require "capybara/apparition" +require "aruba/cucumber" +require "aruba/config/jruby" if RUBY_ENGINE == "jruby" require "simplecov" +# Monkey-patching Capybara::DSL if Capybara::DSLRSpecProxyInstaller has no `extended` hook +unless Module.new.extend(RSpec::Matchers).extend(Capybara::DSL).singleton_class.ancestors.include?(Capybara::RSpecMatcherProxies) + Capybara::DSL.extend(Module.new do + def extended(base) + base.extend(Capybara::RSpecMatcherProxies) if defined?(RSpec::Matchers) && base.is_a?(RSpec::Matchers) + super + end + end) +end + # Rack app for Capybara which returns the latest coverage report from Aruba temp project dir coverage_dir = File.expand_path("../../tmp/aruba/project/coverage/", __dir__) Capybara.app = Rack::Builder.new do @@ -39,7 +49,15 @@ Before("@process_fork") do # Process.fork is NotImplementedError in jruby - skip_this_scenario if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby" + skip_this_scenario if jruby? +end + +Before("@no_jruby") do + skip_this_scenario if jruby? +end + +def jruby? + defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby" end Aruba.configure do |config| diff --git a/features/warnings.feature b/features/warnings.feature index 58403277..a1350efb 100644 --- a/features/warnings.feature +++ b/features/warnings.feature @@ -1,4 +1,5 @@ -@rspec +# deactivating on JRuby due to https://github.com/jruby/jruby/issues/8200 +@rspec @no_jruby Feature: Running SimpleCov with verbosity enabled does not yield warnings. diff --git a/lib/minitest/simplecov_plugin.rb b/lib/minitest/simplecov_plugin.rb index 26809705..43d226a9 100644 --- a/lib/minitest/simplecov_plugin.rb +++ b/lib/minitest/simplecov_plugin.rb @@ -4,7 +4,7 @@ # https://github.com/seattlerb/minitest#writing-extensions module Minitest def self.plugin_simplecov_init(_options) - if defined?(SimpleCov) + if defined?(SimpleCov) && SimpleCov.respond_to?(:at_exit_behavior) SimpleCov.external_at_exit = true Minitest.after_run do diff --git a/lib/simplecov.rb b/lib/simplecov.rb index c8863836..797ac4a2 100644 --- a/lib/simplecov.rb +++ b/lib/simplecov.rb @@ -11,9 +11,9 @@ # @see https://github.com/simplecov-ruby/simplecov/issues/86 # @see https://jira.codehaus.org/browse/JRUBY-6106 - warn 'Coverage may be inaccurate; set the "--debug" command line option,' \ - ' or do JRUBY_OPTS="--debug"' \ - ' or set the "debug.fullTrace=true" option in your .jrubyrc' + warn 'Coverage may be inaccurate; set the "--debug" command line option, ' \ + 'or do JRUBY_OPTS="--debug" ' \ + 'or set the "debug.fullTrace=true" option in your .jrubyrc' end # @@ -48,8 +48,8 @@ class << self def start(profile = nil, &block) require "coverage" initial_setup(profile, &block) - require_relative "./simplecov/process" if SimpleCov.enabled_for_subprocesses? && - ::Process.respond_to?(:fork) + require_relative "simplecov/process" if SimpleCov.enabled_for_subprocesses? && + ::Process.respond_to?(:fork) make_parallel_tests_available @@ -293,7 +293,7 @@ def write_last_run(result) def initial_setup(profile, &block) load_profile(profile) if profile - configure(&block) if block_given? + configure(&block) if block self.running = true end @@ -334,7 +334,7 @@ def start_coverage_measurement if coverage_start_arguments_supported? start_coverage_with_criteria else - Coverage.start unless Coverage.running? + Coverage.start unless coverage_running? end end @@ -345,7 +345,13 @@ def start_coverage_with_criteria start_arguments[:eval] = true if coverage_for_eval_enabled? - Coverage.start(start_arguments) unless Coverage.running? + Coverage.start(start_arguments) unless coverage_running? + end + + def coverage_running? + # for ruby versions which do not implement Coverage.running?, + # Coverage.start may be called multiple times without raising. + Coverage.respond_to?(:running?) && Coverage.running? end CRITERION_TO_RUBY_COVERAGE = { @@ -425,7 +431,7 @@ def make_parallel_tests_available end def probably_running_parallel_tests? - ENV["TEST_ENV_NUMBER"] && ENV["PARALLEL_TEST_GROUPS"] + ENV.fetch("TEST_ENV_NUMBER", nil) && ENV.fetch("PARALLEL_TEST_GROUPS", nil) end end end diff --git a/lib/simplecov/combine/files_combiner.rb b/lib/simplecov/combine/files_combiner.rb index 390bd0d6..e27af858 100644 --- a/lib/simplecov/combine/files_combiner.rb +++ b/lib/simplecov/combine/files_combiner.rb @@ -20,7 +20,7 @@ def combine(cov_a, cov_b) combination[:lines] = Combine.combine(LinesCombiner, cov_a[:lines], cov_b[:lines]) if SimpleCov.branch_coverage? # rubocop:disable Style/IfUnlessModifier - combination[:branches] = Combine.combine(BranchesCombiner, cov_a[:branches], cov_b[:branches]) + combination[:branches] = Combine.combine(BranchesCombiner, cov_a[:branches], cov_b[:branches]) || {} end if SimpleCov.method_coverage? # rubocop:disable Style/IfUnlessModifier diff --git a/lib/simplecov/combine/lines_combiner.rb b/lib/simplecov/combine/lines_combiner.rb index 92241f18..cddffa51 100644 --- a/lib/simplecov/combine/lines_combiner.rb +++ b/lib/simplecov/combine/lines_combiner.rb @@ -10,11 +10,13 @@ module LinesCombiner module_function def combine(coverage_a, coverage_b) - coverage_a - .zip(coverage_b) - .map do |coverage_a_val, coverage_b_val| - merge_line_coverage(coverage_a_val, coverage_b_val) - end + acc = coverage_a.size > coverage_b.size ? coverage_a : coverage_b + + acc.size.times do |index| + acc[index] = merge_line_coverage(coverage_a[index], coverage_b[index]) + end + + acc end # Return depends on coverage in a specific line diff --git a/lib/simplecov/command_guesser.rb b/lib/simplecov/command_guesser.rb index bc949ffd..b0e2dd18 100644 --- a/lib/simplecov/command_guesser.rb +++ b/lib/simplecov/command_guesser.rb @@ -23,9 +23,9 @@ def from_env # If being run from inside parallel_tests set the command name according to the process number return unless ENV["PARALLEL_TEST_GROUPS"] && ENV["TEST_ENV_NUMBER"] - number = ENV["TEST_ENV_NUMBER"] + number = ENV.fetch("TEST_ENV_NUMBER", nil) number = "1" if number.empty? - "(#{number}/#{ENV['PARALLEL_TEST_GROUPS']})" + "(#{number}/#{ENV.fetch('PARALLEL_TEST_GROUPS', nil)})" end def from_command_line_options diff --git a/lib/simplecov/configuration.rb b/lib/simplecov/configuration.rb index 81e2cdd3..7061fe75 100644 --- a/lib/simplecov/configuration.rb +++ b/lib/simplecov/configuration.rb @@ -35,7 +35,7 @@ def coverage_dir(dir = nil) return @coverage_dir if defined?(@coverage_dir) && dir.nil? @coverage_path = nil # invalidate cache - @coverage_dir = (dir || "coverage") + @coverage_dir = dir || "coverage" end # @@ -140,7 +140,7 @@ def print_error_status def nocov_token(nocov_token = nil) return @nocov_token if defined?(@nocov_token) && nocov_token.nil? - @nocov_token = (nocov_token || "nocov") + @nocov_token = nocov_token || "nocov" end alias skip_token nocov_token @@ -191,9 +191,9 @@ def configure(&block) # end # def at_exit(&block) - return Proc.new unless running || block_given? + return Proc.new unless running || block - @at_exit = block if block_given? + @at_exit = block if block @at_exit ||= proc { SimpleCov.result.format! } end @@ -231,7 +231,7 @@ def enabled_for_subprocesses? # end # def at_fork(&block) - @at_fork = block if block_given? + @at_fork = block if block @at_fork ||= lambda { |pid| # This needs a unique name so it won't be ovewritten SimpleCov.command_name "#{SimpleCov.command_name} (subprocess: #{pid})" diff --git a/lib/simplecov/defaults.rb b/lib/simplecov/defaults.rb index 21cba877..2d82d952 100644 --- a/lib/simplecov/defaults.rb +++ b/lib/simplecov/defaults.rb @@ -44,7 +44,7 @@ load filename rescue LoadError, StandardError warn "Warning: Error occurred while trying to load #{filename}. " \ - "Error message: #{$!.message}" + "Error message: #{$!.message}" end break end diff --git a/lib/simplecov/formatter/simple_formatter.rb b/lib/simplecov/formatter/simple_formatter.rb index 5f66af24..4ddcf3fc 100644 --- a/lib/simplecov/formatter/simple_formatter.rb +++ b/lib/simplecov/formatter/simple_formatter.rb @@ -11,10 +11,10 @@ def format(result) output = +"" result.groups.each do |name, files| output << "Group: #{name}\n" - output << "=" * 40 + output << ("=" * 40) output << "\n" files.each do |file| - output << "#{file.filename} (coverage: #{file.covered_percent.round(2)}%)\n" + output << "#{file.filename} (coverage: #{file.covered_percent.floor(2)}%)\n" end output << "\n" end diff --git a/lib/simplecov/load_global_config.rb b/lib/simplecov/load_global_config.rb index 64dc62ae..72e235fb 100644 --- a/lib/simplecov/load_global_config.rb +++ b/lib/simplecov/load_global_config.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "etc" -home_dir = (ENV["HOME"] && File.expand_path("~")) || Etc.getpwuid.dir || (ENV["USER"] && File.expand_path("~#{ENV['USER']}")) +home_dir = (ENV.fetch("HOME", nil) && File.expand_path("~")) || Etc.getpwuid.dir || (ENV.fetch("USER", nil) && File.expand_path("~#{ENV.fetch('USER', nil)}")) if home_dir global_config_path = File.join(home_dir, ".simplecov") load global_config_path if File.exist?(global_config_path) diff --git a/lib/simplecov/process.rb b/lib/simplecov/process.rb index fbe59068..2d9a254e 100644 --- a/lib/simplecov/process.rb +++ b/lib/simplecov/process.rb @@ -6,7 +6,7 @@ def fork_with_simplecov(&block) if defined?(SimpleCov) && SimpleCov.running fork_without_simplecov do SimpleCov.at_fork.call(Process.pid) - block.call if block_given? + yield if block end else fork_without_simplecov(&block) diff --git a/lib/simplecov/result.rb b/lib/simplecov/result.rb index 89e7cf83..04de8577 100644 --- a/lib/simplecov/result.rb +++ b/lib/simplecov/result.rb @@ -79,7 +79,7 @@ def self.from_hash(hash) def coverage keys = original_result.keys & filenames - Hash[keys.zip(original_result.values_at(*keys))] + keys.zip(original_result.values_at(*keys)).to_h end # Applies all configured SimpleCov filters on this result's source files diff --git a/lib/simplecov/source_file.rb b/lib/simplecov/source_file.rb index 782406dd..97d56e9f 100644 --- a/lib/simplecov/source_file.rb +++ b/lib/simplecov/source_file.rb @@ -152,7 +152,7 @@ def branches_for_line(line_number) # @return [Boolean] # def line_with_missed_branch?(line_number) - branches_for_line(line_number).select { |_type, count| count.zero? }.any? + branches_for_line(line_number).any? { |_type, count| count.zero? } end def methods @@ -239,11 +239,7 @@ def ensure_remove_undefs(file_lines) # also setting these option on `file.set_encoding` doesn't seem to work # properly so it has to be done here. file_lines.each do |line| - if line.encoding == Encoding::UTF_8 - line - else - line.encode!("UTF-8", invalid: :replace, undef: :replace) - end + line.encode!("UTF-8", invalid: :replace, undef: :replace) unless line.encoding == Encoding::UTF_8 end end diff --git a/lib/simplecov/source_file/branch.rb b/lib/simplecov/source_file/branch.rb index 8e23bf58..709f4ae3 100644 --- a/lib/simplecov/source_file/branch.rb +++ b/lib/simplecov/source_file/branch.rb @@ -33,7 +33,7 @@ def covered? end # - # Check if branche missed or not + # Check if branch missed or not # # @return [Boolean] # diff --git a/lib/simplecov/source_file/line.rb b/lib/simplecov/source_file/line.rb index 7aab40c2..2491e586 100644 --- a/lib/simplecov/source_file/line.rb +++ b/lib/simplecov/source_file/line.rb @@ -65,7 +65,8 @@ def status return "skipped" if skipped? return "never" if never? return "missed" if missed? - return "covered" if covered? + + "covered" if covered? end end end diff --git a/lib/simplecov/useless_results_remover.rb b/lib/simplecov/useless_results_remover.rb index 5d45604a..22441b00 100644 --- a/lib/simplecov/useless_results_remover.rb +++ b/lib/simplecov/useless_results_remover.rb @@ -12,7 +12,7 @@ def self.call(coverage_result) end def self.root_regx - @root_regx ||= /\A#{Regexp.escape(SimpleCov.root + File::SEPARATOR)}/i.freeze + @root_regx ||= /\A#{Regexp.escape(SimpleCov.root + File::SEPARATOR)}/i end end end diff --git a/simplecov.gemspec b/simplecov.gemspec index c770c14d..21f35eeb 100644 --- a/simplecov.gemspec +++ b/simplecov.gemspec @@ -29,7 +29,8 @@ Gem::Specification.new do |gem| "changelog_uri" => "https://github.com/simplecov-ruby/simplecov/blob/main/CHANGELOG.md", "documentation_uri" => "https://www.rubydoc.info/gems/simplecov/#{gem.version}", "mailing_list_uri" => "https://groups.google.com/forum/#!forum/simplecov", - "source_code_uri" => "https://github.com/simplecov-ruby/simplecov/tree/v#{gem.version}" + "source_code_uri" => "https://github.com/simplecov-ruby/simplecov/tree/v#{gem.version}", +"rubygems_mfa_required" => "true" } gem.required_ruby_version = ">= 2.5.0" diff --git a/spec/combine/results_combiner_spec.rb b/spec/combine/results_combiner_spec.rb index 2e4e2759..64e8e203 100644 --- a/spec/combine/results_combiner_spec.rb +++ b/spec/combine/results_combiner_spec.rb @@ -107,6 +107,10 @@ it "has proper results for three.rb" do expect(subject[source_fixture("three.rb")][:lines]).to eq([nil, 3, 7]) end + + it "always returns a Hash object for branches", if: SimpleCov.branch_coverage_supported? do + expect(subject[source_fixture("three.rb")][:branches]).to eq({}) + end end end diff --git a/spec/command_guesser_spec.rb b/spec/command_guesser_spec.rb index 4fbb1e0e..a42cf930 100644 --- a/spec/command_guesser_spec.rb +++ b/spec/command_guesser_spec.rb @@ -4,6 +4,7 @@ describe SimpleCov::CommandGuesser do subject { SimpleCov::CommandGuesser } + it 'correctly guesses "Unit Tests" for unit tests' do allow(subject).to receive(:original_run_command) { "/some/path/test/units/foo_bar_test.rb" } expect(subject.guess).to eq("Unit Tests") diff --git a/spec/config_loader_spec.rb b/spec/config_loader_spec.rb index 662303c0..bbf86465 100644 --- a/spec/config_loader_spec.rb +++ b/spec/config_loader_spec.rb @@ -4,7 +4,7 @@ describe "loading config" do context "without ENV[HOME]" do - it "shouldn't raise any errors" do + it "does not raise any errors" do home = ENV.delete("HOME") begin expect { load "simplecov/load_global_config.rb" }.not_to raise_error diff --git a/spec/configuration_spec.rb b/spec/configuration_spec.rb index 1ac1ed1d..9fd65fe0 100644 --- a/spec/configuration_spec.rb +++ b/spec/configuration_spec.rb @@ -19,6 +19,7 @@ context "when manually set" do before { config.print_error_status = false } + it { is_expected.to be false } end end @@ -26,6 +27,7 @@ describe "#tracked_files" do context "when configured" do let(:glob) { "{app,lib}/**/*.rb" } + before { config.track_files(glob) } it "returns the configured glob" do @@ -48,7 +50,7 @@ end shared_examples "setting coverage expectations" do |coverage_setting| - after :each do + after do config.clear_coverage_criteria end @@ -109,7 +111,7 @@ end context "when primary coverage is set" do - before(:each) do + before do config.enable_coverage :branch config.primary_coverage :branch end @@ -135,34 +137,34 @@ end describe "#refuse_coverage_drop" do - after :each do + after do config.clear_coverage_criteria end it "sets the right coverage value when called with `:line`" do - config.public_send(:refuse_coverage_drop, :line) + config.refuse_coverage_drop(:line) - expect(config.public_send(:maximum_coverage_drop)).to eq line: 0 + expect(config.maximum_coverage_drop).to eq line: 0 end it "sets the right coverage value when called with `:branch`" do config.enable_coverage :branch - config.public_send(:refuse_coverage_drop, :branch) + config.refuse_coverage_drop(:branch) - expect(config.public_send(:maximum_coverage_drop)).to eq branch: 0 + expect(config.maximum_coverage_drop).to eq branch: 0 end it "sets the right coverage value when called with `:line` and `:branch`" do config.enable_coverage :branch - config.public_send(:refuse_coverage_drop, :line, :branch) + config.refuse_coverage_drop(:line, :branch) - expect(config.public_send(:maximum_coverage_drop)).to eq line: 0, branch: 0 + expect(config.maximum_coverage_drop).to eq line: 0, branch: 0 end it "sets the right coverage value when called with no args" do - config.public_send(:refuse_coverage_drop) + config.refuse_coverage_drop - expect(config.public_send(:maximum_coverage_drop)).to eq line: 0 + expect(config.maximum_coverage_drop).to eq line: 0 end end @@ -278,7 +280,7 @@ describe "#primary_coverage" do context "when branch coverage is enabled" do - before(:each) { config.enable_coverage :branch } + before { config.enable_coverage :branch } it "can set primary coverage to branch" do config.primary_coverage :branch @@ -289,7 +291,7 @@ end context "when branch coverage is not enabled" do - it "cannot set primary coverage to branch " do + it "cannot set primary coverage to branch" do expect do config.primary_coverage :branch end.to raise_error(/branch.*disabled/i) diff --git a/spec/coverage_for_eval_spec.rb b/spec/coverage_for_eval_spec.rb index 5e582cb9..37a20f03 100644 --- a/spec/coverage_for_eval_spec.rb +++ b/spec/coverage_for_eval_spec.rb @@ -16,10 +16,10 @@ end context "foo" do - let(:command) { "ruby eval_test.rb" } + let(:command) { "bundle e ruby eval_test.rb" } it "records coverage for erb" do - expect(@stdout).to include("Line coverage: 2 / 3") + expect(@stdout).to include("Line coverage: 2 / 3 (66.67%)") end end end diff --git a/spec/exit_codes/maximum_coverage_drop_check_spec.rb b/spec/exit_codes/maximum_coverage_drop_check_spec.rb index f64d20e1..b236ce87 100644 --- a/spec/exit_codes/maximum_coverage_drop_check_spec.rb +++ b/spec/exit_codes/maximum_coverage_drop_check_spec.rb @@ -3,6 +3,8 @@ require "helper" RSpec.describe SimpleCov::ExitCodes::MaximumCoverageDropCheck do + subject { described_class.new(result, maximum_coverage_drop) } + let(:result) do instance_double(SimpleCov::Result, coverage_statistics: stats) end @@ -19,9 +21,8 @@ end let(:last_coverage) { {line: 80.0, branch: 80.0} } let(:maximum_coverage_drop) { {line: 0, branch: 0} } - subject { described_class.new(result, maximum_coverage_drop) } - before :each do + before do expect(SimpleCov::LastRun).to receive(:read).and_return(last_run) end diff --git a/spec/exit_codes/minimum_coverage_by_file_check_spec.rb b/spec/exit_codes/minimum_coverage_by_file_check_spec.rb index 597c26dc..6aa09375 100644 --- a/spec/exit_codes/minimum_coverage_by_file_check_spec.rb +++ b/spec/exit_codes/minimum_coverage_by_file_check_spec.rb @@ -3,6 +3,8 @@ require "helper" RSpec.describe SimpleCov::ExitCodes::MinimumCoverageByFileCheck do + subject { described_class.new(result, minimum_coverage_by_file) } + let(:result) do instance_double(SimpleCov::Result, coverage_statistics_by_file: stats) end @@ -12,8 +14,6 @@ } end - subject { described_class.new(result, minimum_coverage_by_file) } - context "all files passing requirements" do let(:minimum_coverage_by_file) { {line: 80} } diff --git a/spec/exit_codes/minimum_overall_coverage_check_spec.rb b/spec/exit_codes/minimum_overall_coverage_check_spec.rb index 20eb95c8..1947245b 100644 --- a/spec/exit_codes/minimum_overall_coverage_check_spec.rb +++ b/spec/exit_codes/minimum_overall_coverage_check_spec.rb @@ -3,6 +3,8 @@ require "helper" RSpec.describe SimpleCov::ExitCodes::MinimumOverallCoverageCheck do + subject { described_class.new(result, minimum_coverage) } + let(:result) do instance_double(SimpleCov::Result, coverage_statistics: stats) end @@ -13,8 +15,6 @@ } end - subject { described_class.new(result, minimum_coverage) } - context "everything exactly ok" do let(:minimum_coverage) { {line: 80.0} } diff --git a/spec/filters_spec.rb b/spec/filters_spec.rb index 82028303..1d6704b8 100644 --- a/spec/filters_spec.rb +++ b/spec/filters_spec.rb @@ -36,15 +36,15 @@ expect(SimpleCov::StringFilter.new(parent_dir_name)).not_to be_matches subject end - it "matches a new SimpleCov::RegexFilter /\/fixtures\//" do + it "matches a new SimpleCov::RegexFilter //fixtures//" do expect(SimpleCov::RegexFilter.new(/\/fixtures\//)).to be_matches subject end - it "doesn't match a new SimpleCov::RegexFilter /^\/fixtures\//" do + it "doesn't match a new SimpleCov::RegexFilter /^/fixtures//" do expect(SimpleCov::RegexFilter.new(/^\/fixtures\//)).not_to be_matches subject end - it "matches a new SimpleCov::RegexFilter /^\/spec\//" do + it "matches a new SimpleCov::RegexFilter /^/spec//" do expect(SimpleCov::RegexFilter.new(/^\/spec\//)).to be_matches subject end @@ -108,15 +108,15 @@ def matches?(_source_file) end context "with no filters set up and a basic source file in an array" do + subject do + [SimpleCov::SourceFile.new(source_fixture("sample.rb"), [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil])] + end + before do @prev_filters = SimpleCov.filters SimpleCov.filters = [] end - subject do - [SimpleCov::SourceFile.new(source_fixture("sample.rb"), [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil])] - end - after do SimpleCov.filters = @prev_filters end diff --git a/spec/fixtures/branches.rb b/spec/fixtures/branches.rb index d7443ebf..0f5a6346 100644 --- a/spec/fixtures/branches.rb +++ b/spec/fixtures/branches.rb @@ -2,7 +2,7 @@ class Branches def call(arg) return if arg < 0 - arg == 42 ? :yes : :no + _val = (arg == 42 ? :yes : :no) if arg.odd? :yes diff --git a/spec/fixtures/frameworks/rspec_bad.rb b/spec/fixtures/frameworks/rspec_bad.rb index bb7e5ad7..efefcc28 100644 --- a/spec/fixtures/frameworks/rspec_bad.rb +++ b/spec/fixtures/frameworks/rspec_bad.rb @@ -4,7 +4,7 @@ SimpleCov.print_error_status = ENV["PRINT_ERROR_STATUS"] == "true" if ENV.key? "PRINT_ERROR_STATUS" SimpleCov.start describe "exit status" do - it "should exit with a non-zero exit status when assertion fails" do + it "exits with a non-zero exit status when assertion fails" do expect(1).to eq(2) end end diff --git a/spec/fixtures/frameworks/rspec_good.rb b/spec/fixtures/frameworks/rspec_good.rb index 1a45e07b..dfc6f168 100644 --- a/spec/fixtures/frameworks/rspec_good.rb +++ b/spec/fixtures/frameworks/rspec_good.rb @@ -3,7 +3,7 @@ require "rspec" SimpleCov.start describe "exit status" do - it "should exit with a zero exit status when assertion fails" do + it "exits with a zero exit status when assertion fails" do expect(1).to eq(1) end end diff --git a/spec/fixtures/nocov_complex.rb b/spec/fixtures/nocov_complex.rb index 9005f83a..95beb0c0 100644 --- a/spec/fixtures/nocov_complex.rb +++ b/spec/fixtures/nocov_complex.rb @@ -1,5 +1,5 @@ # So much skippping -# rubocop:disable Metrics/MethodLength +# rubocop:disable Metrics/MethodLength, Lint/Void module NoCovComplex def self.call(arg) # :nocov: @@ -24,4 +24,4 @@ def self.call(arg) end end end -# rubocop:enable Metrics/MethodLength +# rubocop:enable Metrics/MethodLength, Lint/Void diff --git a/spec/last_run_spec.rb b/spec/last_run_spec.rb index a1543067..b6d7d295 100644 --- a/spec/last_run_spec.rb +++ b/spec/last_run_spec.rb @@ -18,7 +18,7 @@ context "reading" do context "but the last_run file does not exist" do - before { File.delete(subject.last_run_path) if File.exist?(subject.last_run_path) } + before { FileUtils.rm_f(subject.last_run_path) } it "returns nil" do expect(subject.read).to be_nil diff --git a/spec/result_merger_spec.rb b/spec/result_merger_spec.rb index 0617131f..9120222d 100644 --- a/spec/result_merger_spec.rb +++ b/spec/result_merger_spec.rb @@ -6,7 +6,7 @@ describe SimpleCov::ResultMerger do after do - File.delete(SimpleCov::ResultMerger.resultset_path) if File.exist?(SimpleCov::ResultMerger.resultset_path) + FileUtils.rm_f(SimpleCov::ResultMerger.resultset_path) end let(:resultset1) do @@ -105,12 +105,12 @@ let(:resultset2_path) { "#{resultset_prefix}2.json" } describe "merging behavior" do - before :each do + before do store_result(result1, path: resultset1_path) store_result(result2, path: resultset2_path) end - after :each do + after do FileUtils.rm Dir.glob("#{resultset_prefix}*.json") end @@ -238,7 +238,7 @@ let(:file_path) { "old_resultset.json" } let(:content) { {source_fixture("three.rb") => [nil, 1, 2]} } - before :each do + before do data = { "some command name" => { "coverage" => content, @@ -250,7 +250,7 @@ end end - after :each do + after do FileUtils.rm file_path end diff --git a/spec/result_spec.rb b/spec/result_spec.rb index 9a6bd43d..47070887 100644 --- a/spec/result_spec.rb +++ b/spec/result_spec.rb @@ -125,6 +125,10 @@ end context "with groups set up for all files" do + subject do + SimpleCov::Result.new(original_result) + end + before do SimpleCov.add_group "Models", "app/models" SimpleCov.add_group "Controllers", ["app/controllers"] @@ -133,10 +137,6 @@ end end - subject do - SimpleCov::Result.new(original_result) - end - it "has 3 groups" do expect(subject.groups.length).to eq(3) end @@ -176,6 +176,8 @@ end context "with groups set up that do not match all files" do + subject { SimpleCov::Result.new(original_result) } + before do SimpleCov.configure do add_group "Models", "app/models" @@ -183,8 +185,6 @@ end end - subject { SimpleCov::Result.new(original_result) } - it "has 3 groups" do expect(subject.groups.length).to eq(3) end diff --git a/spec/return_codes_spec.rb b/spec/return_codes_spec.rb index e3656b3a..d8f1cac3 100644 --- a/spec/return_codes_spec.rb +++ b/spec/return_codes_spec.rb @@ -34,6 +34,9 @@ end it "prints a message to STDERR" do + # https://github.com/oracle/truffleruby/issues/3535 + skip "fails on truffleruby" if RUBY_ENGINE == "truffleruby" && Object::Object::RUBY_ENGINE_VERSION < "24.1" && command.include?("testunit_bad.rb") + expect(@stderr).to match(/stopped.+SimpleCov.+previous.+error/i) end end @@ -53,21 +56,25 @@ context "when running testunit_good.rb" do let(:command) { "ruby testunit_good.rb" } + it_behaves_like "good tests" end context "when running rspec_good.rb" do let(:command) { "rspec rspec_good.rb" } + it_behaves_like "good tests" end context "when running testunit_bad.rb" do let(:command) { "ruby testunit_bad.rb" } + it_behaves_like "bad tests" end context "when running rspec_bad.rb" do let(:command) { "rspec rspec_bad.rb" } + it_behaves_like "bad tests" end end diff --git a/spec/simplecov_spec.rb b/spec/simplecov_spec.rb index 62dfa829..b2bb9630 100644 --- a/spec/simplecov_spec.rb +++ b/spec/simplecov_spec.rb @@ -13,7 +13,7 @@ context "with merging disabled" do before do allow(SimpleCov).to receive(:use_merging).once.and_return(false) - expect(SimpleCov).to_not receive(:wait_for_other_processes) + expect(SimpleCov).not_to receive(:wait_for_other_processes) end context "when not running" do @@ -322,7 +322,7 @@ def expect_merged # Normally wouldn't test private methods but just start has side effects that # cause errors so for time this is pragmatic (tm) describe ".start_coverage_measurement", if: SimpleCov.coverage_start_arguments_supported? do - after :each do + after do # SimpleCov is a Singleton/global object so once any test enables # any kind of coverage data it stays there. # Hence, we use clear_coverage_data to create a "clean slate" for these tests @@ -330,13 +330,13 @@ def expect_merged end it "starts coverage in lines mode by default" do - expect(Coverage).to receive(:start).with(lines: true) + expect(Coverage).to receive(:start).with({lines: true}) SimpleCov.send :start_coverage_measurement end it "starts coverage with lines and branches if branch coverage is activated" do - expect(Coverage).to receive(:start).with(lines: true, branches: true) + expect(Coverage).to receive(:start).with({lines: true, branches: true}) SimpleCov.enable_coverage :branch @@ -344,7 +344,7 @@ def expect_merged end it "starts coverage with lines and methods if method coverage is activated" do - expect(Coverage).to receive(:start).with(lines: true, methods: true) + expect(Coverage).to receive(:start).with({lines: true, methods: true}) SimpleCov.enable_coverage :method diff --git a/spec/source_file/line_spec.rb b/spec/source_file/line_spec.rb index a2b36ec6..e5a47d1c 100644 --- a/spec/source_file/line_spec.rb +++ b/spec/source_file/line_spec.rb @@ -29,6 +29,7 @@ before do subject.skipped! end + it "is not covered" do expect(subject).not_to be_covered end diff --git a/spec/support/fail_rspec_on_ruby_warning.rb b/spec/support/fail_rspec_on_ruby_warning.rb index b5115161..5d99c2b2 100644 --- a/spec/support/fail_rspec_on_ruby_warning.rb +++ b/spec/support/fail_rspec_on_ruby_warning.rb @@ -54,9 +54,7 @@ def write_other_warnings_to_tmp(other_warnings) output_dir = File.join(@app_root, "tmp") FileUtils.mkdir_p(output_dir) output_file = File.join(output_dir, "warnings.txt") - File.open(output_file, "w") do |file| - file.write(other_warnings.join("\n") << "\n") - end + File.write(output_file, other_warnings.join("\n") << "\n") puts puts "Non-app warnings written to tmp/warnings.txt" puts diff --git a/spec/useless_results_remover_spec.rb b/spec/useless_results_remover_spec.rb index b24e96ed..e7750078 100644 --- a/spec/useless_results_remover_spec.rb +++ b/spec/useless_results_remover_spec.rb @@ -3,6 +3,10 @@ require "helper" describe SimpleCov::UselessResultsRemover do + subject do + SimpleCov::UselessResultsRemover.call(result_set) + end + let(:gem_file_path) { "usr/bin/lib/2.5.0/gems/sample-gem/sample.rb" } let(:source_path) { source_fixture("app/models/user.rb") } @@ -21,17 +25,13 @@ } end - subject do - SimpleCov::UselessResultsRemover.call(result_set) - end - it "Result ignore gem file path from result set" do - expect(result_set[gem_file_path]).to be_kind_of(Hash) + expect(result_set[gem_file_path]).to be_a(Hash) expect(subject).not_to have_key(gem_file_path) end it "still retains the app path" do expect(subject).to have_key(source_path) - expect(subject[source_path][:lines]).to be_kind_of(Array) + expect(subject[source_path][:lines]).to be_a(Array) end end diff --git a/test_projects/rails/rspec_rails/Gemfile b/test_projects/rails/rspec_rails/Gemfile index d26716e9..edc605b2 100644 --- a/test_projects/rails/rspec_rails/Gemfile +++ b/test_projects/rails/rspec_rails/Gemfile @@ -3,6 +3,7 @@ source "https://rubygems.org" # added gems +gem "logger" gem "rspec-rails" gem "simplecov", path: "../../.." @@ -13,10 +14,8 @@ else gem "sqlite3", "~> 1.4" end -gem "nokogiri", "~> 1.13.10" - # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem "rails", "~> 6.1.4" +gem "rails", "~> 6.1.0" # Use Puma as the app server gem "puma", "~> 5.0" # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder @@ -41,7 +40,7 @@ end group :test do # Adds support for Capybara system testing and selenium driver - gem "capybara", ">= 3.36.0" + gem "capybara", ">= 3.26" # 'selenium-webdriver' and 'webdrivers' did not work with Ruby 3.0 at the # moment this file was updated. Since they are not needed to run # SimpleCov's specs, they have been commented out @@ -52,3 +51,7 @@ end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem "tzinfo-data", platforms: %i[mingw mswin x64_mingw jruby] + +gem "bigdecimal" if RUBY_VERSION >= '3.4' +gem "mutex_m" if RUBY_VERSION >= '3.4' +gem "drb" if RUBY_VERSION >= '3.4' diff --git a/test_projects/rails/rspec_rails/Gemfile.lock b/test_projects/rails/rspec_rails/Gemfile.lock deleted file mode 100644 index 2c627bb8..00000000 --- a/test_projects/rails/rspec_rails/Gemfile.lock +++ /dev/null @@ -1,226 +0,0 @@ -PATH - remote: ../../.. - specs: - simplecov (0.22.0) - docile (~> 1.1) - simplecov-html (~> 0.11) - simplecov_json_formatter (~> 0.1) - -GEM - remote: https://rubygems.org/ - specs: - actioncable (6.1.7) - actionpack (= 6.1.7) - activesupport (= 6.1.7) - nio4r (~> 2.0) - websocket-driver (>= 0.6.1) - actionmailbox (6.1.7) - actionpack (= 6.1.7) - activejob (= 6.1.7) - activerecord (= 6.1.7) - activestorage (= 6.1.7) - activesupport (= 6.1.7) - mail (>= 2.7.1) - actionmailer (6.1.7) - actionpack (= 6.1.7) - actionview (= 6.1.7) - activejob (= 6.1.7) - activesupport (= 6.1.7) - mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 2.0) - actionpack (6.1.7) - actionview (= 6.1.7) - activesupport (= 6.1.7) - rack (~> 2.0, >= 2.0.9) - rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.1.7) - actionpack (= 6.1.7) - activerecord (= 6.1.7) - activestorage (= 6.1.7) - activesupport (= 6.1.7) - nokogiri (>= 1.8.5) - actionview (6.1.7) - activesupport (= 6.1.7) - builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.1.7) - activesupport (= 6.1.7) - globalid (>= 0.3.6) - activemodel (6.1.7) - activesupport (= 6.1.7) - activerecord (6.1.7) - activemodel (= 6.1.7) - activesupport (= 6.1.7) - activestorage (6.1.7) - actionpack (= 6.1.7) - activejob (= 6.1.7) - activerecord (= 6.1.7) - activesupport (= 6.1.7) - marcel (~> 1.0) - mini_mime (>= 1.1.0) - activesupport (6.1.7) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 1.6, < 2) - minitest (>= 5.1) - tzinfo (~> 2.0) - zeitwerk (~> 2.3) - addressable (2.8.1) - public_suffix (>= 2.0.2, < 6.0) - bindex (0.8.1) - bootsnap (1.5.1) - msgpack (~> 1.0) - bootsnap (1.5.1-java) - msgpack (~> 1.0) - builder (3.2.4) - byebug (11.1.3) - capybara (3.36.0) - addressable - matrix - mini_mime (>= 0.1.3) - nokogiri (~> 1.8) - rack (>= 1.6.0) - rack-test (>= 0.6.3) - regexp_parser (>= 1.5, < 3.0) - xpath (~> 3.2) - concurrent-ruby (1.1.7) - crass (1.0.6) - diff-lcs (1.4.4) - docile (1.4.0) - erubi (1.10.0) - globalid (1.0.0) - activesupport (>= 5.0) - i18n (1.8.5) - concurrent-ruby (~> 1.0) - jbuilder (2.10.1) - activesupport (>= 5.0.0) - loofah (2.8.0) - crass (~> 1.0.2) - nokogiri (>= 1.5.9) - mail (2.7.1) - mini_mime (>= 0.1.1) - marcel (1.0.2) - matrix (0.4.2) - method_source (1.0.0) - mini_mime (1.1.2) - mini_portile2 (2.8.2) - minitest (5.15.0) - msgpack (1.3.3) - msgpack (1.3.3-java) - nio4r (2.5.4) - nio4r (2.5.4-java) - nokogiri (1.13.10) - mini_portile2 (~> 2.8.0) - racc (~> 1.4) - nokogiri (1.13.10-java) - racc (~> 1.4) - public_suffix (4.0.7) - puma (5.1.1) - nio4r (~> 2.0) - puma (5.1.1-java) - nio4r (~> 2.0) - racc (1.7.1) - racc (1.7.1-java) - rack (2.2.7) - rack-test (1.1.0) - rack (>= 1.0, < 3) - rails (6.1.7) - actioncable (= 6.1.7) - actionmailbox (= 6.1.7) - actionmailer (= 6.1.7) - actionpack (= 6.1.7) - actiontext (= 6.1.7) - actionview (= 6.1.7) - activejob (= 6.1.7) - activemodel (= 6.1.7) - activerecord (= 6.1.7) - activestorage (= 6.1.7) - activesupport (= 6.1.7) - bundler (>= 1.15.0) - railties (= 6.1.7) - sprockets-rails (>= 2.0.0) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) - nokogiri (>= 1.6) - rails-html-sanitizer (1.3.0) - loofah (~> 2.3) - railties (6.1.7) - actionpack (= 6.1.7) - activesupport (= 6.1.7) - method_source - rake (>= 12.2) - thor (~> 1.0) - rake (13.0.3) - regexp_parser (2.6.1) - rspec-core (3.10.0) - rspec-support (~> 3.10.0) - rspec-expectations (3.10.0) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.10.0) - rspec-mocks (3.10.0) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.10.0) - rspec-rails (4.0.1) - actionpack (>= 4.2) - activesupport (>= 4.2) - railties (>= 4.2) - rspec-core (~> 3.9) - rspec-expectations (~> 3.9) - rspec-mocks (~> 3.9) - rspec-support (~> 3.9) - rspec-support (3.10.0) - simplecov-html (0.12.3) - simplecov_json_formatter (0.1.4) - spring (2.1.1) - sprockets (4.1.1) - concurrent-ruby (~> 1.0) - rack (> 1, < 3) - sprockets-rails (3.4.2) - actionpack (>= 5.2) - activesupport (>= 5.2) - sprockets (>= 3.0.0) - sqlite3 (1.4.4) - thor (1.0.1) - tzinfo (2.0.4) - concurrent-ruby (~> 1.0) - tzinfo-data (1.2022.6) - tzinfo (>= 1.0.0) - web-console (4.1.0) - actionview (>= 6.0.0) - activemodel (>= 6.0.0) - bindex (>= 0.4.0) - railties (>= 6.0.0) - websocket-driver (0.7.5) - websocket-extensions (>= 0.1.0) - websocket-driver (0.7.5-java) - websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.5) - xpath (3.2.0) - nokogiri (~> 1.8) - zeitwerk (2.4.2) - -PLATFORMS - java - ruby - universal-java-1.8 - -DEPENDENCIES - bootsnap (>= 1.4.4) - byebug - capybara (>= 3.36.0) - jbuilder (~> 2.7) - nokogiri (~> 1.13.10) - puma (~> 5.0) - rails (~> 6.1.4) - rspec-rails - simplecov! - spring - sqlite3 (~> 1.4) - tzinfo-data - web-console (>= 4.1.0) - -BUNDLED WITH - 2.3.4 diff --git a/test_projects/rails/rspec_rails/config/application.rb b/test_projects/rails/rspec_rails/config/application.rb index 3bae3ab6..edda9f85 100644 --- a/test_projects/rails/rspec_rails/config/application.rb +++ b/test_projects/rails/rspec_rails/config/application.rb @@ -1,5 +1,6 @@ require_relative "boot" +require "logger" require "rails" # Pick the frameworks you want: require "active_model/railtie"