simplecov 0.9.2 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +7 -7
  2. data/.gitignore +0 -1
  3. data/.rubocop.yml +69 -0
  4. data/CHANGELOG.md +39 -22
  5. data/Gemfile +16 -15
  6. data/MIT-LICENSE +1 -1
  7. data/README.md +183 -178
  8. data/Rakefile +16 -7
  9. data/doc/alternate-formatters.md +36 -0
  10. data/doc/commercial-services.md +20 -0
  11. data/doc/editor-integration.md +13 -0
  12. data/features/rspec_basic.feature +3 -2
  13. data/features/rspec_groups_and_filters_complex.feature +2 -0
  14. data/features/rspec_groups_using_filter_class.feature +3 -2
  15. data/features/step_definitions/html_steps.rb +6 -7
  16. data/features/step_definitions/simplecov_steps.rb +18 -16
  17. data/features/step_definitions/transformers.rb +2 -2
  18. data/features/step_definitions/web_steps.rb +4 -4
  19. data/features/support/env.rb +17 -15
  20. data/lib/simplecov.rb +35 -24
  21. data/lib/simplecov/command_guesser.rb +33 -34
  22. data/lib/simplecov/configuration.rb +238 -234
  23. data/lib/simplecov/defaults.rb +37 -36
  24. data/lib/simplecov/exit_codes.rb +7 -5
  25. data/lib/simplecov/file_list.rb +38 -36
  26. data/lib/simplecov/filter.rb +12 -2
  27. data/lib/simplecov/formatter.rb +2 -2
  28. data/lib/simplecov/formatter/simple_formatter.rb +1 -1
  29. data/lib/simplecov/jruby_fix.rb +4 -4
  30. data/lib/simplecov/last_run.rb +15 -13
  31. data/lib/simplecov/merge_helpers.rb +26 -27
  32. data/lib/simplecov/no_defaults.rb +2 -2
  33. data/lib/simplecov/profiles.rb +21 -19
  34. data/lib/simplecov/railtie.rb +1 -1
  35. data/lib/simplecov/railties/tasks.rake +7 -7
  36. data/lib/simplecov/result.rb +5 -5
  37. data/lib/simplecov/result_merger.rb +65 -62
  38. data/lib/simplecov/source_file.rb +23 -24
  39. data/lib/simplecov/version.rb +20 -1
  40. data/simplecov.gemspec +14 -12
  41. data/test/faked_project/Gemfile +5 -5
  42. data/test/faked_project/Rakefile +4 -4
  43. data/test/faked_project/features/step_definitions/my_steps.rb +3 -4
  44. data/test/faked_project/features/support/env.rb +5 -5
  45. data/test/faked_project/lib/faked_project.rb +1 -1
  46. data/test/faked_project/lib/faked_project/some_class.rb +3 -4
  47. data/test/faked_project/spec/faked_spec.rb +2 -2
  48. data/test/faked_project/spec/forking_spec.rb +7 -0
  49. data/test/faked_project/spec/meta_magic_spec.rb +1 -1
  50. data/test/faked_project/spec/some_class_spec.rb +3 -3
  51. data/test/faked_project/spec/spec_helper.rb +4 -8
  52. data/test/faked_project/test/faked_test.rb +2 -2
  53. data/test/faked_project/test/meta_magic_test.rb +1 -1
  54. data/test/faked_project/test/some_class_test.rb +3 -3
  55. data/test/faked_project/test/test_helper.rb +5 -9
  56. data/test/fixtures/app/controllers/sample_controller.rb +1 -1
  57. data/test/fixtures/app/models/user.rb +1 -1
  58. data/test/fixtures/deleted_source_sample.rb +3 -3
  59. data/test/fixtures/frameworks/rspec_bad.rb +4 -4
  60. data/test/fixtures/frameworks/rspec_good.rb +4 -4
  61. data/test/fixtures/frameworks/testunit_bad.rb +3 -3
  62. data/test/fixtures/frameworks/testunit_good.rb +3 -3
  63. data/test/fixtures/resultset2.rb +0 -1
  64. data/test/fixtures/sample.rb +1 -1
  65. data/test/fixtures/utf-8.rb +1 -1
  66. data/test/helper.rb +8 -8
  67. data/test/test_1_8_fallbacks.rb +6 -6
  68. data/test/test_command_guesser.rb +7 -7
  69. data/test/test_deleted_source.rb +2 -2
  70. data/test/test_file_list.rb +8 -6
  71. data/test/test_filters.rb +29 -13
  72. data/test/test_merge_helpers.rb +26 -23
  73. data/test/test_result.rb +32 -23
  74. data/test/test_return_codes.rb +3 -3
  75. data/test/test_source_file.rb +4 -4
  76. data/test/test_source_file_line.rb +13 -13
  77. metadata +145 -63
  78. data/lib/simplecov/json.rb +0 -27
@@ -1,51 +1,57 @@
1
1
  # Load default formatter gem
2
- require 'simplecov-html'
2
+ require "simplecov-html"
3
3
 
4
- SimpleCov.profiles.define 'root_filter' do
4
+ SimpleCov.profiles.define "root_filter" do
5
5
  # Exclude all files outside of simplecov root
6
6
  add_filter do |src|
7
7
  !(src.filename =~ /^#{Regexp.escape(SimpleCov.root)}/i)
8
8
  end
9
9
  end
10
10
 
11
- SimpleCov.profiles.define 'test_frameworks' do
12
- add_filter '/test/'
13
- add_filter '/features/'
14
- add_filter '/spec/'
15
- add_filter '/autotest/'
11
+ SimpleCov.profiles.define "test_frameworks" do
12
+ add_filter "/test/"
13
+ add_filter "/features/"
14
+ add_filter "/spec/"
15
+ add_filter "/autotest/"
16
16
  end
17
17
 
18
- SimpleCov.profiles.define 'rails' do
19
- load_profile 'test_frameworks'
18
+ SimpleCov.profiles.define "bundler_filter" do
19
+ add_filter "/vendor/bundle/"
20
+ end
21
+
22
+ SimpleCov.profiles.define "rails" do
23
+ load_profile "test_frameworks"
20
24
 
21
- add_filter '/config/'
22
- add_filter '/db/'
23
- add_filter '/vendor/bundle/'
25
+ add_filter "/config/"
26
+ add_filter "/db/"
24
27
 
25
- add_group 'Controllers', 'app/controllers'
26
- add_group 'Models', 'app/models'
27
- add_group 'Mailers', 'app/mailers'
28
- add_group 'Helpers', 'app/helpers'
29
- add_group 'Libraries', 'lib'
28
+ add_group "Controllers", "app/controllers"
29
+ add_group "Models", "app/models"
30
+ add_group "Mailers", "app/mailers"
31
+ add_group "Helpers", "app/helpers"
32
+ add_group "Libraries", "lib"
30
33
  end
31
34
 
32
35
  # Default configuration
33
36
  SimpleCov.configure do
34
37
  formatter SimpleCov::Formatter::HTMLFormatter
38
+ load_profile "bundler_filter"
35
39
  # Exclude files outside of SimpleCov.root
36
- load_profile 'root_filter'
40
+ load_profile "root_filter"
37
41
  end
38
42
 
39
43
  # Gotta stash this a-s-a-p, see the CommandGuesser class and i.e. #110 for further info
40
- SimpleCov::CommandGuesser.original_run_command = "#{$0} #{ARGV.join(" ")}"
44
+ SimpleCov::CommandGuesser.original_run_command = "#{$PROGRAM_NAME} #{ARGV.join(' ')}"
41
45
 
42
46
  at_exit do
47
+ # If we are in a different process than called start, don't interfere.
48
+ next if SimpleCov.pid != Process.pid
43
49
 
44
- if $! # was an exception thrown?
50
+ if $ERROR_INFO # was an exception thrown?
45
51
  # if it was a SystemExit, use the accompanying status
46
52
  # otherwise set a non-zero status representing termination by some other exception
47
53
  # (see github issue 41)
48
- @exit_status = $!.is_a?(SystemExit) ? $!.status : SimpleCov::ExitCodes::EXCEPTION
54
+ @exit_status = $ERROR_INFO.is_a?(SystemExit) ? $ERROR_INFO.status : SimpleCov::ExitCodes::EXCEPTION
49
55
  else
50
56
  # Store the exit status of the test run since it goes away after calling the at_exit proc...
51
57
  @exit_status = SimpleCov::ExitCodes::SUCCESS
@@ -57,18 +63,13 @@ at_exit do
57
63
  covered_percent = SimpleCov.result.covered_percent.round(2)
58
64
 
59
65
  if @exit_status == SimpleCov::ExitCodes::SUCCESS # No other errors
60
- if covered_percent < SimpleCov.minimum_coverage
61
- $stderr.puts "Coverage (%.2f%%) is below the expected minimum coverage (%.2f%%)." % \
62
- [covered_percent, SimpleCov.minimum_coverage]
63
-
66
+ if covered_percent < SimpleCov.minimum_coverage # rubocop:disable Metrics/BlockNesting
67
+ $stderr.printf("Coverage (%.2f%%) is below the expected minimum coverage (%.2f%%).\n", covered_percent, SimpleCov.minimum_coverage)
64
68
  @exit_status = SimpleCov::ExitCodes::MINIMUM_COVERAGE
65
-
66
- elsif (last_run = SimpleCov::LastRun.read)
67
- diff = last_run['result']['covered_percent'] - covered_percent
68
- if diff > SimpleCov.maximum_coverage_drop
69
- $stderr.puts "Coverage has dropped by %.2f%% since the last time (maximum allowed: %.2f%%)." % \
70
- [diff, SimpleCov.maximum_coverage_drop]
71
-
69
+ elsif (last_run = SimpleCov::LastRun.read) # rubocop:disable Metrics/BlockNesting
70
+ diff = last_run["result"]["covered_percent"] - covered_percent
71
+ if diff > SimpleCov.maximum_coverage_drop # rubocop:disable Metrics/BlockNesting
72
+ $stderr.printf("Coverage has dropped by %.2f%% since the last time (maximum allowed: %.2f%%).\n", diff, SimpleCov.maximum_coverage_drop)
72
73
  @exit_status = SimpleCov::ExitCodes::MAXIMUM_COVERAGE_DROP
73
74
  end
74
75
  end
@@ -83,13 +84,13 @@ at_exit do
83
84
  end
84
85
 
85
86
  # Autoload config from ~/.simplecov if present
86
- require 'etc'
87
- home_dir = File.expand_path('~') || Etc.getpwuid.dir || (user = ENV["USER"] && File.expand_path("~#{user}"))
87
+ require "etc"
88
+ home_dir = File.expand_path("~") || Etc.getpwuid.dir || (ENV["USER"] && File.expand_path("~#{ENV['USER']}"))
88
89
  if home_dir
89
- global_config_path = File.join(home_dir, '.simplecov')
90
+ global_config_path = File.join(home_dir, ".simplecov")
90
91
  load global_config_path if File.exist?(global_config_path)
91
92
  end
92
93
 
93
94
  # Autoload config from .simplecov if present
94
- config_path = File.join(SimpleCov.root, '.simplecov')
95
+ config_path = File.join(SimpleCov.root, ".simplecov")
95
96
  load config_path if File.exist?(config_path)
@@ -1,6 +1,8 @@
1
- module SimpleCov::ExitCodes
2
- SUCCESS = 0
3
- EXCEPTION = 1
4
- MINIMUM_COVERAGE = 2
5
- MAXIMUM_COVERAGE_DROP = 3
1
+ module SimpleCov
2
+ module ExitCodes
3
+ SUCCESS = 0
4
+ EXCEPTION = 1
5
+ MINIMUM_COVERAGE = 2
6
+ MAXIMUM_COVERAGE_DROP = 3
7
+ end
6
8
  end
@@ -1,46 +1,48 @@
1
1
  # An array of SimpleCov SourceFile instances with additional collection helper
2
2
  # methods for calculating coverage across them etc.
3
- class SimpleCov::FileList < Array
4
- # Returns the count of lines that have coverage
5
- def covered_lines
6
- return 0.0 if empty?
7
- map {|f| f.covered_lines.count }.inject(&:+)
8
- end
3
+ module SimpleCov
4
+ class FileList < Array
5
+ # Returns the count of lines that have coverage
6
+ def covered_lines
7
+ return 0.0 if empty?
8
+ map { |f| f.covered_lines.count }.inject(&:+)
9
+ end
9
10
 
10
- # Returns the count of lines that have been missed
11
- def missed_lines
12
- return 0.0 if empty?
13
- map {|f| f.missed_lines.count }.inject(&:+)
14
- end
11
+ # Returns the count of lines that have been missed
12
+ def missed_lines
13
+ return 0.0 if empty?
14
+ map { |f| f.missed_lines.count }.inject(&:+)
15
+ end
15
16
 
16
- # Returns the count of lines that are not relevant for coverage
17
- def never_lines
18
- return 0.0 if empty?
19
- map {|f| f.never_lines.count }.inject(&:+)
20
- end
17
+ # Returns the count of lines that are not relevant for coverage
18
+ def never_lines
19
+ return 0.0 if empty?
20
+ map { |f| f.never_lines.count }.inject(&:+)
21
+ end
21
22
 
22
- # Returns the count of skipped lines
23
- def skipped_lines
24
- return 0.0 if empty?
25
- map {|f| f.skipped_lines.count }.inject(&:+)
26
- end
23
+ # Returns the count of skipped lines
24
+ def skipped_lines
25
+ return 0.0 if empty?
26
+ map { |f| f.skipped_lines.count }.inject(&:+)
27
+ end
27
28
 
28
- # Returns the overall amount of relevant lines of code across all files in this list
29
- def lines_of_code
30
- covered_lines + missed_lines
31
- end
29
+ # Returns the overall amount of relevant lines of code across all files in this list
30
+ def lines_of_code
31
+ covered_lines + missed_lines
32
+ end
32
33
 
33
- # Computes the coverage based upon lines covered and lines missed
34
- # @return [Float]
35
- def covered_percent
36
- return 100.0 if empty? or lines_of_code == 0
37
- Float(covered_lines * 100.0 / lines_of_code)
38
- end
34
+ # Computes the coverage based upon lines covered and lines missed
35
+ # @return [Float]
36
+ def covered_percent
37
+ return 100.0 if empty? || lines_of_code.zero?
38
+ Float(covered_lines * 100.0 / lines_of_code)
39
+ end
39
40
 
40
- # Computes the strength (hits / line) based upon lines covered and lines missed
41
- # @return [Float]
42
- def covered_strength
43
- return 0.0 if empty? or lines_of_code == 0
44
- Float(map {|f| f.covered_strength * f.lines_of_code }.inject(&:+) / lines_of_code)
41
+ # Computes the strength (hits / line) based upon lines covered and lines missed
42
+ # @return [Float]
43
+ def covered_strength
44
+ return 0.0 if empty? || lines_of_code.zero?
45
+ Float(map { |f| f.covered_strength * f.lines_of_code }.inject(&:+) / lines_of_code)
46
+ end
45
47
  end
46
48
  end
@@ -16,8 +16,8 @@ module SimpleCov
16
16
  @filter_argument = filter_argument
17
17
  end
18
18
 
19
- def matches?(source_file)
20
- raise "The base filter class is not intended for direct use"
19
+ def matches?(_)
20
+ fail "The base filter class is not intended for direct use"
21
21
  end
22
22
 
23
23
  def passes?(source_file)
@@ -41,4 +41,14 @@ module SimpleCov
41
41
  filter_argument.call(source_file)
42
42
  end
43
43
  end
44
+
45
+ class ArrayFilter < SimpleCov::Filter
46
+ # Returns true if any of the file paths passed in the given array matches the string
47
+ # configured when initializing this Filter with StringFilter.new(['some/path', 'other/path'])
48
+ def matches?(source_files_list)
49
+ filter_argument.any? do |arg|
50
+ source_files_list.filename =~ /#{arg}/
51
+ end
52
+ end
53
+ end
44
54
  end
@@ -4,5 +4,5 @@ module SimpleCov
4
4
  end
5
5
  end
6
6
 
7
- require 'simplecov/formatter/simple_formatter'
8
- require 'simplecov/formatter/multi_formatter'
7
+ require "simplecov/formatter/simple_formatter"
8
+ require "simplecov/formatter/multi_formatter"
@@ -9,7 +9,7 @@ module SimpleCov
9
9
  output = ""
10
10
  result.groups.each do |name, files|
11
11
  output << "Group: #{name}\n"
12
- output << "="*40
12
+ output << "=" * 40
13
13
  output << "\n"
14
14
  files.each do |file|
15
15
  output << "#{file.filename} (coverage: #{file.covered_percent.round(2)}%)\n"
@@ -1,6 +1,6 @@
1
1
  if defined?(JRUBY_VERSION) && JRUBY_VERSION.to_f < 1.7
2
- require 'jruby'
3
- java_import 'org.jruby.ast.NodeType'
2
+ require "jruby"
3
+ java_import "org.jruby.ast.NodeType"
4
4
 
5
5
  # Coverage for JRuby < 1.7.0 does not work correctly
6
6
  #
@@ -11,9 +11,9 @@ if defined?(JRUBY_VERSION) && JRUBY_VERSION.to_f < 1.7
11
11
  # This monkey patches Coverage to address those issues
12
12
  module Coverage
13
13
  class << self
14
- alias __broken_result__ result
14
+ alias_method :__broken_result__, :result
15
15
 
16
- def result
16
+ def result # rubocop:disable Metrics/MethodLength
17
17
  fixed = {}
18
18
  __broken_result__.each do |path, executed_lines|
19
19
  next unless File.file? path
@@ -1,20 +1,22 @@
1
- module SimpleCov::LastRun
2
- class << self
3
- def last_run_path
4
- File.join(SimpleCov.coverage_path, '.last_run.json')
5
- end
1
+ require "json"
6
2
 
7
- def read
8
- return nil unless File.exist?(last_run_path)
3
+ module SimpleCov
4
+ module LastRun
5
+ class << self
6
+ def last_run_path
7
+ File.join(SimpleCov.coverage_path, ".last_run.json")
8
+ end
9
9
 
10
- SimpleCov::JSON.parse(File.read(last_run_path))
11
- end
10
+ def read
11
+ return nil unless File.exist?(last_run_path)
12
+ JSON.parse(File.read(last_run_path))
13
+ end
12
14
 
13
- def write(json)
14
- File.open(last_run_path, "w+") do |f|
15
- f.puts SimpleCov::JSON.dump(json)
15
+ def write(json)
16
+ File.open(last_run_path, "w+") do |f|
17
+ f.puts JSON.pretty_generate(json)
18
+ end
16
19
  end
17
20
  end
18
21
  end
19
22
  end
20
-
@@ -1,37 +1,36 @@
1
- module SimpleCov::ArrayMergeHelper
2
- # Merges an array of coverage results with self
3
- def merge_resultset(array)
4
- new_array = []
5
-
6
- self.each_with_index do |element, i|
7
- new_array[i] = element
8
- end
9
-
10
- array.each_with_index do |element, i|
11
- if element.nil? and new_array[i].nil?
12
- new_array[i] = nil
13
- else
14
- local_value = element || 0
15
- other_value = new_array[i] || 0
16
- new_array[i] = local_value + other_value
1
+ module SimpleCov
2
+ module ArrayMergeHelper
3
+ # Merges an array of coverage results with self
4
+ def merge_resultset(array)
5
+ new_array = dup
6
+ array.each_with_index do |element, i|
7
+ if element.nil? && new_array[i].nil?
8
+ new_array[i] = nil
9
+ else
10
+ local_value = element || 0
11
+ other_value = new_array[i] || 0
12
+ new_array[i] = local_value + other_value
13
+ end
17
14
  end
15
+ new_array
18
16
  end
19
- new_array
20
17
  end
21
18
  end
22
19
 
23
- module SimpleCov::HashMergeHelper
24
- # Merges the given Coverage.result hash with self
25
- def merge_resultset(hash)
26
- new_resultset = {}
27
- (self.keys + hash.keys).each do |filename|
28
- new_resultset[filename] = []
29
- end
20
+ module SimpleCov
21
+ module HashMergeHelper
22
+ # Merges the given Coverage.result hash with self
23
+ def merge_resultset(hash)
24
+ new_resultset = {}
25
+ (keys + hash.keys).each do |filename|
26
+ new_resultset[filename] = []
27
+ end
30
28
 
31
- new_resultset.each do |filename, data|
32
- new_resultset[filename] = (self[filename] || []).merge_resultset(hash[filename] || [])
29
+ new_resultset.each_key do |filename|
30
+ new_resultset[filename] = (self[filename] || []).merge_resultset(hash[filename] || [])
31
+ end
32
+ new_resultset
33
33
  end
34
- new_resultset
35
34
  end
36
35
  end
37
36
 
@@ -1,2 +1,2 @@
1
- ENV['SIMPLECOV_NO_DEFAULTS'] = 'yes, no defaults'
2
- require 'simplecov'
1
+ ENV["SIMPLECOV_NO_DEFAULTS"] = "yes, no defaults"
2
+ require "simplecov"
@@ -5,25 +5,27 @@
5
5
  # # SimpleCov configuration here, same as in SimpleCov.configure
6
6
  # end
7
7
  #
8
- class SimpleCov::Profiles < Hash
9
- #
10
- # Define a SimpleCov profile:
11
- # SimpleCov.profiles.define 'rails' do
12
- # # Same as SimpleCov.configure do .. here
13
- # end
14
- #
15
- def define(name, &blk)
16
- name = name.to_sym
17
- raise "SimpleCov Profile '#{name}' is already defined" unless self[name].nil?
18
- self[name] = blk
19
- end
8
+ module SimpleCov
9
+ class Profiles < Hash
10
+ #
11
+ # Define a SimpleCov profile:
12
+ # SimpleCov.profiles.define 'rails' do
13
+ # # Same as SimpleCov.configure do .. here
14
+ # end
15
+ #
16
+ def define(name, &blk)
17
+ name = name.to_sym
18
+ fail "SimpleCov Profile '#{name}' is already defined" unless self[name].nil?
19
+ self[name] = blk
20
+ end
20
21
 
21
- #
22
- # Applies the profile of given name on SimpleCov.configure
23
- #
24
- def load(name)
25
- name = name.to_sym
26
- raise "Could not find SimpleCov Profile called '#{name}'" unless has_key?(name)
27
- SimpleCov.configure(&self[name])
22
+ #
23
+ # Applies the profile of given name on SimpleCov.configure
24
+ #
25
+ def load(name)
26
+ name = name.to_sym
27
+ fail "Could not find SimpleCov Profile called '#{name}'" unless key?(name)
28
+ SimpleCov.configure(&self[name])
29
+ end
28
30
  end
29
31
  end
@@ -1,7 +1,7 @@
1
1
  module SimpleCov
2
2
  class Railtie < ::Rails::Railtie
3
3
  rake_tasks do
4
- load 'simplecov/railties/tasks.rake'
4
+ load "simplecov/railties/tasks.rake"
5
5
  end
6
6
  end
7
7
  end