minitest 5.11.3 → 5.25.4
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
- checksums.yaml.gz.sig +0 -0
- data/History.rdoc +375 -4
- data/Manifest.txt +6 -0
- data/README.rdoc +106 -17
- data/Rakefile +11 -16
- data/lib/hoe/minitest.rb +2 -5
- data/lib/minitest/assertions.rb +255 -93
- data/lib/minitest/autorun.rb +0 -7
- data/lib/minitest/benchmark.rb +13 -16
- data/lib/minitest/compress.rb +94 -0
- data/lib/minitest/error_on_warning.rb +11 -0
- data/lib/minitest/expectations.rb +72 -35
- data/lib/minitest/manual_plugins.rb +16 -0
- data/lib/minitest/mock.rb +151 -44
- data/lib/minitest/parallel.rb +5 -5
- data/lib/minitest/pride_plugin.rb +17 -24
- data/lib/minitest/spec.rb +38 -19
- data/lib/minitest/test.rb +50 -33
- data/lib/minitest/test_task.rb +307 -0
- data/lib/minitest/unit.rb +5 -8
- data/lib/minitest.rb +414 -166
- data/test/minitest/metametameta.rb +65 -17
- data/test/minitest/test_minitest_assertions.rb +1720 -0
- data/test/minitest/test_minitest_benchmark.rb +3 -3
- data/test/minitest/test_minitest_mock.rb +409 -65
- data/test/minitest/test_minitest_reporter.rb +169 -32
- data/test/minitest/test_minitest_spec.rb +369 -193
- data/test/minitest/test_minitest_test.rb +463 -1249
- data/test/minitest/test_minitest_test_task.rb +57 -0
- data.tar.gz.sig +0 -0
- metadata +40 -23
- metadata.gz.sig +0 -0
data/lib/minitest.rb
CHANGED
@@ -1,61 +1,84 @@
|
|
1
1
|
require "optparse"
|
2
|
-
require "thread"
|
3
|
-
require "mutex_m"
|
4
|
-
require "minitest/parallel"
|
5
2
|
require "stringio"
|
3
|
+
require "etc"
|
4
|
+
|
5
|
+
require_relative "minitest/parallel"
|
6
|
+
require_relative "minitest/compress"
|
6
7
|
|
7
8
|
##
|
8
|
-
#
|
9
|
+
# The top-level namespace for Minitest. Also the location of the main
|
10
|
+
# runtime. See +Minitest.run+ for more information.
|
9
11
|
|
10
12
|
module Minitest
|
11
|
-
VERSION = "5.
|
12
|
-
ENCS = "".respond_to? :encoding # :nodoc:
|
13
|
+
VERSION = "5.25.4" # :nodoc:
|
13
14
|
|
14
15
|
@@installed_at_exit ||= false
|
15
16
|
@@after_run = []
|
16
17
|
@extensions = []
|
17
18
|
|
18
|
-
|
19
|
+
def self.cattr_accessor name # :nodoc:
|
20
|
+
(class << self; self; end).attr_accessor name
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# The random seed used for this run. This is used to srand at the
|
25
|
+
# start of the run and between each +Runnable.run+.
|
26
|
+
#
|
27
|
+
# Set via Minitest.run after processing args.
|
28
|
+
|
29
|
+
cattr_accessor :seed
|
19
30
|
|
20
31
|
##
|
21
32
|
# Parallel test executor
|
22
33
|
|
23
|
-
|
24
|
-
|
34
|
+
cattr_accessor :parallel_executor
|
35
|
+
|
36
|
+
warn "DEPRECATED: use MT_CPU instead of N for parallel test runs" if ENV["N"] && ENV["N"].to_i > 0
|
37
|
+
n_threads = (ENV["MT_CPU"] || ENV["N"] || Etc.nprocessors).to_i
|
38
|
+
|
39
|
+
self.parallel_executor = Parallel::Executor.new n_threads
|
25
40
|
|
26
41
|
##
|
27
42
|
# Filter object for backtraces.
|
28
43
|
|
29
|
-
|
44
|
+
cattr_accessor :backtrace_filter
|
30
45
|
|
31
46
|
##
|
32
47
|
# Reporter object to be used for all runs.
|
33
48
|
#
|
34
49
|
# NOTE: This accessor is only available during setup, not during runs.
|
35
50
|
|
36
|
-
|
51
|
+
cattr_accessor :reporter
|
37
52
|
|
38
53
|
##
|
39
54
|
# Names of known extension plugins.
|
40
55
|
|
41
|
-
|
56
|
+
cattr_accessor :extensions
|
42
57
|
|
43
58
|
##
|
44
59
|
# The signal to use for dumping information to STDERR. Defaults to "INFO".
|
45
60
|
|
46
|
-
|
61
|
+
cattr_accessor :info_signal
|
47
62
|
self.info_signal = "INFO"
|
48
63
|
|
64
|
+
cattr_accessor :allow_fork
|
65
|
+
self.allow_fork = false
|
66
|
+
|
49
67
|
##
|
50
68
|
# Registers Minitest to run at process exit
|
51
69
|
|
52
70
|
def self.autorun
|
71
|
+
Warning[:deprecated] = true if
|
72
|
+
Object.const_defined?(:Warning) && Warning.respond_to?(:[]=)
|
73
|
+
|
53
74
|
at_exit {
|
54
75
|
next if $! and not ($!.kind_of? SystemExit and $!.success?)
|
55
76
|
|
56
77
|
exit_code = nil
|
57
78
|
|
79
|
+
pid = Process.pid
|
58
80
|
at_exit {
|
81
|
+
next if !Minitest.allow_fork && Process.pid != pid
|
59
82
|
@@after_run.reverse_each(&:call)
|
60
83
|
exit exit_code || false
|
61
84
|
}
|
@@ -75,20 +98,19 @@ module Minitest
|
|
75
98
|
@@after_run << block
|
76
99
|
end
|
77
100
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
101
|
+
##
|
102
|
+
# Register a plugin to be used. Does NOT require / load it.
|
103
|
+
|
104
|
+
def self.register_plugin name_or_mod
|
105
|
+
self.extensions << name_or_mod
|
106
|
+
nil
|
83
107
|
end
|
84
108
|
|
85
109
|
def self.load_plugins # :nodoc:
|
86
|
-
return unless
|
110
|
+
return unless defined? Gem
|
87
111
|
|
88
112
|
seen = {}
|
89
113
|
|
90
|
-
require "rubygems" unless defined? Gem
|
91
|
-
|
92
114
|
Gem.find_files("minitest/*_plugin.rb").each do |plugin_path|
|
93
115
|
name = File.basename plugin_path, "_plugin.rb"
|
94
116
|
|
@@ -100,69 +122,27 @@ module Minitest
|
|
100
122
|
end
|
101
123
|
end
|
102
124
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
# klass.new(runnable_method).run
|
119
|
-
|
120
|
-
def self.run args = []
|
121
|
-
self.load_plugins unless args.delete("--no-plugins") || ENV["MT_NO_PLUGINS"]
|
122
|
-
|
123
|
-
options = process_args args
|
124
|
-
|
125
|
-
reporter = CompositeReporter.new
|
126
|
-
reporter << SummaryReporter.new(options[:io], options)
|
127
|
-
reporter << ProgressReporter.new(options[:io], options)
|
128
|
-
|
129
|
-
self.reporter = reporter # this makes it available to plugins
|
130
|
-
self.init_plugins options
|
131
|
-
self.reporter = nil # runnables shouldn't depend on the reporter, ever
|
132
|
-
|
133
|
-
self.parallel_executor.start if parallel_executor.respond_to?(:start)
|
134
|
-
reporter.start
|
135
|
-
begin
|
136
|
-
__run reporter, options
|
137
|
-
rescue Interrupt
|
138
|
-
warn "Interrupted. Exiting..."
|
125
|
+
def self.init_plugins options # :nodoc:
|
126
|
+
self.extensions.each do |mod_or_meth|
|
127
|
+
case mod_or_meth
|
128
|
+
when Symbol, String then
|
129
|
+
name = mod_or_meth
|
130
|
+
msg = "plugin_#{name}_init"
|
131
|
+
next unless self.respond_to? msg
|
132
|
+
send msg, options
|
133
|
+
when Module then
|
134
|
+
recv = mod_or_meth
|
135
|
+
next unless recv.respond_to? :minitest_plugin_init
|
136
|
+
recv.minitest_plugin_init options
|
137
|
+
else
|
138
|
+
raise ArgumentError, "plugin is %p, but it must be a symbol, string or module" % [mod_or_meth]
|
139
|
+
end
|
139
140
|
end
|
140
|
-
self.parallel_executor.shutdown
|
141
|
-
reporter.report
|
142
|
-
|
143
|
-
reporter.passed?
|
144
|
-
end
|
145
|
-
|
146
|
-
##
|
147
|
-
# Internal run method. Responsible for telling all Runnable
|
148
|
-
# sub-classes to run.
|
149
|
-
|
150
|
-
def self.__run reporter, options
|
151
|
-
suites = Runnable.runnables.reject { |s| s.runnable_methods.empty? }.shuffle
|
152
|
-
parallel, serial = suites.partition { |s| s.test_order == :parallel }
|
153
|
-
|
154
|
-
# If we run the parallel tests before the serial tests, the parallel tests
|
155
|
-
# could run in parallel with the serial tests. This would be bad because
|
156
|
-
# the serial tests won't lock around Reporter#record. Run the serial tests
|
157
|
-
# first, so that after they complete, the parallel tests will lock when
|
158
|
-
# recording results.
|
159
|
-
serial.map { |suite| suite.run reporter, options } +
|
160
|
-
parallel.map { |suite| suite.run reporter, options }
|
161
141
|
end
|
162
142
|
|
163
143
|
def self.process_args args = [] # :nodoc:
|
164
144
|
options = {
|
165
|
-
|
145
|
+
:io => $stdout,
|
166
146
|
}
|
167
147
|
orig_args = args.dup
|
168
148
|
|
@@ -186,6 +166,14 @@ module Minitest
|
|
186
166
|
options[:verbose] = true
|
187
167
|
end
|
188
168
|
|
169
|
+
opts.on "-q", "--quiet", "Quiet. Show no progress processing files." do
|
170
|
+
options[:quiet] = true
|
171
|
+
end
|
172
|
+
|
173
|
+
opts.on "--show-skips", "Show skipped at the end of run." do
|
174
|
+
options[:show_skips] = true
|
175
|
+
end
|
176
|
+
|
189
177
|
opts.on "-n", "--name PATTERN", "Filter run on /regexp/ or string." do |a|
|
190
178
|
options[:filter] = a
|
191
179
|
end
|
@@ -194,13 +182,41 @@ module Minitest
|
|
194
182
|
options[:exclude] = a
|
195
183
|
end
|
196
184
|
|
185
|
+
opts.on "-S", "--skip CODES", String, "Skip reporting of certain types of results (eg E)." do |s|
|
186
|
+
options[:skip] = s.chars.to_a
|
187
|
+
end
|
188
|
+
|
189
|
+
ruby27plus = ::Warning.respond_to? :[]=
|
190
|
+
|
191
|
+
opts.on "-W[error]", String, "Turn Ruby warnings into errors" do |s|
|
192
|
+
options[:Werror] = true
|
193
|
+
case s
|
194
|
+
when "error", "all", nil then
|
195
|
+
require "minitest/error_on_warning"
|
196
|
+
$VERBOSE = true
|
197
|
+
::Warning[:deprecated] = true if ruby27plus
|
198
|
+
else
|
199
|
+
::Warning[s.to_sym] = true if ruby27plus # check validity of category
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
197
203
|
unless extensions.empty?
|
198
204
|
opts.separator ""
|
199
|
-
opts.separator "Known extensions: #{extensions.join
|
200
|
-
|
201
|
-
extensions.each do |
|
202
|
-
|
203
|
-
|
205
|
+
opts.separator "Known extensions: #{extensions.join ", "}"
|
206
|
+
|
207
|
+
extensions.each do |mod_or_meth|
|
208
|
+
case mod_or_meth
|
209
|
+
when Symbol, String then
|
210
|
+
meth = mod_or_meth
|
211
|
+
msg = "plugin_#{meth}_options"
|
212
|
+
send msg, opts, options if respond_to? msg
|
213
|
+
when Module
|
214
|
+
recv = mod_or_meth
|
215
|
+
next unless recv.respond_to? :minitest_plugin_options
|
216
|
+
recv.minitest_plugin_options opts, options
|
217
|
+
else
|
218
|
+
raise ArgumentError, "plugin is %p, but it must be a symbol, string or module" % [mod_or_meth]
|
219
|
+
end
|
204
220
|
end
|
205
221
|
end
|
206
222
|
|
@@ -223,17 +239,104 @@ module Minitest
|
|
223
239
|
orig_args << "--seed" << options[:seed].to_s
|
224
240
|
end
|
225
241
|
|
226
|
-
srand options[:seed]
|
227
|
-
|
228
242
|
options[:args] = orig_args.map { |s|
|
229
|
-
s
|
243
|
+
s.match?(/[\s|&<>$()]/) ? s.inspect : s
|
230
244
|
}.join " "
|
231
245
|
|
232
246
|
options
|
233
247
|
end
|
234
248
|
|
249
|
+
##
|
250
|
+
# This is the top-level run method. Everything starts from here. It
|
251
|
+
# tells each Runnable sub-class to run, and each of those are
|
252
|
+
# responsible for doing whatever they do.
|
253
|
+
#
|
254
|
+
# The overall structure of a run looks like this:
|
255
|
+
#
|
256
|
+
# Minitest.autorun
|
257
|
+
# Minitest.run(args)
|
258
|
+
# Minitest.load_plugins
|
259
|
+
# Minitest.process_args
|
260
|
+
# Minitest.init_plugins
|
261
|
+
# Minitest.__run(reporter, options)
|
262
|
+
# Runnable.runnables.each
|
263
|
+
# runnable_klass.run(reporter, options)
|
264
|
+
# self.runnable_methods.each
|
265
|
+
# self.run_one_method(self, runnable_method, reporter)
|
266
|
+
# Minitest.run_one_method(klass, runnable_method)
|
267
|
+
# klass.new(runnable_method).run
|
268
|
+
|
269
|
+
def self.run args = []
|
270
|
+
self.load_plugins unless args.delete("--no-plugins") || ENV["MT_NO_PLUGINS"]
|
271
|
+
|
272
|
+
options = process_args args
|
273
|
+
|
274
|
+
Minitest.seed = options[:seed]
|
275
|
+
srand Minitest.seed
|
276
|
+
|
277
|
+
reporter = CompositeReporter.new
|
278
|
+
reporter << SummaryReporter.new(options[:io], options)
|
279
|
+
reporter << ProgressReporter.new(options[:io], options) unless options[:quiet]
|
280
|
+
|
281
|
+
self.reporter = reporter # this makes it available to plugins
|
282
|
+
self.init_plugins options
|
283
|
+
self.reporter = nil # runnables shouldn't depend on the reporter, ever
|
284
|
+
|
285
|
+
self.parallel_executor.start if parallel_executor.respond_to? :start
|
286
|
+
reporter.start
|
287
|
+
begin
|
288
|
+
__run reporter, options
|
289
|
+
rescue Interrupt
|
290
|
+
warn "Interrupted. Exiting..."
|
291
|
+
end
|
292
|
+
self.parallel_executor.shutdown
|
293
|
+
|
294
|
+
# might have been removed/replaced during init_plugins:
|
295
|
+
summary = reporter.reporters.grep(SummaryReporter).first
|
296
|
+
|
297
|
+
reporter.report
|
298
|
+
|
299
|
+
return empty_run! options if summary && summary.count == 0
|
300
|
+
reporter.passed?
|
301
|
+
end
|
302
|
+
|
303
|
+
def self.empty_run! options # :nodoc:
|
304
|
+
filter = options[:filter]
|
305
|
+
return true unless filter # no filter, but nothing ran == success
|
306
|
+
|
307
|
+
warn "Nothing ran for filter: %s" % [filter]
|
308
|
+
|
309
|
+
require "did_you_mean" # soft dependency, punt if it doesn't load
|
310
|
+
|
311
|
+
ms = Runnable.runnables.flat_map(&:runnable_methods)
|
312
|
+
cs = DidYouMean::SpellChecker.new(dictionary: ms).correct filter
|
313
|
+
|
314
|
+
warn DidYouMean::Formatter.message_for cs unless cs.empty?
|
315
|
+
rescue LoadError
|
316
|
+
# do nothing
|
317
|
+
end
|
318
|
+
|
319
|
+
##
|
320
|
+
# Internal run method. Responsible for telling all Runnable
|
321
|
+
# sub-classes to run.
|
322
|
+
|
323
|
+
def self.__run reporter, options
|
324
|
+
suites = Runnable.runnables.shuffle
|
325
|
+
parallel, serial = suites.partition { |s| s.test_order == :parallel }
|
326
|
+
|
327
|
+
# If we run the parallel tests before the serial tests, the parallel tests
|
328
|
+
# could run in parallel with the serial tests. This would be bad because
|
329
|
+
# the serial tests won't lock around Reporter#record. Run the serial tests
|
330
|
+
# first, so that after they complete, the parallel tests will lock when
|
331
|
+
# recording results.
|
332
|
+
serial.map { |suite| suite.run reporter, options } +
|
333
|
+
parallel.map { |suite| suite.run reporter, options }
|
334
|
+
end
|
335
|
+
|
235
336
|
def self.filter_backtrace bt # :nodoc:
|
236
|
-
backtrace_filter.filter bt
|
337
|
+
result = backtrace_filter.filter bt
|
338
|
+
result = bt.dup if result.empty?
|
339
|
+
result
|
237
340
|
end
|
238
341
|
|
239
342
|
##
|
@@ -300,24 +403,34 @@ module Minitest
|
|
300
403
|
# reporter to record.
|
301
404
|
|
302
405
|
def self.run reporter, options = {}
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
filtered_methods = self.runnable_methods.find_all { |m|
|
307
|
-
filter === m || filter === "#{self}##{m}"
|
308
|
-
}
|
406
|
+
pos = options[:filter]
|
407
|
+
neg = options[:exclude]
|
309
408
|
|
310
|
-
|
311
|
-
|
409
|
+
pos = Regexp.new $1 if pos.kind_of?(String) && pos =~ %r%/(.*)/%
|
410
|
+
neg = Regexp.new $1 if neg.kind_of?(String) && neg =~ %r%/(.*)/%
|
312
411
|
|
313
|
-
filtered_methods
|
314
|
-
|
315
|
-
|
412
|
+
filtered_methods = self.runnable_methods
|
413
|
+
.select { |m| !pos || pos === m || pos === "#{self}##{m}" }
|
414
|
+
.reject { |m| neg && (neg === m || neg === "#{self}##{m}") }
|
316
415
|
|
317
416
|
return if filtered_methods.empty?
|
318
417
|
|
418
|
+
t0 = name = nil
|
419
|
+
|
420
|
+
@_info_handler = lambda do
|
421
|
+
unless reporter.passed? then
|
422
|
+
warn "Current results:"
|
423
|
+
warn reporter.reporters.grep(SummaryReporter).first
|
424
|
+
end
|
425
|
+
|
426
|
+
warn "Current: %s#%s %.2fs" % [self, name, Minitest.clock_time - t0]
|
427
|
+
end
|
428
|
+
|
319
429
|
with_info_handler reporter do
|
320
430
|
filtered_methods.each do |method_name|
|
431
|
+
name = method_name
|
432
|
+
t0 = Minitest.clock_time
|
433
|
+
|
321
434
|
run_one_method self, method_name, reporter
|
322
435
|
end
|
323
436
|
end
|
@@ -334,17 +447,16 @@ module Minitest
|
|
334
447
|
reporter.record Minitest.run_one_method(klass, method_name)
|
335
448
|
end
|
336
449
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
end
|
345
|
-
end
|
450
|
+
##
|
451
|
+
# Defines the order to run tests (:random by default). Override
|
452
|
+
# this or use a convenience method to change it for your tests.
|
453
|
+
|
454
|
+
def self.test_order
|
455
|
+
:random
|
456
|
+
end
|
346
457
|
|
347
|
-
|
458
|
+
def self.with_info_handler reporter, &block # :nodoc:
|
459
|
+
on_signal ::Minitest.info_signal, @_info_handler, &block
|
348
460
|
end
|
349
461
|
|
350
462
|
SIGNALS = Signal.list # :nodoc:
|
@@ -382,7 +494,7 @@ module Minitest
|
|
382
494
|
def marshal_dump # :nodoc:
|
383
495
|
unless @@marshal_dump_warned then
|
384
496
|
warn ["Minitest::Runnable#marshal_dump is deprecated.",
|
385
|
-
"You might be violating internals. From", caller.first].join " "
|
497
|
+
"You might be violating internals. From", caller(1..1).first].join " "
|
386
498
|
@@marshal_dump_warned = true
|
387
499
|
end
|
388
500
|
|
@@ -401,6 +513,31 @@ module Minitest
|
|
401
513
|
self.name = name
|
402
514
|
self.failures = []
|
403
515
|
self.assertions = 0
|
516
|
+
# lazy initializer for metadata
|
517
|
+
end
|
518
|
+
|
519
|
+
##
|
520
|
+
# Metadata you attach to the test results that get sent to the reporter.
|
521
|
+
#
|
522
|
+
# Lazily initializes to a hash, to keep memory down.
|
523
|
+
#
|
524
|
+
# NOTE: this data *must* be plain (read: marshal-able) data!
|
525
|
+
# Hashes! Arrays! Strings!
|
526
|
+
|
527
|
+
def metadata
|
528
|
+
@metadata ||= {}
|
529
|
+
end
|
530
|
+
|
531
|
+
##
|
532
|
+
# Sets metadata, mainly used for +Result.from+.
|
533
|
+
|
534
|
+
attr_writer :metadata
|
535
|
+
|
536
|
+
##
|
537
|
+
# Returns true if metadata exists.
|
538
|
+
|
539
|
+
def metadata?
|
540
|
+
defined? @metadata
|
404
541
|
end
|
405
542
|
|
406
543
|
##
|
@@ -422,7 +559,8 @@ module Minitest
|
|
422
559
|
|
423
560
|
##
|
424
561
|
# Returns a single character string to print based on the result
|
425
|
-
# of the run.
|
562
|
+
# of the run. One of <tt>"."</tt>, <tt>"F"</tt>,
|
563
|
+
# <tt>"E"</tt> or <tt>"S"</tt>.
|
426
564
|
|
427
565
|
def result_code
|
428
566
|
raise NotImplementedError, "subclass responsibility"
|
@@ -451,12 +589,14 @@ module Minitest
|
|
451
589
|
not self.failure
|
452
590
|
end
|
453
591
|
|
592
|
+
BASE_DIR = "#{Dir.pwd}/" # :nodoc:
|
593
|
+
|
454
594
|
##
|
455
595
|
# The location identifier of this test. Depends on a method
|
456
596
|
# existing called class_name.
|
457
597
|
|
458
598
|
def location
|
459
|
-
loc = " [#{self.failure.location}]" unless passed? or error?
|
599
|
+
loc = " [#{self.failure.location.delete_prefix BASE_DIR}]" unless passed? or error?
|
460
600
|
"#{self.class_name}##{self.name}#{loc}"
|
461
601
|
end
|
462
602
|
|
@@ -482,7 +622,7 @@ module Minitest
|
|
482
622
|
# Did this run error?
|
483
623
|
|
484
624
|
def error?
|
485
|
-
self.failures.any?
|
625
|
+
self.failures.any? UnexpectedError
|
486
626
|
end
|
487
627
|
end
|
488
628
|
|
@@ -520,6 +660,7 @@ module Minitest
|
|
520
660
|
r.assertions = o.assertions
|
521
661
|
r.failures = o.failures.dup
|
522
662
|
r.time = o.time
|
663
|
+
r.metadata = o.metadata if o.metadata?
|
523
664
|
|
524
665
|
r.source_location = o.method(o.name).source_location rescue ["unknown", -1]
|
525
666
|
|
@@ -544,7 +685,10 @@ module Minitest
|
|
544
685
|
# you want. Go nuts.
|
545
686
|
|
546
687
|
class AbstractReporter
|
547
|
-
|
688
|
+
|
689
|
+
def initialize # :nodoc:
|
690
|
+
@mutex = Mutex.new
|
691
|
+
end
|
548
692
|
|
549
693
|
##
|
550
694
|
# Starts reporting on the run.
|
@@ -560,8 +704,10 @@ module Minitest
|
|
560
704
|
end
|
561
705
|
|
562
706
|
##
|
563
|
-
#
|
564
|
-
# result
|
707
|
+
# Output and record the result of the test. Call
|
708
|
+
# {result#result_code}[rdoc-ref:Runnable#result_code] to get the
|
709
|
+
# result character string. Stores the result of the run if the run
|
710
|
+
# did not pass.
|
565
711
|
|
566
712
|
def record result
|
567
713
|
end
|
@@ -578,6 +724,10 @@ module Minitest
|
|
578
724
|
def passed?
|
579
725
|
true
|
580
726
|
end
|
727
|
+
|
728
|
+
def synchronize &block # :nodoc:
|
729
|
+
@mutex.synchronize(&block)
|
730
|
+
end
|
581
731
|
end
|
582
732
|
|
583
733
|
class Reporter < AbstractReporter # :nodoc:
|
@@ -607,11 +757,11 @@ module Minitest
|
|
607
757
|
# own.
|
608
758
|
|
609
759
|
class ProgressReporter < Reporter
|
610
|
-
def prerecord klass, name
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
760
|
+
def prerecord klass, name # :nodoc:
|
761
|
+
return unless options[:verbose]
|
762
|
+
|
763
|
+
io.print "%s#%s = " % [klass.name, name]
|
764
|
+
io.flush
|
615
765
|
end
|
616
766
|
|
617
767
|
def record result # :nodoc:
|
@@ -628,18 +778,68 @@ module Minitest
|
|
628
778
|
#
|
629
779
|
# If you want to create an entirely different type of output (eg,
|
630
780
|
# CI, HTML, etc), this is the place to start.
|
781
|
+
#
|
782
|
+
# Example:
|
783
|
+
#
|
784
|
+
# class JenkinsCIReporter < StatisticsReporter
|
785
|
+
# def report
|
786
|
+
# super # Needed to calculate some statistics
|
787
|
+
#
|
788
|
+
# print "<testsuite "
|
789
|
+
# print "tests='#{count}' "
|
790
|
+
# print "failures='#{failures}' "
|
791
|
+
# # Remaining XML...
|
792
|
+
# end
|
793
|
+
# end
|
631
794
|
|
632
795
|
class StatisticsReporter < Reporter
|
633
|
-
|
796
|
+
##
|
797
|
+
# Total number of assertions.
|
798
|
+
|
634
799
|
attr_accessor :assertions
|
800
|
+
|
801
|
+
##
|
802
|
+
# Total number of test cases.
|
803
|
+
|
635
804
|
attr_accessor :count
|
805
|
+
|
806
|
+
##
|
807
|
+
# An +Array+ of test cases that failed or were skipped.
|
808
|
+
|
636
809
|
attr_accessor :results
|
810
|
+
|
811
|
+
##
|
812
|
+
# Time the test run started. If available, the monotonic clock is
|
813
|
+
# used and this is a +Float+, otherwise it's an instance of
|
814
|
+
# +Time+.
|
815
|
+
|
637
816
|
attr_accessor :start_time
|
817
|
+
|
818
|
+
##
|
819
|
+
# Test run time. If available, the monotonic clock is used and
|
820
|
+
# this is a +Float+, otherwise it's an instance of +Time+.
|
821
|
+
|
638
822
|
attr_accessor :total_time
|
823
|
+
|
824
|
+
##
|
825
|
+
# Total number of tests that failed.
|
826
|
+
|
639
827
|
attr_accessor :failures
|
828
|
+
|
829
|
+
##
|
830
|
+
# Total number of tests that erred.
|
831
|
+
|
640
832
|
attr_accessor :errors
|
833
|
+
|
834
|
+
##
|
835
|
+
# Total number of tests that warned.
|
836
|
+
|
837
|
+
attr_accessor :warnings
|
838
|
+
|
839
|
+
##
|
840
|
+
# Total number of tests that where skipped.
|
841
|
+
|
641
842
|
attr_accessor :skips
|
642
|
-
# :startdoc:
|
643
843
|
|
644
844
|
def initialize io = $stdout, options = {} # :nodoc:
|
645
845
|
super
|
@@ -651,6 +851,7 @@ module Minitest
|
|
651
851
|
self.total_time = nil
|
652
852
|
self.failures = nil
|
653
853
|
self.errors = nil
|
854
|
+
self.warnings = nil
|
654
855
|
self.skips = nil
|
655
856
|
end
|
656
857
|
|
@@ -669,13 +870,17 @@ module Minitest
|
|
669
870
|
results << result if not result.passed? or result.skipped?
|
670
871
|
end
|
671
872
|
|
672
|
-
|
873
|
+
##
|
874
|
+
# Report on the tracked statistics.
|
875
|
+
|
876
|
+
def report
|
673
877
|
aggregate = results.group_by { |r| r.failure.class }
|
674
878
|
aggregate.default = [] # dumb. group_by should provide this
|
675
879
|
|
676
880
|
self.total_time = Minitest.clock_time - start_time
|
677
881
|
self.failures = aggregate[Assertion].size
|
678
882
|
self.errors = aggregate[UnexpectedError].size
|
883
|
+
self.warnings = aggregate[UnexpectedWarning].size
|
679
884
|
self.skips = aggregate[Skip].size
|
680
885
|
end
|
681
886
|
end
|
@@ -690,10 +895,8 @@ module Minitest
|
|
690
895
|
# own.
|
691
896
|
|
692
897
|
class SummaryReporter < StatisticsReporter
|
693
|
-
# :
|
694
|
-
attr_accessor :
|
695
|
-
attr_accessor :old_sync
|
696
|
-
# :startdoc:
|
898
|
+
attr_accessor :sync # :nodoc:
|
899
|
+
attr_accessor :old_sync # :nodoc:
|
697
900
|
|
698
901
|
def start # :nodoc:
|
699
902
|
super
|
@@ -703,7 +906,7 @@ module Minitest
|
|
703
906
|
io.puts "# Running:"
|
704
907
|
io.puts
|
705
908
|
|
706
|
-
self.sync = io.respond_to? :"sync="
|
909
|
+
self.sync = io.respond_to? :"sync="
|
707
910
|
self.old_sync, io.sync = io.sync, true if self.sync
|
708
911
|
end
|
709
912
|
|
@@ -726,9 +929,14 @@ module Minitest
|
|
726
929
|
|
727
930
|
def aggregated_results io # :nodoc:
|
728
931
|
filtered_results = results.dup
|
729
|
-
filtered_results.reject!(&:skipped?) unless
|
932
|
+
filtered_results.reject!(&:skipped?) unless
|
933
|
+
options[:verbose] or options[:show_skips]
|
934
|
+
|
935
|
+
skip = options[:skip] || []
|
730
936
|
|
731
937
|
filtered_results.each_with_index { |result, i|
|
938
|
+
next if skip.include? result.result_code
|
939
|
+
|
732
940
|
io.puts "\n%3d) %s" % [i+1, result]
|
733
941
|
}
|
734
942
|
io.puts
|
@@ -736,25 +944,22 @@ module Minitest
|
|
736
944
|
end
|
737
945
|
|
738
946
|
def to_s # :nodoc:
|
739
|
-
aggregated_results(StringIO.new(
|
947
|
+
aggregated_results(StringIO.new("".b)).string
|
740
948
|
end
|
741
949
|
|
742
950
|
def summary # :nodoc:
|
743
|
-
extra =
|
744
|
-
|
745
|
-
extra = "\n\nYou have skipped tests. Run with --verbose for details." if
|
746
|
-
results.any?(&:skipped?) unless options[:verbose] or ENV["MT_NO_SKIP_MSG"]
|
951
|
+
extra = []
|
747
952
|
|
748
|
-
|
749
|
-
[count, assertions, failures, errors, skips, extra]
|
750
|
-
end
|
953
|
+
extra << ", %d warnings" % [warnings] if options[:Werror]
|
751
954
|
|
752
|
-
|
955
|
+
extra << "\n\nYou have skipped tests. Run with --verbose for details." if
|
956
|
+
results.any?(&:skipped?) unless
|
957
|
+
options[:verbose] or
|
958
|
+
options[:show_skips] or
|
959
|
+
ENV["MT_NO_SKIP_MSG"]
|
753
960
|
|
754
|
-
|
755
|
-
|
756
|
-
else
|
757
|
-
def binary_string; ''.force_encoding(Encoding::ASCII_8BIT); end
|
961
|
+
"%d runs, %d assertions, %d failures, %d errors, %d skips%s" %
|
962
|
+
[count, assertions, failures, errors, skips, extra.join]
|
758
963
|
end
|
759
964
|
end
|
760
965
|
|
@@ -813,6 +1018,8 @@ module Minitest
|
|
813
1018
|
# Represents run failures.
|
814
1019
|
|
815
1020
|
class Assertion < Exception
|
1021
|
+
RE = /in [`'](?:[^']+[#.])?(?:assert|refute|flunk|pass|fail|raise|must|wont)/ # :nodoc:
|
1022
|
+
|
816
1023
|
def error # :nodoc:
|
817
1024
|
self
|
818
1025
|
end
|
@@ -821,12 +1028,11 @@ module Minitest
|
|
821
1028
|
# Where was this run before an assertion was raised?
|
822
1029
|
|
823
1030
|
def location
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
last_before_assertion.sub(/:in .*$/, "")
|
1031
|
+
bt = Minitest.filter_backtrace self.backtrace
|
1032
|
+
idx = bt.rindex { |s| s.match? RE } || -1 # fall back to first item
|
1033
|
+
loc = bt[idx+1] || bt.last || "unknown:-1"
|
1034
|
+
|
1035
|
+
loc.sub(/:in .*$/, "")
|
830
1036
|
end
|
831
1037
|
|
832
1038
|
def result_code # :nodoc:
|
@@ -851,24 +1057,34 @@ module Minitest
|
|
851
1057
|
# Assertion wrapping an unexpected error that was raised during a run.
|
852
1058
|
|
853
1059
|
class UnexpectedError < Assertion
|
854
|
-
|
1060
|
+
include Minitest::Compress
|
855
1061
|
|
856
|
-
|
1062
|
+
# TODO: figure out how to use `cause` instead
|
1063
|
+
attr_accessor :error # :nodoc:
|
1064
|
+
|
1065
|
+
def initialize error # :nodoc:
|
857
1066
|
super "Unexpected exception"
|
858
|
-
|
1067
|
+
|
1068
|
+
if SystemStackError === error then
|
1069
|
+
bt = error.backtrace
|
1070
|
+
new_bt = compress bt
|
1071
|
+
error = error.exception "#{bt.size} -> #{new_bt.size}"
|
1072
|
+
error.set_backtrace new_bt
|
1073
|
+
end
|
1074
|
+
|
1075
|
+
self.error = error
|
859
1076
|
end
|
860
1077
|
|
861
1078
|
def backtrace # :nodoc:
|
862
|
-
self.
|
1079
|
+
self.error.backtrace
|
863
1080
|
end
|
864
1081
|
|
865
|
-
|
866
|
-
self.exception
|
867
|
-
end
|
1082
|
+
BASE_RE = %r%#{Dir.pwd}/% # :nodoc:
|
868
1083
|
|
869
1084
|
def message # :nodoc:
|
870
|
-
bt = Minitest.filter_backtrace(self.backtrace).join
|
871
|
-
|
1085
|
+
bt = Minitest.filter_backtrace(self.backtrace).join("\n ")
|
1086
|
+
.gsub(BASE_RE, "")
|
1087
|
+
"#{self.error.class}: #{self.error.message}\n #{bt}"
|
872
1088
|
end
|
873
1089
|
|
874
1090
|
def result_label # :nodoc:
|
@@ -876,6 +1092,15 @@ module Minitest
|
|
876
1092
|
end
|
877
1093
|
end
|
878
1094
|
|
1095
|
+
##
|
1096
|
+
# Assertion raised on warning when running in -Werror mode.
|
1097
|
+
|
1098
|
+
class UnexpectedWarning < Assertion
|
1099
|
+
def result_label # :nodoc:
|
1100
|
+
"Warning"
|
1101
|
+
end
|
1102
|
+
end
|
1103
|
+
|
879
1104
|
##
|
880
1105
|
# Provides a simple set of guards that you can use in your tests
|
881
1106
|
# to skip execution if it is not applicable. These methods are
|
@@ -904,6 +1129,9 @@ module Minitest
|
|
904
1129
|
# Is this running on maglev?
|
905
1130
|
|
906
1131
|
def maglev? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
|
1132
|
+
where = Minitest.filter_backtrace(caller).first
|
1133
|
+
where = where.split(":in ", 2).first # clean up noise
|
1134
|
+
warn "DEPRECATED: `maglev?` called from #{where}. This will fail in Minitest 6."
|
907
1135
|
"maglev" == platform
|
908
1136
|
end
|
909
1137
|
|
@@ -911,13 +1139,23 @@ module Minitest
|
|
911
1139
|
# Is this running on mri?
|
912
1140
|
|
913
1141
|
def mri? platform = RUBY_DESCRIPTION
|
914
|
-
|
1142
|
+
platform.start_with? "ruby"
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
##
|
1146
|
+
# Is this running on macOS?
|
1147
|
+
|
1148
|
+
def osx? platform = RUBY_PLATFORM
|
1149
|
+
platform.include? "darwin"
|
915
1150
|
end
|
916
1151
|
|
917
1152
|
##
|
918
1153
|
# Is this running on rubinius?
|
919
1154
|
|
920
1155
|
def rubinius? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
|
1156
|
+
where = Minitest.filter_backtrace(caller).first
|
1157
|
+
where = where.split(":in ", 2).first # clean up noise
|
1158
|
+
warn "DEPRECATED: `rubinius?` called from #{where}. This will fail in Minitest 6."
|
921
1159
|
"rbx" == platform
|
922
1160
|
end
|
923
1161
|
|
@@ -925,7 +1163,7 @@ module Minitest
|
|
925
1163
|
# Is this running on windows?
|
926
1164
|
|
927
1165
|
def windows? platform = RUBY_PLATFORM
|
928
|
-
/mswin|mingw
|
1166
|
+
/mswin|mingw/.match? platform
|
929
1167
|
end
|
930
1168
|
end
|
931
1169
|
|
@@ -936,19 +1174,29 @@ module Minitest
|
|
936
1174
|
|
937
1175
|
class BacktraceFilter
|
938
1176
|
|
939
|
-
MT_RE = %r%lib/minitest%
|
1177
|
+
MT_RE = %r%lib/minitest|internal:warning% # :nodoc:
|
1178
|
+
|
1179
|
+
##
|
1180
|
+
# The regular expression to use to filter backtraces. Defaults to +MT_RE+.
|
1181
|
+
|
1182
|
+
attr_accessor :regexp
|
1183
|
+
|
1184
|
+
def initialize regexp = MT_RE # :nodoc:
|
1185
|
+
self.regexp = regexp
|
1186
|
+
end
|
940
1187
|
|
941
1188
|
##
|
942
|
-
# Filter +bt+ to something useful. Returns the whole thing if
|
1189
|
+
# Filter +bt+ to something useful. Returns the whole thing if
|
1190
|
+
# $DEBUG (ruby) or $MT_DEBUG (env).
|
943
1191
|
|
944
1192
|
def filter bt
|
945
1193
|
return ["No backtrace"] unless bt
|
946
1194
|
|
947
|
-
return bt.dup if $DEBUG
|
1195
|
+
return bt.dup if $DEBUG || ENV["MT_DEBUG"]
|
948
1196
|
|
949
|
-
new_bt = bt.take_while { |line| line
|
950
|
-
new_bt = bt.select { |line| line
|
951
|
-
new_bt = bt.dup
|
1197
|
+
new_bt = bt.take_while { |line| !regexp.match? line.to_s }
|
1198
|
+
new_bt = bt.select { |line| !regexp.match? line.to_s } if new_bt.empty?
|
1199
|
+
new_bt = bt.dup if new_bt.empty?
|
952
1200
|
|
953
1201
|
new_bt
|
954
1202
|
end
|