minitest 5.14.4 → 5.25.5
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 +283 -2
- data/Manifest.txt +5 -0
- data/README.rdoc +78 -36
- data/Rakefile +8 -1
- data/lib/hoe/minitest.rb +2 -5
- data/lib/minitest/assertions.rb +131 -83
- data/lib/minitest/autorun.rb +0 -7
- data/lib/minitest/benchmark.rb +11 -14
- data/lib/minitest/compress.rb +94 -0
- data/lib/minitest/error_on_warning.rb +11 -0
- data/lib/minitest/expectations.rb +18 -0
- data/lib/minitest/manual_plugins.rb +16 -0
- data/lib/minitest/mock.rb +148 -45
- data/lib/minitest/parallel.rb +5 -5
- data/lib/minitest/pride_plugin.rb +17 -24
- data/lib/minitest/spec.rb +20 -12
- data/lib/minitest/test.rb +51 -34
- data/lib/minitest/test_task.rb +307 -0
- data/lib/minitest/unit.rb +5 -8
- data/lib/minitest.rb +333 -154
- data/test/minitest/metametameta.rb +33 -19
- data/test/minitest/test_minitest_assertions.rb +292 -147
- data/test/minitest/test_minitest_benchmark.rb +3 -3
- data/test/minitest/test_minitest_mock.rb +396 -62
- data/test/minitest/test_minitest_reporter.rb +169 -32
- data/test/minitest/test_minitest_spec.rb +174 -72
- data/test/minitest/test_minitest_test.rb +420 -130
- data/test/minitest/test_minitest_test_task.rb +57 -0
- data.tar.gz.sig +0 -0
- metadata +23 -20
- metadata.gz.sig +0 -0
data/lib/minitest.rb
CHANGED
@@ -1,58 +1,76 @@
|
|
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.5" # :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
|
-
|
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
|
24
38
|
|
25
|
-
warn "DEPRECATED: use MT_CPU instead of N for parallel test runs" if ENV["N"]
|
26
|
-
n_threads = (ENV["MT_CPU"] || ENV["N"] || 2).to_i
|
27
39
|
self.parallel_executor = Parallel::Executor.new n_threads
|
28
40
|
|
29
41
|
##
|
30
42
|
# Filter object for backtraces.
|
31
43
|
|
32
|
-
|
44
|
+
cattr_accessor :backtrace_filter
|
33
45
|
|
34
46
|
##
|
35
47
|
# Reporter object to be used for all runs.
|
36
48
|
#
|
37
49
|
# NOTE: This accessor is only available during setup, not during runs.
|
38
50
|
|
39
|
-
|
51
|
+
cattr_accessor :reporter
|
40
52
|
|
41
53
|
##
|
42
54
|
# Names of known extension plugins.
|
43
55
|
|
44
|
-
|
56
|
+
cattr_accessor :extensions
|
45
57
|
|
46
58
|
##
|
47
59
|
# The signal to use for dumping information to STDERR. Defaults to "INFO".
|
48
60
|
|
49
|
-
|
61
|
+
cattr_accessor :info_signal
|
50
62
|
self.info_signal = "INFO"
|
51
63
|
|
64
|
+
cattr_accessor :allow_fork
|
65
|
+
self.allow_fork = false
|
66
|
+
|
52
67
|
##
|
53
68
|
# Registers Minitest to run at process exit
|
54
69
|
|
55
70
|
def self.autorun
|
71
|
+
Warning[:deprecated] = true if
|
72
|
+
Object.const_defined?(:Warning) && Warning.respond_to?(:[]=)
|
73
|
+
|
56
74
|
at_exit {
|
57
75
|
next if $! and not ($!.kind_of? SystemExit and $!.success?)
|
58
76
|
|
@@ -60,7 +78,7 @@ module Minitest
|
|
60
78
|
|
61
79
|
pid = Process.pid
|
62
80
|
at_exit {
|
63
|
-
next if Process.pid != pid
|
81
|
+
next if !Minitest.allow_fork && Process.pid != pid
|
64
82
|
@@after_run.reverse_each(&:call)
|
65
83
|
exit exit_code || false
|
66
84
|
}
|
@@ -80,20 +98,19 @@ module Minitest
|
|
80
98
|
@@after_run << block
|
81
99
|
end
|
82
100
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
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
|
88
107
|
end
|
89
108
|
|
90
109
|
def self.load_plugins # :nodoc:
|
91
|
-
return unless
|
110
|
+
return unless defined? Gem
|
92
111
|
|
93
112
|
seen = {}
|
94
113
|
|
95
|
-
require "rubygems" unless defined? Gem
|
96
|
-
|
97
114
|
Gem.find_files("minitest/*_plugin.rb").each do |plugin_path|
|
98
115
|
name = File.basename plugin_path, "_plugin.rb"
|
99
116
|
|
@@ -105,69 +122,27 @@ module Minitest
|
|
105
122
|
end
|
106
123
|
end
|
107
124
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
# klass.new(runnable_method).run
|
124
|
-
|
125
|
-
def self.run args = []
|
126
|
-
self.load_plugins unless args.delete("--no-plugins") || ENV["MT_NO_PLUGINS"]
|
127
|
-
|
128
|
-
options = process_args args
|
129
|
-
|
130
|
-
reporter = CompositeReporter.new
|
131
|
-
reporter << SummaryReporter.new(options[:io], options)
|
132
|
-
reporter << ProgressReporter.new(options[:io], options)
|
133
|
-
|
134
|
-
self.reporter = reporter # this makes it available to plugins
|
135
|
-
self.init_plugins options
|
136
|
-
self.reporter = nil # runnables shouldn't depend on the reporter, ever
|
137
|
-
|
138
|
-
self.parallel_executor.start if parallel_executor.respond_to?(:start)
|
139
|
-
reporter.start
|
140
|
-
begin
|
141
|
-
__run reporter, options
|
142
|
-
rescue Interrupt
|
143
|
-
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
|
144
140
|
end
|
145
|
-
self.parallel_executor.shutdown
|
146
|
-
reporter.report
|
147
|
-
|
148
|
-
reporter.passed?
|
149
|
-
end
|
150
|
-
|
151
|
-
##
|
152
|
-
# Internal run method. Responsible for telling all Runnable
|
153
|
-
# sub-classes to run.
|
154
|
-
|
155
|
-
def self.__run reporter, options
|
156
|
-
suites = Runnable.runnables.reject { |s| s.runnable_methods.empty? }.shuffle
|
157
|
-
parallel, serial = suites.partition { |s| s.test_order == :parallel }
|
158
|
-
|
159
|
-
# If we run the parallel tests before the serial tests, the parallel tests
|
160
|
-
# could run in parallel with the serial tests. This would be bad because
|
161
|
-
# the serial tests won't lock around Reporter#record. Run the serial tests
|
162
|
-
# first, so that after they complete, the parallel tests will lock when
|
163
|
-
# recording results.
|
164
|
-
serial.map { |suite| suite.run reporter, options } +
|
165
|
-
parallel.map { |suite| suite.run reporter, options }
|
166
141
|
end
|
167
142
|
|
168
143
|
def self.process_args args = [] # :nodoc:
|
169
144
|
options = {
|
170
|
-
|
145
|
+
:io => $stdout,
|
171
146
|
}
|
172
147
|
orig_args = args.dup
|
173
148
|
|
@@ -191,6 +166,14 @@ module Minitest
|
|
191
166
|
options[:verbose] = true
|
192
167
|
end
|
193
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
|
+
|
194
177
|
opts.on "-n", "--name PATTERN", "Filter run on /regexp/ or string." do |a|
|
195
178
|
options[:filter] = a
|
196
179
|
end
|
@@ -199,13 +182,41 @@ module Minitest
|
|
199
182
|
options[:exclude] = a
|
200
183
|
end
|
201
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
|
+
|
202
203
|
unless extensions.empty?
|
203
204
|
opts.separator ""
|
204
|
-
opts.separator "Known extensions: #{extensions.join
|
205
|
-
|
206
|
-
extensions.each do |
|
207
|
-
|
208
|
-
|
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
|
209
220
|
end
|
210
221
|
end
|
211
222
|
|
@@ -228,15 +239,100 @@ module Minitest
|
|
228
239
|
orig_args << "--seed" << options[:seed].to_s
|
229
240
|
end
|
230
241
|
|
231
|
-
srand options[:seed]
|
232
|
-
|
233
242
|
options[:args] = orig_args.map { |s|
|
234
|
-
s
|
243
|
+
s.match?(/[\s|&<>$()]/) ? s.inspect : s
|
235
244
|
}.join " "
|
236
245
|
|
237
246
|
options
|
238
247
|
end
|
239
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
|
+
|
240
336
|
def self.filter_backtrace bt # :nodoc:
|
241
337
|
result = backtrace_filter.filter bt
|
242
338
|
result = bt.dup if result.empty?
|
@@ -307,24 +403,34 @@ module Minitest
|
|
307
403
|
# reporter to record.
|
308
404
|
|
309
405
|
def self.run reporter, options = {}
|
310
|
-
|
311
|
-
|
406
|
+
pos = options[:filter]
|
407
|
+
neg = options[:exclude]
|
312
408
|
|
313
|
-
|
314
|
-
|
315
|
-
}
|
316
|
-
|
317
|
-
exclude = options[:exclude]
|
318
|
-
exclude = Regexp.new $1 if exclude =~ %r%/(.*)/%
|
409
|
+
pos = Regexp.new $1 if pos.kind_of?(String) && pos =~ %r%/(.*)/%
|
410
|
+
neg = Regexp.new $1 if neg.kind_of?(String) && neg =~ %r%/(.*)/%
|
319
411
|
|
320
|
-
filtered_methods
|
321
|
-
|
322
|
-
|
412
|
+
filtered_methods = self.runnable_methods
|
413
|
+
.select { |m| !pos || pos === m || pos === "#{self}##{m}" }
|
414
|
+
.reject { |m| neg && (neg === m || neg === "#{self}##{m}") }
|
323
415
|
|
324
416
|
return if filtered_methods.empty?
|
325
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
|
+
|
326
429
|
with_info_handler reporter do
|
327
430
|
filtered_methods.each do |method_name|
|
431
|
+
name = method_name
|
432
|
+
t0 = Minitest.clock_time
|
433
|
+
|
328
434
|
run_one_method self, method_name, reporter
|
329
435
|
end
|
330
436
|
end
|
@@ -341,17 +447,16 @@ module Minitest
|
|
341
447
|
reporter.record Minitest.run_one_method(klass, method_name)
|
342
448
|
end
|
343
449
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
end
|
352
|
-
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
|
353
457
|
|
354
|
-
|
458
|
+
def self.with_info_handler reporter, &block # :nodoc:
|
459
|
+
on_signal ::Minitest.info_signal, @_info_handler, &block
|
355
460
|
end
|
356
461
|
|
357
462
|
SIGNALS = Signal.list # :nodoc:
|
@@ -389,7 +494,7 @@ module Minitest
|
|
389
494
|
def marshal_dump # :nodoc:
|
390
495
|
unless @@marshal_dump_warned then
|
391
496
|
warn ["Minitest::Runnable#marshal_dump is deprecated.",
|
392
|
-
"You might be violating internals. From", caller.first].join " "
|
497
|
+
"You might be violating internals. From", caller(1..1).first].join " "
|
393
498
|
@@marshal_dump_warned = true
|
394
499
|
end
|
395
500
|
|
@@ -408,6 +513,31 @@ module Minitest
|
|
408
513
|
self.name = name
|
409
514
|
self.failures = []
|
410
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
|
411
541
|
end
|
412
542
|
|
413
543
|
##
|
@@ -459,12 +589,14 @@ module Minitest
|
|
459
589
|
not self.failure
|
460
590
|
end
|
461
591
|
|
592
|
+
BASE_DIR = "#{Dir.pwd}/" # :nodoc:
|
593
|
+
|
462
594
|
##
|
463
595
|
# The location identifier of this test. Depends on a method
|
464
596
|
# existing called class_name.
|
465
597
|
|
466
598
|
def location
|
467
|
-
loc = " [#{self.failure.location}]" unless passed? or error?
|
599
|
+
loc = " [#{self.failure.location.delete_prefix BASE_DIR}]" unless passed? or error?
|
468
600
|
"#{self.class_name}##{self.name}#{loc}"
|
469
601
|
end
|
470
602
|
|
@@ -490,7 +622,7 @@ module Minitest
|
|
490
622
|
# Did this run error?
|
491
623
|
|
492
624
|
def error?
|
493
|
-
self.failures.any?
|
625
|
+
self.failures.any? UnexpectedError
|
494
626
|
end
|
495
627
|
end
|
496
628
|
|
@@ -528,6 +660,7 @@ module Minitest
|
|
528
660
|
r.assertions = o.assertions
|
529
661
|
r.failures = o.failures.dup
|
530
662
|
r.time = o.time
|
663
|
+
r.metadata = o.metadata if o.metadata?
|
531
664
|
|
532
665
|
r.source_location = o.method(o.name).source_location rescue ["unknown", -1]
|
533
666
|
|
@@ -552,7 +685,10 @@ module Minitest
|
|
552
685
|
# you want. Go nuts.
|
553
686
|
|
554
687
|
class AbstractReporter
|
555
|
-
|
688
|
+
|
689
|
+
def initialize # :nodoc:
|
690
|
+
@mutex = Mutex.new
|
691
|
+
end
|
556
692
|
|
557
693
|
##
|
558
694
|
# Starts reporting on the run.
|
@@ -588,6 +724,10 @@ module Minitest
|
|
588
724
|
def passed?
|
589
725
|
true
|
590
726
|
end
|
727
|
+
|
728
|
+
def synchronize &block # :nodoc:
|
729
|
+
@mutex.synchronize(&block)
|
730
|
+
end
|
591
731
|
end
|
592
732
|
|
593
733
|
class Reporter < AbstractReporter # :nodoc:
|
@@ -617,11 +757,11 @@ module Minitest
|
|
617
757
|
# own.
|
618
758
|
|
619
759
|
class ProgressReporter < Reporter
|
620
|
-
def prerecord klass, name
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
760
|
+
def prerecord klass, name # :nodoc:
|
761
|
+
return unless options[:verbose]
|
762
|
+
|
763
|
+
io.print "%s#%s = " % [klass.name, name]
|
764
|
+
io.flush
|
625
765
|
end
|
626
766
|
|
627
767
|
def record result # :nodoc:
|
@@ -691,6 +831,11 @@ module Minitest
|
|
691
831
|
|
692
832
|
attr_accessor :errors
|
693
833
|
|
834
|
+
##
|
835
|
+
# Total number of tests that warned.
|
836
|
+
|
837
|
+
attr_accessor :warnings
|
838
|
+
|
694
839
|
##
|
695
840
|
# Total number of tests that where skipped.
|
696
841
|
|
@@ -706,6 +851,7 @@ module Minitest
|
|
706
851
|
self.total_time = nil
|
707
852
|
self.failures = nil
|
708
853
|
self.errors = nil
|
854
|
+
self.warnings = nil
|
709
855
|
self.skips = nil
|
710
856
|
end
|
711
857
|
|
@@ -734,6 +880,7 @@ module Minitest
|
|
734
880
|
self.total_time = Minitest.clock_time - start_time
|
735
881
|
self.failures = aggregate[Assertion].size
|
736
882
|
self.errors = aggregate[UnexpectedError].size
|
883
|
+
self.warnings = aggregate[UnexpectedWarning].size
|
737
884
|
self.skips = aggregate[Skip].size
|
738
885
|
end
|
739
886
|
end
|
@@ -748,10 +895,8 @@ module Minitest
|
|
748
895
|
# own.
|
749
896
|
|
750
897
|
class SummaryReporter < StatisticsReporter
|
751
|
-
# :
|
752
|
-
attr_accessor :
|
753
|
-
attr_accessor :old_sync
|
754
|
-
# :startdoc:
|
898
|
+
attr_accessor :sync # :nodoc:
|
899
|
+
attr_accessor :old_sync # :nodoc:
|
755
900
|
|
756
901
|
def start # :nodoc:
|
757
902
|
super
|
@@ -761,7 +906,7 @@ module Minitest
|
|
761
906
|
io.puts "# Running:"
|
762
907
|
io.puts
|
763
908
|
|
764
|
-
self.sync = io.respond_to? :"sync="
|
909
|
+
self.sync = io.respond_to? :"sync="
|
765
910
|
self.old_sync, io.sync = io.sync, true if self.sync
|
766
911
|
end
|
767
912
|
|
@@ -784,9 +929,14 @@ module Minitest
|
|
784
929
|
|
785
930
|
def aggregated_results io # :nodoc:
|
786
931
|
filtered_results = results.dup
|
787
|
-
filtered_results.reject!(&:skipped?) unless
|
932
|
+
filtered_results.reject!(&:skipped?) unless
|
933
|
+
options[:verbose] or options[:show_skips]
|
934
|
+
|
935
|
+
skip = options[:skip] || []
|
788
936
|
|
789
937
|
filtered_results.each_with_index { |result, i|
|
938
|
+
next if skip.include? result.result_code
|
939
|
+
|
790
940
|
io.puts "\n%3d) %s" % [i+1, result]
|
791
941
|
}
|
792
942
|
io.puts
|
@@ -794,25 +944,22 @@ module Minitest
|
|
794
944
|
end
|
795
945
|
|
796
946
|
def to_s # :nodoc:
|
797
|
-
aggregated_results(StringIO.new(
|
947
|
+
aggregated_results(StringIO.new("".b)).string
|
798
948
|
end
|
799
949
|
|
800
950
|
def summary # :nodoc:
|
801
|
-
extra =
|
951
|
+
extra = []
|
802
952
|
|
803
|
-
extra
|
804
|
-
results.any?(&:skipped?) unless options[:verbose] or ENV["MT_NO_SKIP_MSG"]
|
953
|
+
extra << ", %d warnings" % [warnings] if options[:Werror]
|
805
954
|
|
806
|
-
"
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
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"]
|
811
960
|
|
812
|
-
|
813
|
-
|
814
|
-
else
|
815
|
-
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]
|
816
963
|
end
|
817
964
|
end
|
818
965
|
|
@@ -871,6 +1018,8 @@ module Minitest
|
|
871
1018
|
# Represents run failures.
|
872
1019
|
|
873
1020
|
class Assertion < Exception
|
1021
|
+
RE = /in [`'](?:[^']+[#.])?(?:assert|refute|flunk|pass|fail|raise|must|wont)/ # :nodoc:
|
1022
|
+
|
874
1023
|
def error # :nodoc:
|
875
1024
|
self
|
876
1025
|
end
|
@@ -879,12 +1028,11 @@ module Minitest
|
|
879
1028
|
# Where was this run before an assertion was raised?
|
880
1029
|
|
881
1030
|
def location
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
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 .*$/, "")
|
888
1036
|
end
|
889
1037
|
|
890
1038
|
def result_code # :nodoc:
|
@@ -909,11 +1057,21 @@ module Minitest
|
|
909
1057
|
# Assertion wrapping an unexpected error that was raised during a run.
|
910
1058
|
|
911
1059
|
class UnexpectedError < Assertion
|
1060
|
+
include Minitest::Compress
|
1061
|
+
|
912
1062
|
# TODO: figure out how to use `cause` instead
|
913
1063
|
attr_accessor :error # :nodoc:
|
914
1064
|
|
915
1065
|
def initialize error # :nodoc:
|
916
1066
|
super "Unexpected exception"
|
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
|
+
|
917
1075
|
self.error = error
|
918
1076
|
end
|
919
1077
|
|
@@ -921,8 +1079,11 @@ module Minitest
|
|
921
1079
|
self.error.backtrace
|
922
1080
|
end
|
923
1081
|
|
1082
|
+
BASE_RE = %r%#{Dir.pwd}/% # :nodoc:
|
1083
|
+
|
924
1084
|
def message # :nodoc:
|
925
|
-
bt = Minitest.filter_backtrace(self.backtrace).join
|
1085
|
+
bt = Minitest.filter_backtrace(self.backtrace).join("\n ")
|
1086
|
+
.gsub(BASE_RE, "")
|
926
1087
|
"#{self.error.class}: #{self.error.message}\n #{bt}"
|
927
1088
|
end
|
928
1089
|
|
@@ -931,6 +1092,15 @@ module Minitest
|
|
931
1092
|
end
|
932
1093
|
end
|
933
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
|
+
|
934
1104
|
##
|
935
1105
|
# Provides a simple set of guards that you can use in your tests
|
936
1106
|
# to skip execution if it is not applicable. These methods are
|
@@ -960,7 +1130,7 @@ module Minitest
|
|
960
1130
|
|
961
1131
|
def maglev? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
|
962
1132
|
where = Minitest.filter_backtrace(caller).first
|
963
|
-
where = where.split(
|
1133
|
+
where = where.split(":in ", 2).first # clean up noise
|
964
1134
|
warn "DEPRECATED: `maglev?` called from #{where}. This will fail in Minitest 6."
|
965
1135
|
"maglev" == platform
|
966
1136
|
end
|
@@ -969,14 +1139,14 @@ module Minitest
|
|
969
1139
|
# Is this running on mri?
|
970
1140
|
|
971
1141
|
def mri? platform = RUBY_DESCRIPTION
|
972
|
-
|
1142
|
+
platform.start_with? "ruby"
|
973
1143
|
end
|
974
1144
|
|
975
1145
|
##
|
976
1146
|
# Is this running on macOS?
|
977
1147
|
|
978
1148
|
def osx? platform = RUBY_PLATFORM
|
979
|
-
|
1149
|
+
platform.include? "darwin"
|
980
1150
|
end
|
981
1151
|
|
982
1152
|
##
|
@@ -984,7 +1154,7 @@ module Minitest
|
|
984
1154
|
|
985
1155
|
def rubinius? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
|
986
1156
|
where = Minitest.filter_backtrace(caller).first
|
987
|
-
where = where.split(
|
1157
|
+
where = where.split(":in ", 2).first # clean up noise
|
988
1158
|
warn "DEPRECATED: `rubinius?` called from #{where}. This will fail in Minitest 6."
|
989
1159
|
"rbx" == platform
|
990
1160
|
end
|
@@ -993,7 +1163,7 @@ module Minitest
|
|
993
1163
|
# Is this running on windows?
|
994
1164
|
|
995
1165
|
def windows? platform = RUBY_PLATFORM
|
996
|
-
/mswin|mingw
|
1166
|
+
/mswin|mingw/.match? platform
|
997
1167
|
end
|
998
1168
|
end
|
999
1169
|
|
@@ -1004,7 +1174,16 @@ module Minitest
|
|
1004
1174
|
|
1005
1175
|
class BacktraceFilter
|
1006
1176
|
|
1007
|
-
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
|
1008
1187
|
|
1009
1188
|
##
|
1010
1189
|
# Filter +bt+ to something useful. Returns the whole thing if
|
@@ -1015,9 +1194,9 @@ module Minitest
|
|
1015
1194
|
|
1016
1195
|
return bt.dup if $DEBUG || ENV["MT_DEBUG"]
|
1017
1196
|
|
1018
|
-
new_bt = bt.take_while { |line| line
|
1019
|
-
new_bt = bt.select { |line| line
|
1020
|
-
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?
|
1021
1200
|
|
1022
1201
|
new_bt
|
1023
1202
|
end
|