simplecov 0.17.1 → 0.18.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -1
- data/CODE_OF_CONDUCT.md +76 -0
- data/README.md +167 -63
- data/doc/alternate-formatters.md +5 -0
- data/lib/simplecov.rb +147 -65
- data/lib/simplecov/combine.rb +30 -0
- data/lib/simplecov/combine/branches_combiner.rb +32 -0
- data/lib/simplecov/combine/files_combiner.rb +25 -0
- data/lib/simplecov/combine/lines_combiner.rb +43 -0
- data/lib/simplecov/combine/results_combiner.rb +60 -0
- data/lib/simplecov/command_guesser.rb +6 -3
- data/lib/simplecov/configuration.rb +77 -8
- data/lib/simplecov/defaults.rb +1 -1
- data/lib/simplecov/file_list.rb +30 -3
- data/lib/simplecov/filter.rb +2 -1
- data/lib/simplecov/formatter/multi_formatter.rb +2 -2
- data/lib/simplecov/formatter/simple_formatter.rb +4 -4
- data/lib/simplecov/last_run.rb +2 -0
- data/lib/simplecov/lines_classifier.rb +2 -2
- data/lib/simplecov/profiles.rb +9 -7
- data/lib/simplecov/result.rb +21 -4
- data/lib/simplecov/result_adapter.rb +30 -0
- data/lib/simplecov/result_merger.rb +12 -11
- data/lib/simplecov/simulate_coverage.rb +29 -0
- data/lib/simplecov/source_file.rb +219 -109
- data/lib/simplecov/source_file/branch.rb +106 -0
- data/lib/simplecov/source_file/line.rb +72 -0
- data/lib/simplecov/useless_results_remover.rb +16 -0
- data/lib/simplecov/version.rb +1 -1
- metadata +33 -168
- data/lib/simplecov/jruby_fix.rb +0 -44
- data/lib/simplecov/railtie.rb +0 -9
- data/lib/simplecov/railties/tasks.rake +0 -13
- data/lib/simplecov/raw_coverage.rb +0 -41
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
# Helper that tries to find out what test suite is running (for SimpleCov.command_name)
|
5
|
-
#
|
6
3
|
module SimpleCov
|
4
|
+
#
|
5
|
+
# Helper that tries to find out what test suite is running (for SimpleCov.command_name)
|
6
|
+
#
|
7
7
|
module CommandGuesser
|
8
8
|
class << self
|
9
9
|
# Storage for the original command line call that invoked the test suite.
|
@@ -22,6 +22,7 @@ module SimpleCov
|
|
22
22
|
def from_env
|
23
23
|
# If being run from inside parallel_tests set the command name according to the process number
|
24
24
|
return unless ENV["PARALLEL_TEST_GROUPS"] && ENV["TEST_ENV_NUMBER"]
|
25
|
+
|
25
26
|
number = ENV["TEST_ENV_NUMBER"]
|
26
27
|
number = "1" if number.empty?
|
27
28
|
"(#{number}/#{ENV['PARALLEL_TEST_GROUPS']})"
|
@@ -48,6 +49,8 @@ module SimpleCov
|
|
48
49
|
"RSpec"
|
49
50
|
elsif defined?(Test::Unit)
|
50
51
|
"Unit Tests"
|
52
|
+
elsif defined?(Minitest)
|
53
|
+
"Minitest"
|
51
54
|
elsif defined?(MiniTest)
|
52
55
|
"MiniTest"
|
53
56
|
else
|
@@ -3,14 +3,15 @@
|
|
3
3
|
require "fileutils"
|
4
4
|
require "docile"
|
5
5
|
require "simplecov/formatter/multi_formatter"
|
6
|
-
|
7
|
-
# Bundles the configuration options used for SimpleCov. All methods
|
8
|
-
# defined here are usable from SimpleCov directly. Please check out
|
9
|
-
# SimpleCov documentation for further info.
|
10
|
-
#
|
6
|
+
|
11
7
|
module SimpleCov
|
12
|
-
|
13
|
-
|
8
|
+
#
|
9
|
+
# Bundles the configuration options used for SimpleCov. All methods
|
10
|
+
# defined here are usable from SimpleCov directly. Please check out
|
11
|
+
# SimpleCov documentation for further info.
|
12
|
+
#
|
13
|
+
module Configuration # rubocop:disable Metrics/ModuleLength
|
14
|
+
attr_writer :filters, :groups, :formatter, :print_error_status
|
14
15
|
|
15
16
|
#
|
16
17
|
# The root for the project. This defaults to the
|
@@ -20,6 +21,7 @@ module SimpleCov
|
|
20
21
|
#
|
21
22
|
def root(root = nil)
|
22
23
|
return @root if defined?(@root) && root.nil?
|
24
|
+
|
23
25
|
@root = File.expand_path(root || Dir.getwd)
|
24
26
|
end
|
25
27
|
|
@@ -30,6 +32,7 @@ module SimpleCov
|
|
30
32
|
#
|
31
33
|
def coverage_dir(dir = nil)
|
32
34
|
return @coverage_dir if defined?(@coverage_dir) && dir.nil?
|
35
|
+
|
33
36
|
@coverage_path = nil # invalidate cache
|
34
37
|
@coverage_dir = (dir || "coverage")
|
35
38
|
end
|
@@ -93,8 +96,10 @@ module SimpleCov
|
|
93
96
|
#
|
94
97
|
def formatter(formatter = nil)
|
95
98
|
return @formatter if defined?(@formatter) && formatter.nil?
|
99
|
+
|
96
100
|
@formatter = formatter
|
97
101
|
raise "No formatter configured. Please specify a formatter using SimpleCov.formatter = SimpleCov::Formatter::SimpleFormatter" unless @formatter
|
102
|
+
|
98
103
|
@formatter
|
99
104
|
end
|
100
105
|
|
@@ -116,6 +121,14 @@ module SimpleCov
|
|
116
121
|
end
|
117
122
|
end
|
118
123
|
|
124
|
+
#
|
125
|
+
# Whether we should print non-success status codes. This can be
|
126
|
+
# configured with the #print_error_status= method.
|
127
|
+
#
|
128
|
+
def print_error_status
|
129
|
+
defined?(@print_error_status) ? @print_error_status : true
|
130
|
+
end
|
131
|
+
|
119
132
|
#
|
120
133
|
# Certain code blocks (i.e. Ruby-implementation specific code) can be excluded from
|
121
134
|
# the coverage metrics by wrapping it inside # :nocov: comment blocks. The nocov token
|
@@ -125,6 +138,7 @@ module SimpleCov
|
|
125
138
|
#
|
126
139
|
def nocov_token(nocov_token = nil)
|
127
140
|
return @nocov_token if defined?(@nocov_token) && nocov_token.nil?
|
141
|
+
|
128
142
|
@nocov_token = (nocov_token || "nocov")
|
129
143
|
end
|
130
144
|
alias skip_token nocov_token
|
@@ -160,7 +174,6 @@ module SimpleCov
|
|
160
174
|
# options at once.
|
161
175
|
#
|
162
176
|
def configure(&block)
|
163
|
-
return false unless SimpleCov.usable?
|
164
177
|
Docile.dsl_eval(self, &block)
|
165
178
|
end
|
166
179
|
|
@@ -178,6 +191,7 @@ module SimpleCov
|
|
178
191
|
#
|
179
192
|
def at_exit(&block)
|
180
193
|
return proc {} unless running || block_given?
|
194
|
+
|
181
195
|
@at_exit = block if block_given?
|
182
196
|
@at_exit ||= proc { SimpleCov.result.format! }
|
183
197
|
end
|
@@ -188,6 +202,7 @@ module SimpleCov
|
|
188
202
|
#
|
189
203
|
def project_name(new_name = nil)
|
190
204
|
return @project_name if defined?(@project_name) && @project_name && new_name.nil?
|
205
|
+
|
191
206
|
@project_name = new_name if new_name.is_a?(String)
|
192
207
|
@project_name ||= File.basename(root.split("/").last).capitalize.tr("_", " ")
|
193
208
|
end
|
@@ -225,6 +240,7 @@ module SimpleCov
|
|
225
240
|
# Default is 0% (disabled)
|
226
241
|
#
|
227
242
|
def minimum_coverage(coverage = nil)
|
243
|
+
minimum_possible_coverage_exceeded("minimum_coverage") if coverage && coverage > 100
|
228
244
|
@minimum_coverage ||= (coverage || 0).to_f.round(2)
|
229
245
|
end
|
230
246
|
|
@@ -246,6 +262,7 @@ module SimpleCov
|
|
246
262
|
# Default is 0% (disabled)
|
247
263
|
#
|
248
264
|
def minimum_coverage_by_file(coverage = nil)
|
265
|
+
minimum_possible_coverage_exceeded("minimum_coverage_by_file") if coverage && coverage > 100
|
249
266
|
@minimum_coverage_by_file ||= (coverage || 0).to_f.round(2)
|
250
267
|
end
|
251
268
|
|
@@ -287,8 +304,60 @@ module SimpleCov
|
|
287
304
|
groups[group_name] = parse_filter(filter_argument, &filter_proc)
|
288
305
|
end
|
289
306
|
|
307
|
+
SUPPORTED_COVERAGE_CRITERIA = %i[line branch].freeze
|
308
|
+
DEFAULT_COVERAGE_CRITERION = :line
|
309
|
+
#
|
310
|
+
# Define which coverage criterion should be evaluated.
|
311
|
+
#
|
312
|
+
# Possible coverage criteria:
|
313
|
+
# * :line - coverage based on lines aka has this line been executed?
|
314
|
+
# * :branch - coverage based on branches aka has this branch (think conditions) been executed?
|
315
|
+
#
|
316
|
+
# If not set the default is is `:line`
|
317
|
+
#
|
318
|
+
# @param [Symbol] criterion
|
319
|
+
#
|
320
|
+
def coverage_criterion(criterion = nil)
|
321
|
+
return @coverage_criterion ||= DEFAULT_COVERAGE_CRITERION unless criterion
|
322
|
+
|
323
|
+
raise_if_criterion_unsupported(criterion)
|
324
|
+
|
325
|
+
@coverage_criterion = criterion
|
326
|
+
end
|
327
|
+
|
328
|
+
def enable_coverage(criterion)
|
329
|
+
raise_if_criterion_unsupported(criterion)
|
330
|
+
|
331
|
+
coverage_criteria << criterion
|
332
|
+
end
|
333
|
+
|
334
|
+
def coverage_criteria
|
335
|
+
@coverage_criteria ||= Set[DEFAULT_COVERAGE_CRITERION]
|
336
|
+
end
|
337
|
+
|
338
|
+
def branch_coverage?
|
339
|
+
branch_coverage_supported? && coverage_criteria.member?(:branch)
|
340
|
+
end
|
341
|
+
|
342
|
+
def branch_coverage_supported?
|
343
|
+
require "coverage"
|
344
|
+
!Coverage.method(:start).arity.zero?
|
345
|
+
end
|
346
|
+
|
290
347
|
private
|
291
348
|
|
349
|
+
def raise_if_criterion_unsupported(criterion)
|
350
|
+
raise_criterion_unsupported(criterion) unless SUPPORTED_COVERAGE_CRITERIA.member?(criterion)
|
351
|
+
end
|
352
|
+
|
353
|
+
def raise_criterion_unsupported(criterion)
|
354
|
+
raise "Unsupported coverage criterion #{criterion}, supported values are #{SUPPORTED_COVERAGE_CRITERIA}"
|
355
|
+
end
|
356
|
+
|
357
|
+
def minimum_possible_coverage_exceeded(coverage_option)
|
358
|
+
warn "The coverage you set for #{coverage_option} is greater than 100%"
|
359
|
+
end
|
360
|
+
|
292
361
|
#
|
293
362
|
# The actual filter processor. Not meant for direct use
|
294
363
|
#
|
data/lib/simplecov/defaults.rb
CHANGED
@@ -42,7 +42,7 @@ loop do
|
|
42
42
|
begin
|
43
43
|
load filename
|
44
44
|
rescue LoadError, StandardError
|
45
|
-
|
45
|
+
warn "Warning: Error occurred while trying to load #{filename}. " \
|
46
46
|
"Error message: #{$!.message}"
|
47
47
|
end
|
48
48
|
break
|
data/lib/simplecov/file_list.rb
CHANGED
@@ -1,30 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# An array of SimpleCov SourceFile instances with additional collection helper
|
4
|
-
# methods for calculating coverage across them etc.
|
5
3
|
module SimpleCov
|
4
|
+
# An array of SimpleCov SourceFile instances with additional collection helper
|
5
|
+
# methods for calculating coverage across them etc.
|
6
6
|
class FileList < Array
|
7
7
|
# Returns the count of lines that have coverage
|
8
8
|
def covered_lines
|
9
9
|
return 0.0 if empty?
|
10
|
+
|
10
11
|
map { |f| f.covered_lines.count }.inject(:+)
|
11
12
|
end
|
12
13
|
|
13
14
|
# Returns the count of lines that have been missed
|
14
15
|
def missed_lines
|
15
16
|
return 0.0 if empty?
|
17
|
+
|
16
18
|
map { |f| f.missed_lines.count }.inject(:+)
|
17
19
|
end
|
18
20
|
|
19
21
|
# Returns the count of lines that are not relevant for coverage
|
20
22
|
def never_lines
|
21
23
|
return 0.0 if empty?
|
24
|
+
|
22
25
|
map { |f| f.never_lines.count }.inject(:+)
|
23
26
|
end
|
24
27
|
|
25
28
|
# Returns the count of skipped lines
|
26
29
|
def skipped_lines
|
27
30
|
return 0.0 if empty?
|
31
|
+
|
28
32
|
map { |f| f.skipped_lines.count }.inject(:+)
|
29
33
|
end
|
30
34
|
|
@@ -36,7 +40,7 @@ module SimpleCov
|
|
36
40
|
|
37
41
|
# Finds the least covered file and returns that file's name
|
38
42
|
def least_covered_file
|
39
|
-
|
43
|
+
min_by(&:covered_percent).filename
|
40
44
|
end
|
41
45
|
|
42
46
|
# Returns the overall amount of relevant lines of code across all files in this list
|
@@ -48,6 +52,7 @@ module SimpleCov
|
|
48
52
|
# @return [Float]
|
49
53
|
def covered_percent
|
50
54
|
return 100.0 if empty? || lines_of_code.zero?
|
55
|
+
|
51
56
|
Float(covered_lines * 100.0 / lines_of_code)
|
52
57
|
end
|
53
58
|
|
@@ -55,7 +60,29 @@ module SimpleCov
|
|
55
60
|
# @return [Float]
|
56
61
|
def covered_strength
|
57
62
|
return 0.0 if empty? || lines_of_code.zero?
|
63
|
+
|
58
64
|
Float(map { |f| f.covered_strength * f.lines_of_code }.inject(:+) / lines_of_code)
|
59
65
|
end
|
66
|
+
|
67
|
+
# Return total count of branches in all files
|
68
|
+
def total_branches
|
69
|
+
return 0 if empty?
|
70
|
+
|
71
|
+
map { |file| file.total_branches.count }.inject(:+)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Return total count of covered branches
|
75
|
+
def covered_branches
|
76
|
+
return 0 if empty?
|
77
|
+
|
78
|
+
map { |file| file.covered_branches.count }.inject(:+)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Return total count of covered branches
|
82
|
+
def missed_branches
|
83
|
+
return 0 if empty?
|
84
|
+
|
85
|
+
map { |file| file.missed_branches.count }.inject(:+)
|
86
|
+
end
|
60
87
|
end
|
61
88
|
end
|
data/lib/simplecov/filter.rb
CHANGED
@@ -18,7 +18,7 @@ module SimpleCov
|
|
18
18
|
@filter_argument = filter_argument
|
19
19
|
end
|
20
20
|
|
21
|
-
def matches?(
|
21
|
+
def matches?(_source_file)
|
22
22
|
raise "The base filter class is not intended for direct use"
|
23
23
|
end
|
24
24
|
|
@@ -29,6 +29,7 @@ module SimpleCov
|
|
29
29
|
|
30
30
|
def self.build_filter(filter_argument)
|
31
31
|
return filter_argument if filter_argument.is_a?(SimpleCov::Filter)
|
32
|
+
|
32
33
|
class_for_argument(filter_argument).new(filter_argument)
|
33
34
|
end
|
34
35
|
|
@@ -8,8 +8,8 @@ module SimpleCov
|
|
8
8
|
formatters.map do |formatter|
|
9
9
|
begin
|
10
10
|
formatter.new.format(result)
|
11
|
-
rescue => e
|
12
|
-
|
11
|
+
rescue StandardError => e
|
12
|
+
warn("Formatter #{formatter} failed with #{e.class}: #{e.message} (#{e.backtrace.first})")
|
13
13
|
nil
|
14
14
|
end
|
15
15
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
# A ridiculously simple formatter for SimpleCov results.
|
5
|
-
#
|
6
3
|
module SimpleCov
|
7
4
|
module Formatter
|
5
|
+
#
|
6
|
+
# A ridiculously simple formatter for SimpleCov results.
|
7
|
+
#
|
8
8
|
class SimpleFormatter
|
9
9
|
# Takes a SimpleCov::Result and generates a string out of it
|
10
10
|
def format(result)
|
11
|
-
output = ""
|
11
|
+
output = +""
|
12
12
|
result.groups.each do |name, files|
|
13
13
|
output << "Group: #{name}\n"
|
14
14
|
output << "=" * 40
|
data/lib/simplecov/last_run.rb
CHANGED
@@ -8,8 +8,8 @@ module SimpleCov
|
|
8
8
|
RELEVANT = 0
|
9
9
|
NOT_RELEVANT = nil
|
10
10
|
|
11
|
-
WHITESPACE_LINE = /^\s
|
12
|
-
COMMENT_LINE = /^\s
|
11
|
+
WHITESPACE_LINE = /^\s*$/.freeze
|
12
|
+
COMMENT_LINE = /^\s*#/.freeze
|
13
13
|
WHITESPACE_OR_COMMENT_LINE = Regexp.union(WHITESPACE_LINE, COMMENT_LINE)
|
14
14
|
|
15
15
|
def self.no_cov_line
|
data/lib/simplecov/profiles.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
# Profiles are SimpleCov configuration procs that can be easily
|
5
|
-
# loaded using SimpleCov.start :rails and defined using
|
6
|
-
# SimpleCov.profiles.define :foo do
|
7
|
-
# # SimpleCov configuration here, same as in SimpleCov.configure
|
8
|
-
# end
|
9
|
-
#
|
10
3
|
module SimpleCov
|
4
|
+
#
|
5
|
+
# Profiles are SimpleCov configuration procs that can be easily
|
6
|
+
# loaded using SimpleCov.start :rails and defined using
|
7
|
+
# SimpleCov.profiles.define :foo do
|
8
|
+
# # SimpleCov configuration here, same as in SimpleCov.configure
|
9
|
+
# end
|
10
|
+
#
|
11
11
|
class Profiles < Hash
|
12
12
|
#
|
13
13
|
# Define a SimpleCov profile:
|
@@ -18,6 +18,7 @@ module SimpleCov
|
|
18
18
|
def define(name, &blk)
|
19
19
|
name = name.to_sym
|
20
20
|
raise "SimpleCov Profile '#{name}' is already defined" unless self[name].nil?
|
21
|
+
|
21
22
|
self[name] = blk
|
22
23
|
end
|
23
24
|
|
@@ -27,6 +28,7 @@ module SimpleCov
|
|
27
28
|
def load(name)
|
28
29
|
name = name.to_sym
|
29
30
|
raise "Could not find SimpleCov Profile called '#{name}'" unless key?(name)
|
31
|
+
|
30
32
|
SimpleCov.configure(&self[name])
|
31
33
|
end
|
32
34
|
end
|
data/lib/simplecov/result.rb
CHANGED
@@ -5,7 +5,7 @@ require "forwardable"
|
|
5
5
|
|
6
6
|
module SimpleCov
|
7
7
|
#
|
8
|
-
# A simplecov code coverage result, initialized from the Hash Ruby
|
8
|
+
# A simplecov code coverage result, initialized from the Hash Ruby's built-in coverage
|
9
9
|
# library generates (Coverage.result).
|
10
10
|
#
|
11
11
|
class Result
|
@@ -20,7 +20,7 @@ module SimpleCov
|
|
20
20
|
# Explicitly set the command name that was used for this coverage result. Defaults to SimpleCov.command_name
|
21
21
|
attr_writer :command_name
|
22
22
|
|
23
|
-
def_delegators :files, :covered_percent, :covered_percentages, :least_covered_file, :covered_strength, :covered_lines, :missed_lines
|
23
|
+
def_delegators :files, :covered_percent, :covered_percentages, :least_covered_file, :covered_strength, :covered_lines, :missed_lines, :total_branches, :covered_branches, :missed_branches
|
24
24
|
def_delegator :files, :lines_of_code, :total_lines
|
25
25
|
|
26
26
|
# Initialize a new SimpleCov::Result from given Coverage.result (a Hash of filenames each containing an array of
|
@@ -28,7 +28,7 @@ module SimpleCov
|
|
28
28
|
def initialize(original_result)
|
29
29
|
@original_result = original_result.freeze
|
30
30
|
@files = SimpleCov::FileList.new(original_result.map do |filename, coverage|
|
31
|
-
SimpleCov::SourceFile.new(filename, coverage) if File.file?(filename)
|
31
|
+
SimpleCov::SourceFile.new(filename, JSON.parse(JSON.dump(coverage), :symbolize_names => true)) if File.file?(filename.to_s)
|
32
32
|
end.compact.sort_by(&:filename))
|
33
33
|
filter!
|
34
34
|
end
|
@@ -67,12 +67,29 @@ module SimpleCov
|
|
67
67
|
# Loads a SimpleCov::Result#to_hash dump
|
68
68
|
def self.from_hash(hash)
|
69
69
|
command_name, data = hash.first
|
70
|
-
|
70
|
+
|
71
|
+
result = SimpleCov::Result.new(
|
72
|
+
symbolize_names_of_coverage_results(data["coverage"])
|
73
|
+
)
|
74
|
+
|
71
75
|
result.command_name = command_name
|
72
76
|
result.created_at = Time.at(data["timestamp"])
|
73
77
|
result
|
74
78
|
end
|
75
79
|
|
80
|
+
# Manage symbolize the keys of coverage hash.
|
81
|
+
# JSON.parse gives coverage hash with stringified keys what breaks some logics
|
82
|
+
# inside the process that expects them as symboles.
|
83
|
+
#
|
84
|
+
# @return [Hash]
|
85
|
+
def self.symbolize_names_of_coverage_results(coverage_data)
|
86
|
+
coverage_data.each_with_object({}) do |(file_name, file_coverage_result), coverage_results|
|
87
|
+
coverage_results[file_name] = file_coverage_result.each_with_object({}) do |(k, v), cov_elem|
|
88
|
+
cov_elem[k.to_sym] = v
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
76
93
|
private
|
77
94
|
|
78
95
|
def coverage
|