simplecov 0.19.0 → 0.21.2

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.
data/README.md CHANGED
@@ -73,9 +73,10 @@ Getting started
73
73
  analysis to happen on. When testing a server process (e.g. a JSON API
74
74
  endpoint) via a separate test process (e.g. when using Selenium) where you
75
75
  want to see all code executed by the `rails server`, and not just code
76
- executed in your actual test files, you'll want to add something like this
76
+ executed in your actual test files, you need to require SimpleCov in the
77
+ server process. For rails for instance, you'll want to add something like this
77
78
  to the top of `bin/rails`, but below the "shebang" line (`#! /usr/bin/env
78
- ruby`):
79
+ ruby`) and after config/boot is required:
79
80
 
80
81
  ```ruby
81
82
  if ENV['RAILS_ENV'] == 'test'
@@ -294,7 +295,6 @@ information to be lost.
294
295
  Add branch coverage measurement statistics to your results. Supported in CRuby versions 2.5+.
295
296
 
296
297
  ```ruby
297
- # or in configure or just SimpleCov.enable_coverage :branch
298
298
  SimpleCov.start do
299
299
  enable_coverage :branch
300
300
  end
@@ -340,6 +340,22 @@ Hence, we recommend looking at both metrics together. Branch coverage might also
340
340
  overall metric to look at - while you might be missing only 10% of your lines that might
341
341
  account for 50% of your branches for instance.
342
342
 
343
+ ## Primary Coverage
344
+
345
+ By default, the primary coverage type is `line`. To set the primary coverage to something else, use the following:
346
+
347
+ ```ruby
348
+ # or in configure SimpleCov.primary_coverage :branch
349
+ SimpleCov.start do
350
+ enable_coverage :branch
351
+ primary_coverage :branch
352
+ end
353
+ ```
354
+
355
+ 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`).
356
+
357
+ Note that coverage must first be enabled for non-default coverage types.
358
+
343
359
  ## Filters
344
360
 
345
361
  Filters can be used to remove selected files from your coverage data. By default, a filter is applied that removes all
@@ -786,30 +802,36 @@ to help ensure coverage is relatively consistent, rather than being skewed by pa
786
802
 
787
803
  ```ruby
788
804
  SimpleCov.minimum_coverage_by_file 80
805
+ # same as above (the default is to check line coverage by file)
806
+ SimpleCov.minimum_coverage_by_file line: 80
807
+ # check for a minimum line coverage by file of 90% and minimum 80% branch coverage
808
+ SimpleCov.minimum_coverage_by_file line: 90, branch: 80
789
809
  ```
790
810
 
791
- (not yet supported for branch coverage)
792
-
793
811
  ### Maximum coverage drop
794
812
 
795
813
  You can define the maximum coverage drop percentage at once. SimpleCov will return non-zero if exceeded.
796
814
 
797
815
  ```ruby
798
816
  SimpleCov.maximum_coverage_drop 5
817
+ # same as above (the default is to check line drop)
818
+ SimpleCov.maximum_coverage_drop line: 5
819
+ # check for a maximum line drop of 5% and maximum 10% branch drop
820
+ SimpleCov.maximum_coverage_drop line: 5, branch: 10
799
821
  ```
800
822
 
801
- (not yet supported for branch coverage)
802
-
803
823
  ### Refuse dropping coverage
804
824
 
805
825
  You can also entirely refuse dropping coverage between test runs:
806
826
 
807
827
  ```ruby
808
828
  SimpleCov.refuse_coverage_drop
829
+ # same as above (the default is to only refuse line drop)
830
+ SimpleCov.refuse_coverage_drop :line
831
+ # refuse drop for line and branch
832
+ SimpleCov.refuse_coverage_drop :line, :branch
809
833
  ```
810
834
 
811
- (not yet supported for branch coverage)
812
-
813
835
  ## Using your own formatter
814
836
 
815
837
  You can use your own formatter with:
@@ -833,6 +855,20 @@ SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new([
833
855
  ])
834
856
  ```
835
857
 
858
+ ## JSON formatter
859
+
860
+ SimpleCov is packaged with a separate gem called [simplecov_json_formatter](https://github.com/codeclimate-community/simplecov_json_formatter) that provides you with a JSON formatter, this formatter could be useful for different use cases, such as for CI consumption or for reporting to external services.
861
+
862
+ In order to use it you will need to manually load the installed gem like so:
863
+
864
+ ```ruby
865
+ require "simplecov_json_formatter"
866
+ SimpleCov.formatter = SimpleCov::Formatter::JSONFormatter
867
+ ```
868
+
869
+ > _Note:_ In case you plan to report your coverage results to CodeClimate services, know that SimpleCov will automatically use the
870
+ > JSON formatter along with the HTML formatter when the `CC_TEST_REPORTER_ID` variable is present in the environment.
871
+
836
872
  ## Available formatters, editor integrations and hosted services
837
873
 
838
874
  * [Open Source formatter and integration plugins for SimpleCov](doc/alternate-formatters.md)
@@ -60,6 +60,11 @@ A formatter that prints the coverage of the file under test when you run a singl
60
60
 
61
61
  t_wada AA formatter for SimpleCov
62
62
 
63
+ #### [simplecov-tailwindcss](https://github.com/chiefpansancolt/simplecov-tailwindcss)
64
+ *by [Chiefpansancolt](https://github.com/chiefpansancolt)*
65
+
66
+ A TailwindCSS & TailwindUI Designed HTML formatter with clean and easy search of files with a tabular left Navigation.
67
+
63
68
  #### [simplecov-material](https://github.com/chiefpansancolt/simplecov-material)
64
69
  *by [Chiefpansancolt](https://github.com/chiefpansancolt)*
65
70
 
@@ -3,7 +3,7 @@
3
3
  require "English"
4
4
 
5
5
  # Coverage may be inaccurate under JRUBY.
6
- if defined?(JRUBY_VERSION) && defined?(JRuby)
6
+ if defined?(JRUBY_VERSION) && defined?(JRuby) && !org.jruby.RubyInstanceConfig.FULL_TRACE_ENABLED
7
7
 
8
8
  # @see https://github.com/jruby/jruby/issues/1196
9
9
  # @see https://github.com/metricfu/metric_fu/pull/226
@@ -11,11 +11,9 @@ if defined?(JRUBY_VERSION) && defined?(JRuby)
11
11
  # @see https://github.com/simplecov-ruby/simplecov/issues/86
12
12
  # @see https://jira.codehaus.org/browse/JRUBY-6106
13
13
 
14
- unless org.jruby.RubyInstanceConfig.FULL_TRACE_ENABLED
15
- warn 'Coverage may be inaccurate; set the "--debug" command line option,' \
16
- ' or do JRUBY_OPTS="--debug"' \
17
- ' or set the "debug.fullTrace=true" option in your .jrubyrc'
18
- end
14
+ warn 'Coverage may be inaccurate; set the "--debug" command line option,' \
15
+ ' or do JRUBY_OPTS="--debug"' \
16
+ ' or set the "debug.fullTrace=true" option in your .jrubyrc'
19
17
  end
20
18
 
21
19
  #
@@ -50,7 +48,9 @@ module SimpleCov
50
48
  def start(profile = nil, &block)
51
49
  require "coverage"
52
50
  initial_setup(profile, &block)
53
- require_relative "./simplecov/process" if SimpleCov.enabled_for_subprocesses?
51
+ require_relative "./simplecov/process" if SimpleCov.enabled_for_subprocesses? &&
52
+ ::Process.respond_to?(:fork)
53
+
54
54
  make_parallel_tests_available
55
55
 
56
56
  @result = nil
@@ -61,6 +61,7 @@ module SimpleCov
61
61
 
62
62
  #
63
63
  # Collate a series of SimpleCov result files into a single SimpleCov output.
64
+ #
64
65
  # You can optionally specify configuration with a block:
65
66
  # SimpleCov.collate Dir["simplecov-resultset-*/.resultset.json"]
66
67
  # OR
@@ -78,18 +79,17 @@ module SimpleCov
78
79
  # available config options, or checkout the README for more in-depth
79
80
  # information about coverage collation
80
81
  #
81
- def collate(result_filenames, profile = nil, &block)
82
- raise "There's no reports to be merged" if result_filenames.empty?
82
+ # By default `collate` ignores the merge_timeout so all results of all files specified will be
83
+ # merged together. If you want to honor the merge_timeout then provide the keyword argument
84
+ # `ignore_timeout: false`.
85
+ #
86
+ def collate(result_filenames, profile = nil, ignore_timeout: true, &block)
87
+ raise "There are no reports to be merged" if result_filenames.empty?
83
88
 
84
89
  initial_setup(profile, &block)
85
90
 
86
- results = result_filenames.flat_map do |filename|
87
- # Re-create each included instance of SimpleCov::Result from the stored run data.
88
- Result.from_hash(JSON.parse(File.read(filename)) || {})
89
- end
90
-
91
91
  # Use the ResultMerger to produce a single, merged result, ready to use.
92
- @result = ResultMerger.merge_and_store(*results)
92
+ @result = ResultMerger.merge_and_store(*result_filenames, ignore_timeout: ignore_timeout)
93
93
 
94
94
  run_exit_tasks!
95
95
  end
@@ -283,7 +283,10 @@ module SimpleCov
283
283
  # @api private
284
284
  #
285
285
  def write_last_run(result)
286
- SimpleCov::LastRun.write(result: {covered_percent: round_coverage(result.covered_percent)})
286
+ SimpleCov::LastRun.write(result:
287
+ result.coverage_statistics.transform_values do |stats|
288
+ round_coverage(stats.percent)
289
+ end)
287
290
  end
288
291
 
289
292
  #
@@ -10,7 +10,7 @@ module SimpleCov
10
10
  # defined here are usable from SimpleCov directly. Please check out
11
11
  # SimpleCov documentation for further info.
12
12
  #
13
- module Configuration # rubocop:disable Metrics/ModuleLength
13
+ module Configuration
14
14
  attr_writer :filters, :groups, :formatter, :print_error_status
15
15
 
16
16
  #
@@ -22,6 +22,7 @@ module SimpleCov
22
22
  def root(root = nil)
23
23
  return @root if defined?(@root) && root.nil?
24
24
 
25
+ @coverage_path = nil # invalidate cache
25
26
  @root = File.expand_path(root || Dir.getwd)
26
27
  end
27
28
 
@@ -190,7 +191,7 @@ module SimpleCov
190
191
  # end
191
192
  #
192
193
  def at_exit(&block)
193
- return proc {} unless running || block_given?
194
+ return Proc.new unless running || block_given?
194
195
 
195
196
  @at_exit = block if block_given?
196
197
  @at_exit ||= proc { SimpleCov.result.format! }
@@ -199,8 +200,9 @@ module SimpleCov
199
200
  # gets or sets the enabled_for_subprocess configuration
200
201
  # when true, this will inject SimpleCov code into Process.fork
201
202
  def enable_for_subprocesses(value = nil)
202
- @enable_for_subprocesses = value unless value.nil?
203
- @enable_for_subprocesses || false
203
+ return @enable_for_subprocesses if defined?(@enable_for_subprocesses) && value.nil?
204
+
205
+ @enable_for_subprocesses = value || false
204
206
  end
205
207
 
206
208
  # gets the enabled_for_subprocess configuration
@@ -285,20 +287,22 @@ module SimpleCov
285
287
  #
286
288
  # Default is 0% (disabled)
287
289
  #
288
-
289
- # rubocop:disable Metrics/CyclomaticComplexity
290
290
  def minimum_coverage(coverage = nil)
291
291
  return @minimum_coverage ||= {} unless coverage
292
292
 
293
- coverage = {DEFAULT_COVERAGE_CRITERION => coverage} if coverage.is_a?(Numeric)
293
+ coverage = {primary_coverage => coverage} if coverage.is_a?(Numeric)
294
+
295
+ raise_on_invalid_coverage(coverage, "minimum_coverage")
296
+
297
+ @minimum_coverage = coverage
298
+ end
299
+
300
+ def raise_on_invalid_coverage(coverage, coverage_setting)
294
301
  coverage.each_key { |criterion| raise_if_criterion_disabled(criterion) }
295
302
  coverage.each_value do |percent|
296
- minimum_possible_coverage_exceeded("minimum_coverage") if percent && percent > 100
303
+ minimum_possible_coverage_exceeded(coverage_setting) if percent && percent > 100
297
304
  end
298
-
299
- @minimum_coverage = coverage
300
305
  end
301
- # rubocop:enable Metrics/CyclomaticComplexity
302
306
 
303
307
  #
304
308
  # Defines the maximum coverage drop at once allowed for the testsuite to pass.
@@ -307,7 +311,13 @@ module SimpleCov
307
311
  # Default is 100% (disabled)
308
312
  #
309
313
  def maximum_coverage_drop(coverage_drop = nil)
310
- @maximum_coverage_drop ||= (coverage_drop || 100).to_f.round(2)
314
+ return @maximum_coverage_drop ||= {} unless coverage_drop
315
+
316
+ coverage_drop = {primary_coverage => coverage_drop} if coverage_drop.is_a?(Numeric)
317
+
318
+ raise_on_invalid_coverage(coverage_drop, "maximum_coverage_drop")
319
+
320
+ @maximum_coverage_drop = coverage_drop
311
321
  end
312
322
 
313
323
  #
@@ -318,16 +328,23 @@ module SimpleCov
318
328
  # Default is 0% (disabled)
319
329
  #
320
330
  def minimum_coverage_by_file(coverage = nil)
321
- minimum_possible_coverage_exceeded("minimum_coverage_by_file") if coverage && coverage > 100
322
- @minimum_coverage_by_file ||= (coverage || 0).to_f.round(2)
331
+ return @minimum_coverage_by_file ||= {} unless coverage
332
+
333
+ coverage = {primary_coverage => coverage} if coverage.is_a?(Numeric)
334
+
335
+ raise_on_invalid_coverage(coverage, "minimum_coverage_by_file")
336
+
337
+ @minimum_coverage_by_file = coverage
323
338
  end
324
339
 
325
340
  #
326
341
  # Refuses any coverage drop. That is, coverage is only allowed to increase.
327
342
  # SimpleCov will return non-zero if the coverage decreases.
328
343
  #
329
- def refuse_coverage_drop
330
- maximum_coverage_drop 0
344
+ def refuse_coverage_drop(*criteria)
345
+ criteria = coverage_criteria if criteria.empty?
346
+
347
+ maximum_coverage_drop(criteria.map { |c| [c, 0] }.to_h)
331
348
  end
332
349
 
333
350
  #
@@ -374,7 +391,7 @@ module SimpleCov
374
391
  # @param [Symbol] criterion
375
392
  #
376
393
  def coverage_criterion(criterion = nil)
377
- return @coverage_criterion ||= DEFAULT_COVERAGE_CRITERION unless criterion
394
+ return @coverage_criterion ||= primary_coverage unless criterion
378
395
 
379
396
  raise_if_criterion_unsupported(criterion)
380
397
 
@@ -387,8 +404,17 @@ module SimpleCov
387
404
  coverage_criteria << criterion
388
405
  end
389
406
 
407
+ def primary_coverage(criterion = nil)
408
+ if criterion.nil?
409
+ @primary_coverage ||= DEFAULT_COVERAGE_CRITERION
410
+ else
411
+ raise_if_criterion_disabled(criterion)
412
+ @primary_coverage = criterion
413
+ end
414
+ end
415
+
390
416
  def coverage_criteria
391
- @coverage_criteria ||= Set[DEFAULT_COVERAGE_CRITERION]
417
+ @coverage_criteria ||= Set[primary_coverage]
392
418
  end
393
419
 
394
420
  def coverage_criterion_enabled?(criterion)
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "simplecov-html"
4
+ module SimpleCov
5
+ module Formatter
6
+ class << self
7
+ def from_env(env)
8
+ formatters = [SimpleCov::Formatter::HTMLFormatter]
9
+
10
+ # When running under a CI that uses CodeClimate, JSON output is expected
11
+ if env.fetch("CC_TEST_REPORTER_ID", nil)
12
+ require "simplecov_json_formatter"
13
+ formatters.push(SimpleCov::Formatter::JSONFormatter)
14
+ end
15
+
16
+ formatters
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Load default formatter gem
4
- require "simplecov-html"
5
4
  require "pathname"
5
+ require_relative "default_formatter"
6
6
  require_relative "profiles/root_filter"
7
7
  require_relative "profiles/test_frameworks"
8
8
  require_relative "profiles/bundler_filter"
@@ -11,7 +11,10 @@ require_relative "profiles/rails"
11
11
 
12
12
  # Default configuration
13
13
  SimpleCov.configure do
14
- formatter SimpleCov::Formatter::HTMLFormatter
14
+ formatter SimpleCov::Formatter::MultiFormatter.new(
15
+ SimpleCov::Formatter.from_env(ENV)
16
+ )
17
+
15
18
  load_profile "bundler_filter"
16
19
  load_profile "hidden_filter"
17
20
  # Exclude files outside of SimpleCov.root
@@ -11,15 +11,18 @@ module SimpleCov
11
11
  def failing?
12
12
  return false unless maximum_coverage_drop && last_run
13
13
 
14
- coverage_diff > maximum_coverage_drop
14
+ coverage_drop_violations.any?
15
15
  end
16
16
 
17
17
  def report
18
- $stderr.printf(
19
- "Coverage has dropped by %<drop_percent>.2f%% since the last time (maximum allowed: %<max_drop>.2f%%).\n",
20
- drop_percent: coverage_diff,
21
- max_drop: maximum_coverage_drop
22
- )
18
+ coverage_drop_violations.each do |violation|
19
+ $stderr.printf(
20
+ "%<criterion>s coverage has dropped by %<drop_percent>.2f%% since the last time (maximum allowed: %<max_drop>.2f%%).\n",
21
+ criterion: violation[:criterion].capitalize,
22
+ drop_percent: SimpleCov.round_coverage(violation[:drop_percent]),
23
+ max_drop: violation[:max_drop]
24
+ )
25
+ end
23
26
  end
24
27
 
25
28
  def exit_code
@@ -36,14 +39,44 @@ module SimpleCov
36
39
  @last_run = SimpleCov::LastRun.read
37
40
  end
38
41
 
39
- def coverage_diff
40
- raise "Trying to access coverage_diff although there is no last run" unless last_run
42
+ def coverage_drop_violations
43
+ @coverage_drop_violations ||=
44
+ compute_coverage_drop_data.select do |achieved|
45
+ achieved.fetch(:max_drop) < achieved.fetch(:drop_percent)
46
+ end
47
+ end
48
+
49
+ def compute_coverage_drop_data
50
+ maximum_coverage_drop.map do |criterion, percent|
51
+ {
52
+ criterion: criterion,
53
+ max_drop: percent,
54
+ drop_percent: drop_percent(criterion)
55
+ }
56
+ end
57
+ end
41
58
 
42
- @coverage_diff ||= last_run[:result][:covered_percent] - covered_percent
59
+ # if anyone says "max_coverage_drop 0.000000000000000001" I appologize. Please don't.
60
+ MAX_DROP_ACCURACY = 10
61
+ def drop_percent(criterion)
62
+ drop = last_coverage(criterion) -
63
+ SimpleCov.round_coverage(
64
+ result.coverage_statistics.fetch(criterion).percent
65
+ )
66
+
67
+ # floats, I tell ya.
68
+ # irb(main):001:0* 80.01 - 80.0
69
+ # => 0.010000000000005116
70
+ drop.floor(MAX_DROP_ACCURACY)
43
71
  end
44
72
 
45
- def covered_percent
46
- SimpleCov.round_coverage(result.covered_percent)
73
+ def last_coverage(criterion)
74
+ last_coverage_percent = last_run[:result][criterion]
75
+
76
+ # fallback for old file format
77
+ last_coverage_percent = last_run[:result][:covered_percent] if !last_coverage_percent && criterion == :line
78
+
79
+ last_coverage_percent || 0
47
80
  end
48
81
  end
49
82
  end