minitest 5.23.1 → 5.25.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/minitest.rb CHANGED
@@ -6,10 +6,11 @@ require_relative "minitest/parallel"
6
6
  require_relative "minitest/compress"
7
7
 
8
8
  ##
9
- # :include: README.rdoc
9
+ # The top-level namespace for Minitest. Also the location of the main
10
+ # runtime. See +Minitest.run+ for more information.
10
11
 
11
12
  module Minitest
12
- VERSION = "5.23.1" # :nodoc:
13
+ VERSION = "5.25.2" # :nodoc:
13
14
 
14
15
  @@installed_at_exit ||= false
15
16
  @@after_run = []
@@ -67,9 +68,8 @@ module Minitest
67
68
  # Registers Minitest to run at process exit
68
69
 
69
70
  def self.autorun
70
- if Object.const_defined?(:Warning) && Warning.respond_to?(:[]=)
71
- Warning[:deprecated] = true
72
- end
71
+ Warning[:deprecated] = true if
72
+ Object.const_defined?(:Warning) && Warning.respond_to?(:[]=)
73
73
 
74
74
  at_exit {
75
75
  next if $! and not ($!.kind_of? SystemExit and $!.success?)
@@ -98,20 +98,19 @@ module Minitest
98
98
  @@after_run << block
99
99
  end
100
100
 
101
- def self.init_plugins options # :nodoc:
102
- self.extensions.each do |name|
103
- msg = "plugin_#{name}_init"
104
- send msg, options if self.respond_to? msg
105
- end
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
106
107
  end
107
108
 
108
109
  def self.load_plugins # :nodoc:
109
- return unless self.extensions.empty?
110
+ return unless defined? Gem
110
111
 
111
112
  seen = {}
112
113
 
113
- require "rubygems" unless defined? Gem
114
-
115
114
  Gem.find_files("minitest/*_plugin.rb").each do |plugin_path|
116
115
  name = File.basename plugin_path, "_plugin.rb"
117
116
 
@@ -123,93 +122,27 @@ module Minitest
123
122
  end
124
123
  end
125
124
 
126
- ##
127
- # This is the top-level run method. Everything starts from here. It
128
- # tells each Runnable sub-class to run, and each of those are
129
- # responsible for doing whatever they do.
130
- #
131
- # The overall structure of a run looks like this:
132
- #
133
- # Minitest.autorun
134
- # Minitest.run(args)
135
- # Minitest.__run(reporter, options)
136
- # Runnable.runnables.each
137
- # runnable_klass.run(reporter, options)
138
- # self.runnable_methods.each
139
- # self.run_one_method(self, runnable_method, reporter)
140
- # Minitest.run_one_method(klass, runnable_method)
141
- # klass.new(runnable_method).run
142
-
143
- def self.run args = []
144
- self.load_plugins unless args.delete("--no-plugins") || ENV["MT_NO_PLUGINS"]
145
-
146
- options = process_args args
147
-
148
- Minitest.seed = options[:seed]
149
- srand Minitest.seed
150
-
151
- reporter = CompositeReporter.new
152
- reporter << SummaryReporter.new(options[:io], options)
153
- reporter << ProgressReporter.new(options[:io], options) unless options[:quiet]
154
-
155
- self.reporter = reporter # this makes it available to plugins
156
- self.init_plugins options
157
- self.reporter = nil # runnables shouldn't depend on the reporter, ever
158
-
159
- self.parallel_executor.start if parallel_executor.respond_to?(:start)
160
- reporter.start
161
- begin
162
- __run reporter, options
163
- rescue Interrupt
164
- 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
165
140
  end
166
- self.parallel_executor.shutdown
167
-
168
- # might have been removed/replaced during init_plugins:
169
- summary = reporter.reporters.grep(SummaryReporter).first
170
-
171
- reporter.report
172
-
173
- return empty_run! options if summary && summary.count == 0
174
- reporter.passed?
175
- end
176
-
177
- def self.empty_run! options # :nodoc:
178
- filter = options[:filter]
179
- return true unless filter # no filter, but nothing ran == success
180
-
181
- warn "Nothing ran for filter: %s" % [filter]
182
-
183
- require "did_you_mean" # soft dependency, punt if it doesn't load
184
-
185
- ms = Runnable.runnables.flat_map(&:runnable_methods)
186
- cs = DidYouMean::SpellChecker.new(dictionary: ms).correct filter
187
-
188
- warn DidYouMean::Formatter.message_for cs unless cs.empty?
189
- rescue LoadError
190
- # do nothing
191
- end
192
-
193
- ##
194
- # Internal run method. Responsible for telling all Runnable
195
- # sub-classes to run.
196
-
197
- def self.__run reporter, options
198
- suites = Runnable.runnables.shuffle
199
- parallel, serial = suites.partition { |s| s.test_order == :parallel }
200
-
201
- # If we run the parallel tests before the serial tests, the parallel tests
202
- # could run in parallel with the serial tests. This would be bad because
203
- # the serial tests won't lock around Reporter#record. Run the serial tests
204
- # first, so that after they complete, the parallel tests will lock when
205
- # recording results.
206
- serial.map { |suite| suite.run reporter, options } +
207
- parallel.map { |suite| suite.run reporter, options }
208
141
  end
209
142
 
210
143
  def self.process_args args = [] # :nodoc:
211
144
  options = {
212
- :io => $stdout,
145
+ :io => $stdout,
213
146
  }
214
147
  orig_args = args.dup
215
148
 
@@ -253,7 +186,7 @@ module Minitest
253
186
  options[:skip] = s.chars.to_a
254
187
  end
255
188
 
256
- ruby27plus = ::Warning.respond_to?(:[]=)
189
+ ruby27plus = ::Warning.respond_to? :[]=
257
190
 
258
191
  opts.on "-W[error]", String, "Turn Ruby warnings into errors" do |s|
259
192
  options[:Werror] = true
@@ -269,11 +202,21 @@ module Minitest
269
202
 
270
203
  unless extensions.empty?
271
204
  opts.separator ""
272
- opts.separator "Known extensions: #{extensions.join(", ")}"
273
-
274
- extensions.each do |meth|
275
- msg = "plugin_#{meth}_options"
276
- send msg, opts, options if self.respond_to?(msg)
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
277
220
  end
278
221
  end
279
222
 
@@ -297,12 +240,99 @@ module Minitest
297
240
  end
298
241
 
299
242
  options[:args] = orig_args.map { |s|
300
- s =~ /[\s|&<>$()]/ ? s.inspect : s
243
+ s.match?(/[\s|&<>$()]/) ? s.inspect : s
301
244
  }.join " "
302
245
 
303
246
  options
304
247
  end
305
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
+
306
336
  def self.filter_backtrace bt # :nodoc:
307
337
  result = backtrace_filter.filter bt
308
338
  result = bt.dup if result.empty?
@@ -376,8 +406,8 @@ module Minitest
376
406
  pos = options[:filter]
377
407
  neg = options[:exclude]
378
408
 
379
- pos = Regexp.new $1 if pos.is_a?(String) && pos =~ %r%/(.*)/%
380
- neg = Regexp.new $1 if neg.is_a?(String) && neg =~ %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%/(.*)/%
381
411
 
382
412
  filtered_methods = self.runnable_methods
383
413
  .select { |m| !pos || pos === m || pos === "#{self}##{m}" }
@@ -385,8 +415,22 @@ module Minitest
385
415
 
386
416
  return if filtered_methods.empty?
387
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
+
388
429
  with_info_handler reporter do
389
430
  filtered_methods.each do |method_name|
431
+ name = method_name
432
+ t0 = Minitest.clock_time
433
+
390
434
  run_one_method self, method_name, reporter
391
435
  end
392
436
  end
@@ -412,16 +456,7 @@ module Minitest
412
456
  end
413
457
 
414
458
  def self.with_info_handler reporter, &block # :nodoc:
415
- handler = lambda do
416
- unless reporter.passed? then
417
- warn "Current results:"
418
- warn ""
419
- warn reporter.reporters.first
420
- warn ""
421
- end
422
- end
423
-
424
- on_signal ::Minitest.info_signal, handler, &block
459
+ on_signal ::Minitest.info_signal, @_info_handler, &block
425
460
  end
426
461
 
427
462
  SIGNALS = Signal.list # :nodoc:
@@ -459,7 +494,7 @@ module Minitest
459
494
  def marshal_dump # :nodoc:
460
495
  unless @@marshal_dump_warned then
461
496
  warn ["Minitest::Runnable#marshal_dump is deprecated.",
462
- "You might be violating internals. From", caller.first].join " "
497
+ "You might be violating internals. From", caller(1..1).first].join " "
463
498
  @@marshal_dump_warned = true
464
499
  end
465
500
 
@@ -587,7 +622,7 @@ module Minitest
587
622
  # Did this run error?
588
623
 
589
624
  def error?
590
- self.failures.any? { |f| UnexpectedError === f }
625
+ self.failures.any? UnexpectedError
591
626
  end
592
627
  end
593
628
 
@@ -690,7 +725,7 @@ module Minitest
690
725
  true
691
726
  end
692
727
 
693
- def synchronize(&block) # :nodoc:
728
+ def synchronize &block # :nodoc:
694
729
  @mutex.synchronize(&block)
695
730
  end
696
731
  end
@@ -722,11 +757,11 @@ module Minitest
722
757
  # own.
723
758
 
724
759
  class ProgressReporter < Reporter
725
- def prerecord klass, name #:nodoc:
726
- if options[:verbose] then
727
- io.print "%s#%s = " % [klass.name, name]
728
- io.flush
729
- end
760
+ def prerecord klass, name # :nodoc:
761
+ return unless options[:verbose]
762
+
763
+ io.print "%s#%s = " % [klass.name, name]
764
+ io.flush
730
765
  end
731
766
 
732
767
  def record result # :nodoc:
@@ -860,10 +895,8 @@ module Minitest
860
895
  # own.
861
896
 
862
897
  class SummaryReporter < StatisticsReporter
863
- # :stopdoc:
864
- attr_accessor :sync
865
- attr_accessor :old_sync
866
- # :startdoc:
898
+ attr_accessor :sync # :nodoc:
899
+ attr_accessor :old_sync # :nodoc:
867
900
 
868
901
  def start # :nodoc:
869
902
  super
@@ -911,20 +944,22 @@ module Minitest
911
944
  end
912
945
 
913
946
  def to_s # :nodoc:
914
- aggregated_results(StringIO.new(''.b)).string
947
+ aggregated_results(StringIO.new("".b)).string
915
948
  end
916
949
 
917
950
  def summary # :nodoc:
918
- extra = ""
951
+ extra = []
919
952
 
920
- extra = "\n\nYou have skipped tests. Run with --verbose for details." if
921
- results.any?(&:skipped?) unless
922
- options[:verbose] or options[:show_skips] or ENV["MT_NO_SKIP_MSG"]
953
+ extra << ", %d warnings" % [warnings] if options[:Werror]
923
954
 
924
- extra.prepend ", %d warnings" % [warnings] if options[:Werror]
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"]
925
960
 
926
961
  "%d runs, %d assertions, %d failures, %d errors, %d skips%s" %
927
- [count, assertions, failures, errors, skips, extra]
962
+ [count, assertions, failures, errors, skips, extra.join]
928
963
  end
929
964
  end
930
965
 
@@ -1095,7 +1130,7 @@ module Minitest
1095
1130
 
1096
1131
  def maglev? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
1097
1132
  where = Minitest.filter_backtrace(caller).first
1098
- where = where.split(/:in /, 2).first # clean up noise
1133
+ where = where.split(":in ", 2).first # clean up noise
1099
1134
  warn "DEPRECATED: `maglev?` called from #{where}. This will fail in Minitest 6."
1100
1135
  "maglev" == platform
1101
1136
  end
@@ -1104,14 +1139,14 @@ module Minitest
1104
1139
  # Is this running on mri?
1105
1140
 
1106
1141
  def mri? platform = RUBY_DESCRIPTION
1107
- /^ruby/ =~ platform
1142
+ platform.start_with? "ruby"
1108
1143
  end
1109
1144
 
1110
1145
  ##
1111
1146
  # Is this running on macOS?
1112
1147
 
1113
1148
  def osx? platform = RUBY_PLATFORM
1114
- /darwin/ =~ platform
1149
+ platform.include? "darwin"
1115
1150
  end
1116
1151
 
1117
1152
  ##
@@ -1119,7 +1154,7 @@ module Minitest
1119
1154
 
1120
1155
  def rubinius? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
1121
1156
  where = Minitest.filter_backtrace(caller).first
1122
- where = where.split(/:in /, 2).first # clean up noise
1157
+ where = where.split(":in ", 2).first # clean up noise
1123
1158
  warn "DEPRECATED: `rubinius?` called from #{where}. This will fail in Minitest 6."
1124
1159
  "rbx" == platform
1125
1160
  end
@@ -1128,7 +1163,7 @@ module Minitest
1128
1163
  # Is this running on windows?
1129
1164
 
1130
1165
  def windows? platform = RUBY_PLATFORM
1131
- /mswin|mingw/ =~ platform
1166
+ /mswin|mingw/.match? platform
1132
1167
  end
1133
1168
  end
1134
1169
 
@@ -1139,11 +1174,14 @@ module Minitest
1139
1174
 
1140
1175
  class BacktraceFilter
1141
1176
 
1142
- MT_RE = %r%lib/minitest|internal:warning% #:nodoc:
1177
+ MT_RE = %r%lib/minitest|internal:warning% # :nodoc:
1178
+
1179
+ ##
1180
+ # The regular expression to use to filter backtraces. Defaults to +MT_RE+.
1143
1181
 
1144
1182
  attr_accessor :regexp
1145
1183
 
1146
- def initialize regexp = MT_RE
1184
+ def initialize regexp = MT_RE # :nodoc:
1147
1185
  self.regexp = regexp
1148
1186
  end
1149
1187
 
@@ -1156,9 +1194,9 @@ module Minitest
1156
1194
 
1157
1195
  return bt.dup if $DEBUG || ENV["MT_DEBUG"]
1158
1196
 
1159
- new_bt = bt.take_while { |line| line.to_s !~ regexp }
1160
- new_bt = bt.select { |line| line.to_s !~ regexp } if new_bt.empty?
1161
- new_bt = bt.dup if new_bt.empty?
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?
1162
1200
 
1163
1201
  new_bt
1164
1202
  end
@@ -3,10 +3,6 @@ require "stringio"
3
3
  require "minitest/autorun"
4
4
 
5
5
  class Minitest::Test
6
- def clean s
7
- s.gsub(/^ {6}/, "")
8
- end
9
-
10
6
  def with_empty_backtrace_filter
11
7
  with_backtrace_filter Minitest::BacktraceFilter.new %r%.% do
12
8
  yield
@@ -31,6 +27,7 @@ class Minitest::Test
31
27
  end
32
28
 
33
29
  def assert_deprecation re = /DEPRECATED/
30
+ re = // if $-w.nil? # "skip" if running `rake testW0`
34
31
  assert_output "", re do
35
32
  yield
36
33
  end
@@ -67,7 +64,7 @@ class MetaMetaMetaTestCase < Minitest::Test
67
64
  def run_tu_with_fresh_reporter flags = %w[--seed 42]
68
65
  options = Minitest.process_args flags
69
66
 
70
- @output = StringIO.new("".encode(Encoding::UTF_8))
67
+ @output = StringIO.new(+"")
71
68
 
72
69
  self.reporter = Minitest::CompositeReporter.new
73
70
  reporter << Minitest::SummaryReporter.new(@output, options)
@@ -76,7 +73,7 @@ class MetaMetaMetaTestCase < Minitest::Test
76
73
  with_stderr @output do
77
74
  reporter.start
78
75
 
79
- yield(reporter) if block_given?
76
+ yield reporter if block_given?
80
77
 
81
78
  @tus ||= [@tu]
82
79
  @tus.each do |tu|
@@ -94,8 +91,8 @@ class MetaMetaMetaTestCase < Minitest::Test
94
91
  end
95
92
 
96
93
  def assert_report expected, flags = %w[--seed 42], &block
97
- header = clean <<-EOM
98
- Run options: #{flags.map { |s| s =~ /\|/ ? s.inspect : s }.join " "}
94
+ header = <<~EOM
95
+ Run options: #{flags.map { |s| s.include?("|") ? s.inspect : s }.join " "}
99
96
 
100
97
  # Running:
101
98
 
@@ -130,7 +127,7 @@ class MetaMetaMetaTestCase < Minitest::Test
130
127
  output.gsub!(/in [`']block in (?:([^']+)[#.])?/, "in 'block in")
131
128
  output.gsub!(/in [`'](?:([^']+)[#.])?/, "in '")
132
129
 
133
- output.gsub!(/( at )[^:]+:\d+/) { "#{$1}[#{file[$2]}:LINE]" } # eval?
130
+ output.gsub!(/( at )([^:]+):\d+/) { "#{$1}[#{file[$2]}:LINE]" } # eval?
134
131
 
135
132
  output
136
133
  end