simplecov-patched 0.14.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.
Files changed (126) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +31 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +88 -0
  5. data/.travis.yml +29 -0
  6. data/.yardopts +1 -0
  7. data/CHANGELOG.md +435 -0
  8. data/CONTRIBUTING.md +48 -0
  9. data/Gemfile +38 -0
  10. data/MIT-LICENSE +20 -0
  11. data/README.md +646 -0
  12. data/Rakefile +41 -0
  13. data/cucumber.yml +13 -0
  14. data/doc/alternate-formatters.md +36 -0
  15. data/doc/commercial-services.md +20 -0
  16. data/doc/editor-integration.md +13 -0
  17. data/features/config_autoload.feature +46 -0
  18. data/features/config_command_name.feature +45 -0
  19. data/features/config_coverage_dir.feature +33 -0
  20. data/features/config_deactivate_merging.feature +42 -0
  21. data/features/config_formatters.feature +77 -0
  22. data/features/config_merge_timeout.feature +39 -0
  23. data/features/config_nocov_token.feature +79 -0
  24. data/features/config_profiles.feature +44 -0
  25. data/features/config_project_name.feature +27 -0
  26. data/features/config_styles.feature +121 -0
  27. data/features/config_tracked_files.feature +29 -0
  28. data/features/cucumber_basic.feature +29 -0
  29. data/features/maximum_coverage_drop.feature +89 -0
  30. data/features/merging_test_unit_and_rspec.feature +44 -0
  31. data/features/minimum_coverage.feature +59 -0
  32. data/features/refuse_coverage_drop.feature +95 -0
  33. data/features/rspec_basic.feature +32 -0
  34. data/features/rspec_fails_on_initialization.feature +14 -0
  35. data/features/rspec_groups_and_filters_basic.feature +29 -0
  36. data/features/rspec_groups_and_filters_complex.feature +37 -0
  37. data/features/rspec_groups_using_filter_class.feature +41 -0
  38. data/features/rspec_without_simplecov.feature +20 -0
  39. data/features/skipping_code_blocks_manually.feature +70 -0
  40. data/features/step_definitions/html_steps.rb +44 -0
  41. data/features/step_definitions/simplecov_steps.rb +68 -0
  42. data/features/step_definitions/transformers.rb +13 -0
  43. data/features/step_definitions/web_steps.rb +64 -0
  44. data/features/support/env.rb +50 -0
  45. data/features/test_unit_basic.feature +34 -0
  46. data/features/test_unit_groups_and_filters_basic.feature +29 -0
  47. data/features/test_unit_groups_and_filters_complex.feature +35 -0
  48. data/features/test_unit_groups_using_filter_class.feature +40 -0
  49. data/features/test_unit_without_simplecov.feature +20 -0
  50. data/features/unicode_compatiblity.feature +67 -0
  51. data/lib/simplecov.rb +189 -0
  52. data/lib/simplecov/command_guesser.rb +59 -0
  53. data/lib/simplecov/configuration.rb +307 -0
  54. data/lib/simplecov/defaults.rb +121 -0
  55. data/lib/simplecov/exit_codes.rb +8 -0
  56. data/lib/simplecov/file_list.rb +59 -0
  57. data/lib/simplecov/filter.rb +54 -0
  58. data/lib/simplecov/formatter.rb +8 -0
  59. data/lib/simplecov/formatter/multi_formatter.rb +32 -0
  60. data/lib/simplecov/formatter/simple_formatter.rb +23 -0
  61. data/lib/simplecov/jruby_fix.rb +42 -0
  62. data/lib/simplecov/last_run.rb +24 -0
  63. data/lib/simplecov/load_global_config.rb +6 -0
  64. data/lib/simplecov/no_defaults.rb +2 -0
  65. data/lib/simplecov/profiles.rb +31 -0
  66. data/lib/simplecov/railtie.rb +7 -0
  67. data/lib/simplecov/railties/tasks.rake +11 -0
  68. data/lib/simplecov/raw_coverage.rb +39 -0
  69. data/lib/simplecov/result.rb +86 -0
  70. data/lib/simplecov/result_merger.rb +95 -0
  71. data/lib/simplecov/source_file.rb +196 -0
  72. data/lib/simplecov/version.rb +25 -0
  73. data/spec/1_8_fallbacks_spec.rb +31 -0
  74. data/spec/command_guesser_spec.rb +48 -0
  75. data/spec/config_loader_spec.rb +14 -0
  76. data/spec/configuration_spec.rb +35 -0
  77. data/spec/deleted_source_spec.rb +12 -0
  78. data/spec/faked_project/Gemfile +6 -0
  79. data/spec/faked_project/Rakefile +8 -0
  80. data/spec/faked_project/cucumber.yml +13 -0
  81. data/spec/faked_project/features/step_definitions/my_steps.rb +22 -0
  82. data/spec/faked_project/features/support/env.rb +12 -0
  83. data/spec/faked_project/features/test_stuff.feature +6 -0
  84. data/spec/faked_project/lib/faked_project.rb +11 -0
  85. data/spec/faked_project/lib/faked_project/framework_specific.rb +18 -0
  86. data/spec/faked_project/lib/faked_project/meta_magic.rb +24 -0
  87. data/spec/faked_project/lib/faked_project/some_class.rb +28 -0
  88. data/spec/faked_project/lib/faked_project/untested_class.rb +11 -0
  89. data/spec/faked_project/spec/faked_spec.rb +11 -0
  90. data/spec/faked_project/spec/forking_spec.rb +8 -0
  91. data/spec/faked_project/spec/meta_magic_spec.rb +15 -0
  92. data/spec/faked_project/spec/some_class_spec.rb +13 -0
  93. data/spec/faked_project/spec/spec_helper.rb +11 -0
  94. data/spec/faked_project/test/faked_test.rb +11 -0
  95. data/spec/faked_project/test/meta_magic_test.rb +13 -0
  96. data/spec/faked_project/test/some_class_test.rb +15 -0
  97. data/spec/faked_project/test/test_helper.rb +12 -0
  98. data/spec/file_list_spec.rb +50 -0
  99. data/spec/filters_spec.rb +98 -0
  100. data/spec/fixtures/app/controllers/sample_controller.rb +10 -0
  101. data/spec/fixtures/app/models/user.rb +10 -0
  102. data/spec/fixtures/deleted_source_sample.rb +15 -0
  103. data/spec/fixtures/frameworks/rspec_bad.rb +9 -0
  104. data/spec/fixtures/frameworks/rspec_good.rb +9 -0
  105. data/spec/fixtures/frameworks/testunit_bad.rb +9 -0
  106. data/spec/fixtures/frameworks/testunit_good.rb +9 -0
  107. data/spec/fixtures/iso-8859.rb +3 -0
  108. data/spec/fixtures/never.rb +2 -0
  109. data/spec/fixtures/resultset1.rb +4 -0
  110. data/spec/fixtures/resultset2.rb +4 -0
  111. data/spec/fixtures/sample.rb +16 -0
  112. data/spec/fixtures/skipped.rb +4 -0
  113. data/spec/fixtures/skipped_and_executed.rb +8 -0
  114. data/spec/fixtures/utf-8.rb +3 -0
  115. data/spec/helper.rb +26 -0
  116. data/spec/last_run_spec.rb +48 -0
  117. data/spec/multi_formatter_spec.rb +20 -0
  118. data/spec/raw_coverage_spec.rb +92 -0
  119. data/spec/result_merger_spec.rb +96 -0
  120. data/spec/result_spec.rb +209 -0
  121. data/spec/return_codes_spec.rb +34 -0
  122. data/spec/simplecov_spec.rb +110 -0
  123. data/spec/source_file_line_spec.rb +155 -0
  124. data/spec/source_file_spec.rb +141 -0
  125. data/spec/support/fail_rspec_on_ruby_warning.rb +75 -0
  126. metadata +320 -0
@@ -0,0 +1,59 @@
1
+ #
2
+ # Helper that tries to find out what test suite is running (for SimpleCov.command_name)
3
+ #
4
+ module SimpleCov
5
+ module CommandGuesser
6
+ class << self
7
+ # Storage for the original command line call that invoked the test suite.
8
+ # This has got to be stored as early as possible because i.e. rake and test/unit 2
9
+ # have a habit of tampering with ARGV, which makes i.e. the automatic distinction
10
+ # between rails unit/functional/integration tests impossible without this cached
11
+ # item.
12
+ attr_accessor :original_run_command
13
+
14
+ def guess
15
+ from_env || from_command_line_options || from_defined_constants
16
+ end
17
+
18
+ private
19
+
20
+ def from_env
21
+ # If being run from inside parallel_tests set the command name according to the process number
22
+ return unless ENV["PARALLEL_TEST_GROUPS"] && ENV["TEST_ENV_NUMBER"]
23
+ number = ENV["TEST_ENV_NUMBER"]
24
+ number = "1" if number.empty?
25
+ "(#{number}/#{ENV['PARALLEL_TEST_GROUPS']})"
26
+ end
27
+
28
+ def from_command_line_options
29
+ case original_run_command
30
+ when /test\/functional\//, /test\/\{.*functional.*\}\//
31
+ "Functional Tests"
32
+ when /test\/integration\//
33
+ "Integration Tests"
34
+ when /test\//
35
+ "Unit Tests"
36
+ when /spec/
37
+ "RSpec"
38
+ when /cucumber/, /features/
39
+ "Cucumber Features"
40
+ end
41
+ end
42
+
43
+ def from_defined_constants
44
+ # If the command regexps fail, let's try checking defined constants.
45
+ if defined?(RSpec)
46
+ "RSpec"
47
+ elsif defined?(Test::Unit)
48
+ "Unit Tests"
49
+ elsif defined?(MiniTest)
50
+ "MiniTest"
51
+ else
52
+ # TODO: Provide link to docs/wiki article
53
+ warn "SimpleCov failed to recognize the test framework and/or suite used. Please specify manually using SimpleCov.command_name 'Unit Tests'."
54
+ "Unknown Test Framework"
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,307 @@
1
+ require "fileutils"
2
+ require "docile"
3
+ require "simplecov/formatter/multi_formatter"
4
+ #
5
+ # Bundles the configuration options used for SimpleCov. All methods
6
+ # defined here are usable from SimpleCov directly. Please check out
7
+ # SimpleCov documentation for further info.
8
+ #
9
+ module SimpleCov
10
+ module Configuration # rubocop:disable ModuleLength
11
+ attr_writer :filters, :groups, :formatter
12
+
13
+ #
14
+ # The root for the project. This defaults to the
15
+ # current working directory.
16
+ #
17
+ # Configure with SimpleCov.root('/my/project/path')
18
+ #
19
+ def root(root = nil)
20
+ return @root if defined?(@root) && root.nil?
21
+ @root = File.expand_path(root || Dir.getwd)
22
+ end
23
+
24
+ #
25
+ # The name of the output and cache directory. Defaults to 'coverage'
26
+ #
27
+ # Configure with SimpleCov.coverage_dir('cov')
28
+ #
29
+ def coverage_dir(dir = nil)
30
+ return @coverage_dir if defined?(@coverage_dir) && dir.nil?
31
+ @coverage_path = nil # invalidate cache
32
+ @coverage_dir = (dir || "coverage")
33
+ end
34
+
35
+ #
36
+ # Returns the full path to the output directory using SimpleCov.root
37
+ # and SimpleCov.coverage_dir, so you can adjust this by configuring those
38
+ # values. Will create the directory if it's missing
39
+ #
40
+ def coverage_path
41
+ @coverage_path ||= begin
42
+ coverage_path = File.expand_path(coverage_dir, root)
43
+ FileUtils.mkdir_p coverage_path
44
+ coverage_path
45
+ end
46
+ end
47
+
48
+ #
49
+ # Coverage results will always include files matched by this glob, whether
50
+ # or not they were explicitly required. Without this, un-required files
51
+ # will not be present in the final report.
52
+ #
53
+ def track_files(glob)
54
+ @tracked_files = glob
55
+ end
56
+
57
+ #
58
+ # Returns the glob that will be used to include files that were not
59
+ # explicitly required.
60
+ #
61
+ def tracked_files
62
+ @tracked_files if defined?(@tracked_files)
63
+ end
64
+
65
+ #
66
+ # Returns the list of configured filters. Add filters using SimpleCov.add_filter.
67
+ #
68
+ def filters
69
+ @filters ||= []
70
+ end
71
+
72
+ # The name of the command (a.k.a. Test Suite) currently running. Used for result
73
+ # merging and caching. It first tries to make a guess based upon the command line
74
+ # arguments the current test suite is running on and should automatically detect
75
+ # unit tests, functional tests, integration tests, rpsec and cucumber and label
76
+ # them properly. If it fails to recognize the current command, the command name
77
+ # is set to the shell command that the current suite is running on.
78
+ #
79
+ # You can specify it manually with SimpleCov.command_name("test:units") - please
80
+ # also check out the corresponding section in README.rdoc
81
+ def command_name(name = nil)
82
+ @name = name unless name.nil?
83
+ @name ||= SimpleCov::CommandGuesser.guess
84
+ @name
85
+ end
86
+
87
+ #
88
+ # Gets or sets the configured formatter.
89
+ #
90
+ # Configure with: SimpleCov.formatter(SimpleCov::Formatter::SimpleFormatter)
91
+ #
92
+ def formatter(formatter = nil)
93
+ return @formatter if defined?(@formatter) && formatter.nil?
94
+ @formatter = formatter
95
+ raise "No formatter configured. Please specify a formatter using SimpleCov.formatter = SimpleCov::Formatter::SimpleFormatter" unless @formatter
96
+ @formatter
97
+ end
98
+
99
+ #
100
+ # Sets the configured formatters.
101
+ #
102
+ def formatters=(formatters)
103
+ @formatter = SimpleCov::Formatter::MultiFormatter.new(formatters)
104
+ end
105
+
106
+ #
107
+ # Gets the configured formatters.
108
+ #
109
+ def formatters
110
+ if @formatter.is_a?(SimpleCov::Formatter::MultiFormatter)
111
+ @formatter.formatters
112
+ else
113
+ Array(formatter)
114
+ end
115
+ end
116
+
117
+ #
118
+ # Certain code blocks (i.e. Ruby-implementation specific code) can be excluded from
119
+ # the coverage metrics by wrapping it inside # :nocov: comment blocks. The nocov token
120
+ # can be configured to be any other string using this.
121
+ #
122
+ # Configure with SimpleCov.nocov_token('skip') or it's alias SimpleCov.skip_token('skip')
123
+ #
124
+ def nocov_token(nocov_token = nil)
125
+ return @nocov_token if defined?(@nocov_token) && nocov_token.nil?
126
+ @nocov_token = (nocov_token || "nocov")
127
+ end
128
+ alias skip_token nocov_token
129
+
130
+ #
131
+ # Returns the configured groups. Add groups using SimpleCov.add_group
132
+ #
133
+ def groups
134
+ @groups ||= {}
135
+ end
136
+
137
+ #
138
+ # Returns the hash of available profiles
139
+ #
140
+ def profiles
141
+ @profiles ||= SimpleCov::Profiles.new
142
+ end
143
+
144
+ def adapters
145
+ warn "#{Kernel.caller.first}: [DEPRECATION] #adapters is deprecated. Use #profiles instead."
146
+ profiles
147
+ end
148
+
149
+ #
150
+ # Allows you to configure simplecov in a block instead of prepending SimpleCov to all config methods
151
+ # you're calling.
152
+ #
153
+ # SimpleCov.configure do
154
+ # add_filter 'foobar'
155
+ # end
156
+ #
157
+ # This is equivalent to SimpleCov.add_filter 'foobar' and thus makes it easier to set a bunch of configure
158
+ # options at once.
159
+ #
160
+ def configure(&block)
161
+ return false unless SimpleCov.usable?
162
+ Docile.dsl_eval(self, &block)
163
+ end
164
+
165
+ #
166
+ # Gets or sets the behavior to process coverage results.
167
+ #
168
+ # By default, it will call SimpleCov.result.format!
169
+ #
170
+ # Configure with:
171
+ #
172
+ # SimpleCov.at_exit do
173
+ # puts "Coverage done"
174
+ # SimpleCov.result.format!
175
+ # end
176
+ #
177
+ def at_exit(&block)
178
+ return proc {} unless running || block_given?
179
+ @at_exit = block if block_given?
180
+ @at_exit ||= proc { SimpleCov.result.format! }
181
+ end
182
+
183
+ #
184
+ # Returns the project name - currently assuming the last dirname in
185
+ # the SimpleCov.root is this.
186
+ #
187
+ def project_name(new_name = nil)
188
+ return @project_name if defined?(@project_name) && @project_name && new_name.nil?
189
+ @project_name = new_name if new_name.is_a?(String)
190
+ @project_name ||= File.basename(root.split("/").last).capitalize.tr("_", " ")
191
+ end
192
+
193
+ #
194
+ # Defines whether to use result merging so all your test suites (test:units, test:functionals, cucumber, ...)
195
+ # are joined and combined into a single coverage report
196
+ #
197
+ def use_merging(use = nil)
198
+ @use_merging = use unless use.nil?
199
+ @use_merging = true unless defined?(@use_merging) && @use_merging == false
200
+ end
201
+
202
+ #
203
+ # Defines the maximum age (in seconds) of a resultset to still be included in merged results.
204
+ # i.e. If you run cucumber features, then later rake test, if the stored cucumber resultset is
205
+ # more seconds ago than specified here, it won't be taken into account when merging (and is also
206
+ # purged from the resultset cache)
207
+ #
208
+ # Of course, this only applies when merging is active (e.g. SimpleCov.use_merging is not false!)
209
+ #
210
+ # Default is 600 seconds (10 minutes)
211
+ #
212
+ # Configure with SimpleCov.merge_timeout(3600) # 1hr
213
+ #
214
+ def merge_timeout(seconds = nil)
215
+ @merge_timeout = seconds if seconds.is_a?(Integer)
216
+ @merge_timeout ||= 600
217
+ end
218
+
219
+ #
220
+ # Defines the minimum overall coverage required for the testsuite to pass.
221
+ # SimpleCov will return non-zero if the current coverage is below this threshold.
222
+ #
223
+ # Default is 0% (disabled)
224
+ #
225
+ def minimum_coverage(coverage = nil)
226
+ @minimum_coverage ||= (coverage || 0).to_f.round(2)
227
+ end
228
+
229
+ #
230
+ # Defines the maximum coverage drop at once allowed for the testsuite to pass.
231
+ # SimpleCov will return non-zero if the coverage decreases by more than this threshold.
232
+ #
233
+ # Default is 100% (disabled)
234
+ #
235
+ def maximum_coverage_drop(coverage_drop = nil)
236
+ @maximum_coverage_drop ||= (coverage_drop || 100).to_f.round(2)
237
+ end
238
+
239
+ #
240
+ # Defines the minimum coverage per file required for the testsuite to pass.
241
+ # SimpleCov will return non-zero if the current coverage of the least covered file
242
+ # is below this threshold.
243
+ #
244
+ # Default is 0% (disabled)
245
+ #
246
+ def minimum_coverage_by_file(coverage = nil)
247
+ @minimum_coverage_by_file ||= (coverage || 0).to_f.round(2)
248
+ end
249
+
250
+ #
251
+ # Refuses any coverage drop. That is, coverage is only allowed to increase.
252
+ # SimpleCov will return non-zero if the coverage decreases.
253
+ #
254
+ def refuse_coverage_drop
255
+ maximum_coverage_drop 0
256
+ end
257
+
258
+ #
259
+ # Add a filter to the processing chain.
260
+ # There are four ways to define a filter:
261
+ #
262
+ # * as a String that will then be matched against all source files' file paths,
263
+ # SimpleCov.add_filter 'app/models' # will reject all your models
264
+ # * as a block which will be passed the source file in question and should either
265
+ # return a true or false value, depending on whether the file should be removed
266
+ # SimpleCov.add_filter do |src_file|
267
+ # File.basename(src_file.filename) == 'environment.rb'
268
+ # end # Will exclude environment.rb files from the results
269
+ # * as an array of strings that are matched against all sorce files' file
270
+ # paths and then ignored (basically string filter multiple times)
271
+ # SimpleCov.add_filter ['app/models', 'app/helpers'] # ignores both dirs
272
+ # * as an instance of a subclass of SimpleCov::Filter. See the documentation there
273
+ # on how to define your own filter classes
274
+ #
275
+ def add_filter(filter_argument = nil, &filter_proc)
276
+ filters << parse_filter(filter_argument, &filter_proc)
277
+ end
278
+
279
+ #
280
+ # Define a group for files. Works similar to add_filter, only that the first
281
+ # argument is the desired group name and files PASSING the filter end up in the group
282
+ # (while filters exclude when the filter is applicable).
283
+ #
284
+ def add_group(group_name, filter_argument = nil, &filter_proc)
285
+ groups[group_name] = parse_filter(filter_argument, &filter_proc)
286
+ end
287
+
288
+ private
289
+
290
+ #
291
+ # The actual filter processor. Not meant for direct use
292
+ #
293
+ def parse_filter(filter_argument = nil, &filter_proc)
294
+ if filter_argument.is_a?(SimpleCov::Filter)
295
+ filter_argument
296
+ elsif filter_argument.is_a?(String)
297
+ SimpleCov::StringFilter.new(filter_argument)
298
+ elsif filter_proc
299
+ SimpleCov::BlockFilter.new(filter_proc)
300
+ elsif filter_argument.is_a?(Array)
301
+ SimpleCov::ArrayFilter.new(filter_argument)
302
+ else
303
+ raise ArgumentError, "Please specify either a string or a block to filter with"
304
+ end
305
+ end
306
+ end
307
+ end
@@ -0,0 +1,121 @@
1
+ # Load default formatter gem
2
+ require "simplecov-html"
3
+ require "pathname"
4
+
5
+ SimpleCov.profiles.define "root_filter" do
6
+ # Exclude all files outside of simplecov root
7
+ root_filter = nil
8
+ add_filter do |src|
9
+ root_filter ||= /\A#{Regexp.escape(SimpleCov.root)}/io
10
+ src.filename !~ root_filter
11
+ end
12
+ end
13
+
14
+ SimpleCov.profiles.define "test_frameworks" do
15
+ add_filter "/test/"
16
+ add_filter "/features/"
17
+ add_filter "/spec/"
18
+ add_filter "/autotest/"
19
+ end
20
+
21
+ SimpleCov.profiles.define "bundler_filter" do
22
+ add_filter "/vendor/bundle/"
23
+ end
24
+
25
+ SimpleCov.profiles.define "rails" do
26
+ load_profile "test_frameworks"
27
+
28
+ add_filter "/config/"
29
+ add_filter "/db/"
30
+
31
+ add_group "Controllers", "app/controllers"
32
+ add_group "Channels", "app/channels" if defined?(ActionCable)
33
+ add_group "Models", "app/models"
34
+ add_group "Mailers", "app/mailers"
35
+ add_group "Helpers", "app/helpers"
36
+ add_group "Jobs", %w[app/jobs app/workers]
37
+ add_group "Libraries", "lib"
38
+
39
+ track_files "{app,lib}/**/*.rb"
40
+ end
41
+
42
+ # Default configuration
43
+ SimpleCov.configure do
44
+ formatter SimpleCov::Formatter::HTMLFormatter
45
+ load_profile "bundler_filter"
46
+ # Exclude files outside of SimpleCov.root
47
+ load_profile "root_filter"
48
+ end
49
+
50
+ # Gotta stash this a-s-a-p, see the CommandGuesser class and i.e. #110 for further info
51
+ SimpleCov::CommandGuesser.original_run_command = "#{$PROGRAM_NAME} #{ARGV.join(' ')}"
52
+
53
+ at_exit do # rubocop:disable Metrics/BlockLength
54
+ # If we are in a different process than called start, don't interfere.
55
+ next if SimpleCov.pid != Process.pid
56
+
57
+ @exit_status = if $! # was an exception thrown?
58
+ # if it was a SystemExit, use the accompanying status
59
+ # otherwise set a non-zero status representing termination by
60
+ # some other exception (see github issue 41)
61
+ $!.is_a?(SystemExit) ? $!.status : SimpleCov::ExitCodes::EXCEPTION
62
+ else
63
+ # Store the exit status of the test run since it goes away
64
+ # after calling the at_exit proc...
65
+ SimpleCov::ExitCodes::SUCCESS
66
+ end
67
+
68
+ SimpleCov.at_exit.call
69
+
70
+ if SimpleCov.result? # Result has been computed
71
+ covered_percent = SimpleCov.result.covered_percent.round(2)
72
+ covered_percentages = SimpleCov.result.covered_percentages.map { |p| p.round(2) }
73
+
74
+ if @exit_status == SimpleCov::ExitCodes::SUCCESS # No other errors
75
+ if covered_percent < SimpleCov.minimum_coverage # rubocop:disable Metrics/BlockNesting
76
+ $stderr.printf("Coverage (%.2f%%) is below the expected minimum coverage (%.2f%%).\n", covered_percent, SimpleCov.minimum_coverage)
77
+ @exit_status = SimpleCov::ExitCodes::MINIMUM_COVERAGE
78
+ elsif covered_percentages.any? { |p| p < SimpleCov.minimum_coverage_by_file } # rubocop:disable Metrics/BlockNesting
79
+ $stderr.printf("File (%s) is only (%.2f%%) covered. This is below the expected minimum coverage per file of (%.2f%%).\n", SimpleCov.result.least_covered_file, covered_percentages.min, SimpleCov.minimum_coverage_by_file)
80
+ @exit_status = SimpleCov::ExitCodes::MINIMUM_COVERAGE
81
+ elsif (last_run = SimpleCov::LastRun.read) # rubocop:disable Metrics/BlockNesting
82
+ coverage_diff = last_run["result"]["covered_percent"] - covered_percent
83
+ if coverage_diff > SimpleCov.maximum_coverage_drop # rubocop:disable Metrics/BlockNesting
84
+ $stderr.printf("Coverage has dropped by %.2f%% since the last time (maximum allowed: %.2f%%).\n", coverage_diff, SimpleCov.maximum_coverage_drop)
85
+ @exit_status = SimpleCov::ExitCodes::MAXIMUM_COVERAGE_DROP
86
+ end
87
+ end
88
+ end
89
+
90
+ # Don't overwrite last_run file if refuse_coverage_drop option is enabled and the coverage has dropped
91
+ unless @exit_status == SimpleCov::ExitCodes::MAXIMUM_COVERAGE_DROP
92
+ SimpleCov::LastRun.write(:result => {:covered_percent => covered_percent})
93
+ end
94
+ end
95
+
96
+ # Force exit with stored status (see github issue #5)
97
+ # unless it's nil or 0 (see github issue #281)
98
+ Kernel.exit @exit_status if @exit_status && @exit_status > 0
99
+ end
100
+
101
+ # Autoload config from ~/.simplecov if present
102
+ require "simplecov/load_global_config"
103
+
104
+ # Autoload config from .simplecov if present
105
+ # Recurse upwards until we find .simplecov or reach the root directory
106
+
107
+ config_path = Pathname.new(SimpleCov.root)
108
+ loop do
109
+ filename = config_path.join(".simplecov")
110
+ if filename.exist?
111
+ begin
112
+ load filename
113
+ rescue LoadError, StandardError
114
+ $stderr.puts "Warning: Error occurred while trying to load #{filename}. " \
115
+ "Error message: #{$!.message}"
116
+ end
117
+ break
118
+ end
119
+ config_path, = config_path.split
120
+ break if config_path.root?
121
+ end