-
Notifications
You must be signed in to change notification settings - Fork 553
/
simplecov.rb
281 lines (247 loc) · 8.61 KB
/
simplecov.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# frozen_string_literal: true
require "English"
#
# Code coverage for ruby 1.9. Please check out README for a full introduction.
#
# Coverage may be inaccurate under JRUBY.
if defined?(JRUBY_VERSION) && defined?(JRuby)
# @see https://github.com/jruby/jruby/issues/1196
# @see https://github.com/metricfu/metric_fu/pull/226
# @see https://github.com/colszowka/simplecov/issues/420
# @see https://github.com/colszowka/simplecov/issues/86
# @see https://jira.codehaus.org/browse/JRUBY-6106
unless org.jruby.RubyInstanceConfig.FULL_TRACE_ENABLED
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
end
module SimpleCov
class << self
attr_accessor :running
attr_accessor :pid
attr_reader :exit_exception
#
# Sets up SimpleCov to run against your project.
# You can optionally specify a profile to use as well as configuration with a block:
# SimpleCov.start
# OR
# SimpleCov.start 'rails' # using rails profile
# OR
# SimpleCov.start do
# add_filter 'test'
# end
# OR
# SimpleCov.start 'rails' do
# add_filter 'test'
# end
#
# Please check out the RDoc for SimpleCov::Configuration to find about available config options
#
def start(profile = nil, &block)
if SimpleCov.usable?
load_profile(profile) if profile
configure(&block) if block_given?
@result = nil
self.running = true
self.pid = Process.pid
Coverage.start
else
warn "WARNING: SimpleCov is activated, but you're not running Ruby 1.9+ - no coverage analysis will happen"
warn "Starting with SimpleCov 1.0.0, even no-op compatibility with Ruby <= 1.8 will be entirely dropped."
false
end
end
#
# Finds files that were to be tracked but were not loaded and initializes
# the line-by-line coverage to zero (if relevant) or nil (comments / whitespace etc).
#
def add_not_loaded_files(result)
if tracked_files
result = result.dup
Dir[tracked_files].each do |file|
absolute = File.expand_path(file)
result[absolute] ||= LinesClassifier.new.classify(File.foreach(absolute))
end
end
result
end
#
# Returns the result for the current coverage run, merging it across test suites
# from cache using SimpleCov::ResultMerger if use_merging is activated (default)
#
def result
return @result if result?
# Collect our coverage result
if running
@result = SimpleCov::Result.new add_not_loaded_files(Coverage.result)
end
# If we're using merging of results, store the current result
# first (if there is one), then merge the results and return those
if use_merging
SimpleCov::ResultMerger.store_result(@result) if result?
@result = SimpleCov::ResultMerger.merged_result
end
@result
ensure
self.running = false
end
#
# Returns nil if the result has not been computed
# Otherwise, returns the result
#
def result?
defined?(@result) && @result
end
#
# Applies the configured filters to the given array of SimpleCov::SourceFile items
#
def filtered(files)
result = files.clone
filters.each do |filter|
result = result.reject { |source_file| filter.matches?(source_file) }
end
SimpleCov::FileList.new result
end
#
# Applies the configured groups to the given array of SimpleCov::SourceFile items
#
def grouped(files)
grouped = {}
grouped_files = []
groups.each do |name, filter|
grouped[name] = SimpleCov::FileList.new(files.select { |source_file| filter.matches?(source_file) })
grouped_files += grouped[name]
end
if !groups.empty? && !(other_files = files.reject { |source_file| grouped_files.include?(source_file) }).empty?
grouped["Ungrouped"] = SimpleCov::FileList.new(other_files)
end
grouped
end
#
# Applies the profile of given name on SimpleCov configuration
#
def load_profile(name)
profiles.load(name)
end
def load_adapter(name)
warn "#{Kernel.caller.first}: [DEPRECATION] #load_adapter is deprecated. Use #load_profile instead."
load_profile(name)
end
#
# Checks whether we're on a proper version of Ruby (likely 1.9+) which
# provides coverage support
#
def usable?
return @usable if defined?(@usable) && !@usable.nil?
@usable = begin
require "coverage"
require "simplecov/jruby_fix"
true
rescue LoadError
false
end
end
#
# Clear out the previously cached .result. Primarily useful in testing
#
def clear_result
@result = nil
end
#
# Capture the current exception if it exists
# This will get called inside the at_exit block
#
def set_exit_exception
@exit_exception = $ERROR_INFO
end
#
# Returns the exit status from the exit exception
#
def exit_status_from_exception
return SimpleCov::ExitCodes::SUCCESS unless exit_exception
if exit_exception.is_a?(SystemExit)
exit_exception.status
else
SimpleCov::ExitCodes::EXCEPTION
end
end
# @api private
#
# Called from at_exit block
#
def run_exit_tasks!
exit_status = SimpleCov.exit_status_from_exception
SimpleCov.at_exit.call
exit_status = SimpleCov.process_result(SimpleCov.result, exit_status)
# Force exit with stored status (see github issue #5)
# unless it's nil or 0 (see github issue #281)
Kernel.exit exit_status if exit_status && exit_status > 0
end
# @api private
#
# Usage:
# exit_status = SimpleCov.process_result(SimpleCov.result, exit_status)
#
def process_result(result, exit_status)
return exit_status unless SimpleCov.result? # Result has been computed
return exit_status if exit_status != SimpleCov::ExitCodes::SUCCESS # Existing errors
covered_percent = result.covered_percent.round(2)
result_exit_status = result_exit_status(result, covered_percent)
if result_exit_status == SimpleCov::ExitCodes::SUCCESS # No result errors
write_last_run(covered_percent)
end
result_exit_status
end
# @api private
#
# rubocop:disable Metrics/MethodLength
def result_exit_status(result, covered_percent)
covered_percentages = result.covered_percentages.map { |percentage| percentage.round(2) }
if covered_percent < SimpleCov.minimum_coverage
$stderr.printf("Coverage (%.2f%%) is below the expected minimum coverage (%.2f%%).\n", covered_percent, SimpleCov.minimum_coverage)
SimpleCov::ExitCodes::MINIMUM_COVERAGE
elsif covered_percentages.any? { |p| p < SimpleCov.minimum_coverage_by_file }
$stderr.printf("File (%s) is only (%.2f%%) covered. This is below the expected minimum coverage per file of (%.2f%%).\n", result.least_covered_file, covered_percentages.min, SimpleCov.minimum_coverage_by_file)
SimpleCov::ExitCodes::MINIMUM_COVERAGE
elsif (last_run = SimpleCov::LastRun.read)
coverage_diff = last_run["result"]["covered_percent"] - covered_percent
if coverage_diff > SimpleCov.maximum_coverage_drop
$stderr.printf("Coverage has dropped by %.2f%% since the last time (maximum allowed: %.2f%%).\n", coverage_diff, SimpleCov.maximum_coverage_drop)
SimpleCov::ExitCodes::MAXIMUM_COVERAGE_DROP
else
SimpleCov::ExitCodes::SUCCESS
end
else
SimpleCov::ExitCodes::SUCCESS
end
end
# rubocop:enable Metrics/MethodLength
#
# @api private
#
def write_last_run(covered_percent)
SimpleCov::LastRun.write(:result => {:covered_percent => covered_percent})
end
end
end
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__)))
require "simplecov/configuration"
SimpleCov.send :extend, SimpleCov::Configuration
require "simplecov/exit_codes"
require "simplecov/profiles"
require "simplecov/source_file"
require "simplecov/file_list"
require "simplecov/result"
require "simplecov/filter"
require "simplecov/formatter"
require "simplecov/last_run"
require "simplecov/lines_classifier"
require "simplecov/raw_coverage"
require "simplecov/result_merger"
require "simplecov/command_guesser"
require "simplecov/version"
# Load default config
require "simplecov/defaults" unless ENV["SIMPLECOV_NO_DEFAULTS"]
# Load Rails integration (only for Rails 3, see #113)
require "simplecov/railtie" if defined? Rails::Railtie